1 /*
2 * Copyright (c) 2023 Balthazar Deliers
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT aosong_ags10
8
9 #include <zephyr/drivers/sensor.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/logging/log.h>
12 #include <zephyr/sys/byteorder.h>
13 #include <zephyr/sys/crc.h>
14
15 #include "ags10.h"
16
17 LOG_MODULE_REGISTER(AGS10, CONFIG_SENSOR_LOG_LEVEL);
18
19 #define AGS10_MAX_PAYLOAD_SIZE 5U /* Payload will be max 4 bytes + CRC (datasheet 3.1) */
20
ags10_read(const struct device * dev,uint8_t cmd,uint8_t * data,uint8_t rx_bytes)21 static int ags10_read(const struct device *dev, uint8_t cmd, uint8_t *data, uint8_t rx_bytes)
22 {
23 if (rx_bytes > AGS10_MAX_PAYLOAD_SIZE) {
24 return -EINVAL;
25 }
26
27 const struct ags10_config *conf = dev->config;
28
29 uint8_t recv_buf[AGS10_MAX_PAYLOAD_SIZE] = {0};
30 int ret = i2c_write_read_dt(&conf->bus, &cmd, sizeof(cmd), &recv_buf, rx_bytes);
31
32 if (ret < 0) {
33 return ret;
34 }
35
36 memcpy(data, recv_buf, rx_bytes);
37
38 return 0;
39 }
40
ags10_sample_fetch(const struct device * dev,enum sensor_channel chan)41 static int ags10_sample_fetch(const struct device *dev, enum sensor_channel chan)
42 {
43 if (chan != SENSOR_CHAN_VOC && chan != SENSOR_CHAN_ALL) {
44 return -ENOTSUP;
45 }
46
47 struct ags10_data *data = dev->data;
48 int ret = -ENOTSUP;
49 uint8_t recv_buf[5] = {0};
50
51 ret = ags10_read(dev, AGS10_CMD_DATA_ACQUISITION, recv_buf, 5);
52
53 if (ret == 0) {
54 /* If CRC is valid and data is valid too */
55 if (crc8(&recv_buf[0], 4, 0x31, 0xFF, false) == recv_buf[4] &&
56 ((recv_buf[0] & AGS10_MSK_STATUS) == AGS10_REG_STATUS_NRDY_READY)) {
57 data->status = recv_buf[0] & AGS10_MSK_STATUS;
58 data->tvoc_ppb = sys_get_be24(&recv_buf[1]);
59 return 0;
60 }
61
62 LOG_WRN("Bad CRC or data not ready");
63 ret = -EIO;
64 }
65
66 return ret;
67 }
68
ags10_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)69 static int ags10_channel_get(const struct device *dev, enum sensor_channel chan,
70 struct sensor_value *val)
71 {
72 struct ags10_data *data = dev->data;
73
74 if (chan == SENSOR_CHAN_VOC) {
75 val->val1 = data->tvoc_ppb;
76 } else {
77 return -ENOTSUP;
78 }
79
80 val->val2 = 0;
81
82 return 0;
83 }
84
ags10_init(const struct device * dev)85 static int ags10_init(const struct device *dev)
86 {
87 const struct ags10_config *conf = dev->config;
88 struct ags10_data *data = dev->data;
89 int ret;
90
91 if (!i2c_is_ready_dt(&conf->bus)) {
92 LOG_ERR("Device not ready");
93 return -ENODEV;
94 }
95
96 /* Set initial data values */
97 data->tvoc_ppb = 0;
98 data->status = 0xFF;
99 data->version = 0;
100
101 /* Read firmware version and check CRC */
102 uint8_t recv_buf[5] = {0};
103
104 ret = ags10_read(dev, AGS10_CMD_READ_VERSION, recv_buf, 5);
105
106 /* Bytes 0 to 2 are reserved, byte 3 is version, byte 4 is CRC */
107 if (ret == 0 && crc8(&recv_buf[0], 4, 0x31, 0xFF, false) == recv_buf[4]) {
108 data->version = recv_buf[3];
109 LOG_DBG("Sensor detected");
110 } else if (ret != 0) {
111 LOG_ERR("No reply from sensor");
112 ret = -ENODEV;
113 } else {
114 LOG_WRN("Bad CRC");
115 ret = -EIO;
116 }
117
118 return ret;
119 }
120
121 static DEVICE_API(sensor, ags10_api) = {
122 .sample_fetch = ags10_sample_fetch,
123 .channel_get = ags10_channel_get,
124 };
125
126 #define AGS10_INIT(n) \
127 static struct ags10_data ags10_data_##n; \
128 \
129 static const struct ags10_config ags10_config_##n = { \
130 .bus = I2C_DT_SPEC_INST_GET(n), \
131 }; \
132 \
133 SENSOR_DEVICE_DT_INST_DEFINE(n, ags10_init, NULL, &ags10_data_##n, &ags10_config_##n, \
134 POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, &ags10_api);
135
136 DT_INST_FOREACH_STATUS_OKAY(AGS10_INIT)
137