ca3e23b8fcad0081a203fd01f8fe843128c6568b
[openwrt/staging/ldir.git] /
1 From 62129a0849d27cc94ced832bcf9dcde283dcbe08 Mon Sep 17 00:00:00 2001
2 From: Tomasz Duszynski <tduszyns@gmail.com>
3 Date: Tue, 15 Jan 2019 20:00:06 +0100
4 Subject: [PATCH] iio: chemical: sps30: allow changing self cleaning period
5
6 Sensor can periodically trigger self cleaning. Period can be changed by
7 writing a new value to a dedicated attribute. Upon attribute read
8 current period gets returned.
9
10 Signed-off-by: Tomasz Duszynski <tduszyns@gmail.com>
11 Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
12 ---
13 Documentation/ABI/testing/sysfs-bus-iio-sps30 | 20 +++
14 drivers/iio/chemical/sps30.c | 143 +++++++++++++++---
15 2 files changed, 145 insertions(+), 18 deletions(-)
16
17 diff --git a/Documentation/ABI/testing/sysfs-bus-iio-sps30 b/Documentation/ABI/testing/sysfs-bus-iio-sps30
18 index e7ce2c57635e..143df8e89d08 100644
19 --- a/Documentation/ABI/testing/sysfs-bus-iio-sps30
20 +++ b/Documentation/ABI/testing/sysfs-bus-iio-sps30
21 @@ -6,3 +6,23 @@ Description:
22 Writing 1 starts sensor self cleaning. Internal fan accelerates
23 to its maximum speed and keeps spinning for about 10 seconds in
24 order to blow out accumulated dust.
25 +
26 +What: /sys/bus/iio/devices/iio:deviceX/cleaning_period
27 +Date: January 2019
28 +KernelVersion: 5.1
29 +Contact: linux-iio@vger.kernel.org
30 +Description:
31 + Sensor is capable of triggering self cleaning periodically.
32 + Period can be changed by writing a new value here. Upon reading
33 + the current one is returned. Units are seconds.
34 +
35 + Writing 0 disables periodical self cleaning entirely.
36 +
37 +What: /sys/bus/iio/devices/iio:deviceX/cleaning_period_available
38 +Date: January 2019
39 +KernelVersion: 5.1
40 +Contact: linux-iio@vger.kernel.org
41 +Description:
42 + The range of available values in seconds represented as the
43 + minimum value, the step and the maximum value, all enclosed in
44 + square brackets.
45 diff --git a/drivers/iio/chemical/sps30.c b/drivers/iio/chemical/sps30.c
46 index f3b4390c8f5c..376fac41ecb5 100644
47 --- a/drivers/iio/chemical/sps30.c
48 +++ b/drivers/iio/chemical/sps30.c
49 @@ -5,9 +5,6 @@
50 * Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
51 *
52 * I2C slave address: 0x69
53 - *
54 - * TODO:
55 - * - support for reading/setting auto cleaning interval
56 */
57
58 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
59 @@ -21,6 +18,7 @@
60 #include <linux/iio/sysfs.h>
61 #include <linux/iio/trigger_consumer.h>
62 #include <linux/iio/triggered_buffer.h>
63 +#include <linux/kernel.h>
64 #include <linux/module.h>
65
66 #define SPS30_CRC8_POLYNOMIAL 0x31
67 @@ -28,6 +26,9 @@
68 #define SPS30_MAX_READ_SIZE 48
69 /* sensor measures reliably up to 3000 ug / m3 */
70 #define SPS30_MAX_PM 3000
71 +/* minimum and maximum self cleaning periods in seconds */
72 +#define SPS30_AUTO_CLEANING_PERIOD_MIN 0
73 +#define SPS30_AUTO_CLEANING_PERIOD_MAX 604800
74
75 /* SPS30 commands */
76 #define SPS30_START_MEAS 0x0010
77 @@ -37,6 +38,9 @@
78 #define SPS30_READ_DATA 0x0300
79 #define SPS30_READ_SERIAL 0xd033
80 #define SPS30_START_FAN_CLEANING 0x5607
81 +#define SPS30_AUTO_CLEANING_PERIOD 0x8004
82 +/* not a sensor command per se, used only to distinguish write from read */
83 +#define SPS30_READ_AUTO_CLEANING_PERIOD 0x8005
84
85 enum {
86 PM1,
87 @@ -45,6 +49,11 @@ enum {
88 PM10,
89 };
90
91 +enum {
92 + RESET,
93 + MEASURING,
94 +};
95 +
96 struct sps30_state {
97 struct i2c_client *client;
98 /*
99 @@ -52,6 +61,7 @@ struct sps30_state {
100 * Must be held whenever sequence of commands is to be executed.
101 */
102 struct mutex lock;
103 + int state;
104 };
105
106 DECLARE_CRC8_TABLE(sps30_crc8_table);
107 @@ -107,6 +117,9 @@ static int sps30_do_cmd(struct sps30_state *state, u16 cmd, u8 *data, int size)
108 case SPS30_START_FAN_CLEANING:
109 ret = sps30_write_then_read(state, buf, 2, NULL, 0);
110 break;
111 + case SPS30_READ_AUTO_CLEANING_PERIOD:
112 + buf[0] = SPS30_AUTO_CLEANING_PERIOD >> 8;
113 + buf[1] = (u8)SPS30_AUTO_CLEANING_PERIOD;
114 case SPS30_READ_DATA_READY_FLAG:
115 case SPS30_READ_DATA:
116 case SPS30_READ_SERIAL:
117 @@ -114,6 +127,15 @@ static int sps30_do_cmd(struct sps30_state *state, u16 cmd, u8 *data, int size)
118 size += size / 2;
119 ret = sps30_write_then_read(state, buf, 2, buf, size);
120 break;
121 + case SPS30_AUTO_CLEANING_PERIOD:
122 + buf[2] = data[0];
123 + buf[3] = data[1];
124 + buf[4] = crc8(sps30_crc8_table, &buf[2], 2, CRC8_INIT_VALUE);
125 + buf[5] = data[2];
126 + buf[6] = data[3];
127 + buf[7] = crc8(sps30_crc8_table, &buf[5], 2, CRC8_INIT_VALUE);
128 + ret = sps30_write_then_read(state, buf, 8, NULL, 0);
129 + break;
130 }
131
132 if (ret)
133 @@ -170,6 +192,14 @@ static int sps30_do_meas(struct sps30_state *state, s32 *data, int size)
134 int i, ret, tries = 5;
135 u8 tmp[16];
136
137 + if (state->state == RESET) {
138 + ret = sps30_do_cmd(state, SPS30_START_MEAS, NULL, 0);
139 + if (ret)
140 + return ret;
141 +
142 + state->state = MEASURING;
143 + }
144 +
145 while (tries--) {
146 ret = sps30_do_cmd(state, SPS30_READ_DATA_READY_FLAG, tmp, 2);
147 if (ret)
148 @@ -276,6 +306,24 @@ static int sps30_read_raw(struct iio_dev *indio_dev,
149 return -EINVAL;
150 }
151
152 +static int sps30_do_cmd_reset(struct sps30_state *state)
153 +{
154 + int ret;
155 +
156 + ret = sps30_do_cmd(state, SPS30_RESET, NULL, 0);
157 + msleep(300);
158 + /*
159 + * Power-on-reset causes sensor to produce some glitch on i2c bus and
160 + * some controllers end up in error state. Recover simply by placing
161 + * some data on the bus, for example STOP_MEAS command, which
162 + * is NOP in this case.
163 + */
164 + sps30_do_cmd(state, SPS30_STOP_MEAS, NULL, 0);
165 + state->state = RESET;
166 +
167 + return ret;
168 +}
169 +
170 static ssize_t start_cleaning_store(struct device *dev,
171 struct device_attribute *attr,
172 const char *buf, size_t len)
173 @@ -296,10 +344,82 @@ static ssize_t start_cleaning_store(struct device *dev,
174 return len;
175 }
176
177 +static ssize_t cleaning_period_show(struct device *dev,
178 + struct device_attribute *attr,
179 + char *buf)
180 +{
181 + struct iio_dev *indio_dev = dev_to_iio_dev(dev);
182 + struct sps30_state *state = iio_priv(indio_dev);
183 + u8 tmp[4];
184 + int ret;
185 +
186 + mutex_lock(&state->lock);
187 + ret = sps30_do_cmd(state, SPS30_READ_AUTO_CLEANING_PERIOD, tmp, 4);
188 + mutex_unlock(&state->lock);
189 + if (ret)
190 + return ret;
191 +
192 + return sprintf(buf, "%d\n", get_unaligned_be32(tmp));
193 +}
194 +
195 +static ssize_t cleaning_period_store(struct device *dev,
196 + struct device_attribute *attr,
197 + const char *buf, size_t len)
198 +{
199 + struct iio_dev *indio_dev = dev_to_iio_dev(dev);
200 + struct sps30_state *state = iio_priv(indio_dev);
201 + int val, ret;
202 + u8 tmp[4];
203 +
204 + if (kstrtoint(buf, 0, &val))
205 + return -EINVAL;
206 +
207 + if ((val < SPS30_AUTO_CLEANING_PERIOD_MIN) ||
208 + (val > SPS30_AUTO_CLEANING_PERIOD_MAX))
209 + return -EINVAL;
210 +
211 + put_unaligned_be32(val, tmp);
212 +
213 + mutex_lock(&state->lock);
214 + ret = sps30_do_cmd(state, SPS30_AUTO_CLEANING_PERIOD, tmp, 0);
215 + if (ret) {
216 + mutex_unlock(&state->lock);
217 + return ret;
218 + }
219 +
220 + msleep(20);
221 +
222 + /*
223 + * sensor requires reset in order to return up to date self cleaning
224 + * period
225 + */
226 + ret = sps30_do_cmd_reset(state);
227 + if (ret)
228 + dev_warn(dev,
229 + "period changed but reads will return the old value\n");
230 +
231 + mutex_unlock(&state->lock);
232 +
233 + return len;
234 +}
235 +
236 +static ssize_t cleaning_period_available_show(struct device *dev,
237 + struct device_attribute *attr,
238 + char *buf)
239 +{
240 + return snprintf(buf, PAGE_SIZE, "[%d %d %d]\n",
241 + SPS30_AUTO_CLEANING_PERIOD_MIN, 1,
242 + SPS30_AUTO_CLEANING_PERIOD_MAX);
243 +}
244 +
245 static IIO_DEVICE_ATTR_WO(start_cleaning, 0);
246 +static IIO_DEVICE_ATTR_RW(cleaning_period, 0);
247 +static IIO_DEVICE_ATTR_RO(cleaning_period_available, 0);
248
249 static struct attribute *sps30_attrs[] = {
250 &iio_dev_attr_start_cleaning.dev_attr.attr,
251 + &iio_dev_attr_cleaning_period.dev_attr.attr,
252 + &iio_dev_attr_cleaning_period_available.dev_attr.attr,
253 NULL
254 };
255
256 @@ -362,6 +482,7 @@ static int sps30_probe(struct i2c_client *client)
257 state = iio_priv(indio_dev);
258 i2c_set_clientdata(client, indio_dev);
259 state->client = client;
260 + state->state = RESET;
261 indio_dev->dev.parent = &client->dev;
262 indio_dev->info = &sps30_info;
263 indio_dev->name = client->name;
264 @@ -373,19 +494,11 @@ static int sps30_probe(struct i2c_client *client)
265 mutex_init(&state->lock);
266 crc8_populate_msb(sps30_crc8_table, SPS30_CRC8_POLYNOMIAL);
267
268 - ret = sps30_do_cmd(state, SPS30_RESET, NULL, 0);
269 + ret = sps30_do_cmd_reset(state);
270 if (ret) {
271 dev_err(&client->dev, "failed to reset device\n");
272 return ret;
273 }
274 - msleep(300);
275 - /*
276 - * Power-on-reset causes sensor to produce some glitch on i2c bus and
277 - * some controllers end up in error state. Recover simply by placing
278 - * some data on the bus, for example STOP_MEAS command, which
279 - * is NOP in this case.
280 - */
281 - sps30_do_cmd(state, SPS30_STOP_MEAS, NULL, 0);
282
283 ret = sps30_do_cmd(state, SPS30_READ_SERIAL, buf, sizeof(buf));
284 if (ret) {
285 @@ -395,12 +508,6 @@ static int sps30_probe(struct i2c_client *client)
286 /* returned serial number is already NUL terminated */
287 dev_info(&client->dev, "serial number: %s\n", buf);
288
289 - ret = sps30_do_cmd(state, SPS30_START_MEAS, NULL, 0);
290 - if (ret) {
291 - dev_err(&client->dev, "failed to start measurement\n");
292 - return ret;
293 - }
294 -
295 ret = devm_add_action_or_reset(&client->dev, sps30_stop_meas, state);
296 if (ret)
297 return ret;