1 /*
2  * Copyright (c) 2018 Alexander Wachter.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT ams_iaqcore
8 
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/i2c.h>
11 #include <zephyr/kernel.h>
12 #include <zephyr/sys/byteorder.h>
13 #include <zephyr/sys/util.h>
14 #include <zephyr/drivers/sensor.h>
15 #include <zephyr/sys/__assert.h>
16 #include <zephyr/logging/log.h>
17 
18 #include "iAQcore.h"
19 
20 LOG_MODULE_REGISTER(IAQ_CORE, CONFIG_SENSOR_LOG_LEVEL);
21 
iaqcore_sample_fetch(const struct device * dev,enum sensor_channel chan)22 static int iaqcore_sample_fetch(const struct device *dev,
23 				enum sensor_channel chan)
24 {
25 	struct iaq_core_data *drv_data = dev->data;
26 	const struct iaq_core_config *config = dev->config;
27 	struct iaq_registers buf;
28 	struct i2c_msg msg;
29 	int ret, tries;
30 
31 	__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL);
32 
33 	msg.buf = (uint8_t *)&buf;
34 	msg.len = sizeof(struct iaq_registers);
35 	msg.flags = I2C_MSG_READ | I2C_MSG_STOP;
36 
37 	for (tries = 0; tries < CONFIG_IAQ_CORE_MAX_READ_RETRIES; tries++) {
38 
39 		ret = i2c_transfer_dt(&config->i2c, &msg, 1);
40 		if (ret < 0) {
41 			LOG_ERR("Failed to read registers data [%d].", ret);
42 			return -EIO;
43 		}
44 
45 		drv_data->status = buf.status;
46 
47 		if (buf.status == 0x00) {
48 			drv_data->co2 = sys_be16_to_cpu(buf.co2_pred);
49 			drv_data->voc = sys_be16_to_cpu(buf.voc);
50 			drv_data->status = buf.status;
51 			drv_data->resistance = sys_be32_to_cpu(buf.resistance);
52 
53 			return 0;
54 		}
55 
56 		k_sleep(K_MSEC(100));
57 	}
58 
59 	if (drv_data->status == 0x01) {
60 		LOG_INF("Sensor data not available");
61 	}
62 
63 	if (drv_data->status == 0x80) {
64 		LOG_ERR("Sensor Error");
65 	}
66 
67 	return -EIO;
68 }
69 
iaqcore_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)70 static int iaqcore_channel_get(const struct device *dev,
71 			       enum sensor_channel chan,
72 			       struct sensor_value *val)
73 {
74 	struct iaq_core_data *drv_data = dev->data;
75 
76 	switch (chan) {
77 	case SENSOR_CHAN_CO2:
78 		val->val1 = drv_data->co2;
79 		val->val2 = 0;
80 		break;
81 	case SENSOR_CHAN_VOC:
82 		val->val1 = drv_data->voc;
83 		val->val2 = 0;
84 		break;
85 	case SENSOR_CHAN_RESISTANCE:
86 		val->val1 = drv_data->resistance;
87 		val->val2 = 0;
88 		break;
89 	default:
90 		return -ENOTSUP;
91 	}
92 
93 	return 0;
94 }
95 
96 static DEVICE_API(sensor, iaq_core_driver_api) = {
97 	.sample_fetch = iaqcore_sample_fetch,
98 	.channel_get = iaqcore_channel_get,
99 };
100 
iaq_core_init(const struct device * dev)101 static int iaq_core_init(const struct device *dev)
102 {
103 	const struct iaq_core_config *config = dev->config;
104 
105 	if (!device_is_ready(config->i2c.bus)) {
106 		LOG_ERR("Bus device is not ready");
107 		return -ENODEV;
108 	}
109 
110 	return 0;
111 }
112 
113 #define IAQ_CORE_DEFINE(inst)								\
114 	static struct iaq_core_data iaq_core_data_##inst;				\
115 											\
116 	static const struct iaq_core_config iaq_core_config_##inst = {			\
117 		.i2c = I2C_DT_SPEC_INST_GET(inst),					\
118 	};										\
119 											\
120 	SENSOR_DEVICE_DT_INST_DEFINE(inst, iaq_core_init, NULL, &iaq_core_data_##inst,	\
121 			      &iaq_core_config_##inst, POST_KERNEL,			\
122 			      CONFIG_SENSOR_INIT_PRIORITY, &iaq_core_driver_api);	\
123 
124 DT_INST_FOREACH_STATUS_OKAY(IAQ_CORE_DEFINE)
125