I have an imx6q based board, which was designed with 6 devices connected to ecspi4.
conencting these to a different spi bus would be problematic for various reasons, and since we are using gpio chipselects, it seems like more than 4 spi devices ought to be supportable.
I have made an attempt that mostly works. I let cs0, cs1, and cs2 work the same as they always have, and reuse cs3 for cs3, cs4 and cs5:
The only problem is this shared cs3 arrangement make the spi master unreliable. calls to write to spi sometimes work and sometimes don't.
I am also observing that the CLK line for the spi seems to be active when it should not be, (possibly the source of instability). One of the devices sharing cs3 is a cs-active-high device, so this might contribute to the problem if there is some internal hardware state that think the same device is being accessed when it is not.
I also (less successfully) tried to reset the spi control register at the beginning of mx51_ecspi_config
Here is my patch:
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 3637847..751574c 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -314,6 +314,12 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
u32 ctrl = MX51_ECSPI_CTRL_ENABLE, cfg = 0, dma = 0;
u32 tx_wml_cfg, rx_wml_cfg, rxt_wml_cfg;
u32 clk = config->speed_hz, delay;
+ u8 cs;
+
+ if (config->cs < 3)
+ cs = config->cs;
+ else
+ cs = 3;
/*
* The hardware seems to have a race condition when changing modes. The
@@ -328,21 +334,21 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
ctrl |= mx51_ecspi_clkdiv(spi_imx->spi_clk, config->speed_hz, &clk);
/* set chip select to use */
- ctrl |= MX51_ECSPI_CTRL_CS(config->cs);
+ ctrl |= MX51_ECSPI_CTRL_CS(cs);
ctrl |= (config->bpw - 1) << MX51_ECSPI_CTRL_BL_OFFSET;
- cfg |= MX51_ECSPI_CONFIG_SBBCTRL(config->cs);
+ cfg |= MX51_ECSPI_CONFIG_SBBCTRL(cs);
if (config->mode & SPI_CPHA)
- cfg |= MX51_ECSPI_CONFIG_SCLKPHA(config->cs);
+ cfg |= MX51_ECSPI_CONFIG_SCLKPHA(cs);
if (config->mode & SPI_CPOL) {
- cfg |= MX51_ECSPI_CONFIG_SCLKPOL(config->cs);
- cfg |= MX51_ECSPI_CONFIG_SCLKCTL(config->cs);
+ cfg |= MX51_ECSPI_CONFIG_SCLKPOL(cs);
+ cfg |= MX51_ECSPI_CONFIG_SCLKCTL(cs);
}
if (config->mode & SPI_CS_HIGH)
- cfg |= MX51_ECSPI_CONFIG_SSBPOL(config->cs);
+ cfg |= MX51_ECSPI_CONFIG_SSBPOL(cs);
writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
writel(cfg, spi_imx->base + MX51_ECSPI_CONFIG);
Any thoughts on what I might try next would be appreciated.
If one of the chip selects needs to be active high you need to pass "spi-cs-high" property.
Take a look at: Documentation/devicetree/bindings/spi/spi-bus.txt and also at arch/arm/boot/dts/imx51-babbage.dts for an example.
I have set the chipselect appropriately for that device ( the nxp rtc-pcf2123)
In fact I know the the spi configurations for each device are correct individually, because if I take out any two, the remaining 4 devices function as expected.
With an unmodified spi-imx.c, accessing the 5th or 6th device results in an unkillable spidev_test process, and permantly locking up the spi master (until reboot).
Noting that the spi-imx.c driver bitshifts config options by the chipselect id, it cannot possibly work with more than 4 chipselects.
for reference, my spi dts section:
&ecspi5 {
fsl,spi-num-chipselects = <6>;
cs-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>,
<&gpio1 13 GPIO_ACTIVE_LOW>,
<&gpio1 12 GPIO_ACTIVE_LOW>,
<&gpio2 9 GPIO_ACTIVE_HIGH>,
<&gpio7 6 GPIO_ACTIVE_LOW>,
<&gpio7 7 GPIO_ACTIVE_LOW>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ecspi5 &pinctrl_ecspi5_cs>;
status = "okay";
pwr_mcu: lpc1227@0 {
compatible = "uniwest,evi-pb";
spi-max-frequency = <2450000>;
reg = <0>;
};
pb_flash: m25p80@1 {
compatible = "spidev";
spi-max-frequency = <2450000>;
reg = <1>;
};
temp0: temp@3 {
compatible = "spidev";
spi-max-frequency = <2450000>;
reg = <2>;
};
pb_rtc: rtc@2 {
compatible = "nxp,rtc-pcf2123";
spi-max-frequency = <2450000>;
spi-cs-high;
reg = <3>;
};
temp1: temp@4 {
compatible = "spidev";
spi-max-frequency = <2450000>;
reg = <4>;
};
lvds_dim: lvds_dim@5 {
compatible = "spidev";
spi-max-frequency = <2450000>;
reg = <5>;
};
};
&ecspi5 {
fsl,spi-num-chipselects = <6>;
cs-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>,
<&gpio1 13 GPIO_ACTIVE_LOW>,
<&gpio1 12 GPIO_ACTIVE_LOW>,
<&gpio2 9 GPIO_ACTIVE_HIGH>,
<&gpio7 6 GPIO_ACTIVE_LOW>,
<&gpio7 7 GPIO_ACTIVE_LOW>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ecspi5 &pinctrl_ecspi5_cs>;
status = "okay";
pwr_mcu: lpc1227@0 {
compatible = "uniwest,evi-pb";
spi-max-frequency = <2450000>;
reg = <0>;
};
pb_flash: m25p80@1 {
compatible = "spidev";
spi-max-frequency = <2450000>;
reg = <1>;
};
temp0: temp@3 {
compatible = "spidev";
spi-max-frequency = <245000>;
reg = <2>;
};
pb_rtc: rtc@2 {
compatible = "nxp,rtc-pcf2123";
spi-max-frequency = <2450000>;
spi-cs-high;
reg = <3>;
};
temp1: temp@4 {
compatible = "spidev";
spi-max-frequency = <2450000>;
reg = <4>;
};
lvds_dim: lvds_dim@5 {
compatible = "spidev";
spi-max-frequency = <2450000>;
reg = <5>;
};
};
Just a comment about your dts: the @x number must match the reg = <x> field. It seems you swapped @2 and @3 nodes.
Thanks, Fabio.
I'm sure that the wrong addresses are the result of all the experimentation I was doing.
I fixed them and didn't see a change (though I didn't expect one).