3

I found GPIO driver in the kernel leave /sys/class/gpio to control gpio, but I found GPIO can be controlled by /dev/mem as well, I found this mapping may be done in the spi-bcm2708 (which call the __ioremap as a platform driver), but I don't understand the relationship between spi and GPIO,how they work together in the linux?

Sam Protsenko
  • 14,045
  • 4
  • 59
  • 75
ggaaooppeenngg
  • 1,323
  • 3
  • 17
  • 27

1 Answers1

5

As I understand you are talking about this driver (which is used, for example, in Raspberry Pi). First of all, take a look at BCM2835 datasheet. Review next sections:

  • 1.1 Overview
  • 6.0 General Purpose I/O (GPIO)
  • 6.2 Alternative Functions Assignments (see Table 6-31)

From driver code (see 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 (either SPI or SD, in this case).

Alternative Functions Assignment

Such a selection is done using pin muxing. So basically you need to connect GPIO7..GPIO11 pins to SPI module. To do so you need to select ALT0 function for each of GPIO7..GPIO11 pins. This can be done by writing corresponding values to GPFSEL0 and GPFSEL1 registers (see tables 6-1..6-3 in datasheet):

GPFSEL0 address

GPFSELn register description

And this is how the driver is actually doing this:

/*
 * 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
}

which looks like quick hack to me, and they actually mentioned it: the correct way would be to use kernel mechanism called pinctrl.

Conclusion: BCM2708 driver doesn't actually trigger any GPIO pins, it's just doing pin muxing in order to connect GPIO7..GPIO11 pins to SPI module. And to do so this driver writes to GPFSELn registers, which happen to be GPIO registers. This is pretty much all relationship between SPI and GPIO in this driver.

P.S.: if you are curious about possible relationship between SPI and GPIO, read about bit banging. See for example spi-bitbang.c driver in Linux kernel.

Sam Protsenko
  • 14,045
  • 4
  • 59
  • 75