diff --git a/CODEOWNERS b/CODEOWNERS index 50be48fa0a5..576326c014b 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -146,6 +146,7 @@ /drivers/sensor/lis*/ @avisconti /drivers/sensor/lps*/ @avisconti /drivers/sensor/lsm*/ @avisconti +/drivers/sensor/st*/ @avisconti /drivers/serial/uart_altera_jtag_hal.c @wentongwu /drivers/serial/*ns16550* @gnuless /drivers/serial/Kconfig.litex @mateusz-holenko @kgugala @pgielda diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt index 17b20f7b61a..d9160b76e0d 100644 --- a/drivers/sensor/CMakeLists.txt +++ b/drivers/sensor/CMakeLists.txt @@ -48,6 +48,7 @@ add_subdirectory_ifdef(CONFIG_PMS7003 pms7003) add_subdirectory_ifdef(CONFIG_QDEC_NRFX qdec_nrfx) add_subdirectory_ifdef(CONFIG_TEMP_NRF5 nrf5) add_subdirectory_ifdef(CONFIG_SHT3XD sht3xd) +add_subdirectory_ifdef(CONFIG_STTS751 stts751) add_subdirectory_ifdef(CONFIG_SX9500 sx9500) add_subdirectory_ifdef(CONFIG_TH02 th02) add_subdirectory_ifdef(CONFIG_TMP007 tmp007) diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig index f712d49f54b..b1f0affe65e 100644 --- a/drivers/sensor/Kconfig +++ b/drivers/sensor/Kconfig @@ -121,6 +121,8 @@ source "drivers/sensor/qdec_nrfx/Kconfig" source "drivers/sensor/sht3xd/Kconfig" +source "drivers/sensor/stts751/Kconfig" + source "drivers/sensor/sx9500/Kconfig" source "drivers/sensor/th02/Kconfig" diff --git a/drivers/sensor/stts751/CMakeLists.txt b/drivers/sensor/stts751/CMakeLists.txt new file mode 100644 index 00000000000..b70172f3984 --- /dev/null +++ b/drivers/sensor/stts751/CMakeLists.txt @@ -0,0 +1,11 @@ +# ST Microelectronics STTS751 temperature sensor +# +# Copyright (c) 2019 STMicroelectronics +# +# SPDX-License-Identifier: Apache-2.0 +# +zephyr_library() + +zephyr_library_sources_ifdef(CONFIG_STTS751 stts751.c) +zephyr_library_sources_ifdef(CONFIG_STTS751 stts751_i2c.c) +zephyr_library_sources_ifdef(CONFIG_STTS751_TRIGGER stts751_trigger.c) diff --git a/drivers/sensor/stts751/Kconfig b/drivers/sensor/stts751/Kconfig new file mode 100644 index 00000000000..febe7c9c221 --- /dev/null +++ b/drivers/sensor/stts751/Kconfig @@ -0,0 +1,92 @@ +# ST Microelectronics STTS751 temperature sensor +# +# Copyright (c) 2019 STMicroelectronics +# +# SPDX-License-Identifier: Apache-2.0 +# + +menuconfig STTS751 + bool "STTS751 temperature sensor" + depends on (I2C && HAS_DTS_I2C) + select HAS_STMEMSC + select USE_STDC_STTS751 + help + Enable driver for STTS751 I2C-based temperature sensor. + +if STTS751 + +choice STTS751_TRIGGER_MODE + prompt "Trigger mode" + default STTS751_TRIGGER_GLOBAL_THREAD + help + Specify the type of triggering to be used by the driver. + +config STTS751_TRIGGER_NONE + bool "No trigger" + +config STTS751_TRIGGER_GLOBAL_THREAD + bool "Use global thread" + depends on GPIO + select STTS751_TRIGGER + +config STTS751_TRIGGER_OWN_THREAD + bool "Use own thread" + depends on GPIO + select STTS751_TRIGGER + +endchoice # STTS751_TRIGGER_MODE + +config STTS751_TRIGGER + bool + +config STTS751_THREAD_PRIORITY + int "Thread priority" + depends on STTS751_TRIGGER_OWN_THREAD + default 10 + help + Priority of thread used by the driver to handle interrupts. + +config STTS751_THREAD_STACK_SIZE + int "Thread stack size" + depends on STTS751_TRIGGER_OWN_THREAD + default 1024 + help + Stack size of thread used by the driver to handle interrupts. + +menu "Attributes" + +config STTS751_TEMP_HI_THRESHOLD + depends on STTS751_TRIGGER + int "High temperature threshold alarm" + default 50 + help + HIGH temperature threshold to trigger an alarm + +config STTS751_TEMP_LO_THRESHOLD + depends on STTS751_TRIGGER + int "Low temperature threshold alarm" + default 10 + help + LOW temperature threshold to trigger an alarm + +config STTS751_SAMPLING_RATE + int "Output data rate" + range 0 9 + default 4 + help + Sensor output data rate expressed in conversions per second. + Data rates supported by the chip are: + 0: 1 conv every 16 sec + 1: 1 conv every 8 sec + 2: 1 conv every 4 sec + 3: 1 conv every 2 sec + 4: 1 conv every sec + 5: 2 convs every sec + 6: 4 convs every sec + 7: 8 convs every sec + 8: 16 convs every sec + 9: 32 convs every sec + +endmenu + +endif # STTS751 diff --git a/drivers/sensor/stts751/stts751.c b/drivers/sensor/stts751/stts751.c new file mode 100644 index 00000000000..9142af1f857 --- /dev/null +++ b/drivers/sensor/stts751/stts751.c @@ -0,0 +1,215 @@ +/* ST Microelectronics STTS751 temperature sensor + * + * Copyright (c) 2019 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/stts751.pdf + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "stts751.h" + +#define LOG_LEVEL CONFIG_SENSOR_LOG_LEVEL +LOG_MODULE_REGISTER(STTS751); + +static inline int stts751_set_odr_raw(struct device *dev, u8_t odr) +{ + struct stts751_data *data = dev->driver_data; + + return stts751_temp_data_rate_set(data->ctx, odr); +} + +static int stts751_sample_fetch(struct device *dev, + enum sensor_channel chan) +{ + struct stts751_data *data = dev->driver_data; + axis1bit16_t raw_temp; + + __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL); + + if (stts751_temperature_raw_get(data->ctx, &raw_temp.i16bit) < 0) { + LOG_DBG("Failed to read sample"); + return -EIO; + } + + data->sample_temp = raw_temp.i16bit; + + return 0; +} + +static inline void stts751_temp_convert(struct sensor_value *val, + s16_t raw_val) +{ + val->val1 = raw_val / 256; + val->val2 = ((s32_t)raw_val % 256) * 10000; +} + +static int stts751_channel_get(struct device *dev, + enum sensor_channel chan, + struct sensor_value *val) +{ + struct stts751_data *data = dev->driver_data; + + if (chan == SENSOR_CHAN_AMBIENT_TEMP) { + stts751_temp_convert(val, data->sample_temp); + } else { + return -ENOTSUP; + } + + return 0; +} + +static const struct { + s32_t rate; + s32_t rate_dec; +} stts751_map[] = { + {0, 62500}, + {0, 125000}, + {0, 250000}, + {0, 500000}, + {1, 0}, + {2, 0}, + {4, 0}, + {8, 0}, + {16, 0}, + {32, 0}, + }; + +static int stts751_odr_set(struct device *dev, + const struct sensor_value *val) +{ + int odr; + + for (odr = 0; odr < ARRAY_SIZE(stts751_map); odr++) { + if (val->val1 == stts751_map[odr].rate && + val->val2 == stts751_map[odr].rate_dec) { + break; + } + } + + if (odr == ARRAY_SIZE(stts751_map)) { + LOG_DBG("bad frequency"); + return -EINVAL; + } + + if (stts751_set_odr_raw(dev, odr) < 0) { + LOG_DBG("failed to set sampling rate"); + return -EIO; + } + + return 0; +} + +static int stts751_attr_set(struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, + const struct sensor_value *val) +{ + if (chan != SENSOR_CHAN_ALL) { + LOG_WRN("attr_set() not supported on this channel."); + return -ENOTSUP; + } + + switch (attr) { + case SENSOR_ATTR_SAMPLING_FREQUENCY: + return stts751_odr_set(dev, val); + default: + LOG_DBG("operation not supported."); + return -ENOTSUP; + } + + return 0; +} + +static const struct sensor_driver_api stts751_api_funcs = { + .attr_set = stts751_attr_set, + .sample_fetch = stts751_sample_fetch, + .channel_get = stts751_channel_get, +#if CONFIG_STTS751_TRIGGER + .trigger_set = stts751_trigger_set, +#endif +}; + +static int stts751_init_chip(struct device *dev) +{ + struct stts751_data *data = dev->driver_data; + stts751_id_t chip_id; + + if (stts751_device_id_get(data->ctx, &chip_id) < 0) { + LOG_DBG("Failed reading chip id"); + return -EIO; + } + + if (chip_id.manufacturer_id != STTS751_ID_MAN) { + LOG_DBG("Invalid chip id 0x%x", chip_id.manufacturer_id); + return -EIO; + } + + if (stts751_set_odr_raw(dev, CONFIG_STTS751_SAMPLING_RATE) < 0) { + LOG_DBG("Failed to set sampling rate"); + return -EIO; + } + + if (stts751_resolution_set(data->ctx, STTS751_11bit) < 0) { + LOG_DBG("Failed to set resolution"); + return -EIO; + } + + return 0; +} + +static int stts751_init(struct device *dev) +{ + const struct stts751_config * const config = dev->config->config_info; + struct stts751_data *data = dev->driver_data; + + data->bus = device_get_binding(config->master_dev_name); + if (!data->bus) { + LOG_DBG("bus master not found: %s", config->master_dev_name); + return -EINVAL; + } + + config->bus_init(dev); + + if (stts751_init_chip(dev) < 0) { + LOG_DBG("Failed to initialize chip"); + return -EIO; + } + +#ifdef CONFIG_STTS751_TRIGGER + if (stts751_init_interrupt(dev) < 0) { + LOG_ERR("Failed to initialize interrupt."); + return -EIO; + } +#endif + + return 0; +} + +static struct stts751_data stts751_data; + +static const struct stts751_config stts751_config = { + .master_dev_name = DT_INST_0_ST_STTS751_BUS_NAME, +#ifdef CONFIG_STTS751_TRIGGER + .event_port = DT_INST_0_ST_STTS751_DRDY_GPIOS_CONTROLLER, + .event_pin = DT_INST_0_ST_STTS751_DRDY_GPIOS_PIN, +#endif +#if defined(DT_ST_STTS751_BUS_I2C) + .bus_init = stts751_i2c_init, + .i2c_slv_addr = DT_INST_0_ST_STTS751_BASE_ADDRESS, +#else +#error "BUS MACRO NOT DEFINED IN DTS" +#endif +}; + +DEVICE_AND_API_INIT(stts751, DT_INST_0_ST_STTS751_LABEL, stts751_init, + &stts751_data, &stts751_config, POST_KERNEL, + CONFIG_SENSOR_INIT_PRIORITY, &stts751_api_funcs); diff --git a/drivers/sensor/stts751/stts751.h b/drivers/sensor/stts751/stts751.h new file mode 100644 index 00000000000..878d1d01264 --- /dev/null +++ b/drivers/sensor/stts751/stts751.h @@ -0,0 +1,74 @@ +/* ST Microelectronics STTS751 temperature sensor + * + * Copyright (c) 2019 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/stts751.pdf + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_STTS751_STTS751_H_ +#define ZEPHYR_DRIVERS_SENSOR_STTS751_STTS751_H_ + +#include +#include +#include +#include +#include +#include +#include "stts751_reg.h" + +struct stts751_config { + char *master_dev_name; + int (*bus_init)(struct device *dev); +#ifdef CONFIG_STTS751_TRIGGER + const char *event_port; + u8_t event_pin; +#endif +#ifdef DT_ST_STTS751_BUS_I2C + u16_t i2c_slv_addr; +#endif +}; + +struct stts751_data { + struct device *bus; + s16_t sample_temp; + + stts751_ctx_t *ctx; + +#ifdef DT_ST_STTS751_BUS_I2C + stts751_ctx_t ctx_i2c; +#endif + +#ifdef CONFIG_STTS751_TRIGGER + struct device *gpio; + u32_t pin; + struct gpio_callback gpio_cb; + + struct sensor_trigger data_ready_trigger; + sensor_trigger_handler_t thsld_handler; + +#if defined(CONFIG_STTS751_TRIGGER_OWN_THREAD) + K_THREAD_STACK_MEMBER(thread_stack, CONFIG_STTS751_THREAD_STACK_SIZE); + struct k_thread thread; + struct k_sem gpio_sem; +#elif defined(CONFIG_STTS751_TRIGGER_GLOBAL_THREAD) + struct k_work work; + struct device *dev; +#endif + +#endif /* CONFIG_STTS751_TRIGGER */ +}; + +int stts751_i2c_init(struct device *dev); + +#ifdef CONFIG_STTS751_TRIGGER +int stts751_trigger_set(struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler); + +int stts751_init_interrupt(struct device *dev); +#endif + +#endif /* ZEPHYR_DRIVERS_SENSOR_STTS751_STTS751_H_ */ diff --git a/drivers/sensor/stts751/stts751_i2c.c b/drivers/sensor/stts751/stts751_i2c.c new file mode 100644 index 00000000000..e2da0f788fe --- /dev/null +++ b/drivers/sensor/stts751/stts751_i2c.c @@ -0,0 +1,54 @@ +/* ST Microelectronics STTS751 temperature sensor + * + * Copyright (c) 2019 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/stts751.pdf + */ + +#include +#include +#include + +#include "stts751.h" + +#ifdef DT_ST_STTS751_BUS_I2C + +#define LOG_LEVEL CONFIG_SENSOR_LOG_LEVEL +LOG_MODULE_DECLARE(STTS751); + +static int stts751_i2c_read(struct device *dev, u8_t reg_addr, + u8_t *value, u16_t len) +{ + struct stts751_data *data = dev->driver_data; + const struct stts751_config *cfg = dev->config->config_info; + + return i2c_burst_read(data->bus, cfg->i2c_slv_addr, + reg_addr, value, len); +} + +static int stts751_i2c_write(struct device *dev, u8_t reg_addr, + u8_t *value, u16_t len) +{ + struct stts751_data *data = dev->driver_data; + const struct stts751_config *cfg = dev->config->config_info; + + return i2c_burst_write(data->bus, cfg->i2c_slv_addr, + reg_addr, value, len); +} + +int stts751_i2c_init(struct device *dev) +{ + struct stts751_data *data = dev->driver_data; + + data->ctx_i2c.read_reg = (stts751_read_ptr) stts751_i2c_read; + data->ctx_i2c.write_reg = (stts751_write_ptr) stts751_i2c_write; + + data->ctx = &data->ctx_i2c; + data->ctx->handle = dev; + + return 0; +} +#endif /* DT_ST_STTS751_BUS_I2C */ diff --git a/drivers/sensor/stts751/stts751_trigger.c b/drivers/sensor/stts751/stts751_trigger.c new file mode 100644 index 00000000000..98539f604b0 --- /dev/null +++ b/drivers/sensor/stts751/stts751_trigger.c @@ -0,0 +1,173 @@ +/* ST Microelectronics STTS751 temperature sensor + * + * Copyright (c) 2019 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + * + * Datasheet: + * https://www.st.com/resource/en/datasheet/stts751.pdf + */ + +#include +#include +#include +#include + +#include "stts751.h" + +#define LOG_LEVEL CONFIG_SENSOR_LOG_LEVEL +LOG_MODULE_DECLARE(STTS751); + +/** + * stts751_enable_int - enable selected int pin to generate interrupt + */ +static int stts751_enable_int(struct device *dev, int enable) +{ + struct stts751_data *stts751 = dev->driver_data; + u8_t en = (enable) ? 0 : 1; + + return stts751_pin_event_route_set(stts751->ctx, en); +} + +/** + * stts751_trigger_set - link external trigger to event data ready + */ +int stts751_trigger_set(struct device *dev, + const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + struct stts751_data *stts751 = dev->driver_data; + + if (trig->chan == SENSOR_CHAN_ALL) { + stts751->thsld_handler = handler; + if (handler) { + return stts751_enable_int(dev, 1); + } else { + return stts751_enable_int(dev, 0); + } + } + + return -ENOTSUP; +} + +/** + * stts751_handle_interrupt - handle the thsld event + * read data and call handler if registered any + */ +static void stts751_handle_interrupt(void *arg) +{ + struct device *dev = arg; + struct stts751_data *stts751 = dev->driver_data; + const struct stts751_config *cfg = dev->config->config_info; + struct sensor_trigger thsld_trigger = { + .type = SENSOR_TRIG_THRESHOLD, + }; + stts751_status_t status; + + stts751_status_reg_get(stts751->ctx, &status); + + if (stts751->thsld_handler != NULL && + (status.t_high || status.t_low)) { + stts751->thsld_handler(dev, &thsld_trigger); + } + + gpio_pin_enable_callback(stts751->gpio, cfg->event_pin); +} + +static void stts751_gpio_callback(struct device *dev, + struct gpio_callback *cb, u32_t pins) +{ + const struct stts751_config *cfg = dev->config->config_info; + struct stts751_data *stts751 = + CONTAINER_OF(cb, struct stts751_data, gpio_cb); + + ARG_UNUSED(pins); + + gpio_pin_disable_callback(dev, cfg->event_pin); + +#if defined(CONFIG_STTS751_TRIGGER_OWN_THREAD) + k_sem_give(&stts751->gpio_sem); +#elif defined(CONFIG_STTS751_TRIGGER_GLOBAL_THREAD) + k_work_submit(&stts751->work); +#endif /* CONFIG_STTS751_TRIGGER_OWN_THREAD */ +} + +#ifdef CONFIG_STTS751_TRIGGER_OWN_THREAD +static void stts751_thread(int dev_ptr, int unused) +{ + struct device *dev = INT_TO_POINTER(dev_ptr); + struct stts751_data *stts751 = dev->driver_data; + + ARG_UNUSED(unused); + + while (1) { + k_sem_take(&stts751->gpio_sem, K_FOREVER); + stts751_handle_interrupt(dev); + } +} +#endif /* CONFIG_STTS751_TRIGGER_OWN_THREAD */ + +#ifdef CONFIG_STTS751_TRIGGER_GLOBAL_THREAD +static void stts751_work_cb(struct k_work *work) +{ + struct stts751_data *stts751 = + CONTAINER_OF(work, struct stts751_data, work); + + stts751_handle_interrupt(stts751->dev); +} +#endif /* CONFIG_STTS751_TRIGGER_GLOBAL_THREAD */ + +int stts751_init_interrupt(struct device *dev) +{ + struct stts751_data *stts751 = dev->driver_data; + const struct stts751_config *cfg = dev->config->config_info; + int ret; + + /* setup data ready gpio interrupt */ + stts751->gpio = device_get_binding(cfg->event_port); + if (stts751->gpio == NULL) { + LOG_DBG("Cannot get pointer to %s device", cfg->event_port); + return -EINVAL; + } + +#if defined(CONFIG_STTS751_TRIGGER_OWN_THREAD) + k_sem_init(&stts751->gpio_sem, 0, UINT_MAX); + + k_thread_create(&stts751->thread, stts751->thread_stack, + CONFIG_STTS751_THREAD_STACK_SIZE, + (k_thread_entry_t)stts751_thread, dev, + 0, NULL, K_PRIO_COOP(CONFIG_STTS751_THREAD_PRIORITY), + 0, 0); +#elif defined(CONFIG_STTS751_TRIGGER_GLOBAL_THREAD) + stts751->work.handler = stts751_work_cb; + stts751->dev = dev; +#endif /* CONFIG_STTS751_TRIGGER_OWN_THREAD */ + + ret = gpio_pin_configure(stts751->gpio, cfg->event_pin, + GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE | + GPIO_INT_ACTIVE_LOW | GPIO_INT_DEBOUNCE); + if (ret < 0) { + LOG_DBG("Could not configure gpio"); + return ret; + } + + gpio_init_callback(&stts751->gpio_cb, stts751_gpio_callback, + BIT(cfg->event_pin)); + + if (gpio_add_callback(stts751->gpio, &stts751->gpio_cb) < 0) { + LOG_DBG("Could not set gpio callback"); + return -EIO; + } + + /* Enable interrupt on high temperature */ + float temp_hi = (float) CONFIG_STTS751_TEMP_HI_THRESHOLD; + float temp_lo = (float) CONFIG_STTS751_TEMP_LO_THRESHOLD; + + stts751_high_temperature_threshold_set(stts751->ctx, + stts751_from_celsius_to_lsb(temp_hi)); + + stts751_low_temperature_threshold_set(stts751->ctx, + stts751_from_celsius_to_lsb(temp_lo)); + + return gpio_pin_enable_callback(stts751->gpio, cfg->event_pin); +} diff --git a/dts/bindings/sensor/st,stts751-i2c.yaml b/dts/bindings/sensor/st,stts751-i2c.yaml new file mode 100644 index 00000000000..870d5463f1d --- /dev/null +++ b/dts/bindings/sensor/st,stts751-i2c.yaml @@ -0,0 +1,24 @@ +# +# Copyright (c) 2019 STMicroelectronics +# +# SPDX-License-Identifier: Apache-2.0 +# + +title: STMicroelectronics MEMS sensors STTS751 +version: 0.1 + +description: > + This binding gives a base representation of STTS751 + temperature sensor connected to I2C bus + +inherits: + !include i2c-device.yaml + +properties: + compatible: + constraint: "st,stts751" + + drdy-gpios: + type: compound + category: optional + description: DRDY pin diff --git a/tests/drivers/build_all/dts_fixup.h b/tests/drivers/build_all/dts_fixup.h index 7d2bcbc51ad..4bc54b76e2e 100644 --- a/tests/drivers/build_all/dts_fixup.h +++ b/tests/drivers/build_all/dts_fixup.h @@ -216,6 +216,15 @@ #define DT_INST_0_ST_LSM9DS0_GYRO_IRQ_GPIOS_PIN 1 #endif +#ifndef DT_INST_0_ST_STTS751_LABEL +#define DT_INST_0_ST_STTS751_LABEL "" +#define DT_INST_0_ST_STTS751_BUS_NAME "" +#define DT_INST_0_ST_STTS751_BASE_ADDRESS 0x19 +#define DT_INST_0_ST_STTS751_DRDY_GPIOS_CONTROLLER "" +#define DT_INST_0_ST_STTS751_DRDY_GPIOS_PIN 0 +#define DT_ST_STTS751_BUS_I2C 1 +#endif + #ifndef DT_INST_0_AMS_IAQCORE_LABEL #define DT_INST_0_AMS_IAQCORE_LABEL "" #define DT_INST_0_AMS_IAQCORE_BUS_NAME ""