Commit 6bb477df authored by Yun Zhou's avatar Yun Zhou Committed by Mark Brown

spi: use specific last_cs instead of last_cs_enable

Commit d40f0b6f instroduced last_cs_enable to avoid setting
chipselect if it's not necessary, but it also introduces a bug. The
chipselect may not be set correctly on multi-device SPI busses. The
reason is that we can't judge the chipselect by bool last_cs_enable,
since chipselect may be modified after other devices were accessed.

So we should record the specific state of chipselect in case of
confusion.
Signed-off-by: default avatarYun Zhou <yun.zhou@windriver.com>
Link: https://lore.kernel.org/r/20220217141234.72737-1-yun.zhou@windriver.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent fcaaf76e
...@@ -926,13 +926,14 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force) ...@@ -926,13 +926,14 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force)
* Avoid calling into the driver (or doing delays) if the chip select * Avoid calling into the driver (or doing delays) if the chip select
* isn't actually changing from the last time this was called. * isn't actually changing from the last time this was called.
*/ */
if (!force && (spi->controller->last_cs_enable == enable) && if (!force && ((enable && spi->controller->last_cs == spi->chip_select) ||
(!enable && spi->controller->last_cs != spi->chip_select)) &&
(spi->controller->last_cs_mode_high == (spi->mode & SPI_CS_HIGH))) (spi->controller->last_cs_mode_high == (spi->mode & SPI_CS_HIGH)))
return; return;
trace_spi_set_cs(spi, activate); trace_spi_set_cs(spi, activate);
spi->controller->last_cs_enable = enable; spi->controller->last_cs = enable ? spi->chip_select : -1;
spi->controller->last_cs_mode_high = spi->mode & SPI_CS_HIGH; spi->controller->last_cs_mode_high = spi->mode & SPI_CS_HIGH;
if ((spi->cs_gpiod || !spi->controller->set_cs_timing) && !activate) { if ((spi->cs_gpiod || !spi->controller->set_cs_timing) && !activate) {
...@@ -3016,6 +3017,9 @@ int spi_register_controller(struct spi_controller *ctlr) ...@@ -3016,6 +3017,9 @@ int spi_register_controller(struct spi_controller *ctlr)
goto free_bus_id; goto free_bus_id;
} }
/* setting last_cs to -1 means no chip selected */
ctlr->last_cs = -1;
status = device_add(&ctlr->dev); status = device_add(&ctlr->dev);
if (status < 0) if (status < 0)
goto free_bus_id; goto free_bus_id;
......
...@@ -370,7 +370,8 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch ...@@ -370,7 +370,8 @@ extern struct spi_device *spi_new_ancillary_device(struct spi_device *spi, u8 ch
* @cur_msg_prepared: spi_prepare_message was called for the currently * @cur_msg_prepared: spi_prepare_message was called for the currently
* in-flight message * in-flight message
* @cur_msg_mapped: message has been mapped for DMA * @cur_msg_mapped: message has been mapped for DMA
* @last_cs_enable: was enable true on the last call to set_cs. * @last_cs: the last chip_select that is recorded by set_cs, -1 on non chip
* selected
* @last_cs_mode_high: was (mode & SPI_CS_HIGH) true on the last call to set_cs. * @last_cs_mode_high: was (mode & SPI_CS_HIGH) true on the last call to set_cs.
* @xfer_completion: used by core transfer_one_message() * @xfer_completion: used by core transfer_one_message()
* @busy: message pump is busy * @busy: message pump is busy
...@@ -603,7 +604,7 @@ struct spi_controller { ...@@ -603,7 +604,7 @@ struct spi_controller {
bool auto_runtime_pm; bool auto_runtime_pm;
bool cur_msg_prepared; bool cur_msg_prepared;
bool cur_msg_mapped; bool cur_msg_mapped;
bool last_cs_enable; char last_cs;
bool last_cs_mode_high; bool last_cs_mode_high;
bool fallback; bool fallback;
struct completion xfer_completion; struct completion xfer_completion;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment