SPI2 Multiple cs-gpios

I’ve been trying to attach multiple SPI devices to SPI2 on the Duo but I’ve got a bit stuck.

As I understand it SPI2 only has one hardware CS so I’ve tried to use cs-gpios. This works if cs-gpios is a single value. With something like the below I can successfully drive an SPI screen attached to that CS.

cs-gpios = <&porta 22 GPIO_ACTIVE_LOW>;

However if I change it to the below then I see errors some timeout errors and the screen can’t be driven through /dev/fb0.

cs-gpios = <&porta 22 GPIO_ACTIVE_LOW>, <&porta 25 GPIO_ACTIVE_LOW>;

[    1.245165] fb_ili9341 spi0.1: SPI transfer timed out
[    1.250466] spi_master spi0: failed to transfer one message from queue

I’ve had some success by bringing in the latest 5.10 of drivers/spi and include/spi from the Raspberry Pi Linux repo. Using that I can have a list of multiple cs-gpios and the screen being attached to the first one works. However, if I try to write to the second one then I see timeouts.

I’ve also tried having my cs-gpios contain the hardware CS and a software one and encountered the same errors.

cs-gpios = <0> <&porta 22 GPIO_ACTIVE_LOW>;

This is the spi2 section from my cv1800b_milkv_duo_sd.dts file

&spi2 {
	status = "okay";
	cs-gpios = <&porta 22 GPIO_ACTIVE_LOW>, <&porta 25 GPIO_ACTIVE_LOW>;
	
	ili9341: ili9341@0 {
		compatible = "ilitek,ili9341";
		reg = <0>;
		status = "okay";
		spi-max-frequency = <48000000>;
		spi-cpol;
		spi-cpha;
		rotate = <270>;
		fps = <30>;
		bgr;
		buswidth = <8>;
		dc = <&porta 24 GPIO_ACTIVE_HIGH>;
		reset = <&porta 23 GPIO_ACTIVE_HIGH>;
		debug = <0x0>;
	};

	spidev@0{
		compatible = "spidev";
		reg = <1>;
		status = "okay";
		spi-max-frequency = <48000000>;
	};
};

Has anyone else had any luck with multiple CS pins or any ideas on how to proceed?

I use SPI LoRa radio and SPI ST7789 connected to other CS pins (also not defined in dts - using application)

Meshtastic Linux-Native port with TFT gui (m5stack cardkb i2c) - running on Ubuntu 22.04

1 Like

Thanks mark.birss. Reassuring at least to know it’s possible at the hardware level.

I’ve done a lot of digging. I’ve even tried the linux-next 6.9 with all the patches in to see if SPI worked there. Sadly it did not, which was quite a journey.

Anyway, for anyone who finds this, apply the patch that’s here to be able to use multiple chip-selects in the DTS file. SPI transfer fails with [Errno 110] Connection timed out when there are > 4 CS pins configured · Issue #6159 · raspberrypi/linux · GitHub

A quick guide for anybody who reads this now got it working on the 5.10 kernel in buildroot.

Apply this patch

diff --git a/linux_5.10/drivers/spi/spi-dw-core.c b/linux_5.10/drivers/spi/spi-dw-core.c
index c33866f74..1722c2753 100644
--- a/linux_5.10/drivers/spi/spi-dw-core.c
+++ b/linux_5.10/drivers/spi/spi-dw-core.c
@@ -102,7 +102,8 @@ void dw_spi_set_cs(struct spi_device *spi, bool enable)
         * support active-high or active-low CS level.
         */
        if (cs_high == enable)
-               dw_writel(dws, DW_SPI_SER, BIT(spi->chip_select));
+               dw_writel(dws, DW_SPI_SER,
+                       BIT(spi->cs_gpiod ? 0 : spi->chip_select));
        else
                dw_writel(dws, DW_SPI_SER, 0);
 }

And then you can patch the DTS file like this to create multiple spidev devices, or replace the spidevs with other peripherals.

&spi2 {
	status = "okay";
	cs-gpios = <&porta 22 GPIO_ACTIVE_LOW>, <&porta 25 GPIO_ACTIVE_LOW>;

	spidev@0 {
		compatible = "rohm,dh2228fv";
		reg = <0>;
		status = "okay";
		spi-max-frequency = <48000000>;
	};

	spidev@1 {
		compatible = "rohm,dh2228fv";
		reg = <1>;
		status = "okay";
		spi-max-frequency = <48000000>;
	};
};

See here for mappings. Look for things like XGPIOA[22]. Duo | Milk-V

Be aware that anything to use as a chip select must be muxed as a GPIO.

1 Like

Thank you for sharing your finding and fixes.

Using my approach as i did pictured is not working out on the DuoS at the moment…

On the Raspberry Pi we have to make use of that “dtoverlay=spi0-0cs” overlay to stop the kernel from locking the cs pins.

I will have to look into how that overlay for the Milk-V DuoS it seems

This might be what is still missing with the DuoS… when not using Buildroot OS

I’m not sure there’s anything super-useful I can add but there’s a couple of bits from my digging.

I think the Pi has mux support from the device-tree but the Duo doesn’t seem to yet but it looks like it’s in the works on the mainline patches so any muxing is initialised in U-Boot and then some is overridden with the duo-pinmux command in init.d.

The SPI2_CS pin will always be asserted even when using cs-gpios by the way, so you can’t use hardware CS with GPIO CS. You could re-use that pin though by using duo-pinmux to turn it into a GPIO and then using it as a CS.

Thank you, it helps my understanding