1 /*
2 * Copyright (c) 2024 Jan Fäh
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/device.h>
8 #include <zephyr/kernel.h>
9 #include <zephyr/drivers/sensor.h>
10 #include <zephyr/drivers/i2c.h>
11 #include <zephyr/logging/log.h>
12 #include <zephyr/sys/__assert.h>
13 #include <zephyr/sys/byteorder.h>
14 #include <zephyr/sys/crc.h>
15 #include <zephyr/devicetree.h>
16
17 #include <zephyr/drivers/sensor/scd4x.h>
18 #include "scd4x.h"
19
20 LOG_MODULE_REGISTER(SCD4X, CONFIG_SENSOR_LOG_LEVEL);
21
scd4x_calc_crc(uint16_t value)22 static uint8_t scd4x_calc_crc(uint16_t value)
23 {
24 uint8_t buf[2];
25
26 sys_put_be16(value, buf);
27
28 return crc8(buf, 2, SCD4X_CRC_POLY, SCD4X_CRC_INIT, false);
29 }
30
scd4x_write_command(const struct device * dev,uint8_t cmd)31 static int scd4x_write_command(const struct device *dev, uint8_t cmd)
32 {
33 const struct scd4x_config *cfg = dev->config;
34 uint8_t tx_buf[2];
35 int ret;
36
37 sys_put_be16(scd4x_cmds[cmd].cmd, tx_buf);
38
39 ret = i2c_write_dt(&cfg->bus, tx_buf, sizeof(tx_buf));
40
41 if (scd4x_cmds[cmd].cmd_duration_ms) {
42 k_msleep(scd4x_cmds[cmd].cmd_duration_ms);
43 }
44
45 return ret;
46 }
47
scd4x_read_reg(const struct device * dev,uint8_t * rx_buf,uint8_t rx_buf_size)48 static int scd4x_read_reg(const struct device *dev, uint8_t *rx_buf, uint8_t rx_buf_size)
49 {
50 const struct scd4x_config *cfg = dev->config;
51 int ret;
52
53 ret = i2c_read_dt(&cfg->bus, rx_buf, rx_buf_size);
54 if (ret < 0) {
55 LOG_ERR("Failed to read i2c data.");
56 return ret;
57 }
58
59 for (uint8_t i = 0; i < (rx_buf_size / 3); i++) {
60 ret = scd4x_calc_crc(sys_get_be16(&rx_buf[i * 3]));
61 if (ret != rx_buf[(i * 3) + 2]) {
62 LOG_ERR("Invalid CRC.");
63 return -EIO;
64 }
65 }
66
67 return 0;
68 }
69
scd4x_write_reg(const struct device * dev,uint8_t cmd,uint16_t * data,uint8_t data_size)70 static int scd4x_write_reg(const struct device *dev, uint8_t cmd, uint16_t *data, uint8_t data_size)
71 {
72 const struct scd4x_config *cfg = dev->config;
73 int ret;
74 uint8_t tx_buf[((data_size * 3) + 2)];
75
76 sys_put_be16(scd4x_cmds[cmd].cmd, tx_buf);
77
78 uint8_t tx_buf_pos = 2;
79
80 for (uint8_t i = 0; i < data_size; i++) {
81 sys_put_be16(data[i], &tx_buf[tx_buf_pos]);
82 tx_buf_pos += 2;
83 tx_buf[tx_buf_pos++] = scd4x_calc_crc(data[i]);
84 }
85
86 ret = i2c_write_dt(&cfg->bus, tx_buf, sizeof(tx_buf));
87 if (ret < 0) {
88 LOG_ERR("Failed to write i2c data.");
89 return ret;
90 }
91
92 if (scd4x_cmds[cmd].cmd_duration_ms) {
93 k_msleep(scd4x_cmds[cmd].cmd_duration_ms);
94 }
95 return 0;
96 }
97
scd4x_data_ready(const struct device * dev,bool * is_data_ready)98 static int scd4x_data_ready(const struct device *dev, bool *is_data_ready)
99 {
100 uint8_t rx_data[3];
101 int ret;
102 *is_data_ready = false;
103
104 ret = scd4x_write_command(dev, SCD4X_CMD_GET_DATA_READY_STATUS);
105 if (ret < 0) {
106 LOG_ERR("Failed to write get_data_ready_status command.");
107 return ret;
108 }
109
110 ret = scd4x_read_reg(dev, rx_data, sizeof(rx_data));
111 if (ret < 0) {
112 LOG_ERR("Failed to read get_data_ready_status register.");
113 return ret;
114 }
115
116 uint16_t word = sys_get_be16(rx_data);
117 /* Least significant 11 bits = 0 --> data not ready */
118 if ((word & 0x07FF) > 0) {
119 *is_data_ready = true;
120 }
121
122 return 0;
123 }
124
scd4x_read_sample(const struct device * dev)125 static int scd4x_read_sample(const struct device *dev)
126 {
127 struct scd4x_data *data = dev->data;
128 uint8_t rx_data[9];
129 int ret;
130
131 ret = scd4x_write_command(dev, SCD4X_CMD_READ_MEASUREMENT);
132 if (ret < 0) {
133 LOG_ERR("Failed to write read_measurement command.");
134 return ret;
135 }
136
137 ret = scd4x_read_reg(dev, rx_data, sizeof(rx_data));
138 if (ret < 0) {
139 LOG_ERR("Failed to read read_measurement register.");
140 return ret;
141 }
142
143 data->co2_sample = sys_get_be16(rx_data);
144 data->temp_sample = sys_get_be16(&rx_data[3]);
145 data->humi_sample = sys_get_be16(&rx_data[6]);
146
147 return 0;
148 }
149
scd4x_setup_measurement(const struct device * dev)150 static int scd4x_setup_measurement(const struct device *dev)
151 {
152 const struct scd4x_config *cfg = dev->config;
153 int ret;
154
155 switch ((enum scd4x_mode_t)cfg->mode) {
156 case SCD4X_MODE_NORMAL:
157 ret = scd4x_write_command(dev, SCD4X_CMD_START_PERIODIC_MEASUREMENT);
158 if (ret < 0) {
159 LOG_ERR("Failed to write start_periodic_measurement command.");
160 return ret;
161 }
162 break;
163 case SCD4X_MODE_LOW_POWER:
164 ret = scd4x_write_command(dev, SCD4X_CMD_LOW_POWER_PERIODIC_MEASUREMENT);
165 if (ret < 0) {
166 LOG_ERR("Failed to write start_low_power_periodic_measurement command.");
167 return ret;
168 }
169 break;
170 case SCD4X_MODE_SINGLE_SHOT:
171 ret = scd4x_write_command(dev, SCD4X_CMD_POWER_DOWN);
172 if (ret < 0) {
173 LOG_ERR("Failed to write power_down command.");
174 return ret;
175 }
176 break;
177 default:
178 return -EINVAL;
179 }
180 return 0;
181 }
182
scd4x_set_idle_mode(const struct device * dev)183 static int scd4x_set_idle_mode(const struct device *dev)
184 {
185 const struct scd4x_config *cfg = dev->config;
186 int ret;
187
188 if (cfg->mode == SCD4X_MODE_SINGLE_SHOT) {
189 /*send wake up command twice because of an expected nack return in power down mode*/
190 scd4x_write_command(dev, SCD4X_CMD_WAKE_UP);
191 ret = scd4x_write_command(dev, SCD4X_CMD_WAKE_UP);
192 if (ret < 0) {
193 LOG_ERR("Failed write wake_up command.");
194 return ret;
195 }
196 } else {
197 ret = scd4x_write_command(dev, SCD4X_CMD_STOP_PERIODIC_MEASUREMENT);
198 if (ret < 0) {
199 LOG_ERR("Failed to write stop_periodic_measurement command.");
200 return ret;
201 }
202 }
203
204 return 0;
205 }
206
scd4x_set_temperature_offset(const struct device * dev,const struct sensor_value * val)207 static int scd4x_set_temperature_offset(const struct device *dev, const struct sensor_value *val)
208 {
209 int ret;
210 /*Calculation from Datasheet*/
211 uint16_t offset_temp =
212 (float)(val->val1 + (val->val2 / 1000000.0)) * 0xFFFF / SCD4X_MAX_TEMP;
213
214 ret = scd4x_write_reg(dev, SCD4X_CMD_SET_TEMPERATURE_OFFSET, &offset_temp, 1);
215 if (ret < 0) {
216 LOG_ERR("Failed to write set_temperature_offset register.");
217 return ret;
218 }
219
220 return 0;
221 }
222
scd4x_set_sensor_altitude(const struct device * dev,const struct sensor_value * val)223 static int scd4x_set_sensor_altitude(const struct device *dev, const struct sensor_value *val)
224 {
225 int ret;
226 uint16_t altitude = val->val1;
227
228 ret = scd4x_write_reg(dev, SCD4X_CMD_SET_SENSOR_ALTITUDE, &altitude, 1);
229 if (ret < 0) {
230 LOG_ERR("Failed to write set_sensor_altitude register.");
231 return ret;
232 }
233 return 0;
234 }
235
scd4x_set_ambient_pressure(const struct device * dev,const struct sensor_value * val)236 static int scd4x_set_ambient_pressure(const struct device *dev, const struct sensor_value *val)
237 {
238 int ret;
239
240 uint16_t ambient_pressure = val->val1;
241
242 ret = scd4x_write_reg(dev, SCD4X_CMD_SET_AMBIENT_PRESSURE, &ambient_pressure, 1);
243 if (ret < 0) {
244 LOG_ERR("Failed to write set_ambient_pressure register.");
245 return ret;
246 }
247
248 return 0;
249 }
250
scd4x_set_automatic_calib_enable(const struct device * dev,const struct sensor_value * val)251 static int scd4x_set_automatic_calib_enable(const struct device *dev,
252 const struct sensor_value *val)
253 {
254 int ret;
255 uint16_t automatic_calib_enable = val->val1;
256
257 ret = scd4x_write_reg(dev, SCD4X_CMD_SET_AUTOMATIC_CALIB_ENABLE, &automatic_calib_enable,
258 1);
259 if (ret < 0) {
260 LOG_ERR("Failed to write set_automatic_calibration_enable register.");
261 return ret;
262 }
263
264 return 0;
265 }
266
scd4x_set_self_calib_initial_period(const struct device * dev,const struct sensor_value * val)267 static int scd4x_set_self_calib_initial_period(const struct device *dev,
268 const struct sensor_value *val)
269 {
270 int ret;
271 uint16_t initial_period = val->val1;
272
273 ret = scd4x_write_reg(dev, SCD4X_CMD_SET_SELF_CALIB_INITIAL_PERIOD, &initial_period, 1);
274 if (ret < 0) {
275 LOG_ERR("Failed to write set_automatic_self_calibration_initial_period register.");
276 return ret;
277 }
278
279 return 0;
280 }
281
scd4x_set_self_calib_standard_period(const struct device * dev,const struct sensor_value * val)282 static int scd4x_set_self_calib_standard_period(const struct device *dev,
283 const struct sensor_value *val)
284 {
285 int ret;
286 uint16_t standard_period = val->val1;
287
288 ret = scd4x_write_reg(dev, SCD4X_CMD_SET_SELF_CALIB_STANDARD_PERIOD, &standard_period, 1);
289 if (ret < 0) {
290 LOG_ERR("Failed to write set_automatic_self_calibration_standard_period register.");
291 return ret;
292 }
293
294 return 0;
295 }
296
scd4x_get_temperature_offset(const struct device * dev,struct sensor_value * val)297 static int scd4x_get_temperature_offset(const struct device *dev, struct sensor_value *val)
298 {
299 int ret;
300 uint8_t rx_buf[3];
301
302 ret = scd4x_write_command(dev, SCD4X_CMD_GET_TEMPERATURE_OFFSET);
303 if (ret < 0) {
304 LOG_ERR("Failed to write get_temperature_offset command.");
305 return ret;
306 }
307
308 ret = scd4x_read_reg(dev, rx_buf, sizeof(rx_buf));
309 if (ret < 0) {
310 LOG_ERR("Failed to read get_temperature_offset register.");
311 return ret;
312 }
313
314 int32_t temp;
315
316 /*Calculation from Datasheet*/
317 temp = sys_get_be16(rx_buf) * SCD4X_MAX_TEMP;
318 val->val1 = (int32_t)(temp / 0xFFFF);
319 val->val2 = ((temp % 0xFFFF) * 1000000) / 0xFFFF;
320
321 return 0;
322 }
323
scd4x_get_sensor_altitude(const struct device * dev,struct sensor_value * val)324 static int scd4x_get_sensor_altitude(const struct device *dev, struct sensor_value *val)
325 {
326 int ret;
327 uint8_t rx_buf[3];
328
329 ret = scd4x_write_command(dev, SCD4X_CMD_GET_SENSOR_ALTITUDE);
330 if (ret < 0) {
331 LOG_ERR("Failed to write get_sensor_altitude command.");
332 return ret;
333 }
334
335 ret = scd4x_read_reg(dev, rx_buf, sizeof(rx_buf));
336 if (ret < 0) {
337 LOG_ERR("Failed to read get_sensor_altitude register.");
338 return ret;
339 }
340
341 val->val1 = sys_get_be16(rx_buf);
342 val->val2 = 0;
343
344 return 0;
345 }
346
scd4x_get_ambient_pressure(const struct device * dev,struct sensor_value * val)347 static int scd4x_get_ambient_pressure(const struct device *dev, struct sensor_value *val)
348 {
349 int ret;
350 uint8_t rx_buf[3];
351
352 ret = scd4x_write_command(dev, SCD4X_CMD_GET_AMBIENT_PRESSURE);
353 if (ret < 0) {
354 LOG_ERR("Failed to write get_ambient_pressure command.");
355 return ret;
356 }
357
358 ret = scd4x_read_reg(dev, rx_buf, sizeof(rx_buf));
359 if (ret < 0) {
360 LOG_ERR("Failed to read get_ambient_pressure register.");
361 return ret;
362 }
363
364 val->val1 = sys_get_be16(rx_buf);
365 val->val2 = 0;
366
367 return 0;
368 }
369
scd4x_get_automatic_calib_enable(const struct device * dev,struct sensor_value * val)370 static int scd4x_get_automatic_calib_enable(const struct device *dev, struct sensor_value *val)
371 {
372 int ret;
373 uint8_t rx_buf[3];
374
375 ret = scd4x_write_command(dev, SCD4X_CMD_GET_AUTOMATIC_CALIB_ENABLE);
376 if (ret < 0) {
377 LOG_ERR("Failed to write get_automatic_calibration_enable command.");
378 return ret;
379 }
380
381 ret = scd4x_read_reg(dev, rx_buf, sizeof(rx_buf));
382 if (ret < 0) {
383 LOG_ERR("Failed to read get_automatic_calibration_enabled register.");
384 return ret;
385 }
386
387 val->val1 = sys_get_be16(rx_buf);
388 val->val2 = 0;
389
390 return 0;
391 }
392
scd4x_get_self_calib_initial_period(const struct device * dev,struct sensor_value * val)393 static int scd4x_get_self_calib_initial_period(const struct device *dev, struct sensor_value *val)
394 {
395 int ret;
396 uint8_t rx_buf[3];
397
398 ret = scd4x_write_command(dev, SCD4X_CMD_GET_SELF_CALIB_INITIAL_PERIOD);
399 if (ret < 0) {
400 LOG_ERR("Failed to write get_automati_calibration_initial_period command.");
401 return ret;
402 }
403
404 ret = scd4x_read_reg(dev, rx_buf, sizeof(rx_buf));
405 if (ret < 0) {
406 LOG_ERR("Failed to read get_automatic_calibration_initial_period register.");
407 return ret;
408 }
409
410 val->val1 = sys_get_be16(rx_buf);
411 val->val2 = 0;
412
413 return 0;
414 }
415
scd4x_get_self_calib_standard_period(const struct device * dev,struct sensor_value * val)416 static int scd4x_get_self_calib_standard_period(const struct device *dev, struct sensor_value *val)
417 {
418 int ret;
419 uint8_t rx_buf[3];
420
421 ret = scd4x_write_command(dev, SCD4X_CMD_GET_SELF_CALIB_STANDARD_PERIOD);
422 if (ret < 0) {
423 LOG_ERR("Failed to write get_automatic_self_calibration_standard_period command.");
424 return ret;
425 }
426
427 ret = scd4x_read_reg(dev, rx_buf, sizeof(rx_buf));
428 if (ret < 0) {
429 LOG_ERR("Failed to read get_automatic_self_calibration_standard_period register.");
430 return ret;
431 }
432
433 val->val1 = sys_get_be16(rx_buf);
434 val->val2 = 0;
435
436 return 0;
437 }
438
scd4x_forced_recalibration(const struct device * dev,uint16_t target_concentration,uint16_t * frc_correction)439 int scd4x_forced_recalibration(const struct device *dev, uint16_t target_concentration,
440 uint16_t *frc_correction)
441 {
442 uint8_t rx_buf[3];
443 int ret;
444
445 ret = scd4x_set_idle_mode(dev);
446 if (ret < 0) {
447 LOG_ERR("Failed to set idle mode.");
448 return ret;
449 }
450
451 ret = scd4x_write_reg(dev, SCD4X_CMD_FORCED_RECALIB, &target_concentration, 1);
452 if (ret < 0) {
453 LOG_ERR("Failed to write perform_forced_recalibration register.");
454 return ret;
455 }
456
457 ret = scd4x_read_reg(dev, rx_buf, sizeof(rx_buf));
458 if (ret < 0) {
459 LOG_ERR("Failed to read perform_forced_recalibration register.");
460 return ret;
461 }
462
463 *frc_correction = sys_get_be16(rx_buf);
464
465 /*from datasheet*/
466 if (*frc_correction == 0xFFFF) {
467 LOG_ERR("FRC failed. Returned 0xFFFF.");
468 return -EIO;
469 }
470
471 *frc_correction -= 0x8000;
472
473 ret = scd4x_setup_measurement(dev);
474 if (ret < 0) {
475 LOG_ERR("Failed to setup measurement.");
476 return ret;
477 }
478
479 return 0;
480 }
481
scd4x_self_test(const struct device * dev)482 int scd4x_self_test(const struct device *dev)
483 {
484 int ret;
485 uint8_t rx_buf[3];
486
487 ret = scd4x_set_idle_mode(dev);
488 if (ret < 0) {
489 LOG_ERR("Failed to set idle mode.");
490 return ret;
491 }
492
493 ret = scd4x_write_command(dev, SCD4X_CMD_SELF_TEST);
494 if (ret < 0) {
495 LOG_ERR("Failed to write perform_self_test command.");
496 return ret;
497 }
498
499 ret = scd4x_read_reg(dev, rx_buf, sizeof(rx_buf));
500 if (ret < 0) {
501 LOG_ERR("Failed to read perform_self_test register.");
502 return ret;
503 }
504
505 uint16_t is_malfunction = sys_get_be16(rx_buf);
506
507 if (is_malfunction) {
508 LOG_ERR("malfunction detected.");
509 return -EIO;
510 }
511
512 ret = scd4x_setup_measurement(dev);
513 if (ret < 0) {
514 LOG_ERR("Failed to setup measurement.");
515 return ret;
516 }
517
518 return 0;
519 }
520
scd4x_persist_settings(const struct device * dev)521 int scd4x_persist_settings(const struct device *dev)
522 {
523 int ret;
524
525 ret = scd4x_set_idle_mode(dev);
526 if (ret < 0) {
527 LOG_ERR("Failed to set idle mode.");
528 return ret;
529 }
530
531 ret = scd4x_write_command(dev, SCD4X_CMD_PERSIST_SETTINGS);
532 if (ret < 0) {
533 LOG_ERR("Failed to write persist_settings command.");
534 return ret;
535 }
536
537 ret = scd4x_setup_measurement(dev);
538 if (ret < 0) {
539 LOG_ERR("Failed to setup measurement.");
540 return ret;
541 }
542
543 return 0;
544 }
545
scd4x_factory_reset(const struct device * dev)546 int scd4x_factory_reset(const struct device *dev)
547 {
548 int ret;
549
550 ret = scd4x_set_idle_mode(dev);
551 if (ret < 0) {
552 LOG_ERR("Failed to set idle mode.");
553 return ret;
554 }
555
556 ret = scd4x_write_command(dev, SCD4X_CMD_FACTORY_RESET);
557 if (ret < 0) {
558 LOG_ERR("Failed to write perfom_factory_reset command.");
559 return ret;
560 }
561
562 ret = scd4x_setup_measurement(dev);
563 if (ret < 0) {
564 LOG_ERR("Failed to setup measurement.");
565 return ret;
566 }
567
568 return 0;
569 }
570
scd4x_sample_fetch(const struct device * dev,enum sensor_channel chan)571 static int scd4x_sample_fetch(const struct device *dev, enum sensor_channel chan)
572 {
573 const struct scd4x_config *cfg = dev->config;
574 bool is_data_ready;
575 int ret;
576
577 if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_AMBIENT_TEMP &&
578 chan != SENSOR_CHAN_HUMIDITY && chan != SENSOR_CHAN_CO2) {
579 return -ENOTSUP;
580 }
581
582 if (cfg->mode == SCD4X_MODE_SINGLE_SHOT) {
583 ret = scd4x_set_idle_mode(dev);
584 if (ret < 0) {
585 LOG_ERR("Failed to set idle mode.");
586 return ret;
587 }
588
589 if (chan == SENSOR_CHAN_HUMIDITY || chan == SENSOR_CHAN_AMBIENT_TEMP) {
590 ret = scd4x_write_command(dev, SCD4X_CMD_MEASURE_SINGLE_SHOT_RHT);
591 if (ret < 0) {
592 LOG_ERR("Failed to write measure_single_shot_rht_only command.");
593 return ret;
594 }
595 } else {
596 ret = scd4x_write_command(dev, SCD4X_CMD_MEASURE_SINGLE_SHOT);
597 if (ret < 0) {
598 LOG_ERR("Failed to write measure_single_shot command.");
599 return ret;
600 }
601 }
602 } else {
603 ret = scd4x_data_ready(dev, &is_data_ready);
604 if (ret < 0) {
605 LOG_ERR("Failed to check data ready.");
606 return ret;
607 }
608 if (!is_data_ready) {
609 return 0;
610 }
611 }
612
613 ret = scd4x_read_sample(dev);
614 if (ret < 0) {
615 LOG_ERR("Failed to get sample data.");
616 return ret;
617 }
618
619 if (cfg->mode == SCD4X_MODE_SINGLE_SHOT) {
620 ret = scd4x_setup_measurement(dev);
621 if (ret < 0) {
622 LOG_ERR("Failed to setup measurement.");
623 return ret;
624 }
625 }
626 return 0;
627 }
628
scd4x_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)629 static int scd4x_channel_get(const struct device *dev, enum sensor_channel chan,
630 struct sensor_value *val)
631 {
632 const struct scd4x_data *data = dev->data;
633 int32_t tmp_val;
634
635 switch ((enum sensor_channel)chan) {
636 case SENSOR_CHAN_AMBIENT_TEMP:
637 /*Calculation from Datasheet*/
638 tmp_val = data->temp_sample * SCD4X_MAX_TEMP;
639 val->val1 = (int32_t)(tmp_val / 0xFFFF) + SCD4X_MIN_TEMP;
640 val->val2 = ((tmp_val % 0xFFFF) * 1000000) / 0xFFFF;
641 break;
642 case SENSOR_CHAN_HUMIDITY:
643 /*Calculation from Datasheet*/
644 tmp_val = data->humi_sample * 100;
645 val->val1 = (int32_t)(tmp_val / 0xFFFF);
646 val->val2 = ((tmp_val % 0xFFFF) * 1000000) / 0xFFFF;
647 break;
648 case SENSOR_CHAN_CO2:
649 val->val1 = data->co2_sample;
650 val->val2 = 0;
651 break;
652 default:
653 return -ENOTSUP;
654 }
655 return 0;
656 }
657
scd4x_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)658 int scd4x_attr_set(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr,
659 const struct sensor_value *val)
660 {
661 const struct scd4x_config *cfg = dev->config;
662 int ret;
663
664 if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_AMBIENT_TEMP &&
665 chan != SENSOR_CHAN_HUMIDITY && chan != SENSOR_CHAN_CO2) {
666 return -ENOTSUP;
667 }
668
669 if ((enum sensor_attribute_scd4x)attr != SENSOR_ATTR_SCD4X_AMBIENT_PRESSURE) {
670 ret = scd4x_set_idle_mode(dev);
671 if (ret < 0) {
672 LOG_ERR("Failed to set idle mode.");
673 return ret;
674 }
675 }
676
677 if (val->val1 < 0 || val->val2 < 0) {
678 return -EINVAL;
679 }
680
681 switch ((enum sensor_attribute_scd4x)attr) {
682 case SENSOR_ATTR_SCD4X_TEMPERATURE_OFFSET:
683 if (val->val1 > SCD4X_TEMPERATURE_OFFSET_IDX_MAX) {
684 return -EINVAL;
685 }
686 ret = scd4x_set_temperature_offset(dev, val);
687 if (ret < 0) {
688 LOG_ERR("Failed to set temperature offset.");
689 return ret;
690 }
691 break;
692 case SENSOR_ATTR_SCD4X_SENSOR_ALTITUDE:
693 if (val->val1 > SCD4X_SENSOR_ALTITUDE_IDX_MAX) {
694 return -EINVAL;
695 }
696 ret = scd4x_set_sensor_altitude(dev, val);
697 if (ret < 0) {
698 LOG_ERR("Failed to set sensor altitude.");
699 return ret;
700 }
701 break;
702 case SENSOR_ATTR_SCD4X_AMBIENT_PRESSURE:
703 if (val->val1 > SCD4X_AMBIENT_PRESSURE_IDX_MAX || val->val1 < 700) {
704 return -EINVAL;
705 }
706 ret = scd4x_set_ambient_pressure(dev, val);
707 if (ret < 0) {
708 LOG_ERR("Failed to set ambient pressure.");
709 return ret;
710 }
711 /* return 0 to not call scd4x_start_measurement */
712 return 0;
713 case SENSOR_ATTR_SCD4X_AUTOMATIC_CALIB_ENABLE:
714 if (val->val1 > SCD4X_BOOL_IDX_MAX) {
715 return -EINVAL;
716 }
717 ret = scd4x_set_automatic_calib_enable(dev, val);
718 if (ret < 0) {
719 LOG_ERR("Failed to set automatic calib enable.");
720 return ret;
721 }
722 break;
723 case SENSOR_ATTR_SCD4X_SELF_CALIB_INITIAL_PERIOD:
724 if (val->val1 % 4) {
725 return -EINVAL;
726 }
727 if (cfg->model == SCD4X_MODEL_SCD40) {
728 LOG_ERR("SELF_CALIB_INITIAL_PERIOD not available for SCD40.");
729 return -ENOTSUP;
730 }
731 ret = scd4x_set_self_calib_initial_period(dev, val);
732 if (ret < 0) {
733 LOG_ERR("Failed to set self calib initial period.");
734 return ret;
735 }
736 break;
737 case SENSOR_ATTR_SCD4X_SELF_CALIB_STANDARD_PERIOD:
738 if (val->val1 % 4) {
739 return -EINVAL;
740 }
741 if (cfg->model == SCD4X_MODEL_SCD40) {
742 LOG_ERR("SELF_CALIB_STANDARD_PERIOD not available for SCD40.");
743 return -ENOTSUP;
744 }
745 ret = scd4x_set_self_calib_standard_period(dev, val);
746 if (ret < 0) {
747 LOG_ERR("Failed to set self calib standard period.");
748 return ret;
749 }
750 break;
751 default:
752 return -ENOTSUP;
753 }
754
755 ret = scd4x_setup_measurement(dev);
756 if (ret < 0) {
757 LOG_ERR("Failed to setup measurement.");
758 return ret;
759 }
760
761 return 0;
762 }
763
scd4x_attr_get(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,struct sensor_value * val)764 static int scd4x_attr_get(const struct device *dev, enum sensor_channel chan,
765 enum sensor_attribute attr, struct sensor_value *val)
766 {
767 const struct scd4x_config *cfg = dev->config;
768 int ret;
769
770 if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_AMBIENT_TEMP &&
771 chan != SENSOR_CHAN_HUMIDITY && chan != SENSOR_CHAN_CO2) {
772 return -ENOTSUP;
773 }
774
775 if ((enum sensor_attribute_scd4x)attr != SENSOR_ATTR_SCD4X_AMBIENT_PRESSURE ||
776 cfg->mode == SCD4X_MODE_SINGLE_SHOT) {
777 ret = scd4x_set_idle_mode(dev);
778 if (ret < 0) {
779 LOG_ERR("Failed to set idle mode.");
780 return ret;
781 }
782 }
783
784 switch ((enum sensor_attribute_scd4x)attr) {
785 case SENSOR_ATTR_SCD4X_TEMPERATURE_OFFSET:
786 ret = scd4x_get_temperature_offset(dev, val);
787 if (ret < 0) {
788 LOG_ERR("Failed to get temperature offset.");
789 return ret;
790 }
791 break;
792 case SENSOR_ATTR_SCD4X_SENSOR_ALTITUDE:
793 ret = scd4x_get_sensor_altitude(dev, val);
794 if (ret < 0) {
795 LOG_ERR("Failed to get sensor altitude.");
796 return ret;
797 }
798 break;
799 case SENSOR_ATTR_SCD4X_AMBIENT_PRESSURE:
800 ret = scd4x_get_ambient_pressure(dev, val);
801 if (ret < 0) {
802 LOG_ERR("Failed to get ambient pressure.");
803 return ret;
804 }
805 /* return 0 to not call scd4x_setup_measurement */
806 return 0;
807 case SENSOR_ATTR_SCD4X_AUTOMATIC_CALIB_ENABLE:
808 ret = scd4x_get_automatic_calib_enable(dev, val);
809 if (ret < 0) {
810 LOG_ERR("Failed to get automatic calib.");
811 return ret;
812 }
813 break;
814 case SENSOR_ATTR_SCD4X_SELF_CALIB_INITIAL_PERIOD:
815 if (cfg->model == SCD4X_MODEL_SCD40) {
816 LOG_ERR("SELF_CALIB_INITIAL_PERIOD not available for SCD40.");
817 return -ENOTSUP;
818 }
819 ret = scd4x_get_self_calib_initial_period(dev, val);
820 if (ret < 0) {
821 LOG_ERR("Failed to set get self calib initial period.");
822 return ret;
823 }
824 break;
825 case SENSOR_ATTR_SCD4X_SELF_CALIB_STANDARD_PERIOD:
826 if (cfg->model == SCD4X_MODEL_SCD40) {
827 LOG_ERR("SELF_CALIB_STANDARD_PERIOD not available for SCD40.");
828 return -ENOTSUP;
829 }
830 ret = scd4x_get_self_calib_standard_period(dev, val);
831 if (ret < 0) {
832 LOG_ERR("Failed to set get self calib standard period.");
833 return ret;
834 }
835 break;
836 default:
837 return -ENOTSUP;
838 }
839
840 ret = scd4x_setup_measurement(dev);
841 if (ret < 0) {
842 LOG_ERR("Failed to setup measurement.");
843 return ret;
844 }
845
846 return 0;
847 }
848
scd4x_init(const struct device * dev)849 static int scd4x_init(const struct device *dev)
850 {
851 const struct scd4x_config *cfg = dev->config;
852 int ret;
853
854 if (!i2c_is_ready_dt(&cfg->bus)) {
855 LOG_ERR("Device not ready.");
856 return -ENODEV;
857 }
858
859 ret = scd4x_write_command(dev, SCD4X_CMD_STOP_PERIODIC_MEASUREMENT);
860 if (ret < 0) {
861 /*send wake up command twice because of an expected nack return in power down mode*/
862 scd4x_write_command(dev, SCD4X_CMD_WAKE_UP);
863 ret = scd4x_write_command(dev, SCD4X_CMD_WAKE_UP);
864 if (ret < 0) {
865 LOG_ERR("Failed to put the device in idle mode.");
866 return ret;
867 }
868 }
869
870 ret = scd4x_write_command(dev, SCD4X_CMD_REINIT);
871 if (ret < 0) {
872 LOG_ERR("Failed to reset the device.");
873 return ret;
874 }
875
876 ret = scd4x_setup_measurement(dev);
877 if (ret < 0) {
878 LOG_ERR("Failed to setup measurement.");
879 return ret;
880 }
881 return 0;
882 }
883
884 static DEVICE_API(sensor, scd4x_api_funcs) = {
885 .sample_fetch = scd4x_sample_fetch,
886 .channel_get = scd4x_channel_get,
887 .attr_set = scd4x_attr_set,
888 .attr_get = scd4x_attr_get,
889 };
890
891 #define SCD4X_INIT(inst, scd4x_model) \
892 static struct scd4x_data scd4x_data_##scd4x_model##_##inst; \
893 static const struct scd4x_config scd4x_config_##scd4x_model##_##inst = { \
894 .bus = I2C_DT_SPEC_INST_GET(inst), \
895 .model = scd4x_model, \
896 .mode = DT_INST_ENUM_IDX_OR(inst, mode, SCD4X_MODE_NORMAL), \
897 }; \
898 SENSOR_DEVICE_DT_INST_DEFINE(inst, scd4x_init, NULL, &scd4x_data_##scd4x_model##_##inst, \
899 &scd4x_config_##scd4x_model##_##inst, POST_KERNEL, \
900 CONFIG_SENSOR_INIT_PRIORITY, &scd4x_api_funcs);
901
902 #define DT_DRV_COMPAT sensirion_scd40
903 DT_INST_FOREACH_STATUS_OKAY_VARGS(SCD4X_INIT, SCD4X_MODEL_SCD40)
904 #undef DT_DRV_COMPAT
905
906 #define DT_DRV_COMPAT sensirion_scd41
907 DT_INST_FOREACH_STATUS_OKAY_VARGS(SCD4X_INIT, SCD4X_MODEL_SCD41)
908 #undef DT_DRV_COMPAT
909