linux-kernellinux-device-driverembedded-linuxspidevice-tree

How do I add a proper description of the spi bus in DTS?


I have a project, where there is a main board with CPU and a daughter board with two e-metering chips, connected to main board with SPI bus. CPU acts as a controller for this bus, it runs on Linux, ARM architecture.

I've been tasked to write a driver (builtin kernel module) for this daughter board, but I have very limited practical experience with SPI linux drivers. This picture shows how my architecture looks. The issue is that different CPU gpios act as Chipselect for each e-meter chip, other "wires" are shared. GPIOS cannot be changed, they are depicted as they are present in schematics.

In Linux spi API, struct spi_device has a cs_gpio field, but no other fields describing miso/mosi/rst and other gpios, so I guess I have to add a proper description of the spi bus in DTS. The question is how to do it correctly? Unfortunately, I can't find a proper dts description, or full description of it's fields I may need. The fact that there are two chips makes it even harder :(

Note, that each chip measurements should be written in different sysfs attributes, as they measure electricity from different power lines. This should be implemented in a single driver, so it can't be instantiated twice for each chip, it should run for both of them, not like in this post answers.

I started by implementing a simple spi driver, but I have no idea what values should be in struct spi_board_info chip_select and bus_num fields, and in struct spi_device there is only cs_gpio field, and no fields for describing mosi/miso/rst/sck lines (gpios).

To sum this up, can you please guide me how to write a dts for my daughter board and spi bus, or tell how to instantiate in a driver / dts that spi bus wires are controlled by the exact gpios?


Solution

  • So thanks to @IanAbbott I found out about spi-gpio driver in Linux (src), and device tree binding description here.

    So this is a proper device tree:

    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>;
        };
    };
    

    The idea is to use spi-gpio driver to communicate with e-meter chips, it can be done via spidev in userspace or in a different kernel module. More info in my other question.