mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-14 04:26:45 +00:00
iio: ad_sigma_delta: Properly handle SPI bus locking vs CS assertion
[ Upstream commit df1d80aee9
]
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: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Alexandru Ardelean <Alexandru.Ardelean@analog.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
5163bc447a
commit
50892cb292
2 changed files with 12 additions and 5 deletions
|
@ -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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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 {
|
||||||
bool irq_dis;
|
bool irq_dis;
|
||||||
|
|
||||||
bool bus_locked;
|
bool bus_locked;
|
||||||
|
bool keep_cs_asserted;
|
||||||
|
|
||||||
uint8_t comm;
|
uint8_t comm;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue