Skip to content

Commit 90826e0

Browse files
gstolsjic23
authored andcommitted
iio: adc: ad7606: remove frstdata check for serial mode
The current implementation attempts to recover from an eventual glitch in the clock by checking frstdata state after reading the first channel's sample: If frstdata is low, it will reset the chip and return -EIO. This will only work in parallel mode, where frstdata pin is set low after the 2nd sample read starts. For the serial mode, according to the datasheet, "The FRSTDATA output returns to a logic low following the 16th SCLK falling edge.", thus after the Xth pulse, X being the number of bits in a sample, the check will always be true, and the driver will not work at all in serial mode if frstdata(optional) is defined in the devicetree as it will reset the chip, and return -EIO every time read_sample is called. Hence, this check must be removed for serial mode. Fixes: b9618c0 ("staging: IIO: ADC: New driver for AD7606/AD7606-6/AD7606-4") Signed-off-by: Guillaume Stols <gstols@baylibre.com> Reviewed-by: Nuno Sa <nuno.sa@analog.com> Link: https://patch.msgid.link/20240702-cleanup-ad7606-v3-1-18d5ea18770e@baylibre.com Cc: <Stable@vger.kernel.org> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
1 parent b48aa99 commit 90826e0

3 files changed

Lines changed: 49 additions & 29 deletions

File tree

drivers/iio/adc/ad7606.c

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ static const unsigned int ad7616_oversampling_avail[8] = {
4949
1, 2, 4, 8, 16, 32, 64, 128,
5050
};
5151

52-
static int ad7606_reset(struct ad7606_state *st)
52+
int ad7606_reset(struct ad7606_state *st)
5353
{
5454
if (st->gpio_reset) {
5555
gpiod_set_value(st->gpio_reset, 1);
@@ -60,6 +60,7 @@ static int ad7606_reset(struct ad7606_state *st)
6060

6161
return -ENODEV;
6262
}
63+
EXPORT_SYMBOL_NS_GPL(ad7606_reset, IIO_AD7606);
6364

6465
static int ad7606_reg_access(struct iio_dev *indio_dev,
6566
unsigned int reg,
@@ -88,31 +89,6 @@ static int ad7606_read_samples(struct ad7606_state *st)
8889
{
8990
unsigned int num = st->chip_info->num_channels - 1;
9091
u16 *data = st->data;
91-
int ret;
92-
93-
/*
94-
* The frstdata signal is set to high while and after reading the sample
95-
* of the first channel and low for all other channels. This can be used
96-
* to check that the incoming data is correctly aligned. During normal
97-
* operation the data should never become unaligned, but some glitch or
98-
* electrostatic discharge might cause an extra read or clock cycle.
99-
* Monitoring the frstdata signal allows to recover from such failure
100-
* situations.
101-
*/
102-
103-
if (st->gpio_frstdata) {
104-
ret = st->bops->read_block(st->dev, 1, data);
105-
if (ret)
106-
return ret;
107-
108-
if (!gpiod_get_value(st->gpio_frstdata)) {
109-
ad7606_reset(st);
110-
return -EIO;
111-
}
112-
113-
data++;
114-
num--;
115-
}
11692

11793
return st->bops->read_block(st->dev, num, data);
11894
}

drivers/iio/adc/ad7606.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
151151
const char *name, unsigned int id,
152152
const struct ad7606_bus_ops *bops);
153153

154+
int ad7606_reset(struct ad7606_state *st);
155+
154156
enum ad7606_supported_device_ids {
155157
ID_AD7605_4,
156158
ID_AD7606_8,

drivers/iio/adc/ad7606_par.c

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include <linux/mod_devicetable.h>
99
#include <linux/module.h>
10+
#include <linux/gpio/consumer.h>
1011
#include <linux/platform_device.h>
1112
#include <linux/types.h>
1213
#include <linux/err.h>
@@ -21,8 +22,29 @@ static int ad7606_par16_read_block(struct device *dev,
2122
struct iio_dev *indio_dev = dev_get_drvdata(dev);
2223
struct ad7606_state *st = iio_priv(indio_dev);
2324

24-
insw((unsigned long)st->base_address, buf, count);
2525

26+
/*
27+
* On the parallel interface, the frstdata signal is set to high while
28+
* and after reading the sample of the first channel and low for all
29+
* other channels. This can be used to check that the incoming data is
30+
* correctly aligned. During normal operation the data should never
31+
* become unaligned, but some glitch or electrostatic discharge might
32+
* cause an extra read or clock cycle. Monitoring the frstdata signal
33+
* allows to recover from such failure situations.
34+
*/
35+
int num = count;
36+
u16 *_buf = buf;
37+
38+
if (st->gpio_frstdata) {
39+
insw((unsigned long)st->base_address, _buf, 1);
40+
if (!gpiod_get_value(st->gpio_frstdata)) {
41+
ad7606_reset(st);
42+
return -EIO;
43+
}
44+
_buf++;
45+
num--;
46+
}
47+
insw((unsigned long)st->base_address, _buf, num);
2648
return 0;
2749
}
2850

@@ -35,8 +57,28 @@ static int ad7606_par8_read_block(struct device *dev,
3557
{
3658
struct iio_dev *indio_dev = dev_get_drvdata(dev);
3759
struct ad7606_state *st = iio_priv(indio_dev);
38-
39-
insb((unsigned long)st->base_address, buf, count * 2);
60+
/*
61+
* On the parallel interface, the frstdata signal is set to high while
62+
* and after reading the sample of the first channel and low for all
63+
* other channels. This can be used to check that the incoming data is
64+
* correctly aligned. During normal operation the data should never
65+
* become unaligned, but some glitch or electrostatic discharge might
66+
* cause an extra read or clock cycle. Monitoring the frstdata signal
67+
* allows to recover from such failure situations.
68+
*/
69+
int num = count;
70+
u16 *_buf = buf;
71+
72+
if (st->gpio_frstdata) {
73+
insb((unsigned long)st->base_address, _buf, 2);
74+
if (!gpiod_get_value(st->gpio_frstdata)) {
75+
ad7606_reset(st);
76+
return -EIO;
77+
}
78+
_buf++;
79+
num--;
80+
}
81+
insb((unsigned long)st->base_address, _buf, num * 2);
4082

4183
return 0;
4284
}

0 commit comments

Comments
 (0)