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