GPIO和SPI有什么关系?

gga*_*ngg 3 driver spi linux-kernel gpio raspberry-pi

我发现内核中的GPIO驱动程序留下/sys/class/gpio来控制gpio,但我发现GPIO也可以被控制/dev/mem,我发现这个映射可能在spi-bcm2708(它调用__ioremap作为平台驱动程序)中完成,但我不这样做了解spi和GPIO之间的关系,它们在linux中如何协同工作?

Sam*_*nko 5

据我了解,您正在谈论这个驱动程序(例如,在 Raspberry Pi 中使用)。首先,看一下BCM2835 datasheet。回顾下几节:

  • 1.1 概述
  • 6.0 通用 I/O (GPIO)
  • 6.2 替代功能分配(见表 6-31)

从驱动程序代码(参见bcm2708_init_pinmode()函数)和数据表(表6-31)中,我们可以看到SPI引脚实际上是GPIO7..11引脚。这些引脚实际上可以连接到不同的硬件模块(在本例中为 SPI 或 SD)。

替代功能分配

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

GPFSEL0地址

GPFSELn 寄存器说明

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

/*
 * 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
}
Run Code Online (Sandbox Code Playgroud)

这对我来说看起来像是快速破解,他们实际上提到了这一点:正确的方法是使用名为pinctrl的内核机制。

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

PS :如果您对 SPI 和 GPIO 之间可能的关系感到好奇,请阅读有关bit banging 的内容。请参阅Linux 内核中的spi-bitbang.c驱动程序示例。