ath79: replace chipselect workaround with a proper patch
authorDavid Bauer <mail@david-bauer.net>
Wed, 3 Mar 2021 16:23:16 +0000 (17:23 +0100)
committerDavid Bauer <mail@david-bauer.net>
Thu, 4 Mar 2021 23:03:47 +0000 (00:03 +0100)
Debugging the SPI CS issue with kernel 5.10 resulted in a better
understanding for the root cause and a proper patch with a better
explanation.

Exchange the old hack patch with a more efficient (and upstreamable)
solution.

Signed-off-by: David Bauer <mail@david-bauer.net>
target/linux/ath79/patches-5.10/0054-spi-always-write-cs.patch [deleted file]
target/linux/ath79/patches-5.10/0054-spi-sync-up-initial-chipselect-state.patch [new file with mode: 0644]

diff --git a/target/linux/ath79/patches-5.10/0054-spi-always-write-cs.patch b/target/linux/ath79/patches-5.10/0054-spi-always-write-cs.patch
deleted file mode 100644 (file)
index 1e461ce..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-Upstream commit d40f0b6f2e21 ("spi: Avoid settingthe chip select if
-we don't need to") causes the SPI CS only to be asserted once and not
-if it's state stays the same.
-
-This seems to cause problems with the SPI on the AR724x and the AR913x
-(but not the AR71xx). AR934x and subsequent chips do not look affected.
-
-ToDo:
- - Analyze if this is a hardware bug or a bug in the software.
- - Send a cleaned up patch upstream.
-
-Signed-off-by: David Bauer <mail@david-bauer.net>
-
---- a/drivers/spi/spi.c
-+++ b/drivers/spi/spi.c
-@@ -791,6 +791,7 @@ static void spi_set_cs(struct spi_device
- {
-       bool enable1 = enable;
-+#if 0
-       /*
-        * Avoid calling into the driver (or doing delays) if the chip select
-        * isn't actually changing from the last time this was called.
-@@ -801,6 +802,7 @@ static void spi_set_cs(struct spi_device
-       spi->controller->last_cs_enable = enable;
-       spi->controller->last_cs_mode_high = spi->mode & SPI_CS_HIGH;
-+#endif
-       if (!spi->controller->set_cs_timing) {
-               if (enable1)
diff --git a/target/linux/ath79/patches-5.10/0054-spi-sync-up-initial-chipselect-state.patch b/target/linux/ath79/patches-5.10/0054-spi-sync-up-initial-chipselect-state.patch
new file mode 100644 (file)
index 0000000..7329ae5
--- /dev/null
@@ -0,0 +1,89 @@
+From 4b7d7f85abac1e7ad9e8b745694e470f0729f527 Mon Sep 17 00:00:00 2001
+From: David Bauer <mail@david-bauer.net>
+Date: Wed, 3 Mar 2021 17:11:34 +0100
+Subject: [PATCH] spi: sync up initial chipselect state
+
+When initially probing the SPI slave device, the call for disabling an
+SPI device without the SPI_CS_HIGH flag is not applied, as the
+condition for checking whether or not the state to be applied equals the
+one currently set evaluates to true.
+
+This however might not necessarily be the case, as the chipselect might
+be active.
+
+Add a force flag to spi_set_cs which allows to override this
+early access condition. Set it to false everywhere except when called
+from spi_setup to sync up the initial CS state.
+
+Fixes commit d40f0b6f2e21 ("spi: Avoid setting the chip select if we don't
+need to")
+
+Signed-off-by: David Bauer <mail@david-bauer.net>
+---
+ drivers/spi/spi.c | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+--- a/drivers/spi/spi.c
++++ b/drivers/spi/spi.c
+@@ -787,7 +787,7 @@ int spi_register_board_info(struct spi_b
+ /*-------------------------------------------------------------------------*/
+-static void spi_set_cs(struct spi_device *spi, bool enable)
++static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
+ {
+       bool enable1 = enable;
+@@ -795,7 +795,7 @@ static void spi_set_cs(struct spi_device
+        * Avoid calling into the driver (or doing delays) if the chip select
+        * isn't actually changing from the last time this was called.
+        */
+-      if ((spi->controller->last_cs_enable == enable) &&
++      if (!force && (spi->controller->last_cs_enable == enable) &&
+           (spi->controller->last_cs_mode_high == (spi->mode & SPI_CS_HIGH)))
+               return;
+@@ -1243,7 +1243,7 @@ static int spi_transfer_one_message(stru
+       struct spi_statistics *statm = &ctlr->statistics;
+       struct spi_statistics *stats = &msg->spi->statistics;
+-      spi_set_cs(msg->spi, true);
++      spi_set_cs(msg->spi, true, false);
+       SPI_STATISTICS_INCREMENT_FIELD(statm, messages);
+       SPI_STATISTICS_INCREMENT_FIELD(stats, messages);
+@@ -1311,9 +1311,9 @@ fallback_pio:
+                                        &msg->transfers)) {
+                               keep_cs = true;
+                       } else {
+-                              spi_set_cs(msg->spi, false);
++                              spi_set_cs(msg->spi, false, false);
+                               _spi_transfer_cs_change_delay(msg, xfer);
+-                              spi_set_cs(msg->spi, true);
++                              spi_set_cs(msg->spi, true, false);
+                       }
+               }
+@@ -1322,7 +1322,7 @@ fallback_pio:
+ out:
+       if (ret != 0 || !keep_cs)
+-              spi_set_cs(msg->spi, false);
++              spi_set_cs(msg->spi, false, false);
+       if (msg->status == -EINPROGRESS)
+               msg->status = ret;
+@@ -3400,11 +3400,11 @@ int spi_setup(struct spi_device *spi)
+                */
+               status = 0;
+-              spi_set_cs(spi, false);
++              spi_set_cs(spi, false, true);
+               pm_runtime_mark_last_busy(spi->controller->dev.parent);
+               pm_runtime_put_autosuspend(spi->controller->dev.parent);
+       } else {
+-              spi_set_cs(spi, false);
++              spi_set_cs(spi, false, true);
+       }
+       mutex_unlock(&spi->controller->io_mutex);