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

最佳答案

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

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

  • 从驱动代码(见bcm2708_init_pinmode()函数)和datasheet(表6-31)可以看出,SPI引脚实际上是GPIO7..11引脚。这些引脚实际上可以连接到不同的 hardware modules(在这种情况下是 SPI 或 SD)。

    linux-kernel - GPIO和SPI有什么关系?-LMLPHP

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

    linux-kernel - GPIO和SPI有什么关系?-LMLPHP

    linux-kernel - GPIO和SPI有什么关系?-LMLPHP

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

    /*
     * 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 驱动程序。

    关于linux-kernel - GPIO和SPI有什么关系?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31635576/

    10-13 04:56