clinux-kernellinux-device-driverembedded-linuxspi

How do I use spi-gpio driver in Linux?


I have a device which runs on linux and I have to write a kernel module that will poll two external devices via SPI bus. This bus is based on CPU GPIOs, so the strategy is to bitbang external devices to get data. To prevent further questions: I can't change the architecture, it has to be bitbanging, and it has to be a kernel built-in module.

The problem is, it's unclear how to use spi-gpio driver (src). In the driver code there is an explanation:

/*
 * Because the overhead of going through four GPIO procedure calls
 * per transferred bit can make performance a problem, this code
 * is set up so that you can use it in either of two ways:
 *
 *   - The slow generic way:  set up platform_data to hold the GPIO
 *     numbers used for MISO/MOSI/SCK, and issue procedure calls for
 *     each of them.  This driver can handle several such busses.
 *
 *   - The quicker inlined way:  only helps with platform GPIO code
 *     that inlines operations for constant GPIOs.  This can give
 *     you tight (fast!) inner loops, but each such bus needs a
 *     new driver.  You'll define a new C file, with Makefile and
 *     Kconfig support; the C code can be a total of six lines:
 *
 *      #define DRIVER_NAME "myboard_spi2"
 *      #define SPI_MISO_GPIO   119
 *      #define SPI_MOSI_GPIO   120
 *      #define SPI_SCK_GPIO    121
 *      #define SPI_N_CHIPSEL   4
 *      #include "spi-gpio.c"
 */

I've added some data in Devicetree:

spi-gpio {
    compatible = "spi-gpio";
    #address-cells = <0x1>;
    ranges;
    status = "okay";

    sck-gpios   = <&pio 4 9 GPIO_ACTIVE_HIGH>;  // PE9
    mosi-gpios  = <&pio 4 6 GPIO_ACTIVE_HIGH>;  // PE6
    miso-gpios  = <&pio 4 8 GPIO_ACTIVE_HIGH>;  // PE8
    cs-gpios    = <&pio 4 4 GPIO_ACTIVE_HIGH>,  // PE4
                  <&pio 4 17 GPIO_ACTIVE_HIGH>; // PE17
    num-chipselects = <2>;

    /* Clients */
    m90e32@0 {
        reg = <0>;
        compatible = "atmel,m90e32";
        spi-max-frequency = <950000>;
    };

    m90e32@1 {
        reg = <1>;
        compatible = "atmel,m90e32";
        spi-max-frequency = <950000>;
    };
};

If I use a second method described in spi-gpio.c, write another kernel module is this way:

#define DRIVER_NAME "myboard_spi2"
#define SPI_MISO_GPIO   119
#define SPI_MOSI_GPIO   120
#define SPI_SCK_GPIO    121
#define SPI_N_CHIPSEL   4
#include "spi-gpio.c"

How do I add a poll cycle in this code? Or do I have to write an overlay for spi-gpio.c and add a poll task there? Personally, I want to go the first way and just use procedures and structures I need from spi-gpio.c. But it's very unclear how to do it correctly and I can't find any examples.

Which methods from this module and in which order do I have to use to create two SPI devices in my module to work with them?


Solution

  • So, after experimenting I've done it, the way it was intended. Device tree looks like this:

    // SPI E-Meter Bus
    spi-gpio {
        compatible = "spi-gpio";
        #address-cells = <0x1>;
        ranges;
        status = "okay";
    
        sck-gpios   = <&pio 4 9 GPIO_ACTIVE_HIGH>;  // PE9
        mosi-gpios  = <&pio 4 6 GPIO_ACTIVE_HIGH>;  // PE6
        miso-gpios  = <&pio 4 8 GPIO_ACTIVE_HIGH>;  // PE8
        cs-gpios    = <&pio 4 4 GPIO_ACTIVE_HIGH>,  // PE4
                      <&pio 4 17 GPIO_ACTIVE_HIGH>; // PE17
        num-chipselects = <2>;
    
        /* Clients */
        m90e32@0 {
            reg = <0>;
            compatible = "atmel,m90e32";
            spi-max-frequency = <100000>;
        };
    
        m90e32@1 {
            reg = <1>;
            compatible = "atmel,m90e32";
            spi-max-frequency = <100000>;
        };
    };
    

    Then I've written spi_driver (not platform driver):

    static const struct of_device_id m90e32_spi_gpio_ids[] = {
        { .compatible = "atmel,m90e32" },
        {}
    };
    MODULE_DEVICE_TABLE(of, m90e32_spi_gpio_ids);
    
    static struct spi_driver m90e32_driver = {
        .driver = {
            .name   = SPI_DRIVER_NAME,
            .of_match_table = of_match_ptr(m90e32_spi_gpio_ids),
        },
        .probe      = m90e32as_probe,
        .remove     = m90e32as_remove,
    };
    module_spi_driver(m90e32_driver);
    

    Probe function is called twice, one time for each m90e32 device. However, there is only one driver instance. There I can read chipselect info to tell them apart, and save pointer to spi_device for future use. It comes to help when I want to use spi_write_** function. spi-gpio module works on it's own, you don't have to explicitly call it to transfer spi messages.