| /* |
| * Copyright (c) 2018 Alexander Wachter. |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #define DT_DRV_COMPAT ams_iaqcore |
| |
| #include <zephyr/device.h> |
| #include <zephyr/drivers/i2c.h> |
| #include <zephyr/kernel.h> |
| #include <zephyr/sys/byteorder.h> |
| #include <zephyr/sys/util.h> |
| #include <zephyr/drivers/sensor.h> |
| #include <zephyr/sys/__assert.h> |
| #include <zephyr/logging/log.h> |
| |
| #include "iAQcore.h" |
| |
| LOG_MODULE_REGISTER(IAQ_CORE, CONFIG_SENSOR_LOG_LEVEL); |
| |
| static int iaqcore_sample_fetch(const struct device *dev, |
| enum sensor_channel chan) |
| { |
| struct iaq_core_data *drv_data = dev->data; |
| const struct iaq_core_config *config = dev->config; |
| struct iaq_registers buf; |
| struct i2c_msg msg; |
| int ret, tries; |
| |
| __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL); |
| |
| msg.buf = (uint8_t *)&buf; |
| msg.len = sizeof(struct iaq_registers); |
| msg.flags = I2C_MSG_READ | I2C_MSG_STOP; |
| |
| for (tries = 0; tries < CONFIG_IAQ_CORE_MAX_READ_RETRIES; tries++) { |
| |
| ret = i2c_transfer_dt(&config->i2c, &msg, 1); |
| if (ret < 0) { |
| LOG_ERR("Failed to read registers data [%d].", ret); |
| return -EIO; |
| } |
| |
| drv_data->status = buf.status; |
| |
| if (buf.status == 0x00) { |
| drv_data->co2 = sys_be16_to_cpu(buf.co2_pred); |
| drv_data->voc = sys_be16_to_cpu(buf.voc); |
| drv_data->status = buf.status; |
| drv_data->resistance = sys_be32_to_cpu(buf.resistance); |
| |
| return 0; |
| } |
| |
| k_sleep(K_MSEC(100)); |
| } |
| |
| if (drv_data->status == 0x01) { |
| LOG_INF("Sensor data not available"); |
| } |
| |
| if (drv_data->status == 0x80) { |
| LOG_ERR("Sensor Error"); |
| } |
| |
| return -EIO; |
| } |
| |
| static int iaqcore_channel_get(const struct device *dev, |
| enum sensor_channel chan, |
| struct sensor_value *val) |
| { |
| struct iaq_core_data *drv_data = dev->data; |
| |
| switch (chan) { |
| case SENSOR_CHAN_CO2: |
| val->val1 = drv_data->co2; |
| val->val2 = 0; |
| break; |
| case SENSOR_CHAN_VOC: |
| val->val1 = drv_data->voc; |
| val->val2 = 0; |
| break; |
| case SENSOR_CHAN_RESISTANCE: |
| val->val1 = drv_data->resistance; |
| val->val2 = 0; |
| break; |
| default: |
| return -ENOTSUP; |
| } |
| |
| return 0; |
| } |
| |
| static const struct sensor_driver_api iaq_core_driver_api = { |
| .sample_fetch = iaqcore_sample_fetch, |
| .channel_get = iaqcore_channel_get, |
| }; |
| |
| static int iaq_core_init(const struct device *dev) |
| { |
| const struct iaq_core_config *config = dev->config; |
| |
| if (!device_is_ready(config->i2c.bus)) { |
| LOG_ERR("Bus device is not ready"); |
| return -ENODEV; |
| } |
| |
| return 0; |
| } |
| |
| #define IAQ_CORE_DEFINE(inst) \ |
| static struct iaq_core_data iaq_core_data_##inst; \ |
| \ |
| static const struct iaq_core_config iaq_core_config_##inst = { \ |
| .i2c = I2C_DT_SPEC_INST_GET(inst), \ |
| }; \ |
| \ |
| SENSOR_DEVICE_DT_INST_DEFINE(inst, iaq_core_init, NULL, &iaq_core_data_##inst, \ |
| &iaq_core_config_##inst, POST_KERNEL, \ |
| CONFIG_SENSOR_INIT_PRIORITY, &iaq_core_driver_api); \ |
| |
| DT_INST_FOREACH_STATUS_OKAY(IAQ_CORE_DEFINE) |