From 5032f099c64753d4a4fb858079ab57dbb22bb2cb Mon Sep 17 00:00:00 2001 From: Margherita Milani Date: Wed, 8 May 2024 16:01:46 +0200 Subject: [PATCH] drivers: sensor: add apds9253 driver Add all the necessary files to add apds9253 Avago sensor driver. Sensor available at https://docs.broadcom.com/doc/APDS-9253-001-DS Signed-off-by: Margherita Milani Signed-off-by: Michael Trimarchi --- drivers/sensor/CMakeLists.txt | 1 + drivers/sensor/Kconfig | 1 + drivers/sensor/apds9253/CMakeLists.txt | 5 + drivers/sensor/apds9253/Kconfig | 11 + drivers/sensor/apds9253/apds9253.c | 253 +++++++++++++++++++ drivers/sensor/apds9253/apds9253.h | 106 ++++++++ dts/bindings/sensor/avago,apds9253.yaml | 80 ++++++ include/zephyr/dt-bindings/sensor/apds9253.h | 55 ++++ tests/drivers/build_all/sensor/i2c.dtsi | 10 + 9 files changed, 522 insertions(+) create mode 100644 drivers/sensor/apds9253/CMakeLists.txt create mode 100644 drivers/sensor/apds9253/Kconfig create mode 100644 drivers/sensor/apds9253/apds9253.c create mode 100644 drivers/sensor/apds9253/apds9253.h create mode 100644 dts/bindings/sensor/avago,apds9253.yaml create mode 100644 include/zephyr/dt-bindings/sensor/apds9253.h diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index 0458ed616661..36b1a670450a 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -30,6 +30,7 @@ add_subdirectory(wsen) add_subdirectory_ifdef(CONFIG_A01NYUB a01nyub) add_subdirectory_ifdef(CONFIG_AMD_SB_TSI amd_sb_tsi) add_subdirectory_ifdef(CONFIG_AMG88XX amg88xx) +add_subdirectory_ifdef(CONFIG_APDS9253 apds9253) add_subdirectory_ifdef(CONFIG_APDS9960 apds9960) add_subdirectory_ifdef(CONFIG_CURRENT_AMP current_amp) add_subdirectory_ifdef(CONFIG_ENS160 ens160) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index ad3e8af27d3f..23adc297f235 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -114,6 +114,7 @@ source "drivers/sensor/wsen/Kconfig" source "drivers/sensor/a01nyub/Kconfig" source "drivers/sensor/amd_sb_tsi/Kconfig" source "drivers/sensor/amg88xx/Kconfig" +source "drivers/sensor/apds9253/Kconfig" source "drivers/sensor/apds9960/Kconfig" source "drivers/sensor/current_amp/Kconfig" source "drivers/sensor/ens160/Kconfig" diff --git a/drivers/sensor/apds9253/CMakeLists.txt b/drivers/sensor/apds9253/CMakeLists.txt new file mode 100644 index 000000000000..64ac05fb0ff3 --- /dev/null +++ b/drivers/sensor/apds9253/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(apds9253.c) diff --git a/drivers/sensor/apds9253/Kconfig b/drivers/sensor/apds9253/Kconfig new file mode 100644 index 000000000000..1ce6a45435e8 --- /dev/null +++ b/drivers/sensor/apds9253/Kconfig @@ -0,0 +1,11 @@ +# Copyright(c) 2017 Intel Corporation +# Copyright(c) 2018 Phytec Messtechnik GmbH +# SPDX-License-Identifier: Apache-2.0 + +config APDS9253 + bool "APDS9253 Sensor" + default y + depends on DT_HAS_AVAGO_APDS9253_ENABLED + select I2C + help + Enable driver for APDS9253 sensors. diff --git a/drivers/sensor/apds9253/apds9253.c b/drivers/sensor/apds9253/apds9253.c new file mode 100644 index 000000000000..539b88299835 --- /dev/null +++ b/drivers/sensor/apds9253/apds9253.c @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2018 Phytec Messtechnik GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT avago_apds9253 + +/* @file + * @brief driver for APDS9253 ALS/RGB/ + */ + +#include +#include +#include +#include + +#include "apds9253.h" + +#define BYTES_PER_VALUE 3 +#define VALUES_PER_SAMPLE 4 + +LOG_MODULE_REGISTER(APDS9253, CONFIG_SENSOR_LOG_LEVEL); + +static inline void apds9253_setup_int(const struct apds9253_config *cfg, bool enable) +{ + gpio_flags_t flags = enable ? GPIO_INT_EDGE_TO_ACTIVE : GPIO_INT_DISABLE; + + gpio_pin_interrupt_configure_dt(&cfg->int_gpio, flags); +} + +static void apds9253_handle_cb(struct apds9253_data *drv_data) +{ + apds9253_setup_int(drv_data->dev->config, false); +} + +static void apds9253_gpio_callback(const struct device *dev, struct gpio_callback *cb, + uint32_t pins) +{ + struct apds9253_data *drv_data = CONTAINER_OF(cb, struct apds9253_data, gpio_cb); + + apds9253_handle_cb(drv_data); +} + +static uint32_t get_value_from_buf(int idx, const uint8_t *buf) +{ + size_t offset = BYTES_PER_VALUE * idx; + + return sys_get_le24(&buf[offset]); +} + +static int apds9253_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + const struct apds9253_config *config = dev->config; + struct apds9253_data *data = dev->data; + uint8_t tmp; + uint8_t buf[BYTES_PER_VALUE * VALUES_PER_SAMPLE]; + + if (chan != SENSOR_CHAN_ALL) { + LOG_ERR("Unsupported sensor channel"); + return -ENOTSUP; + } + + if (i2c_reg_update_byte_dt(&config->i2c, APDS9253_MAIN_CTRL_REG, APDS9253_MAIN_CTRL_LS_EN, + APDS9253_MAIN_CTRL_LS_EN)) { + LOG_ERR("Power on bit not set."); + return -EIO; + } + + if (config->interrupt_enabled) { + k_sem_take(&data->data_sem, K_FOREVER); + } + + if (i2c_reg_read_byte_dt(&config->i2c, APDS9253_MAIN_STATUS_REG, &tmp)) { + return -EIO; + } + + LOG_DBG("status: 0x%x", tmp); + + if (tmp & APDS9253_MAIN_STATUS_LS_STATUS) { + if (i2c_burst_read_dt(&config->i2c, APDS9253_LS_DATA_BASE, buf, sizeof(buf))) { + return -EIO; + } + + for (int i = 0; i < VALUES_PER_SAMPLE; ++i) { + data->sample_crgb[i] = get_value_from_buf(i, buf); + } + + LOG_DBG("IR 0x%x GREEN 0x%x BLUE 0x%x RED 0x%x\n", data->sample_crgb[0], + data->sample_crgb[1], data->sample_crgb[2], data->sample_crgb[3]); + } + + return 0; +} + +static int apds9253_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct apds9253_data *data = dev->data; + + val->val2 = 0; + + switch (chan) { + case SENSOR_CHAN_IR: + val->val1 = sys_le32_to_cpu(data->sample_crgb[0]); + break; + case SENSOR_CHAN_GREEN: + val->val1 = sys_le32_to_cpu(data->sample_crgb[1]); + break; + case SENSOR_CHAN_BLUE: + val->val1 = sys_le32_to_cpu(data->sample_crgb[2]); + break; + case SENSOR_CHAN_RED: + val->val1 = sys_le32_to_cpu(data->sample_crgb[3]); + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static int apds9253_sensor_setup(const struct device *dev) +{ + const struct apds9253_config *config = dev->config; + uint8_t chip_id; + + if (i2c_reg_read_byte_dt(&config->i2c, APDS9253_PART_ID, &chip_id)) { + LOG_ERR("Failed reading chip id"); + return -EIO; + } + + if ((chip_id & APDS9253_PART_ID_ID_MASK) != APDS9253_DEVICE_PART_ID) { + LOG_ERR("Invalid chip id 0x%x", chip_id); + return -EIO; + } + + if (i2c_reg_update_byte_dt(&config->i2c, APDS9253_LS_GAIN_REG, APDS9253_LS_GAIN_MASK, + (config->ls_gain & APDS9253_LS_GAIN_MASK))) { + LOG_ERR("Light sensor gain is not set"); + return -EIO; + } + + if (i2c_reg_update_byte_dt(&config->i2c, APDS9253_LS_MEAS_RATE_REG, + APDS9253_LS_MEAS_RATE_RES_MASK, + (config->ls_resolution & APDS9253_LS_MEAS_RATE_RES_MASK))) { + LOG_ERR("Light sensor resolution is not set"); + return -EIO; + } + + if (i2c_reg_update_byte_dt(&config->i2c, APDS9253_LS_MEAS_RATE_REG, + APDS9253_LS_MEAS_RATE_MES_MASK, + (config->ls_rate & APDS9253_LS_MEAS_RATE_MES_MASK))) { + LOG_ERR("Light sensor rate is not set"); + return -EIO; + } + + if (i2c_reg_update_byte_dt(&config->i2c, APDS9253_MAIN_CTRL_REG, + APDS9253_MAIN_CTRL_RGB_MODE, APDS9253_MAIN_CTRL_RGB_MODE)) { + LOG_ERR("Enable RGB mode failed"); + return -EIO; + } + + return 0; +} + +static int apds9253_init_interrupt(const struct device *dev) +{ + const struct apds9253_config *config = dev->config; + struct apds9253_data *drv_data = dev->data; + int ret = 0; + + if (!gpio_is_ready_dt(&config->int_gpio)) { + LOG_ERR("%s: device %s is not ready", dev->name, config->int_gpio.port->name); + return -ENODEV; + } + + ret = gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT); + if (!ret) { + LOG_ERR("Failed to configure gpio direction"); + return ret; + } + + gpio_init_callback(&drv_data->gpio_cb, apds9253_gpio_callback, BIT(config->int_gpio.pin)); + + if (gpio_add_callback(config->int_gpio.port, &drv_data->gpio_cb) < 0) { + LOG_ERR("Failed to set gpio callback!"); + return -EIO; + } + + drv_data->dev = dev; + + k_sem_init(&drv_data->data_sem, 0, K_SEM_MAX_LIMIT); + apds9253_setup_int(config, true); + + if (gpio_pin_get_dt(&config->int_gpio) > 0) { + apds9253_handle_cb(drv_data); + } + + return 0; +} + +static int apds9253_init(const struct device *dev) +{ + const struct apds9253_config *config = dev->config; + + /* Initialize time 500 us */ + k_msleep(1); + + if (!i2c_is_ready_dt(&config->i2c)) { + LOG_ERR("Bus device is not ready"); + return -EINVAL; + } + + if (apds9253_sensor_setup(dev) < 0) { + LOG_ERR("Failed to setup device!"); + return -EIO; + } + + if (config->interrupt_enabled && apds9253_init_interrupt(dev) < 0) { + LOG_ERR("Failed to initialize interrupt!"); + return -EIO; + } + + return 0; +} + +static const struct sensor_driver_api apds9253_driver_api = { + .sample_fetch = &apds9253_sample_fetch, + .channel_get = &apds9253_channel_get, +}; + +#define APDS9253_INIT(n) \ + static struct apds9253_data apds9253_data_##n = { \ + .sample_crgb = {0}, \ + .pdata = 0U, \ + }; \ + \ + static const struct apds9253_config apds9253_config_##n = { \ + .i2c = I2C_DT_SPEC_INST_GET(n), \ + .interrupt_enabled = DT_INST_NODE_HAS_PROP(n, int_gpios), \ + .int_gpio = GPIO_DT_SPEC_INST_GET_OR(n, int_gpios, {}), \ + .ls_rate = DT_INST_PROP(n, rate), \ + .ls_resolution = DT_INST_PROP(n, resolution), \ + .ls_gain = DT_INST_PROP(n, gain), \ + }; \ + \ + SENSOR_DEVICE_DT_INST_DEFINE(n, apds9253_init, NULL, &apds9253_data_##n, \ + &apds9253_config_##n, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &apds9253_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(APDS9253_INIT) diff --git a/drivers/sensor/apds9253/apds9253.h b/drivers/sensor/apds9253/apds9253.h new file mode 100644 index 000000000000..9fbe4a43bc38 --- /dev/null +++ b/drivers/sensor/apds9253/apds9253.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2018 PHYTEC Messtechnik GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_APDS9253_APDS9253_H_ +#define ZEPHYR_DRIVERS_SENSOR_APDS9253_APDS9253_H_ + +#include + +#define APDS9253_MAIN_CTRL_REG 0x00 +#define APDS9253_MAIN_CTRL_REG_MASK GENMASK(5, 0) +#define APDS9253_MAIN_CTRL_SAI_LS BIT(5) +#define APDS9253_MAIN_CTRL_SW_RESET BIT(4) +#define APDS9253_MAIN_CTRL_RGB_MODE BIT(2) +#define APDS9253_MAIN_CTRL_LS_EN BIT(1) + +#define APDS9253_LS_MEAS_RATE_REG 0x04 +#define APDS9253_LS_MEAS_RATE_RES_MASK GENMASK(6, 4) +#define APDS9253_LS_MEAS_RATE_RES_20BIT_400MS 0 +#define APDS9253_LS_MEAS_RATE_RES_19BIT_200MS BIT(4) +#define APDS9253_LS_MEAS_RATE_RES_18BIT_100MS BIT(5) /* default */ +#define APDS9253_LS_MEAS_RATE_RES_17BIT_50MS (BIT(5) | BIT(4)) +#define APDS9253_LS_MEAS_RATE_RES_16BIT_25MS BIT(6) +#define APDS9253_LS_MEAS_RATE_RES_13_3MS (BIT(6) | BIT(4)) +#define APDS9253_LS_MEAS_RATE_MES_MASK GENMASK(2, 0) +#define APDS9253_LS_MEAS_RATE_MES_2000MS (BIT(2) | BIT(1) | BIT(0)) +#define APDS9253_LS_MEAS_RATE_MES_1000MS (BIT(2) | BIT(0)) +#define APDS9253_LS_MEAS_RATE_MES_500MS BIT(2) +#define APDS9253_LS_MEAS_RATE_MES_200MS (BIT(1) | BIT(0)) +#define APDS9253_LS_MEAS_RATE_MES_100MS BIT(1) /* default */ +#define APDS9253_LS_MEAS_RATE_MES_50MS BIT(0) +#define APDS9253_LS_MEAS_RATE_MES_25MS 0 + +#define APDS9253_LS_GAIN_REG 0x05 +#define APDS9253_LS_GAIN_MASK GENMASK(2, 0) +#define APDS9253_LS_GAIN_RANGE_18 BIT(2) +#define APDS9253_LS_GAIN_RANGE_9 (BIT(1) | BIT(0)) +#define APDS9253_LS_GAIN_RANGE_6 BIT(1) +#define APDS9253_LS_GAIN_RANGE_3 BIT(0) /* default */ +#define APDS9253_LS_GAIN_RANGE_1 0 + +#define APDS9253_PART_ID 0x06 +#define APDS9253_DEVICE_PART_ID 0xC0 +#define APDS9253_PART_ID_REV_MASK GENMASK(3, 0) +#define APDS9253_PART_ID_ID_MASK GENMASK(7, 4) + +#define APDS9253_MAIN_STATUS_REG 0x07 +#define APDS9253_MAIN_STATUS_POWER_ON BIT(5) +#define APDS9253_MAIN_STATUS_LS_INTERRUPT BIT(4) +#define APDS9253_MAIN_STATUS_LS_STATUS BIT(3) + +/* Channels data */ +#define APDS9253_LS_DATA_BASE 0x0A +#define APDS9253_LS_DATA_IR_0 0x0A +#define APDS9253_LS_DATA_IR_1 0x0B +#define APDS9253_LS_DATA_IR_2 0x0C +#define APDS9253_LS_DATA_GREEN_0 0x0D +#define APDS9253_LS_DATA_GREEN_1 0x0E +#define APDS9253_LS_DATA_GREEN_2 0x0F +#define APDS9253_LS_DATA_BLUE_0 0x10 +#define APDS9253_LS_DATA_BLUE_1 0x11 +#define APDS9253_LS_DATA_BLUE_2 0x12 +#define APDS9253_LS_DATA_RED_0 0x13 +#define APDS9253_LS_DATA_RED_1 0x14 +#define APDS9253_LS_DATA_RED_2 0x15 + +#define APDS9253_INT_CFG 0x19 +#define APDS9253_INT_CFG_LS_INT_SEL_IR 0 +#define APDS9253_INT_CFG_LS_INT_SEL_ALS BIT(4) /* default */ +#define APDS9253_INT_CFG_LS_INT_SEL_RED BIT(5) +#define APDS9253_INT_CFG_LS_INT_SEL_BLUE (BIT(5) | BIT(4)) +#define APDS9253_INT_CFG_LS_VAR_MODE_EN BIT(3) +#define APDS9253_INT_CFG_LS_INT_MODE_EN BIT(3) + +#define APDS9253_INT_PST 0x1A +#define APDS9253_LS_THRES_UP_0 0x21 +#define APDS9253_LS_THRES_UP_1 0x22 +#define APDS9253_LS_THRES_UP_2 0x23 +#define APDS9253_LS_THRES_LOW_0 0x24 +#define APDS9253_LS_THRES_LOW_1 0x25 +#define APDS9253_LS_THRES_LOW_2 0x26 +#define APDS9253_LS_THRES_VAR 0x27 +#define APDS9253_DK_CNT_STOR 0x29 + +struct apds9253_config { + struct i2c_dt_spec i2c; + struct gpio_dt_spec int_gpio; + uint8_t ls_gain; + uint8_t ls_rate; + uint8_t ls_resolution; + bool interrupt_enabled; +}; + +struct apds9253_data { + struct gpio_callback gpio_cb; + struct k_work work; + const struct device *dev; + uint32_t sample_crgb[4]; + uint8_t pdata; + struct k_sem data_sem; +}; + +#endif /* ZEPHYR_DRIVERS_SENSOR_APDS9253_APDS9253_H_*/ diff --git a/dts/bindings/sensor/avago,apds9253.yaml b/dts/bindings/sensor/avago,apds9253.yaml new file mode 100644 index 000000000000..97b344e1b95f --- /dev/null +++ b/dts/bindings/sensor/avago,apds9253.yaml @@ -0,0 +1,80 @@ +# Copyright(c) 2018, Phytec Messtechnik GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: APDS9253 ambient light, RGB + +compatible: "avago,apds9253" + +include: [sensor-device.yaml, i2c-device.yaml] + +properties: + int-gpios: + type: phandle-array + description: Interrupt pin. + + The interrupt pin of APDS9253 is open-drain, active low. + If connected directly the MCU pin should be configured + as pull-up, active low. + + rate: + type: int + required: true + description: | + Select the rate interval (ms) for all comparator channel. + Default value is chosen from the official documentation. + - : 6 + - : 5 + - : 4 + - : 3 + - : 2 + - 1 + - 0 + default: 2 + enum: + - 6 + - 5 + - 4 + - 3 + - 2 + - 1 + - 0 + + gain: + type: int + required: true + description: | + Select the gain value for all comparator channel. + Default value is chosen from the official documentation. + - : 4 + - : 3 + - : 2 + - : 1 + - : 0 + default: 1 + enum: + - 4 + - 3 + - 2 + - 1 + - 0 + + resolution: + type: int + required: true + description: | + Select the resolution value for all comparator channel. + Default value is chosen from the official documentation. + - : 0 + - 16 + - : 32 + - : 48 + - : 64 + - : 80 + default: 32 + enum: + - 0 + - 16 + - 32 + - 48 + - 64 + - 80 diff --git a/include/zephyr/dt-bindings/sensor/apds9253.h b/include/zephyr/dt-bindings/sensor/apds9253.h new file mode 100644 index 000000000000..0768ec4ff9e9 --- /dev/null +++ b/include/zephyr/dt-bindings/sensor/apds9253.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2018 PHYTEC Messtechnik GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_SENSOR_APDS9253_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_SENSOR_APDS9253_H_ + +#include + +/** + * @name apds9253 resolution channel references + * @{ + */ + +#define APDS9253_RESOLUTION_20BIT_400MS 0 +#define APDS9253_RESOLUTION_19BIT_200MS BIT(4) +#define APDS9253_RESOLUTION_18BIT_100MS BIT(5) /* default */ +#define APDS9253_RESOLUTION_17BIT_50MS (BIT(5) | BIT(4)) +#define APDS9253_RESOLUTION_16BIT_25MS BIT(6) +#define APDS9253_RESOLUTION_13BIT_3MS (BIT(6) | BIT(4)) + +/** @} */ + +/** + * @name apds9253 measurement rate + * @{ + */ + +#define APDS9253_MEASUREMENT_RATE_2000MS (BIT(2) | BIT(1) | BIT(0)) +#define APDS9253_MEASUREMENT_RATE_1000MS (BIT(2) | BIT(0)) +#define APDS9253_MEASUREMENT_RATE_500MS BIT(2) +#define APDS9253_MEASUREMENT_RATE_200MS (BIT(1) | BIT(0)) +#define APDS9253_MEASUREMENT_RATE_100MS BIT(1) /* default */ +#define APDS9253_MEASUREMENT_RATE_50MS BIT(0) +#define APDS9253_MEASUREMENT_RATE_25MS 0 + +/** @} */ + +/** + * @name apds9253 gain range + * @{ + */ + +#define APDS9253_GAIN_RANGE_18 BIT(2) +#define APDS9253_GAIN_RANGE_9 (BIT(1) | BIT(0)) +#define APDS9253_GAIN_RANGE_6 BIT(1) +#define APDS9253_GAIN_RANGE_3 BIT(0) /* default */ +#define APDS9253_GAIN_RANGE_1 0 + +/** @} */ + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_SENSOR_APDS9253_H_*/ diff --git a/tests/drivers/build_all/sensor/i2c.dtsi b/tests/drivers/build_all/sensor/i2c.dtsi index 669bd9f54d4c..0e6a810ba7ee 100644 --- a/tests/drivers/build_all/sensor/i2c.dtsi +++ b/tests/drivers/build_all/sensor/i2c.dtsi @@ -23,6 +23,7 @@ #include #include #include +#include /**************************************** * PLEASE KEEP REG ADDRESSES SEQUENTIAL * @@ -1096,3 +1097,12 @@ test_i2c_bmp180: bmp180@94 { reg = <0x94>; osr-press = <0x01>; }; + +test_i2c_apds9253: apds9253@91 { + compatible = "avago,apds9253"; + reg = <0x91>; + int-gpios = <&test_gpio 0 0>; + gain = ; + rate = ; + resolution = ; +};