drivers: sensor: Aosong AGS10 TVOC sensor
Added support for Aosong AGS10 TVOC sensor Signed-off-by: Balthazar Deliers <bdeliers@bdeliers.com>
This commit is contained in:
parent
3cdce5b1de
commit
bea34c599d
8 changed files with 214 additions and 0 deletions
|
|
@ -9,6 +9,7 @@ add_subdirectory_ifdef(CONFIG_ADXL345 adxl345)
|
|||
add_subdirectory_ifdef(CONFIG_ADXL362 adxl362)
|
||||
add_subdirectory_ifdef(CONFIG_ADXL367 adxl367)
|
||||
add_subdirectory_ifdef(CONFIG_ADXL372 adxl372)
|
||||
add_subdirectory_ifdef(CONFIG_AGS10 ags10)
|
||||
add_subdirectory_ifdef(CONFIG_AK8975 ak8975)
|
||||
add_subdirectory_ifdef(CONFIG_AKM09918C akm09918c)
|
||||
add_subdirectory_ifdef(CONFIG_AMD_SB_TSI amd_sb_tsi)
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ source "drivers/sensor/adxl345/Kconfig"
|
|||
source "drivers/sensor/adxl362/Kconfig"
|
||||
source "drivers/sensor/adxl367/Kconfig"
|
||||
source "drivers/sensor/adxl372/Kconfig"
|
||||
source "drivers/sensor/ags10/Kconfig"
|
||||
source "drivers/sensor/ak8975/Kconfig"
|
||||
source "drivers/sensor/akm09918c/Kconfig"
|
||||
source "drivers/sensor/amd_sb_tsi/Kconfig"
|
||||
|
|
|
|||
5
drivers/sensor/ags10/CMakeLists.txt
Normal file
5
drivers/sensor/ags10/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
zephyr_library()
|
||||
zephyr_library_sources(ags10.c)
|
||||
12
drivers/sensor/ags10/Kconfig
Normal file
12
drivers/sensor/ags10/Kconfig
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# Copyright (c) 2023 Balthazar Deliers
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# AOSONG AGS10 TVOC sensor driver options.
|
||||
|
||||
config AGS10
|
||||
bool "AOSONG AGS10 TVOC sensor"
|
||||
default y
|
||||
depends on DT_HAS_AOSONG_AGS10_ENABLED
|
||||
select I2C
|
||||
help
|
||||
Enable AOSONG AGS10 TVOC sensor driver.
|
||||
134
drivers/sensor/ags10/ags10.c
Normal file
134
drivers/sensor/ags10/ags10.c
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Balthazar Deliers
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT aosong_ags10
|
||||
|
||||
#include <zephyr/drivers/sensor.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
#include <zephyr/sys/crc.h>
|
||||
|
||||
#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 const struct sensor_driver_api 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)
|
||||
46
drivers/sensor/ags10/ags10.h
Normal file
46
drivers/sensor/ags10/ags10.h
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Balthazar Deliers
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_AGS10_H_
|
||||
#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_AGS10_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/i2c.h>
|
||||
|
||||
#define AGS10_CMD_DATA_ACQUISITION 0x00
|
||||
#define AGS10_CMD_ZERO_POINT_CALIBRATION 0x01
|
||||
#define AGS10_CMD_READ_VERSION 0x11
|
||||
#define AGS10_CMD_READ_RESISTANCE 0x20
|
||||
#define AGS10_CMD_MODIFY_SLAVE_ADDRESS 0x21
|
||||
|
||||
#define AGS10_REG_ZERO_POINT_CALIBRATION_RESET 0xFFFF /* Reset to the factory value */
|
||||
#define AGS10_REG_ZERO_POINT_CALIBRATION_SET 0x0000 /* Set sensor resistance to zero-point */
|
||||
#define AGS10_REG_STATUS_NRDY_READY 0x00 /* Device is ready */
|
||||
#define AGS10_REG_STATUS_CH_PPB 0x00 /* Unit is PPB */
|
||||
|
||||
#define AGS10_MSK_STATUS 0x0F
|
||||
#define AGS10_MSK_STATUS_NRDY 0x01
|
||||
#define AGS10_MSK_STATUS_CH 0x0E
|
||||
|
||||
struct ags10_config {
|
||||
struct i2c_dt_spec bus;
|
||||
};
|
||||
|
||||
struct ags10_data {
|
||||
uint32_t tvoc_ppb;
|
||||
uint8_t status;
|
||||
uint32_t version;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_DRIVERS_SENSOR_AGS10_H_ */
|
||||
10
dts/bindings/sensor/aosong,ags10.yaml
Normal file
10
dts/bindings/sensor/aosong,ags10.yaml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# Copyright (c) 2023 Balthazar Deliers
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: |
|
||||
AOSONG AGS10 a high-performance TVOC Sensor With I2C Interface.
|
||||
See: http://www.aosong.com/en/products-86.html
|
||||
|
||||
compatible: "aosong,ags10"
|
||||
|
||||
include: [sensor-device.yaml, i2c-device.yaml]
|
||||
|
|
@ -884,3 +884,8 @@ test_i2c_bma4xx: bma4xx@7d {
|
|||
compatible = "bosch,bma4xx";
|
||||
reg = <0x7d>;
|
||||
};
|
||||
|
||||
test_i2c_ags10: ags10@7e {
|
||||
compatible = "aosong,ags10";
|
||||
reg = <0x7e>;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue