Commit 0ce6473c authored by Lars-Peter Clausen's avatar Lars-Peter Clausen Committed by Greg Kroah-Hartman

iio: ad_sigma_delta: Properly handle SPI bus locking vs CS assertion

[ Upstream commit df1d80ae ]

For devices from the SigmaDelta family we need to keep CS low when doing a
conversion, since the device will use the MISO line as a interrupt to
indicate that the conversion is complete.

This is why the driver locks the SPI bus and when the SPI bus is locked
keeps as long as a conversion is going on. The current implementation gets
one small detail wrong though. CS is only de-asserted after the SPI bus is
unlocked. This means it is possible for a different SPI device on the same
bus to send a message which would be wrongfully be addressed to the
SigmaDelta device as well. Make sure that the last SPI transfer that is
done while holding the SPI bus lock de-asserts the CS signal.
Signed-off-by: default avatarLars-Peter Clausen <lars@metafoo.de>
Signed-off-by: default avatarAlexandru Ardelean <Alexandru.Ardelean@analog.com>
Signed-off-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent c5e8fa7f
...@@ -62,7 +62,7 @@ int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg, ...@@ -62,7 +62,7 @@ int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg,
struct spi_transfer t = { struct spi_transfer t = {
.tx_buf = data, .tx_buf = data,
.len = size + 1, .len = size + 1,
.cs_change = sigma_delta->bus_locked, .cs_change = sigma_delta->keep_cs_asserted,
}; };
struct spi_message m; struct spi_message m;
int ret; int ret;
...@@ -217,6 +217,7 @@ static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta, ...@@ -217,6 +217,7 @@ static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta,
spi_bus_lock(sigma_delta->spi->master); spi_bus_lock(sigma_delta->spi->master);
sigma_delta->bus_locked = true; sigma_delta->bus_locked = true;
sigma_delta->keep_cs_asserted = true;
reinit_completion(&sigma_delta->completion); reinit_completion(&sigma_delta->completion);
ret = ad_sigma_delta_set_mode(sigma_delta, mode); ret = ad_sigma_delta_set_mode(sigma_delta, mode);
...@@ -234,9 +235,10 @@ static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta, ...@@ -234,9 +235,10 @@ static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta,
ret = 0; ret = 0;
} }
out: out:
sigma_delta->keep_cs_asserted = false;
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
sigma_delta->bus_locked = false; sigma_delta->bus_locked = false;
spi_bus_unlock(sigma_delta->spi->master); spi_bus_unlock(sigma_delta->spi->master);
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
return ret; return ret;
} }
...@@ -288,6 +290,7 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev, ...@@ -288,6 +290,7 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
spi_bus_lock(sigma_delta->spi->master); spi_bus_lock(sigma_delta->spi->master);
sigma_delta->bus_locked = true; sigma_delta->bus_locked = true;
sigma_delta->keep_cs_asserted = true;
reinit_completion(&sigma_delta->completion); reinit_completion(&sigma_delta->completion);
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_SINGLE); ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_SINGLE);
...@@ -297,9 +300,6 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev, ...@@ -297,9 +300,6 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
ret = wait_for_completion_interruptible_timeout( ret = wait_for_completion_interruptible_timeout(
&sigma_delta->completion, HZ); &sigma_delta->completion, HZ);
sigma_delta->bus_locked = false;
spi_bus_unlock(sigma_delta->spi->master);
if (ret == 0) if (ret == 0)
ret = -EIO; ret = -EIO;
if (ret < 0) if (ret < 0)
...@@ -315,7 +315,10 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev, ...@@ -315,7 +315,10 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
sigma_delta->irq_dis = true; sigma_delta->irq_dis = true;
} }
sigma_delta->keep_cs_asserted = false;
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
sigma_delta->bus_locked = false;
spi_bus_unlock(sigma_delta->spi->master);
mutex_unlock(&indio_dev->mlock); mutex_unlock(&indio_dev->mlock);
if (ret) if (ret)
...@@ -352,6 +355,8 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev) ...@@ -352,6 +355,8 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev)
spi_bus_lock(sigma_delta->spi->master); spi_bus_lock(sigma_delta->spi->master);
sigma_delta->bus_locked = true; sigma_delta->bus_locked = true;
sigma_delta->keep_cs_asserted = true;
ret = ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_CONTINUOUS); ret = ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_CONTINUOUS);
if (ret) if (ret)
goto err_unlock; goto err_unlock;
...@@ -380,6 +385,7 @@ static int ad_sd_buffer_postdisable(struct iio_dev *indio_dev) ...@@ -380,6 +385,7 @@ static int ad_sd_buffer_postdisable(struct iio_dev *indio_dev)
sigma_delta->irq_dis = true; sigma_delta->irq_dis = true;
} }
sigma_delta->keep_cs_asserted = false;
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
sigma_delta->bus_locked = false; sigma_delta->bus_locked = false;
......
...@@ -66,6 +66,7 @@ struct ad_sigma_delta { ...@@ -66,6 +66,7 @@ struct ad_sigma_delta {
bool irq_dis; bool irq_dis;
bool bus_locked; bool bus_locked;
bool keep_cs_asserted;
uint8_t comm; uint8_t comm;
......
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