spi: use specific last_cs instead of last_cs_enable
authorYun Zhou <yun.zhou@windriver.com>
Thu, 17 Feb 2022 14:12:34 +0000 (22:12 +0800)
committerMark Brown <broonie@kernel.org>
Mon, 28 Feb 2022 13:36:16 +0000 (13:36 +0000)
Commit d40f0b6f2e21 instroduced last_cs_enable to avoid setting
chipselect if it's not necessary, but it also introduces a bug. The
chipselect may not be set correctly on multi-device SPI busses. The
reason is that we can't judge the chipselect by bool last_cs_enable,
since chipselect may be modified after other devices were accessed.

So we should record the specific state of chipselect in case of
confusion.

Signed-off-by: Yun Zhou <yun.zhou@windriver.com>
Link: https://lore.kernel.org/r/20220217141234.72737-1-yun.zhou@windriver.com
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/spi/spi.c
include/linux/spi/spi.h

index cd4dc31..6326e59 100644 (file)
@@ -926,13 +926,14 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
         * Avoid calling into the driver (or doing delays) if the chip select
         * isn't actually changing from the last time this was called.
         */
-       if (!force && (spi->controller->last_cs_enable == enable) &&
+       if (!force && ((enable && spi->controller->last_cs == spi->chip_select) ||
+                               (!enable && spi->controller->last_cs != spi->chip_select)) &&
            (spi->controller->last_cs_mode_high == (spi->mode & SPI_CS_HIGH)))
                return;
 
        trace_spi_set_cs(spi, activate);
 
-       spi->controller->last_cs_enable = enable;
+       spi->controller->last_cs = enable ? spi->chip_select : -1;
        spi->controller->last_cs_mode_high = spi->mode & SPI_CS_HIGH;
 
        if ((spi->cs_gpiod || !spi->controller->set_cs_timing) && !activate) {
@@ -3016,6 +3017,9 @@ int spi_register_controller(struct spi_controller *ctlr)
                goto free_bus_id;
        }
 
+       /* setting last_cs to -1 means no chip selected */
+       ctlr->last_cs = -1;
+
        status = device_add(&ctlr->dev);
        if (status < 0)
                goto free_bus_id;
index 579d71c..7d005fa 100644 (file)
@@ -370,7 +370,8 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch
  * @cur_msg_prepared: spi_prepare_message was called for the currently
  *                    in-flight message
  * @cur_msg_mapped: message has been mapped for DMA
- * @last_cs_enable: was enable true on the last call to set_cs.
+ * @last_cs: the last chip_select that is recorded by set_cs, -1 on non chip
+ *           selected
  * @last_cs_mode_high: was (mode & SPI_CS_HIGH) true on the last call to set_cs.
  * @xfer_completion: used by core transfer_one_message()
  * @busy: message pump is busy
@@ -603,7 +604,7 @@ struct spi_controller {
        bool                            auto_runtime_pm;
        bool                            cur_msg_prepared;
        bool                            cur_msg_mapped;
-       bool                            last_cs_enable;
+       char                            last_cs;
        bool                            last_cs_mode_high;
        bool                            fallback;
        struct completion               xfer_completion;