我发现内核中的GPIO驱动程序离开/sys/class/gpio
来控制gpio,但我发现GPIO也可以由/dev/mem
控制,我发现这个映射可以在spi-bcm2708中完成(其中将__ioremap
称为平台驱动程序,但我不了解spi和GPIO之间的关系,它们如何在linux中协同工作?
答案 0 :(得分:3)
据我所知,您正在谈论this驱动程序(例如,在Raspberry Pi中使用)。首先,看看BCM2835 datasheet。查看下一节:
从驱动程序代码(参见bcm2708_init_pinmode()函数)和数据表(表6-31),我们可以看到SPI引脚实际上是GPIO7..11引脚。这些引脚实际上可以连接到不同的hardware modules(在这种情况下为SPI或SD)。
使用pin muxing完成此类选择。所以基本上你需要将GPIO7..GPIO11引脚连接到SPI模块。为此,您需要为每个GPIO7..GPIO11引脚选择 ALT0 功能。这可以通过将相应的值写入 GPFSEL0 和 GPFSEL1 寄存器来完成(参见数据表中的表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引脚,它只是执行引脚复用以便将GPIO7..GPIO11引脚连接到SPI模块。为此,该驱动程序写入GPFSELn寄存器,这恰好是GPIO寄存器。这几乎是该驱动程序中SPI和GPIO之间的所有关系。
P.S。:如果您对SPI和GPIO之间可能的关系感到好奇,请阅读bit banging。请参阅Linux内核中的spi-bitbang.c驱动程序。