| From 82f78035ce89c5f517fbc87c953d692f06dc856c Mon Sep 17 00:00:00 2001 |
| From: Serge Semin <Sergey.Semin@baikalelectronics.ru> |
| Date: Fri, 15 May 2020 13:47:43 +0300 |
| Subject: [PATCH] spi: dw: Fix native CS being unset |
| |
| commit 9aea644ca17b94f82ad7fa767cbc4509642f4420 upstream. |
| |
| Commit 6e0a32d6f376 ("spi: dw: Fix default polarity of native |
| chipselect") attempted to fix the problem when GPIO active-high |
| chip-select is utilized to communicate with some SPI slave. It fixed |
| the problem, but broke the normal native CS support. At the same time |
| the reversion commit ada9e3fcc175 ("spi: dw: Correct handling of native |
| chipselect") didn't solve the problem either, since it just inverted |
| the set_cs() polarity perception without taking into account that |
| CS-high might be applicable. Here is what is done to finally fix the |
| problem. |
| |
| DW SPI controller demands any native CS being set in order to proceed |
| with data transfer. So in order to activate the SPI communications we |
| must set any bit in the Slave Select DW SPI controller register no |
| matter whether the platform requests the GPIO- or native CS. Preferably |
| it should be the bit corresponding to the SPI slave CS number. But |
| currently the dw_spi_set_cs() method activates the chip-select |
| only if the second argument is false. Since the second argument of the |
| set_cs callback is expected to be a boolean with "is-high" semantics |
| (actual chip-select pin state value), the bit in the DW SPI Slave |
| Select register will be set only if SPI core requests the driver |
| to set the CS in the low state. So this will work for active-low |
| GPIO-based CS case, and won't work for active-high CS setting |
| the bit when SPI core actually needs to deactivate the CS. |
| |
| This commit fixes the problem for all described cases. So no matter |
| whether an SPI slave needs GPIO- or native-based CS with active-high |
| or low signal the corresponding bit will be set in SER. |
| |
| Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru> |
| Fixes: ada9e3fcc175 ("spi: dw: Correct handling of native chipselect") |
| Fixes: 6e0a32d6f376 ("spi: dw: Fix default polarity of native chipselect") |
| Reviewed-by: Charles Keepax <ckeepax@opensource.cirrus.com> |
| Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> |
| Acked-by: Linus Walleij <linus.walleij@linaro.org> |
| |
| Link: https://lore.kernel.org/r/20200515104758.6934-5-Sergey.Semin@baikalelectronics.ru |
| Signed-off-by: Mark Brown <broonie@kernel.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c |
| index 11cac7e10663..4d3ec45a3885 100644 |
| --- a/drivers/spi/spi-dw.c |
| +++ b/drivers/spi/spi-dw.c |
| @@ -128,12 +128,20 @@ void dw_spi_set_cs(struct spi_device *spi, bool enable) |
| { |
| struct dw_spi *dws = spi_controller_get_devdata(spi->controller); |
| struct chip_data *chip = spi_get_ctldata(spi); |
| + bool cs_high = !!(spi->mode & SPI_CS_HIGH); |
| |
| /* Chip select logic is inverted from spi_set_cs() */ |
| if (chip && chip->cs_control) |
| chip->cs_control(!enable); |
| |
| - if (!enable) |
| + /* |
| + * DW SPI controller demands any native CS being set in order to |
| + * proceed with data transfer. So in order to activate the SPI |
| + * communications we must set a corresponding bit in the Slave |
| + * Enable register no matter whether the SPI core is configured to |
| + * support active-high or active-low CS level. |
| + */ |
| + if (cs_high == enable) |
| dw_writel(dws, DW_SPI_SER, BIT(spi->chip_select)); |
| else if (dws->cs_override) |
| dw_writel(dws, DW_SPI_SER, 0); |
| -- |
| 2.7.4 |
| |