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