Spidev with multiple CS unable to read

When using an SPI device with multiple chip selects (say /dev/spidev1.0 to /dev/spidev1.3), I’m unable to receive data from the devices spidev1.1 to spidev1.3. The read data is always 0xff even though the MISO line carries the correct information. When talking to spidev1.0 this problem does not occur. I suspect there is a problem with the spi-driver, since when changing the cs-gpios in the device tree, it’s always spidev1.0 that works, and spidev1.1 to spidev1.3 cause problems.

I’m on an apalis imx6. My image is built with OpenEmbedded/Yocto and based upon Apalis-iMX6_LXDE-Image_2.8b4.129-20181005. For the kernel package linux-toradex, I use a customized defconfig, device tree, and the patch MLK-15305-2: dma: imx-sdma: force to load context in sdma_config.

I’d appreciate any help in resolving this issue.

Relevant device tree bindings:

/* Apalis SPI1 */
&iomuxc {
    pinctrl_ekt_mot_spi: mot_spi {
        fsl,pins = <
		MX6QDL_PAD_EIM_OE__ECSPI2_MISO 0x100b1 // MOT_MISO
		MX6QDL_PAD_EIM_CS1__ECSPI2_MOSI 0x100b1 // MOT_MOSI
		MX6QDL_PAD_EIM_CS0__ECSPI2_SCLK 0x100b1 // MOT_SCK
		MX6QDL_PAD_EIM_RW__GPIO2_IO26 0x000b1 // MOT_nCS
	    MX6QDL_PAD_NANDF_D4__GPIO2_IO04 0x000b1   // MOT1_nCS
	    MX6QDL_PAD_NANDF_D5__GPIO2_IO05 0x000b1   // MOT2_nCS
	    MX6QDL_PAD_NANDF_D6__GPIO2_IO06 0x000b1   // MOT3_nCS
        >;
    };
};

&ecspi2 {
	status = "okay";
    fsl,spi-num-chipselects = <4>; // obsolete
    num-cs = <4>;
    cs-gpios = <&gpio2 26 GPIO_ACTIVE_HIGH>,
               <&gpio2 4 GPIO_ACTIVE_HIGH>,
               <&gpio2 5 GPIO_ACTIVE_HIGH>,
               <&gpio2 6 GPIO_ACTIVE_HIGH>;

    pinctrl-0 = <&pinctrl_ekt_mot_spi>;

	ekt_spi_tmc429: spi_tmc429@0 {
		compatible = "toradex,evalspi";
		reg = <0>;
		spi-max-frequency = <18000000>;
	};
    ekt_spi_tmc26x1: spi_tmc26x@1 {
		compatible = "toradex,evalspi";
		reg = <1>;
		spi-max-frequency = <18000000>;
	};
    ekt_spi_tmc26x2: spi_tmc26x@2 {
		compatible = "toradex,evalspi";
		reg = <2>;
		spi-max-frequency = <18000000>;
	};
    ekt_spi_tmc26x3: spi_tmc26x@3 {
		compatible = "toradex,evalspi";
		reg = <3>;
		spi-max-frequency = <18000000>;
	};
};

The following minimal code sample will always print “Read: -1” even though the logic analyzer shows the proper response on the MISO line. If /dev/spidev1.0 is used instead, the read value corresponds with the data on the MISO line.

#include <linux/spi/spidev.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    int result;

    int mode = SPI_CPOL | SPI_CPHA;

    uint32_t tx = 0x60000000 | 0x12000000 | 0x01000000;
    uint32_t rx = 0;

    struct spi_ioc_transfer xfr = {
        .tx_buf = (unsigned long)&tx,
        .rx_buf = (unsigned long)&rx,
        .len = 4,
        .bits_per_word = 8,
        .speed_hz = 1000000};

    int fd = open("/dev/spidev1.2", O_RDWR);
    result = ioctl(fd, SPI_IOC_WR_MODE32, &mode);
    if (result != 0)
        return result;

    result = ioctl(fd, SPI_IOC_MESSAGE(1), &xfr);

    printf("Read %d\n", rx);

    close(fd);
}  

Any chance you tried it with any supported BSP e.g. like BSP 2.8b5?

My image is built with OpenEmbedded/Yocto and based upon Apalis-iMX6_LXDE-Image_2.8b4.129-20181005.

I can confirm this problem also exists with the official 2.8b5 tezi image from BSP Layers and Reference Images for Yocto Project Software | Toradex Developer Center with device tree imx6q-apalis-eval.dts plus the changes mentioned in the question (and deleting the spidev@2 node defined in imx6qdl-apalis-eval.dtsi).

Please kindly have a look at the following device tree documentation:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/spi/spi-bus.txt#n30

If I understand the link correctly, I’ve already done what needs to be done. Only that it is not necessary to set num-cs if I use cs-gpios. The problem, however, still persists if I don’t set num-cs and fsl,spi-num-chipselects.

I’ve also tried to use MX6QDL_PAD_EIM_RW__ECSPI2_SS0 as a native chip select with

cs-gpios = <0>, 
                 <&gpio2 4 GPIO_ACTIVE_HIGH>,  
                 <&gpio2 5 GPIO_ACTIVE_HIGH>, 
                 <&gpio2 6 GPIO_ACTIVE_HIGH>;

to no avail.

OK, I think I have it narrowed down.

My first assumption, that it depends on the order of chip-selects was wrong.

The problem seems to be that I’m using GPIO pins as chip-selects that are not native chip-selects of the spi-controller. Maybe the spi-controller somehow monitors its chip-selects and only reads the MISO line when one of its chip-selects is low?

See Can't read from SPI with non-native chip-select GPIOs - Technical Support - Toradex Community as a follow up to this question.

Problem solved. The schematics of our carrier board has a buffer between the MISO testpin and the Apalis’ MISO pin with nEN driven by the MX6QDL_PAD_EIM_RW chip select line. That explains why the driver was only able to read when MX6QDL_PAD_EIM_RW was low.

Sorry for the confusion.

Perfect that it works. Thanks for the feedback.