/* * Copyright (c) 2023 Balthazar Deliers * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT aosong_ags10 #include #include #include #include #include #include "ags10.h" LOG_MODULE_REGISTER(AGS10, CONFIG_SENSOR_LOG_LEVEL); #define AGS10_MAX_PAYLOAD_SIZE 5U /* Payload will be max 4 bytes + CRC (datasheet 3.1) */ static int ags10_read(const struct device *dev, uint8_t cmd, uint8_t *data, uint8_t rx_bytes) { if (rx_bytes > AGS10_MAX_PAYLOAD_SIZE) { return -EINVAL; } const struct ags10_config *conf = dev->config; uint8_t recv_buf[AGS10_MAX_PAYLOAD_SIZE] = {0}; int ret = i2c_write_read_dt(&conf->bus, &cmd, sizeof(cmd), &recv_buf, rx_bytes); if (ret < 0) { return ret; } memcpy(data, recv_buf, rx_bytes); return 0; } static int ags10_sample_fetch(const struct device *dev, enum sensor_channel chan) { if (chan != SENSOR_CHAN_VOC && chan != SENSOR_CHAN_ALL) { return -ENOTSUP; } struct ags10_data *data = dev->data; int ret = -ENOTSUP; uint8_t recv_buf[5] = {0}; ret = ags10_read(dev, AGS10_CMD_DATA_ACQUISITION, recv_buf, 5); if (ret == 0) { /* If CRC is valid and data is valid too */ if (crc8(&recv_buf[0], 4, 0x31, 0xFF, false) == recv_buf[4] && ((recv_buf[0] & AGS10_MSK_STATUS) == AGS10_REG_STATUS_NRDY_READY)) { data->status = recv_buf[0] & AGS10_MSK_STATUS; data->tvoc_ppb = sys_get_be24(&recv_buf[1]); return 0; } LOG_WRN("Bad CRC or data not ready"); ret = -EIO; } return ret; } static int ags10_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) { struct ags10_data *data = dev->data; if (chan == SENSOR_CHAN_VOC) { val->val1 = data->tvoc_ppb; } else { return -ENOTSUP; } val->val2 = 0; return 0; } static int ags10_init(const struct device *dev) { const struct ags10_config *conf = dev->config; struct ags10_data *data = dev->data; int ret; if (!i2c_is_ready_dt(&conf->bus)) { LOG_ERR("Device not ready"); return -ENODEV; } /* Set initial data values */ data->tvoc_ppb = 0; data->status = 0xFF; data->version = 0; /* Read firmware version and check CRC */ uint8_t recv_buf[5] = {0}; ret = ags10_read(dev, AGS10_CMD_READ_VERSION, recv_buf, 5); /* Bytes 0 to 2 are reserved, byte 3 is version, byte 4 is CRC */ if (ret == 0 && crc8(&recv_buf[0], 4, 0x31, 0xFF, false) == recv_buf[4]) { data->version = recv_buf[3]; LOG_DBG("Sensor detected"); } else if (ret != 0) { LOG_ERR("No reply from sensor"); ret = -ENODEV; } else { LOG_WRN("Bad CRC"); ret = -EIO; } return ret; } static DEVICE_API(sensor, ags10_api) = { .sample_fetch = ags10_sample_fetch, .channel_get = ags10_channel_get, }; #define AGS10_INIT(n) \ static struct ags10_data ags10_data_##n; \ \ static const struct ags10_config ags10_config_##n = { \ .bus = I2C_DT_SPEC_INST_GET(n), \ }; \ \ SENSOR_DEVICE_DT_INST_DEFINE(n, ags10_init, NULL, &ags10_data_##n, &ags10_config_##n, \ POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, &ags10_api); DT_INST_FOREACH_STATUS_OKAY(AGS10_INIT)