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?
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.