drivers: sensors: sht3xd: support multiple devices and DT bindings

Add a configuration structure to sht3xd that holds instance-specific
parameters, implemented in a immutable statically allocated object
initialized with material from device tree binding aliases.

Signed-off-by: Peter A. Bigot <pab@pabigot.com>
This commit is contained in:
Peter A. Bigot 2019-01-12 09:06:12 -06:00 committed by Maureen Helm
parent ec6509504d
commit 12836d9280
7 changed files with 154 additions and 134 deletions

View file

@ -53,16 +53,15 @@ static u8_t sht3xd_compute_crc(u16_t value)
return crc;
}
int sht3xd_write_command(struct sht3xd_data *drv_data, u16_t cmd)
int sht3xd_write_command(struct device *dev, u16_t cmd)
{
u8_t tx_buf[2] = { cmd >> 8, cmd & 0xFF };
return i2c_write(drv_data->i2c, tx_buf, sizeof(tx_buf),
SHT3XD_I2C_ADDRESS);
return i2c_write(sht3xd_i2c_device(dev), tx_buf, sizeof(tx_buf),
sht3xd_i2c_address(dev));
}
int sht3xd_write_reg(struct sht3xd_data *drv_data, u16_t cmd,
u16_t val)
int sht3xd_write_reg(struct device *dev, u16_t cmd, u16_t val)
{
u8_t tx_buf[5];
@ -72,13 +71,15 @@ int sht3xd_write_reg(struct sht3xd_data *drv_data, u16_t cmd,
tx_buf[3] = val & 0xFF;
tx_buf[4] = sht3xd_compute_crc(val);
return i2c_write(drv_data->i2c, tx_buf, sizeof(tx_buf),
SHT3XD_I2C_ADDRESS);
return i2c_write(sht3xd_i2c_device(dev), tx_buf, sizeof(tx_buf),
sht3xd_i2c_address(dev));
}
static int sht3xd_sample_fetch(struct device *dev, enum sensor_channel chan)
{
struct sht3xd_data *drv_data = dev->driver_data;
struct sht3xd_data *data = dev->driver_data;
struct device *i2c = sht3xd_i2c_device(dev);
u8_t address = sht3xd_i2c_address(dev);
u8_t rx_buf[6];
u16_t t_sample, rh_sample;
@ -102,7 +103,7 @@ static int sht3xd_sample_fetch(struct device *dev, enum sensor_channel chan)
},
};
if (i2c_transfer(drv_data->i2c, msgs, 2, SHT3XD_I2C_ADDRESS) < 0) {
if (i2c_transfer(i2c, msgs, 2, address) < 0) {
LOG_DBG("Failed to read data sample!");
return -EIO;
}
@ -119,8 +120,8 @@ static int sht3xd_sample_fetch(struct device *dev, enum sensor_channel chan)
return -EIO;
}
drv_data->t_sample = t_sample;
drv_data->rh_sample = rh_sample;
data->t_sample = t_sample;
data->rh_sample = rh_sample;
return 0;
}
@ -129,7 +130,7 @@ static int sht3xd_channel_get(struct device *dev,
enum sensor_channel chan,
struct sensor_value *val)
{
struct sht3xd_data *drv_data = dev->driver_data;
const struct sht3xd_data *data = dev->driver_data;
u64_t tmp;
/*
@ -138,12 +139,12 @@ static int sht3xd_channel_get(struct device *dev,
*/
if (chan == SENSOR_CHAN_AMBIENT_TEMP) {
/* val = -45 + 175 * sample / (2^16 -1) */
tmp = 175 * (u64_t)drv_data->t_sample;
tmp = 175 * (u64_t)data->t_sample;
val->val1 = (s32_t)(tmp / 0xFFFF) - 45;
val->val2 = (1000000 * (tmp % 0xFFFF)) / 0xFFFF;
} else if (chan == SENSOR_CHAN_HUMIDITY) {
/* val = 100 * sample / (2^16 -1) */
u32_t tmp2 = 100 * (u32_t)drv_data->rh_sample;
u32_t tmp2 = 100 * (u32_t)data->rh_sample;
val->val1 = tmp2 / 0xFFFF;
/* x * 100000 / 65536 == x * 15625 / 1024 */
val->val2 = (tmp2 % 0xFFFF) * 15625 / 1024;
@ -165,21 +166,25 @@ static const struct sensor_driver_api sht3xd_driver_api = {
static int sht3xd_init(struct device *dev)
{
struct sht3xd_data *drv_data = dev->driver_data;
struct sht3xd_data *data = dev->driver_data;
const struct sht3xd_config *cfg = dev->config->config_info;
struct device *i2c = device_get_binding(cfg->bus_name);
drv_data->i2c = device_get_binding(DT_SHT3XD_I2C_MASTER_DEV_NAME);
if (drv_data->i2c == NULL) {
if (i2c == NULL) {
LOG_DBG("Failed to get pointer to %s device!",
DT_SHT3XD_I2C_MASTER_DEV_NAME);
cfg->bus_name);
return -EINVAL;
}
if (!SHT3XD_I2C_ADDRESS) {
data->bus = i2c;
if (!cfg->base_address) {
LOG_DBG("No I2C address");
return -EINVAL;
}
data->dev = dev;
/* clear status register */
if (sht3xd_write_command(drv_data, SHT3XD_CMD_CLEAR_STATUS) < 0) {
if (sht3xd_write_command(dev, SHT3XD_CMD_CLEAR_STATUS) < 0) {
LOG_DBG("Failed to clear status register!");
return -EIO;
}
@ -187,7 +192,7 @@ static int sht3xd_init(struct device *dev)
k_busy_wait(SHT3XD_CLEAR_STATUS_WAIT_USEC);
/* set periodic measurement mode */
if (sht3xd_write_command(drv_data,
if (sht3xd_write_command(dev,
measure_cmd[SHT3XD_MPS_IDX][SHT3XD_REPEATABILITY_IDX])
< 0) {
LOG_DBG("Failed to set measurement mode!");
@ -206,8 +211,19 @@ static int sht3xd_init(struct device *dev)
return 0;
}
struct sht3xd_data sht3xd_driver;
struct sht3xd_data sht3xd0_driver;
static const struct sht3xd_config sht3xd0_cfg = {
.bus_name = DT_SENSIRION_SHT3XD_0_BUS_NAME,
#ifdef CONFIG_SHT3XD_TRIGGER
.alert_gpio_name = DT_SENSIRION_SHT3XD_0_ALERT_GPIOS_CONTROLLER,
#endif
.base_address = DT_SENSIRION_SHT3XD_0_BASE_ADDRESS,
#ifdef CONFIG_SHT3XD_TRIGGER
.alert_pin = DT_SENSIRION_SHT3XD_0_ALERT_GPIOS_PIN,
#endif
};
DEVICE_AND_API_INIT(sht3xd, DT_SHT3XD_NAME, sht3xd_init, &sht3xd_driver,
NULL, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY,
DEVICE_AND_API_INIT(sht3xd0, DT_SENSIRION_SHT3XD_0_LABEL,
sht3xd_init, &sht3xd0_driver, &sht3xd0_cfg,
POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY,
&sht3xd_driver_api);

View file

@ -11,8 +11,6 @@
#include <kernel.h>
#include <gpio.h>
#define SHT3XD_I2C_ADDRESS DT_SHT3XD_I2C_ADDR
#define SHT3XD_CMD_FETCH 0xE000
#define SHT3XD_CMD_ART 0x2B32
#define SHT3XD_CMD_READ_STATUS 0xF32D
@ -45,14 +43,28 @@
#define SHT3XD_CLEAR_STATUS_WAIT_USEC 1000
struct sht3xd_config {
char *bus_name;
#ifdef CONFIG_SHT3XD_TRIGGER
char *alert_gpio_name;
#endif /* CONFIG_SHT3XD_TRIGGER */
u8_t base_address;
#ifdef CONFIG_SHT3XD_TRIGGER
s8_t alert_pin;
#endif /* CONFIG_SHT3XD_TRIGGER */
};
struct sht3xd_data {
struct device *i2c;
struct device *dev;
struct device *bus;
u16_t t_sample;
u16_t rh_sample;
#ifdef CONFIG_SHT3XD_TRIGGER
struct device *gpio;
struct gpio_callback gpio_cb;
struct device *alert_gpio;
struct gpio_callback alert_cb;
u16_t t_low;
u16_t t_high;
@ -68,17 +80,29 @@ struct sht3xd_data {
struct k_thread thread;
#elif defined(CONFIG_SHT3XD_TRIGGER_GLOBAL_THREAD)
struct k_work work;
struct device *dev;
#endif
#endif /* CONFIG_SHT3XD_TRIGGER */
};
#ifdef CONFIG_SHT3XD_TRIGGER
int sht3xd_write_command(struct sht3xd_data *drv_data, u16_t cmd);
static inline u8_t sht3xd_i2c_address(struct device *dev)
{
const struct sht3xd_config *dcp = dev->config->config_info;
int sht3xd_write_reg(struct sht3xd_data *drv_data, u16_t cmd,
u16_t val);
return dcp->base_address;
}
static inline struct device *sht3xd_i2c_device(struct device *dev)
{
const struct sht3xd_data *ddp = dev->driver_data;
return ddp->bus;
}
#ifdef CONFIG_SHT3XD_TRIGGER
int sht3xd_write_command(struct device *dev, u16_t cmd);
int sht3xd_write_reg(struct device *dev, u16_t cmd, u16_t val);
int sht3xd_attr_set(struct device *dev,
enum sensor_channel chan,

View file

@ -38,43 +38,43 @@ int sht3xd_attr_set(struct device *dev,
enum sensor_attribute attr,
const struct sensor_value *val)
{
struct sht3xd_data *drv_data = dev->driver_data;
struct sht3xd_data *data = dev->driver_data;
u16_t set_cmd, clear_cmd, reg_val, temp, rh;
if (attr == SENSOR_ATTR_LOWER_THRESH) {
if (chan == SENSOR_CHAN_AMBIENT_TEMP) {
drv_data->t_low = sht3xd_temp_processed_to_raw(val);
data->t_low = sht3xd_temp_processed_to_raw(val);
} else if (chan == SENSOR_CHAN_HUMIDITY) {
drv_data->rh_low = sht3xd_rh_processed_to_raw(val);
data->rh_low = sht3xd_rh_processed_to_raw(val);
} else {
return -ENOTSUP;
}
set_cmd = SHT3XD_CMD_WRITE_TH_LOW_SET;
clear_cmd = SHT3XD_CMD_WRITE_TH_LOW_CLEAR;
temp = drv_data->t_low;
rh = drv_data->rh_low;
temp = data->t_low;
rh = data->rh_low;
} else if (attr == SENSOR_ATTR_UPPER_THRESH) {
if (chan == SENSOR_CHAN_AMBIENT_TEMP) {
drv_data->t_high = sht3xd_temp_processed_to_raw(val);
data->t_high = sht3xd_temp_processed_to_raw(val);
} else if (chan == SENSOR_CHAN_HUMIDITY) {
drv_data->rh_high = sht3xd_rh_processed_to_raw(val);
data->rh_high = sht3xd_rh_processed_to_raw(val);
} else {
return -ENOTSUP;
}
set_cmd = SHT3XD_CMD_WRITE_TH_HIGH_SET;
clear_cmd = SHT3XD_CMD_WRITE_TH_HIGH_CLEAR;
temp = drv_data->t_high;
rh = drv_data->rh_high;
temp = data->t_high;
rh = data->rh_high;
} else {
return -ENOTSUP;
}
reg_val = (rh & 0xFE00) | ((temp & 0xFF80) >> 7);
if (sht3xd_write_reg(drv_data, set_cmd, reg_val) < 0 ||
sht3xd_write_reg(drv_data, clear_cmd, reg_val) < 0) {
if (sht3xd_write_reg(dev, set_cmd, reg_val) < 0 ||
sht3xd_write_reg(dev, clear_cmd, reg_val) < 0) {
LOG_DBG("Failed to write threshold value!");
return -EIO;
}
@ -85,42 +85,44 @@ int sht3xd_attr_set(struct device *dev,
static void sht3xd_gpio_callback(struct device *dev,
struct gpio_callback *cb, u32_t pins)
{
struct sht3xd_data *drv_data =
CONTAINER_OF(cb, struct sht3xd_data, gpio_cb);
struct sht3xd_data *data =
CONTAINER_OF(cb, struct sht3xd_data, alert_cb);
const struct sht3xd_config *cfg = data->dev->config->config_info;
ARG_UNUSED(pins);
gpio_pin_disable_callback(dev, DT_SHT3XD_GPIO_ALERT_PIN);
gpio_pin_disable_callback(dev, cfg->alert_pin);
#if defined(CONFIG_SHT3XD_TRIGGER_OWN_THREAD)
k_sem_give(&drv_data->gpio_sem);
k_sem_give(&data->gpio_sem);
#elif defined(CONFIG_SHT3XD_TRIGGER_GLOBAL_THREAD)
k_work_submit(&drv_data->work);
k_work_submit(&data->work);
#endif
}
static void sht3xd_thread_cb(void *arg)
{
struct device *dev = arg;
struct sht3xd_data *drv_data = dev->driver_data;
struct sht3xd_data *data = dev->driver_data;
const struct sht3xd_config *cfg = dev->config->config_info;
if (drv_data->handler != NULL) {
drv_data->handler(dev, &drv_data->trigger);
if (data->handler != NULL) {
data->handler(dev, &data->trigger);
}
gpio_pin_enable_callback(drv_data->gpio, DT_SHT3XD_GPIO_ALERT_PIN);
gpio_pin_enable_callback(data->alert_gpio, cfg->alert_pin);
}
#ifdef CONFIG_SHT3XD_TRIGGER_OWN_THREAD
static void sht3xd_thread(int dev_ptr, int unused)
{
struct device *dev = INT_TO_POINTER(dev_ptr);
struct sht3xd_data *drv_data = dev->driver_data;
struct sht3xd_data *data = dev->driver_data;
ARG_UNUSED(unused);
while (1) {
k_sem_take(&drv_data->gpio_sem, K_FOREVER);
k_sem_take(&data->gpio_sem, K_FOREVER);
sht3xd_thread_cb(dev);
}
}
@ -129,10 +131,10 @@ static void sht3xd_thread(int dev_ptr, int unused)
#ifdef CONFIG_SHT3XD_TRIGGER_GLOBAL_THREAD
static void sht3xd_work_cb(struct k_work *work)
{
struct sht3xd_data *drv_data =
struct sht3xd_data *data =
CONTAINER_OF(work, struct sht3xd_data, work);
sht3xd_thread_cb(drv_data->dev);
sht3xd_thread_cb(data->dev);
}
#endif
@ -140,85 +142,90 @@ int sht3xd_trigger_set(struct device *dev,
const struct sensor_trigger *trig,
sensor_trigger_handler_t handler)
{
struct sht3xd_data *drv_data = dev->driver_data;
struct sht3xd_data *data = dev->driver_data;
const struct sht3xd_config *cfg = dev->config->config_info;
if (trig->type != SENSOR_TRIG_THRESHOLD) {
return -ENOTSUP;
}
gpio_pin_disable_callback(drv_data->gpio, DT_SHT3XD_GPIO_ALERT_PIN);
drv_data->handler = handler;
drv_data->trigger = *trig;
gpio_pin_enable_callback(drv_data->gpio, DT_SHT3XD_GPIO_ALERT_PIN);
gpio_pin_disable_callback(data->alert_gpio, cfg->alert_pin);
data->handler = handler;
data->trigger = *trig;
gpio_pin_enable_callback(data->alert_gpio, cfg->alert_pin);
return 0;
}
int sht3xd_init_interrupt(struct device *dev)
{
struct sht3xd_data *drv_data = dev->driver_data;
struct sht3xd_data *data = dev->driver_data;
const struct sht3xd_config *cfg = dev->config->config_info;
struct device *gpio = device_get_binding(cfg->alert_gpio_name);
int rc;
drv_data->t_low = 0U;
drv_data->rh_low = 0U;
drv_data->t_high = 0xFFFF;
drv_data->rh_high = 0xFFFF;
/* setup gpio interrupt */
if (gpio == NULL) {
LOG_DBG("Failed to get pointer to %s device!",
cfg->alert_gpio_name);
return -EINVAL;
}
data->alert_gpio = gpio;
rc = gpio_pin_configure(gpio, cfg->alert_pin,
GPIO_DIR_IN | GPIO_INT |
GPIO_INT_EDGE | GPIO_INT_DOUBLE_EDGE |
GPIO_INT_ACTIVE_HIGH | GPIO_INT_DEBOUNCE);
if (rc != 0) {
LOG_DBG("Failed to configure alert pin %u!", cfg->alert_pin);
return -EIO;
}
gpio_init_callback(&data->alert_cb, sht3xd_gpio_callback,
BIT(cfg->alert_pin));
rc = gpio_add_callback(gpio, &data->alert_cb);
if (rc < 0) {
LOG_DBG("Failed to set gpio callback!");
return -EIO;
}
/* set alert thresholds to match reamsurement ranges */
if (sht3xd_write_reg(drv_data, SHT3XD_CMD_WRITE_TH_HIGH_SET, 0xFFFF)
data->t_low = 0U;
data->rh_low = 0U;
data->t_high = 0xFFFF;
data->rh_high = 0xFFFF;
if (sht3xd_write_reg(dev, SHT3XD_CMD_WRITE_TH_HIGH_SET, 0xFFFF)
< 0) {
LOG_DBG("Failed to write threshold high set value!");
return -EIO;
}
if (sht3xd_write_reg(drv_data, SHT3XD_CMD_WRITE_TH_HIGH_CLEAR,
if (sht3xd_write_reg(dev, SHT3XD_CMD_WRITE_TH_HIGH_CLEAR,
0xFFFF) < 0) {
LOG_DBG("Failed to write threshold high clear value!");
return -EIO;
}
if (sht3xd_write_reg(drv_data, SHT3XD_CMD_WRITE_TH_LOW_SET, 0) < 0) {
if (sht3xd_write_reg(dev, SHT3XD_CMD_WRITE_TH_LOW_SET, 0) < 0) {
LOG_DBG("Failed to write threshold low set value!");
return -EIO;
}
if (sht3xd_write_reg(drv_data, SHT3XD_CMD_WRITE_TH_LOW_SET, 0) < 0) {
if (sht3xd_write_reg(dev, SHT3XD_CMD_WRITE_TH_LOW_SET, 0) < 0) {
LOG_DBG("Failed to write threshold low clear value!");
return -EIO;
}
/* setup gpio interrupt */
drv_data->gpio = device_get_binding(DT_SHT3XD_GPIO_ALERT_DEV_NAME);
if (drv_data->gpio == NULL) {
LOG_DBG("Failed to get pointer to %s device!",
DT_SHT3XD_GPIO_ALERT_DEV_NAME);
return -EINVAL;
}
gpio_pin_configure(drv_data->gpio, DT_SHT3XD_GPIO_ALERT_PIN,
GPIO_DIR_IN | GPIO_INT |
GPIO_INT_EDGE | GPIO_INT_DOUBLE_EDGE |
GPIO_INT_ACTIVE_HIGH | GPIO_INT_DEBOUNCE);
gpio_init_callback(&drv_data->gpio_cb,
sht3xd_gpio_callback,
BIT(DT_SHT3XD_GPIO_ALERT_PIN));
if (gpio_add_callback(drv_data->gpio, &drv_data->gpio_cb) < 0) {
LOG_DBG("Failed to set gpio callback!");
return -EIO;
}
#if defined(CONFIG_SHT3XD_TRIGGER_OWN_THREAD)
k_sem_init(&drv_data->gpio_sem, 0, UINT_MAX);
k_sem_init(&data->gpio_sem, 0, UINT_MAX);
k_thread_create(&drv_data->thread, drv_data->thread_stack,
k_thread_create(&data->thread, data->thread_stack,
CONFIG_SHT3XD_THREAD_STACK_SIZE,
(k_thread_entry_t)sht3xd_thread, dev,
0, NULL, K_PRIO_COOP(CONFIG_SHT3XD_THREAD_PRIORITY),
0, 0);
#elif defined(CONFIG_SHT3XD_TRIGGER_GLOBAL_THREAD)
drv_data->work.handler = sht3xd_work_cb;
drv_data->dev = dev;
data->work.handler = sht3xd_work_cb;
#endif
return 0;

View file

@ -1,28 +0,0 @@
/*
* Copyright (c) 2018 Peter Bigot Consulting, LLC
*
* SPDX-License-Identifier: Apache-2.0
*/
#if defined(CONFIG_HAS_DTS_I2C)
#ifndef DT_SHT3XD_NAME
#ifdef DT_NORDIC_NRF_I2C_40003000_SENSIRION_SHT3XD_44_LABEL
#define DT_SHT3XD_NAME DT_NORDIC_NRF_I2C_40003000_SENSIRION_SHT3XD_44_LABEL
#define DT_SHT3XD_I2C_ADDR DT_NORDIC_NRF_I2C_40003000_SENSIRION_SHT3XD_44_BASE_ADDRESS
#define DT_SHT3XD_I2C_MASTER_DEV_NAME DT_NORDIC_NRF_I2C_40003000_SENSIRION_SHT3XD_44_BUS_NAME
#ifdef DT_NORDIC_NRF_I2C_40003000_SENSIRION_SHT3XD_44_ALERT_GPIOS_CONTROLLER
#define DT_SHT3XD_GPIO_ALERT_DEV_NAME DT_NORDIC_NRF_I2C_40003000_SENSIRION_SHT3XD_44_ALERT_GPIOS_CONTROLLER
#define DT_SHT3XD_GPIO_ALERT_PIN DT_NORDIC_NRF_I2C_40003000_SENSIRION_SHT3XD_44_ALERT_GPIOS_PIN
#endif /* GPIO_ALERT */
#else /* board selection */
#error No device tree bindings for SHT3XD
#endif /* board selection */
#endif /* DT_SHT3XD_NAME */
#endif /* CONFIG_HAS_DTS_I2C */

View file

@ -5,7 +5,7 @@
*/
&i2c0 {
sht3xd: sht3xd@44 {
sht3xd@44 {
compatible = "sensirion,sht3xd";
reg = <0x44>;
label = "SHT3XD";

View file

@ -23,7 +23,7 @@ static void trigger_handler(struct device *dev, struct sensor_trigger *trig)
void main(void)
{
struct device *dev = device_get_binding(DT_SHT3XD_NAME);
struct device *dev = device_get_binding("SHT3XD");
int rc;
if (dev == NULL) {

View file

@ -149,12 +149,13 @@
#define DT_LIS2DH_INT2_GPIO_PIN 1
#endif
#ifndef DT_SHT3XD_NAME
#define DT_SHT3XD_NAME ""
#define DT_SHT3XD_I2C_ADDR 0
#define DT_SHT3XD_I2C_MASTER_DEV_NAME ""
#define DT_SHT3XD_GPIO_ALERT_DEV_NAME ""
#define DT_SHT3XD_GPIO_ALERT_PIN 0
#ifndef DT_SENSIRION_SHT3XD_0_LABEL
#define DT_SENSIRION_SHT3XD_0_LABEL ""
#define DT_SENSIRION_SHT3XD_0_ALERT_GPIOS_CONTROLLER ""
#define DT_SENSIRION_SHT3XD_0_ALERT_GPIOS_FLAGS 0
#define DT_SENSIRION_SHT3XD_0_ALERT_GPIOS_PIN 0
#define DT_SENSIRION_SHT3XD_0_BASE_ADDRESS 0x44
#define DT_SENSIRION_SHT3XD_0_BUS_NAME ""
#endif
#ifndef DT_LIS3DH_DEV_NAME