| From 0afa01ef281b59ea3bf1740bd41df8ad7adcd42f Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 16 Apr 2021 21:59:56 +0200 |
| Subject: spi: sync up initial chipselect state |
| |
| From: David Bauer <mail@david-bauer.net> |
| |
| [ Upstream commit d347b4aaa1a042ea528e385d9070b74c77a14321 ] |
| |
| 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 exit 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> |
| Link: https://lore.kernel.org/r/20210416195956.121811-1-mail@david-bauer.net |
| Signed-off-by: Mark Brown <broonie@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/spi/spi.c | 16 ++++++++-------- |
| 1 file changed, 8 insertions(+), 8 deletions(-) |
| |
| diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c |
| index b08efe88ccd6..927c2a28011f 100644 |
| --- a/drivers/spi/spi.c |
| +++ b/drivers/spi/spi.c |
| @@ -795,7 +795,7 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n) |
| |
| /*-------------------------------------------------------------------------*/ |
| |
| -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; |
| |
| @@ -803,7 +803,7 @@ static void spi_set_cs(struct spi_device *spi, bool enable) |
| * 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; |
| |
| @@ -1253,7 +1253,7 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, |
| 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); |
| @@ -1321,9 +1321,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); |
| } |
| } |
| |
| @@ -1332,7 +1332,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; |
| @@ -3423,11 +3423,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); |
| -- |
| 2.30.2 |
| |