linux-spi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] spi: dw: Fix dynamic speed change
@ 2014-11-04 22:36 tthayer-yzvPICuk2ABMcg4IHK0kFoH6Mc4MB0Vx
       [not found] ` <1415140617-2028-1-git-send-email-tthayer-yzvPICuk2ABMcg4IHK0kFoH6Mc4MB0Vx@public.gmane.org>
  0 siblings, 1 reply; 9+ messages in thread
From: tthayer-yzvPICuk2ABMcg4IHK0kFoH6Mc4MB0Vx @ 2014-11-04 22:36 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A
  Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA,
	feng.tang-ral2JQCrhuEAvxtiuMwx3w, setka-3PjVBYxTQDg,
	tthayer-EIB2kfCEclfQT0dZR+AlfA,
	andriy.shevchenko-VuQAYsv1563Yd54FQh9/CA, Thor Thayer

From: Thor Thayer <tthayer-yzvPICuk2ABMcg4IHK0kFoH6Mc4MB0Vx@public.gmane.org>

Changing SPI transfer speed using a utility such as spi_config with
spidev updates chip->speed_hz which is compared to the next transfer
speed.

When speed_hz is not declared in a SPI transfer, the transfer speed is
not updated for the next read/write on /dev/spidevX.Y. The element
spi_transfer->speed_hz is filled with spi->max_speed_hz. The test of
if (transfer->speed_hz != speed) doesn't work because the chip->speed_hz
matches transfer->speed_hz and the clock divider is not updated.

This fix: On each transfer update the clock divider, compare to the
previous clock divider and update if necessary. This fixes another
bug where the clock divider calculation at the top of the
pump_transfers() function could be an odd-number.

Reported-by: Vlastimil Setka <setka-3PjVBYxTQDg@public.gmane.org>
Signed-off-by: Vlastimil Setka <setka-3PjVBYxTQDg@public.gmane.org>
Signed-off-by: Thor Thayer <tthayer-yzvPICuk2ABMcg4IHK0kFoH6Mc4MB0Vx@public.gmane.org>
---
 drivers/spi/spi-dw.c |   33 ++++++++++++++++++---------------
 1 file changed, 18 insertions(+), 15 deletions(-)

diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c
index 72e12ba..3456b34 100644
--- a/drivers/spi/spi-dw.c
+++ b/drivers/spi/spi-dw.c
@@ -376,9 +376,6 @@ static void pump_transfers(unsigned long data)
 	chip = dws->cur_chip;
 	spi = message->spi;
 
-	if (unlikely(!chip->clk_div))
-		chip->clk_div = dws->max_freq / chip->speed_hz;
-
 	if (message->state == ERROR_STATE) {
 		message->status = -EIO;
 		goto early_exit;
@@ -415,21 +412,27 @@ static void pump_transfers(unsigned long data)
 
 	cr0 = chip->cr0;
 
-	/* Handle per transfer options for bpw and speed */
-	if (transfer->speed_hz) {
-		speed = chip->speed_hz;
+	/* Always calculate the desired clock divider */
+	speed = transfer->speed_hz ? transfer->speed_hz : chip->speed_hz;
+
+	if (speed > dws->max_freq) {
+		dev_err(&spi->dev, "Unsupported SPI freq: %d Hz\n", speed);
+		message->status = -EIO;
+		goto early_exit;
+	}
+
+	/* clk_div doesn't support odd number */
+	clk_div = dws->max_freq / speed;
+	clk_div = (clk_div + 1) & 0xfffe;
 
-		if (transfer->speed_hz != speed) {
-			speed = transfer->speed_hz;
+	/* Determine if the clock divider changed, if so update chip struct */
+	if (clk_div != chip->clk_div)
+		chip->clk_div = clk_div;
+	else
+		clk_div = 0; /* Prevent register programming below */
 
-			/* clk_div doesn't support odd number */
-			clk_div = dws->max_freq / speed;
-			clk_div = (clk_div + 1) & 0xfffe;
+	chip->speed_hz = speed;
 
-			chip->speed_hz = speed;
-			chip->clk_div = clk_div;
-		}
-	}
 	if (transfer->bits_per_word) {
 		bits = transfer->bits_per_word;
 		dws->n_bytes = dws->dma_width = bits >> 3;
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 9+ messages in thread
* [PATCH] spi: dw: Fix dynamic speed change.
@ 2014-11-06 19:50 tthayer-yzvPICuk2ABMcg4IHK0kFoH6Mc4MB0Vx
  0 siblings, 0 replies; 9+ messages in thread
From: tthayer-yzvPICuk2ABMcg4IHK0kFoH6Mc4MB0Vx @ 2014-11-06 19:50 UTC (permalink / raw)
  To: broonie-DgEjT+Ai2ygdnm+yROfE0A
  Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA,
	feng.tang-ral2JQCrhuEAvxtiuMwx3w, setka-3PjVBYxTQDg,
	tthayer-EIB2kfCEclfQT0dZR+AlfA,
	andriy.shevchenko-VuQAYsv1563Yd54FQh9/CA, Thor Thayer

From: Thor Thayer <tthayer-yzvPICuk2ABMcg4IHK0kFoH6Mc4MB0Vx@public.gmane.org>

An IOCTL call that calls spi_setup() and then dw_spi_setup() will
overwrite the persisted last transfer speed. On each transfer, the
SPI speed is compared to the last transfer speed to determine if the
clock divider registers need to be updated (did the speed change?).
This bug was observed with the spidev driver using spi-config to
update the max transfer speed.

This fix: Don't overwrite the persisted last transaction clock speed
when updating the SPI parameters in dw_spi_setup(). On the next
transaction, the new speed won't match the persisted last speed
and the hardware registers will be updated.
On initialization, the persisted last transaction clock
speed will be 0 but will be updated after the first SPI
transaction.

Move zeroed clock divider check into clock change test because
chip->clk_div is zero on startup and would cause a divide-by-zero
error. The calculation was wrong as well (can't support odd #).

Reported-by: Vlastimil Setka <setka-3PjVBYxTQDg@public.gmane.org>
Signed-off-by: Vlastimil Setka <setka-3PjVBYxTQDg@public.gmane.org>
Signed-off-by: Thor Thayer <tthayer-yzvPICuk2ABMcg4IHK0kFoH6Mc4MB0Vx@public.gmane.org>
---
v2: Simplify fix so that last persistent SPI transfer speed is not
overwritten.
---
 drivers/spi/spi-dw.c |    6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c
index 72e12ba..d0d5542 100644
--- a/drivers/spi/spi-dw.c
+++ b/drivers/spi/spi-dw.c
@@ -376,9 +376,6 @@ static void pump_transfers(unsigned long data)
 	chip = dws->cur_chip;
 	spi = message->spi;
 
-	if (unlikely(!chip->clk_div))
-		chip->clk_div = dws->max_freq / chip->speed_hz;
-
 	if (message->state == ERROR_STATE) {
 		message->status = -EIO;
 		goto early_exit;
@@ -419,7 +416,7 @@ static void pump_transfers(unsigned long data)
 	if (transfer->speed_hz) {
 		speed = chip->speed_hz;
 
-		if (transfer->speed_hz != speed) {
+		if ((transfer->speed_hz != speed) || (!chip->clk_div)) {
 			speed = transfer->speed_hz;
 
 			/* clk_div doesn't support odd number */
@@ -581,7 +578,6 @@ static int dw_spi_setup(struct spi_device *spi)
 		dev_err(&spi->dev, "No max speed HZ parameter\n");
 		return -EINVAL;
 	}
-	chip->speed_hz = spi->max_speed_hz;
 
 	chip->tmode = 0; /* Tx & Rx */
 	/* Default SPI mode is SCPOL = 0, SCPH = 0 */
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2014-11-06 19:50 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-11-04 22:36 [PATCH] spi: dw: Fix dynamic speed change tthayer-yzvPICuk2ABMcg4IHK0kFoH6Mc4MB0Vx
     [not found] ` <1415140617-2028-1-git-send-email-tthayer-yzvPICuk2ABMcg4IHK0kFoH6Mc4MB0Vx@public.gmane.org>
2014-11-05  9:57   ` Andy Shevchenko
     [not found]     ` <1415181423.472.15.camel-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2014-11-05 20:25       ` Thor Thayer
2014-11-05 10:54   ` Mark Brown
     [not found]     ` <20141105105452.GS3729-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2014-11-05 12:07       ` Vlastimil Šetka
     [not found]         ` <545A1308.4080106-3PjVBYxTQDg@public.gmane.org>
2014-11-05 13:24           ` Mark Brown
     [not found]             ` <20141105132442.GT3729-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2014-11-05 20:25               ` Thor Thayer
     [not found]                 ` <545A87D7.3010705-yzvPICuk2ABMcg4IHK0kFoH6Mc4MB0Vx@public.gmane.org>
2014-11-06 15:48                   ` Mark Brown
  -- strict thread matches above, loose matches on Subject: below --
2014-11-06 19:50 tthayer-yzvPICuk2ABMcg4IHK0kFoH6Mc4MB0Vx

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).