GPIO和SPI有什么关系?

What's the relationship between GPIO and SPI?

我发现内核中的 GPIO 驱动离开 /sys/class/gpio 来控制 gpio,但我发现 GPIO 也可以被 /dev/mem 控制,我发现这个映射可以在 spi-bcm2708 中完成(将 __ioremap 称为平台驱动程序),但我不明白 spi 和 GPIO 之间的关系,它们如何在 linux?

中协同工作

据我了解,您说的是 this driver (which is used, for example, in Raspberry Pi). First of all, take a look at BCM2835 datasheet。查看接下来的部分:

  • 1.1 概述
  • 6.0 通用 I/O (GPIO)
  • 6.2 替代函数赋值(参见Table 6-31)

来自驱动程序代码(参见 bcm2708_init_pinmode() function) and datasheet (table 6-31), we can see that SPI pins are actually GPIO7..11 pins. Those pins can be actually connected to different hardware modules(在本例中为 SPI 或 SD)。

这样的 selection 是使用 pin muxing 完成的。所以基本上你需要将 GPIO7..GPIO11 引脚连接到 SPI 模块。为此,您需要为每个 GPIO7..GPIO11 引脚执行 select ALT0 功能。这可以通过将相应的值写入 GPFSEL0GPFSEL1 寄存器来完成(参见数据表中的表 6-1..6-3):

这就是驱动程序实际执行此操作的方式:

/*
 * This function sets the ALT mode on the SPI pins so that we can use them with
 * the SPI hardware.
 *
 * FIXME: This is a hack. Use pinmux / pinctrl.
 */
static void bcm2708_init_pinmode(void)
{
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define SET_GPIO_ALT(g, a) *(gpio+(((g)/10))) |= (((a) <= 3 ? (a)+4 : (a) == 4 ? 3 : 2)<<(((g)%10)*3))

    int pin;
    u32 *gpio = ioremap(GPIO_BASE, SZ_16K);

    /* SPI is on GPIO 7..11 */
    for (pin = 7; pin <= 11; pin++) {
        INP_GPIO(pin);      /* set mode to GPIO input first */
        SET_GPIO_ALT(pin, 0);   /* set mode to ALT 0 */
    }

    iounmap(gpio);

#undef INP_GPIO
#undef SET_GPIO_ALT
}

对我来说这看起来像是快速破解,他们实际上提到了它:正确的方法是使用称为 pinctrl.

的内核机制

结论:BCM2708 驱动程序实际上并没有触发任何 GPIO 引脚,它只是在进行 pin muxing 以连接 GPIO7.. GPIO11 引脚到 SPI 模块。为此,该驱动程序写入 GPFSELn 寄存器,而这些寄存器恰好是 GPIO 寄存器。这几乎就是这个驱动程序中 SPI 和 GPIO 之间的所有关系。

P.S.:如果您对 SPI 和 GPIO 之间的可能关系感到好奇,请阅读 bit banging. See for example spi-bitbang.c Linux 内核中的驱动程序。