1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Sensirion SCD30 carbon dioxide sensor core driver |
4 | * |
5 | * Copyright (c) 2020 Tomasz Duszynski <tomasz.duszynski@octakon.com> |
6 | */ |
7 | #include <linux/bits.h> |
8 | #include <linux/completion.h> |
9 | #include <linux/delay.h> |
10 | #include <linux/device.h> |
11 | #include <linux/errno.h> |
12 | #include <linux/export.h> |
13 | #include <linux/iio/buffer.h> |
14 | #include <linux/iio/iio.h> |
15 | #include <linux/iio/sysfs.h> |
16 | #include <linux/iio/trigger.h> |
17 | #include <linux/iio/trigger_consumer.h> |
18 | #include <linux/iio/triggered_buffer.h> |
19 | #include <linux/iio/types.h> |
20 | #include <linux/interrupt.h> |
21 | #include <linux/irqreturn.h> |
22 | #include <linux/jiffies.h> |
23 | #include <linux/kernel.h> |
24 | #include <linux/module.h> |
25 | #include <linux/mutex.h> |
26 | #include <linux/regulator/consumer.h> |
27 | #include <linux/string.h> |
28 | #include <linux/sysfs.h> |
29 | #include <linux/types.h> |
30 | #include <asm/byteorder.h> |
31 | |
32 | #include "scd30.h" |
33 | |
34 | #define SCD30_PRESSURE_COMP_MIN_MBAR 700 |
35 | #define SCD30_PRESSURE_COMP_MAX_MBAR 1400 |
36 | #define SCD30_PRESSURE_COMP_DEFAULT 1013 |
37 | #define SCD30_MEAS_INTERVAL_MIN_S 2 |
38 | #define SCD30_MEAS_INTERVAL_MAX_S 1800 |
39 | #define SCD30_MEAS_INTERVAL_DEFAULT SCD30_MEAS_INTERVAL_MIN_S |
40 | #define SCD30_FRC_MIN_PPM 400 |
41 | #define SCD30_FRC_MAX_PPM 2000 |
42 | #define SCD30_TEMP_OFFSET_MAX 655360 |
43 | #define 250 |
44 | |
45 | enum { |
46 | SCD30_CONC, |
47 | SCD30_TEMP, |
48 | SCD30_HR, |
49 | }; |
50 | |
51 | static int scd30_command_write(struct scd30_state *state, enum scd30_cmd cmd, u16 arg) |
52 | { |
53 | return state->command(state, cmd, arg, NULL, 0); |
54 | } |
55 | |
56 | static int scd30_command_read(struct scd30_state *state, enum scd30_cmd cmd, u16 *val) |
57 | { |
58 | __be16 tmp; |
59 | int ret; |
60 | |
61 | ret = state->command(state, cmd, 0, &tmp, sizeof(tmp)); |
62 | *val = be16_to_cpup(p: &tmp); |
63 | |
64 | return ret; |
65 | } |
66 | |
67 | static int scd30_reset(struct scd30_state *state) |
68 | { |
69 | int ret; |
70 | u16 val; |
71 | |
72 | ret = scd30_command_write(state, cmd: CMD_RESET, arg: 0); |
73 | if (ret) |
74 | return ret; |
75 | |
76 | /* sensor boots up within 2 secs */ |
77 | msleep(msecs: 2000); |
78 | /* |
79 | * Power-on-reset causes sensor to produce some glitch on i2c bus and |
80 | * some controllers end up in error state. Try to recover by placing |
81 | * any data on the bus. |
82 | */ |
83 | scd30_command_read(state, cmd: CMD_MEAS_READY, val: &val); |
84 | |
85 | return 0; |
86 | } |
87 | |
88 | /* simplified float to fixed point conversion with a scaling factor of 0.01 */ |
89 | static int scd30_float_to_fp(int float32) |
90 | { |
91 | int fraction, shift, |
92 | mantissa = float32 & GENMASK(22, 0), |
93 | sign = (float32 & BIT(31)) ? -1 : 1, |
94 | exp = (float32 & ~BIT(31)) >> 23; |
95 | |
96 | /* special case 0 */ |
97 | if (!exp && !mantissa) |
98 | return 0; |
99 | |
100 | exp -= 127; |
101 | if (exp < 0) { |
102 | exp = -exp; |
103 | /* return values ranging from 1 to 99 */ |
104 | return sign * ((((BIT(23) + mantissa) * 100) >> 23) >> exp); |
105 | } |
106 | |
107 | /* return values starting at 100 */ |
108 | shift = 23 - exp; |
109 | float32 = BIT(exp) + (mantissa >> shift); |
110 | fraction = mantissa & GENMASK(shift - 1, 0); |
111 | |
112 | return sign * (float32 * 100 + ((fraction * 100) >> shift)); |
113 | } |
114 | |
115 | static int scd30_read_meas(struct scd30_state *state) |
116 | { |
117 | int i, ret; |
118 | |
119 | ret = state->command(state, CMD_READ_MEAS, 0, state->meas, sizeof(state->meas)); |
120 | if (ret) |
121 | return ret; |
122 | |
123 | be32_to_cpu_array(dst: state->meas, src: (__be32 *)state->meas, ARRAY_SIZE(state->meas)); |
124 | |
125 | for (i = 0; i < ARRAY_SIZE(state->meas); i++) |
126 | state->meas[i] = scd30_float_to_fp(float32: state->meas[i]); |
127 | |
128 | /* |
129 | * co2 is left unprocessed while temperature and humidity are scaled |
130 | * to milli deg C and milli percent respectively. |
131 | */ |
132 | state->meas[SCD30_TEMP] *= 10; |
133 | state->meas[SCD30_HR] *= 10; |
134 | |
135 | return 0; |
136 | } |
137 | |
138 | static int scd30_wait_meas_irq(struct scd30_state *state) |
139 | { |
140 | int ret, timeout; |
141 | |
142 | reinit_completion(x: &state->meas_ready); |
143 | enable_irq(irq: state->irq); |
144 | timeout = msecs_to_jiffies(m: state->meas_interval * (1000 + SCD30_EXTRA_TIMEOUT_PER_S)); |
145 | ret = wait_for_completion_interruptible_timeout(x: &state->meas_ready, timeout); |
146 | if (ret > 0) |
147 | ret = 0; |
148 | else if (!ret) |
149 | ret = -ETIMEDOUT; |
150 | |
151 | disable_irq(irq: state->irq); |
152 | |
153 | return ret; |
154 | } |
155 | |
156 | static int scd30_wait_meas_poll(struct scd30_state *state) |
157 | { |
158 | int timeout = state->meas_interval * SCD30_EXTRA_TIMEOUT_PER_S, tries = 5; |
159 | |
160 | do { |
161 | int ret; |
162 | u16 val; |
163 | |
164 | ret = scd30_command_read(state, cmd: CMD_MEAS_READY, val: &val); |
165 | if (ret) |
166 | return -EIO; |
167 | |
168 | /* new measurement available */ |
169 | if (val) |
170 | break; |
171 | |
172 | msleep_interruptible(msecs: timeout); |
173 | } while (--tries); |
174 | |
175 | return tries ? 0 : -ETIMEDOUT; |
176 | } |
177 | |
178 | static int scd30_read_poll(struct scd30_state *state) |
179 | { |
180 | int ret; |
181 | |
182 | ret = scd30_wait_meas_poll(state); |
183 | if (ret) |
184 | return ret; |
185 | |
186 | return scd30_read_meas(state); |
187 | } |
188 | |
189 | static int scd30_read(struct scd30_state *state) |
190 | { |
191 | if (state->irq > 0) |
192 | return scd30_wait_meas_irq(state); |
193 | |
194 | return scd30_read_poll(state); |
195 | } |
196 | |
197 | static int scd30_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, |
198 | int *val, int *val2, long mask) |
199 | { |
200 | struct scd30_state *state = iio_priv(indio_dev); |
201 | int ret = -EINVAL; |
202 | u16 tmp; |
203 | |
204 | mutex_lock(&state->lock); |
205 | switch (mask) { |
206 | case IIO_CHAN_INFO_RAW: |
207 | case IIO_CHAN_INFO_PROCESSED: |
208 | if (chan->output) { |
209 | *val = state->pressure_comp; |
210 | ret = IIO_VAL_INT; |
211 | break; |
212 | } |
213 | |
214 | ret = iio_device_claim_direct_mode(indio_dev); |
215 | if (ret) |
216 | break; |
217 | |
218 | ret = scd30_read(state); |
219 | if (ret) { |
220 | iio_device_release_direct_mode(indio_dev); |
221 | break; |
222 | } |
223 | |
224 | *val = state->meas[chan->address]; |
225 | iio_device_release_direct_mode(indio_dev); |
226 | ret = IIO_VAL_INT; |
227 | break; |
228 | case IIO_CHAN_INFO_SCALE: |
229 | *val = 0; |
230 | *val2 = 1; |
231 | ret = IIO_VAL_INT_PLUS_MICRO; |
232 | break; |
233 | case IIO_CHAN_INFO_SAMP_FREQ: |
234 | ret = scd30_command_read(state, cmd: CMD_MEAS_INTERVAL, val: &tmp); |
235 | if (ret) |
236 | break; |
237 | |
238 | *val = 0; |
239 | *val2 = 1000000000 / tmp; |
240 | ret = IIO_VAL_INT_PLUS_NANO; |
241 | break; |
242 | case IIO_CHAN_INFO_CALIBBIAS: |
243 | ret = scd30_command_read(state, cmd: CMD_TEMP_OFFSET, val: &tmp); |
244 | if (ret) |
245 | break; |
246 | |
247 | *val = tmp; |
248 | ret = IIO_VAL_INT; |
249 | break; |
250 | } |
251 | mutex_unlock(lock: &state->lock); |
252 | |
253 | return ret; |
254 | } |
255 | |
256 | static int scd30_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, |
257 | int val, int val2, long mask) |
258 | { |
259 | struct scd30_state *state = iio_priv(indio_dev); |
260 | int ret = -EINVAL; |
261 | |
262 | mutex_lock(&state->lock); |
263 | switch (mask) { |
264 | case IIO_CHAN_INFO_SAMP_FREQ: |
265 | if (val) |
266 | break; |
267 | |
268 | val = 1000000000 / val2; |
269 | if (val < SCD30_MEAS_INTERVAL_MIN_S || val > SCD30_MEAS_INTERVAL_MAX_S) |
270 | break; |
271 | |
272 | ret = scd30_command_write(state, cmd: CMD_MEAS_INTERVAL, arg: val); |
273 | if (ret) |
274 | break; |
275 | |
276 | state->meas_interval = val; |
277 | break; |
278 | case IIO_CHAN_INFO_RAW: |
279 | switch (chan->type) { |
280 | case IIO_PRESSURE: |
281 | if (val < SCD30_PRESSURE_COMP_MIN_MBAR || |
282 | val > SCD30_PRESSURE_COMP_MAX_MBAR) |
283 | break; |
284 | |
285 | ret = scd30_command_write(state, cmd: CMD_START_MEAS, arg: val); |
286 | if (ret) |
287 | break; |
288 | |
289 | state->pressure_comp = val; |
290 | break; |
291 | default: |
292 | break; |
293 | } |
294 | break; |
295 | case IIO_CHAN_INFO_CALIBBIAS: |
296 | if (val < 0 || val > SCD30_TEMP_OFFSET_MAX) |
297 | break; |
298 | /* |
299 | * Manufacturer does not explicitly specify min/max sensible |
300 | * values hence check is omitted for simplicity. |
301 | */ |
302 | ret = scd30_command_write(state, cmd: CMD_TEMP_OFFSET / 10, arg: val); |
303 | } |
304 | mutex_unlock(lock: &state->lock); |
305 | |
306 | return ret; |
307 | } |
308 | |
309 | static int scd30_write_raw_get_fmt(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, |
310 | long mask) |
311 | { |
312 | switch (mask) { |
313 | case IIO_CHAN_INFO_SAMP_FREQ: |
314 | return IIO_VAL_INT_PLUS_NANO; |
315 | case IIO_CHAN_INFO_RAW: |
316 | case IIO_CHAN_INFO_CALIBBIAS: |
317 | return IIO_VAL_INT; |
318 | } |
319 | |
320 | return -EINVAL; |
321 | } |
322 | |
323 | static const int scd30_pressure_raw_available[] = { |
324 | SCD30_PRESSURE_COMP_MIN_MBAR, 1, SCD30_PRESSURE_COMP_MAX_MBAR, |
325 | }; |
326 | |
327 | static const int scd30_temp_calibbias_available[] = { |
328 | 0, 10, SCD30_TEMP_OFFSET_MAX, |
329 | }; |
330 | |
331 | static int scd30_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, |
332 | const int **vals, int *type, int *length, long mask) |
333 | { |
334 | switch (mask) { |
335 | case IIO_CHAN_INFO_RAW: |
336 | *vals = scd30_pressure_raw_available; |
337 | *type = IIO_VAL_INT; |
338 | |
339 | return IIO_AVAIL_RANGE; |
340 | case IIO_CHAN_INFO_CALIBBIAS: |
341 | *vals = scd30_temp_calibbias_available; |
342 | *type = IIO_VAL_INT; |
343 | |
344 | return IIO_AVAIL_RANGE; |
345 | } |
346 | |
347 | return -EINVAL; |
348 | } |
349 | |
350 | static ssize_t sampling_frequency_available_show(struct device *dev, struct device_attribute *attr, |
351 | char *buf) |
352 | { |
353 | int i = SCD30_MEAS_INTERVAL_MIN_S; |
354 | ssize_t len = 0; |
355 | |
356 | do { |
357 | len += sysfs_emit_at(buf, at: len, fmt: "0.%09u " , 1000000000 / i); |
358 | /* |
359 | * Not all values fit PAGE_SIZE buffer hence print every 6th |
360 | * (each frequency differs by 6s in time domain from the |
361 | * adjacent). Unlisted but valid ones are still accepted. |
362 | */ |
363 | i += 6; |
364 | } while (i <= SCD30_MEAS_INTERVAL_MAX_S); |
365 | |
366 | buf[len - 1] = '\n'; |
367 | |
368 | return len; |
369 | } |
370 | |
371 | static ssize_t calibration_auto_enable_show(struct device *dev, struct device_attribute *attr, |
372 | char *buf) |
373 | { |
374 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); |
375 | struct scd30_state *state = iio_priv(indio_dev); |
376 | int ret; |
377 | u16 val; |
378 | |
379 | mutex_lock(&state->lock); |
380 | ret = scd30_command_read(state, cmd: CMD_ASC, val: &val); |
381 | mutex_unlock(lock: &state->lock); |
382 | |
383 | return ret ?: sysfs_emit(buf, fmt: "%d\n" , val); |
384 | } |
385 | |
386 | static ssize_t calibration_auto_enable_store(struct device *dev, struct device_attribute *attr, |
387 | const char *buf, size_t len) |
388 | { |
389 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); |
390 | struct scd30_state *state = iio_priv(indio_dev); |
391 | bool val; |
392 | int ret; |
393 | |
394 | ret = kstrtobool(s: buf, res: &val); |
395 | if (ret) |
396 | return ret; |
397 | |
398 | mutex_lock(&state->lock); |
399 | ret = scd30_command_write(state, cmd: CMD_ASC, arg: val); |
400 | mutex_unlock(lock: &state->lock); |
401 | |
402 | return ret ?: len; |
403 | } |
404 | |
405 | static ssize_t calibration_forced_value_show(struct device *dev, struct device_attribute *attr, |
406 | char *buf) |
407 | { |
408 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); |
409 | struct scd30_state *state = iio_priv(indio_dev); |
410 | int ret; |
411 | u16 val; |
412 | |
413 | mutex_lock(&state->lock); |
414 | ret = scd30_command_read(state, cmd: CMD_FRC, val: &val); |
415 | mutex_unlock(lock: &state->lock); |
416 | |
417 | return ret ?: sysfs_emit(buf, fmt: "%d\n" , val); |
418 | } |
419 | |
420 | static ssize_t calibration_forced_value_store(struct device *dev, struct device_attribute *attr, |
421 | const char *buf, size_t len) |
422 | { |
423 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); |
424 | struct scd30_state *state = iio_priv(indio_dev); |
425 | int ret; |
426 | u16 val; |
427 | |
428 | ret = kstrtou16(s: buf, base: 0, res: &val); |
429 | if (ret) |
430 | return ret; |
431 | |
432 | if (val < SCD30_FRC_MIN_PPM || val > SCD30_FRC_MAX_PPM) |
433 | return -EINVAL; |
434 | |
435 | mutex_lock(&state->lock); |
436 | ret = scd30_command_write(state, cmd: CMD_FRC, arg: val); |
437 | mutex_unlock(lock: &state->lock); |
438 | |
439 | return ret ?: len; |
440 | } |
441 | |
442 | static IIO_DEVICE_ATTR_RO(sampling_frequency_available, 0); |
443 | static IIO_DEVICE_ATTR_RW(calibration_auto_enable, 0); |
444 | static IIO_DEVICE_ATTR_RW(calibration_forced_value, 0); |
445 | |
446 | static struct attribute *scd30_attrs[] = { |
447 | &iio_dev_attr_sampling_frequency_available.dev_attr.attr, |
448 | &iio_dev_attr_calibration_auto_enable.dev_attr.attr, |
449 | &iio_dev_attr_calibration_forced_value.dev_attr.attr, |
450 | NULL |
451 | }; |
452 | |
453 | static const struct attribute_group scd30_attr_group = { |
454 | .attrs = scd30_attrs, |
455 | }; |
456 | |
457 | static const struct iio_info scd30_info = { |
458 | .attrs = &scd30_attr_group, |
459 | .read_raw = scd30_read_raw, |
460 | .write_raw = scd30_write_raw, |
461 | .write_raw_get_fmt = scd30_write_raw_get_fmt, |
462 | .read_avail = scd30_read_avail, |
463 | }; |
464 | |
465 | #define SCD30_CHAN_SCAN_TYPE(_sign, _realbits) .scan_type = { \ |
466 | .sign = _sign, \ |
467 | .realbits = _realbits, \ |
468 | .storagebits = 32, \ |
469 | .endianness = IIO_CPU, \ |
470 | } |
471 | |
472 | static const struct iio_chan_spec scd30_channels[] = { |
473 | { |
474 | /* |
475 | * this channel is special in a sense we are pretending that |
476 | * sensor is able to change measurement chamber pressure but in |
477 | * fact we're just setting pressure compensation value |
478 | */ |
479 | .type = IIO_PRESSURE, |
480 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), |
481 | .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW), |
482 | .output = 1, |
483 | .scan_index = -1, |
484 | }, |
485 | { |
486 | .type = IIO_CONCENTRATION, |
487 | .channel2 = IIO_MOD_CO2, |
488 | .address = SCD30_CONC, |
489 | .scan_index = SCD30_CONC, |
490 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
491 | BIT(IIO_CHAN_INFO_SCALE), |
492 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), |
493 | .modified = 1, |
494 | |
495 | SCD30_CHAN_SCAN_TYPE('u', 20), |
496 | }, |
497 | { |
498 | .type = IIO_TEMP, |
499 | .address = SCD30_TEMP, |
500 | .scan_index = SCD30_TEMP, |
501 | .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | |
502 | BIT(IIO_CHAN_INFO_CALIBBIAS), |
503 | .info_mask_separate_available = BIT(IIO_CHAN_INFO_CALIBBIAS), |
504 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), |
505 | |
506 | SCD30_CHAN_SCAN_TYPE('s', 18), |
507 | }, |
508 | { |
509 | .type = IIO_HUMIDITYRELATIVE, |
510 | .address = SCD30_HR, |
511 | .scan_index = SCD30_HR, |
512 | .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), |
513 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), |
514 | |
515 | SCD30_CHAN_SCAN_TYPE('u', 17), |
516 | }, |
517 | IIO_CHAN_SOFT_TIMESTAMP(3), |
518 | }; |
519 | |
520 | static int scd30_suspend(struct device *dev) |
521 | { |
522 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
523 | struct scd30_state *state = iio_priv(indio_dev); |
524 | int ret; |
525 | |
526 | ret = scd30_command_write(state, cmd: CMD_STOP_MEAS, arg: 0); |
527 | if (ret) |
528 | return ret; |
529 | |
530 | return regulator_disable(regulator: state->vdd); |
531 | } |
532 | |
533 | static int scd30_resume(struct device *dev) |
534 | { |
535 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
536 | struct scd30_state *state = iio_priv(indio_dev); |
537 | int ret; |
538 | |
539 | ret = regulator_enable(regulator: state->vdd); |
540 | if (ret) |
541 | return ret; |
542 | |
543 | return scd30_command_write(state, cmd: CMD_START_MEAS, arg: state->pressure_comp); |
544 | } |
545 | |
546 | EXPORT_NS_SIMPLE_DEV_PM_OPS(scd30_pm_ops, scd30_suspend, scd30_resume, IIO_SCD30); |
547 | |
548 | static void scd30_stop_meas(void *data) |
549 | { |
550 | struct scd30_state *state = data; |
551 | |
552 | scd30_command_write(state, cmd: CMD_STOP_MEAS, arg: 0); |
553 | } |
554 | |
555 | static void scd30_disable_regulator(void *data) |
556 | { |
557 | struct scd30_state *state = data; |
558 | |
559 | regulator_disable(regulator: state->vdd); |
560 | } |
561 | |
562 | static irqreturn_t scd30_irq_handler(int irq, void *priv) |
563 | { |
564 | struct iio_dev *indio_dev = priv; |
565 | |
566 | if (iio_buffer_enabled(indio_dev)) { |
567 | iio_trigger_poll(trig: indio_dev->trig); |
568 | |
569 | return IRQ_HANDLED; |
570 | } |
571 | |
572 | return IRQ_WAKE_THREAD; |
573 | } |
574 | |
575 | static irqreturn_t scd30_irq_thread_handler(int irq, void *priv) |
576 | { |
577 | struct iio_dev *indio_dev = priv; |
578 | struct scd30_state *state = iio_priv(indio_dev); |
579 | int ret; |
580 | |
581 | ret = scd30_read_meas(state); |
582 | if (ret) |
583 | goto out; |
584 | |
585 | complete_all(&state->meas_ready); |
586 | out: |
587 | return IRQ_HANDLED; |
588 | } |
589 | |
590 | static irqreturn_t scd30_trigger_handler(int irq, void *p) |
591 | { |
592 | struct iio_poll_func *pf = p; |
593 | struct iio_dev *indio_dev = pf->indio_dev; |
594 | struct scd30_state *state = iio_priv(indio_dev); |
595 | struct { |
596 | int data[SCD30_MEAS_COUNT]; |
597 | s64 ts __aligned(8); |
598 | } scan; |
599 | int ret; |
600 | |
601 | mutex_lock(&state->lock); |
602 | if (!iio_trigger_using_own(indio_dev)) |
603 | ret = scd30_read_poll(state); |
604 | else |
605 | ret = scd30_read_meas(state); |
606 | memset(&scan, 0, sizeof(scan)); |
607 | memcpy(scan.data, state->meas, sizeof(state->meas)); |
608 | mutex_unlock(lock: &state->lock); |
609 | if (ret) |
610 | goto out; |
611 | |
612 | iio_push_to_buffers_with_timestamp(indio_dev, data: &scan, timestamp: iio_get_time_ns(indio_dev)); |
613 | out: |
614 | iio_trigger_notify_done(trig: indio_dev->trig); |
615 | return IRQ_HANDLED; |
616 | } |
617 | |
618 | static int scd30_set_trigger_state(struct iio_trigger *trig, bool state) |
619 | { |
620 | struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); |
621 | struct scd30_state *st = iio_priv(indio_dev); |
622 | |
623 | if (state) |
624 | enable_irq(irq: st->irq); |
625 | else |
626 | disable_irq(irq: st->irq); |
627 | |
628 | return 0; |
629 | } |
630 | |
631 | static const struct iio_trigger_ops scd30_trigger_ops = { |
632 | .set_trigger_state = scd30_set_trigger_state, |
633 | .validate_device = iio_trigger_validate_own_device, |
634 | }; |
635 | |
636 | static int scd30_setup_trigger(struct iio_dev *indio_dev) |
637 | { |
638 | struct scd30_state *state = iio_priv(indio_dev); |
639 | struct device *dev = indio_dev->dev.parent; |
640 | struct iio_trigger *trig; |
641 | int ret; |
642 | |
643 | trig = devm_iio_trigger_alloc(dev, "%s-dev%d" , indio_dev->name, |
644 | iio_device_id(indio_dev)); |
645 | if (!trig) |
646 | return dev_err_probe(dev, err: -ENOMEM, fmt: "failed to allocate trigger\n" ); |
647 | |
648 | trig->ops = &scd30_trigger_ops; |
649 | iio_trigger_set_drvdata(trig, data: indio_dev); |
650 | |
651 | ret = devm_iio_trigger_register(dev, trig_info: trig); |
652 | if (ret) |
653 | return ret; |
654 | |
655 | indio_dev->trig = iio_trigger_get(trig); |
656 | |
657 | /* |
658 | * Interrupt is enabled just before taking a fresh measurement |
659 | * and disabled afterwards. This means we need to ensure it is not |
660 | * enabled here to keep calls to enable/disable balanced. |
661 | */ |
662 | ret = devm_request_threaded_irq(dev, irq: state->irq, handler: scd30_irq_handler, |
663 | thread_fn: scd30_irq_thread_handler, |
664 | IRQF_TRIGGER_HIGH | IRQF_ONESHOT | |
665 | IRQF_NO_AUTOEN, |
666 | devname: indio_dev->name, dev_id: indio_dev); |
667 | if (ret) |
668 | return dev_err_probe(dev, err: ret, fmt: "failed to request irq\n" ); |
669 | |
670 | return 0; |
671 | } |
672 | |
673 | int scd30_probe(struct device *dev, int irq, const char *name, void *priv, |
674 | scd30_command_t command) |
675 | { |
676 | static const unsigned long scd30_scan_masks[] = { 0x07, 0x00 }; |
677 | struct scd30_state *state; |
678 | struct iio_dev *indio_dev; |
679 | int ret; |
680 | u16 val; |
681 | |
682 | indio_dev = devm_iio_device_alloc(parent: dev, sizeof_priv: sizeof(*state)); |
683 | if (!indio_dev) |
684 | return -ENOMEM; |
685 | |
686 | state = iio_priv(indio_dev); |
687 | state->dev = dev; |
688 | state->priv = priv; |
689 | state->irq = irq; |
690 | state->pressure_comp = SCD30_PRESSURE_COMP_DEFAULT; |
691 | state->meas_interval = SCD30_MEAS_INTERVAL_DEFAULT; |
692 | state->command = command; |
693 | mutex_init(&state->lock); |
694 | init_completion(x: &state->meas_ready); |
695 | |
696 | dev_set_drvdata(dev, data: indio_dev); |
697 | |
698 | indio_dev->info = &scd30_info; |
699 | indio_dev->name = name; |
700 | indio_dev->channels = scd30_channels; |
701 | indio_dev->num_channels = ARRAY_SIZE(scd30_channels); |
702 | indio_dev->modes = INDIO_DIRECT_MODE; |
703 | indio_dev->available_scan_masks = scd30_scan_masks; |
704 | |
705 | state->vdd = devm_regulator_get(dev, id: "vdd" ); |
706 | if (IS_ERR(ptr: state->vdd)) |
707 | return dev_err_probe(dev, err: PTR_ERR(ptr: state->vdd), fmt: "failed to get regulator\n" ); |
708 | |
709 | ret = regulator_enable(regulator: state->vdd); |
710 | if (ret) |
711 | return ret; |
712 | |
713 | ret = devm_add_action_or_reset(dev, scd30_disable_regulator, state); |
714 | if (ret) |
715 | return ret; |
716 | |
717 | ret = scd30_reset(state); |
718 | if (ret) |
719 | return dev_err_probe(dev, err: ret, fmt: "failed to reset device\n" ); |
720 | |
721 | if (state->irq > 0) { |
722 | ret = scd30_setup_trigger(indio_dev); |
723 | if (ret) |
724 | return dev_err_probe(dev, err: ret, fmt: "failed to setup trigger\n" ); |
725 | } |
726 | |
727 | ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, scd30_trigger_handler, NULL); |
728 | if (ret) |
729 | return ret; |
730 | |
731 | ret = scd30_command_read(state, cmd: CMD_FW_VERSION, val: &val); |
732 | if (ret) |
733 | return dev_err_probe(dev, err: ret, fmt: "failed to read firmware version\n" ); |
734 | dev_info(dev, "firmware version: %d.%d\n" , val >> 8, (char)val); |
735 | |
736 | ret = scd30_command_write(state, cmd: CMD_MEAS_INTERVAL, arg: state->meas_interval); |
737 | if (ret) |
738 | return dev_err_probe(dev, err: ret, fmt: "failed to set measurement interval\n" ); |
739 | |
740 | ret = scd30_command_write(state, cmd: CMD_START_MEAS, arg: state->pressure_comp); |
741 | if (ret) |
742 | return dev_err_probe(dev, err: ret, fmt: "failed to start measurement\n" ); |
743 | |
744 | ret = devm_add_action_or_reset(dev, scd30_stop_meas, state); |
745 | if (ret) |
746 | return ret; |
747 | |
748 | return devm_iio_device_register(dev, indio_dev); |
749 | } |
750 | EXPORT_SYMBOL_NS(scd30_probe, IIO_SCD30); |
751 | |
752 | MODULE_AUTHOR("Tomasz Duszynski <tomasz.duszynski@octakon.com>" ); |
753 | MODULE_DESCRIPTION("Sensirion SCD30 carbon dioxide sensor core driver" ); |
754 | MODULE_LICENSE("GPL v2" ); |
755 | |