| From 0a8727e69778683495058852f783eeda141a754e Mon Sep 17 00:00:00 2001 |
| From: Thor Thayer <tthayer@opensource.altera.com> |
| Date: Thu, 6 Nov 2014 13:54:27 -0600 |
| Subject: spi: dw: Fix dynamic speed change. |
| |
| From: Thor Thayer <tthayer@opensource.altera.com> |
| |
| commit 0a8727e69778683495058852f783eeda141a754e upstream. |
| |
| 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@vsis.cz> |
| Signed-off-by: Vlastimil Setka <setka@vsis.cz> |
| Signed-off-by: Thor Thayer <tthayer@opensource.altera.com> |
| Signed-off-by: Mark Brown <broonie@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/spi/spi-dw.c | 6 +----- |
| 1 file changed, 1 insertion(+), 5 deletions(-) |
| |
| --- a/drivers/spi/spi-dw.c |
| +++ b/drivers/spi/spi-dw.c |
| @@ -394,9 +394,6 @@ static void pump_transfers(unsigned long |
| 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; |
| @@ -437,7 +434,7 @@ static void pump_transfers(unsigned long |
| 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; |
| if (speed > dws->max_freq) { |
| printk(KERN_ERR "MRST SPI0: unsupported" |
| @@ -659,7 +656,6 @@ static int dw_spi_setup(struct spi_devic |
| 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 */ |