]>
Commit | Line | Data |
---|---|---|
a1e97e95 GKH |
1 | From 73e3e3fc50de50cfd68e945d85679c983ed31bd9 Mon Sep 17 00:00:00 2001 |
2 | From: Akinobu Mita <akinobu.mita@gmail.com> | |
3 | Date: Fri, 21 Jul 2017 00:24:20 +0900 | |
4 | Subject: iio: adc: ti-ads1015: avoid getting stale result after runtime resume | |
5 | ||
6 | From: Akinobu Mita <akinobu.mita@gmail.com> | |
7 | ||
8 | commit 73e3e3fc50de50cfd68e945d85679c983ed31bd9 upstream. | |
9 | ||
10 | This driver assumes that the device is operating in the continuous | |
11 | conversion mode which performs the conversion continuously. So this driver | |
12 | doesn't insert a wait time before reading the conversion register if the | |
13 | configuration is not changed from a previous request. | |
14 | ||
15 | This assumption is broken if the device is runtime suspended and entered | |
16 | a power-down state. The forthcoming request causes reading a stale result | |
17 | from the conversion register as the device is runtime resumed just before. | |
18 | ||
19 | Fix it by adding a flag to detect that condition and insert a necessary | |
20 | wait time. | |
21 | ||
22 | Cc: Daniel Baluta <daniel.baluta@gmail.com> | |
23 | Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com> | |
24 | Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> | |
25 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
26 | ||
27 | --- | |
28 | drivers/iio/adc/ti-ads1015.c | 18 ++++++++++++++++-- | |
29 | 1 file changed, 16 insertions(+), 2 deletions(-) | |
30 | ||
31 | --- a/drivers/iio/adc/ti-ads1015.c | |
32 | +++ b/drivers/iio/adc/ti-ads1015.c | |
33 | @@ -176,6 +176,12 @@ struct ads1015_data { | |
34 | struct ads1015_channel_data channel_data[ADS1015_CHANNELS]; | |
35 | ||
36 | unsigned int *data_rate; | |
37 | + /* | |
38 | + * Set to true when the ADC is switched to the continuous-conversion | |
39 | + * mode and exits from a power-down state. This flag is used to avoid | |
40 | + * getting the stale result from the conversion register. | |
41 | + */ | |
42 | + bool conv_invalid; | |
43 | }; | |
44 | ||
45 | static bool ads1015_is_writeable_reg(struct device *dev, unsigned int reg) | |
46 | @@ -254,9 +260,10 @@ int ads1015_get_adc_result(struct ads101 | |
47 | if (ret < 0) | |
48 | return ret; | |
49 | ||
50 | - if (change) { | |
51 | + if (change || data->conv_invalid) { | |
52 | conv_time = DIV_ROUND_UP(USEC_PER_SEC, data->data_rate[dr]); | |
53 | usleep_range(conv_time, conv_time + 1); | |
54 | + data->conv_invalid = false; | |
55 | } | |
56 | ||
57 | return regmap_read(data->regmap, ADS1015_CONV_REG, val); | |
58 | @@ -624,6 +631,8 @@ static int ads1015_probe(struct i2c_clie | |
59 | if (ret) | |
60 | return ret; | |
61 | ||
62 | + data->conv_invalid = true; | |
63 | + | |
64 | ret = pm_runtime_set_active(&client->dev); | |
65 | if (ret) | |
66 | goto err_buffer_cleanup; | |
67 | @@ -679,10 +688,15 @@ static int ads1015_runtime_resume(struct | |
68 | { | |
69 | struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); | |
70 | struct ads1015_data *data = iio_priv(indio_dev); | |
71 | + int ret; | |
72 | ||
73 | - return regmap_update_bits(data->regmap, ADS1015_CFG_REG, | |
74 | + ret = regmap_update_bits(data->regmap, ADS1015_CFG_REG, | |
75 | ADS1015_CFG_MOD_MASK, | |
76 | ADS1015_CONTINUOUS << ADS1015_CFG_MOD_SHIFT); | |
77 | + if (!ret) | |
78 | + data->conv_invalid = true; | |
79 | + | |
80 | + return ret; | |
81 | } | |
82 | #endif | |
83 |