sensor: lps22hh: extend to support being on I3C bus

This extends the lps22hh driver to support being on I3C bus.

Signed-off-by: Daniel Leung <daniel.leung@intel.com>
This commit is contained in:
Daniel Leung 2022-06-02 15:58:20 -07:00 committed by Anas Nashif
commit 34ccd88c12
4 changed files with 164 additions and 24 deletions

View file

@ -8,6 +8,7 @@ menuconfig LPS22HH
default y
depends on DT_HAS_ST_LPS22HH_ENABLED
select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS22HH),i2c)
select I3C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS22HH),i3c)
select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LPS22HH),spi)
select HAS_STMEMSC
select USE_STDC_LPS22HH

View file

@ -155,10 +155,25 @@ static const struct sensor_driver_api lps22hh_driver_api = {
static int lps22hh_init_chip(const struct device *dev)
{
const struct lps22hh_config * const cfg = dev->config;
struct lps22hh_data *data = dev->data;
stmdev_ctx_t *ctx = (stmdev_ctx_t *)&cfg->ctx;
uint8_t chip_id;
int ret;
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
if (cfg->i3c.bus != NULL) {
/*
* Need to grab the pointer to the I3C device descriptor
* before we can talk to the sensor.
*/
data->i3c_dev = i3c_device_find(cfg->i3c.bus, &cfg->i3c.dev_id);
if (data->i3c_dev == NULL) {
LOG_ERR("Cannot find I3C device descriptor");
return -ENODEV;
}
}
#endif
if (lps22hh_device_id_get(ctx, &chip_id) < 0) {
LOG_ERR("%s: Not able to read dev id", dev->name);
return -EIO;
@ -171,6 +186,30 @@ static int lps22hh_init_chip(const struct device *dev)
LOG_DBG("%s: chip id 0x%x", dev->name, chip_id);
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
if (cfg->i3c.bus != NULL) {
/*
* Enabling I3C and disabling I2C are required
* for I3C IBI to work, or else the sensor will not
* send any IBIs.
*/
ret = lps22hh_i3c_interface_set(ctx, LPS22HH_I3C_ENABLE);
if (ret < 0) {
LOG_ERR("Cannot enable I3C interface");
return ret;
}
ret = lps22hh_i2c_interface_set(ctx, LPS22HH_I2C_DISABLE);
if (ret < 0) {
LOG_ERR("Cannot disable I2C interface");
return ret;
}
}
#else
ARG_UNUSED(data);
#endif
/* set sensor default odr */
LOG_DBG("%s: odr: %d", dev->name, cfg->odr);
ret = lps22hh_set_odr_raw(dev, cfg->odr);
@ -266,6 +305,33 @@ static int lps22hh_init(const struct device *dev)
(LPS22HH_CFG_IRQ(inst)), ()) \
}
/*
* Instantiation macros used when a device is on an I#C bus.
*/
#define LPS22HH_CONFIG_I3C(inst) \
{ \
.ctx = { \
.read_reg = \
(stmdev_read_ptr) stmemsc_i3c_read, \
.write_reg = \
(stmdev_write_ptr) stmemsc_i3c_write, \
.handle = \
(void *)&lps22hh_config_##inst.stmemsc_cfg, \
}, \
.stmemsc_cfg = { \
.i3c = &lps22hh_data_##inst.i3c_dev, \
}, \
.odr = DT_INST_PROP(inst, odr), \
.i3c.bus = DEVICE_DT_GET(DT_INST_BUS(inst)), \
.i3c.dev_id = I3C_DEVICE_ID_DT_INST(inst), \
}
#define LPS22HH_CONFIG_I3C_OR_I2C(inst) \
COND_CODE_0(DT_INST_PROP_BY_IDX(inst, reg, 1), \
(LPS22HH_CONFIG_I2C(inst)), \
(LPS22HH_CONFIG_I3C(inst)))
/*
* Main instantiation macro. Use of COND_CODE_1() selects the right
* bus-specific macro at preprocessor time.
@ -276,7 +342,9 @@ static int lps22hh_init(const struct device *dev)
static const struct lps22hh_config lps22hh_config_##inst = \
COND_CODE_1(DT_INST_ON_BUS(inst, spi), \
(LPS22HH_CONFIG_SPI(inst)), \
(LPS22HH_CONFIG_I2C(inst))); \
(COND_CODE_1(DT_INST_ON_BUS(inst, i3c), \
(LPS22HH_CONFIG_I3C_OR_I2C(inst)), \
(LPS22HH_CONFIG_I2C(inst))))); \
DEVICE_DT_INST_DEFINE(inst, lps22hh_init, NULL, &lps22hh_data_##inst, \
&lps22hh_config_##inst, POST_KERNEL, \
CONFIG_SENSOR_INIT_PRIORITY, &lps22hh_driver_api);

View file

@ -23,6 +23,10 @@
#include <zephyr/drivers/i2c.h>
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
#include <zephyr/drivers/i3c.h>
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c) */
struct lps22hh_config {
stmdev_ctx_t ctx;
union {
@ -31,12 +35,22 @@ struct lps22hh_config {
#endif
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
const struct spi_dt_spec spi;
#endif
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
struct i3c_device_desc **i3c;
#endif
} stmemsc_cfg;
uint8_t odr;
#ifdef CONFIG_LPS22HH_TRIGGER
struct gpio_dt_spec gpio_int;
#endif
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
struct {
const struct device *bus;
const struct i3c_device_id dev_id;
} i3c;
#endif
};
struct lps22hh_data {
@ -53,12 +67,16 @@ struct lps22hh_data {
#if defined(CONFIG_LPS22HH_TRIGGER_OWN_THREAD)
K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_LPS22HH_THREAD_STACK_SIZE);
struct k_thread thread;
struct k_sem gpio_sem;
struct k_sem intr_sem;
#elif defined(CONFIG_LPS22HH_TRIGGER_GLOBAL_THREAD)
struct k_work work;
#endif
#endif /* CONFIG_LPS22HH_TRIGGER */
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
struct i3c_device_desc *i3c_dev;
#endif
};
#ifdef CONFIG_LPS22HH_TRIGGER

View file

@ -80,6 +80,16 @@ static void lps22hh_handle_interrupt(const struct device *dev)
lps22hh->handler_drdy(dev, &drdy_trigger);
}
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
if (cfg->i3c.bus != NULL) {
/*
* I3C IBI does not rely on GPIO.
* So no need to enable GPIO pin for interrupt trigger.
*/
return;
}
#endif
ret = gpio_pin_interrupt_configure_dt(&cfg->gpio_int,
GPIO_INT_EDGE_TO_ACTIVE);
if (ret < 0) {
@ -87,6 +97,15 @@ static void lps22hh_handle_interrupt(const struct device *dev)
}
}
static void lps22hh_intr_callback(struct lps22hh_data *lps22hh)
{
#if defined(CONFIG_LPS22HH_TRIGGER_OWN_THREAD)
k_sem_give(&lps22hh->intr_sem);
#elif defined(CONFIG_LPS22HH_TRIGGER_GLOBAL_THREAD)
k_work_submit(&lps22hh->work);
#endif /* CONFIG_LPS22HH_TRIGGER_OWN_THREAD */
}
static void lps22hh_gpio_callback(const struct device *dev,
struct gpio_callback *cb, uint32_t pins)
{
@ -102,18 +121,14 @@ static void lps22hh_gpio_callback(const struct device *dev,
LOG_ERR("%s: Not able to configure pin_int", dev->name);
}
#if defined(CONFIG_LPS22HH_TRIGGER_OWN_THREAD)
k_sem_give(&lps22hh->gpio_sem);
#elif defined(CONFIG_LPS22HH_TRIGGER_GLOBAL_THREAD)
k_work_submit(&lps22hh->work);
#endif /* CONFIG_LPS22HH_TRIGGER_OWN_THREAD */
lps22hh_intr_callback(lps22hh);
}
#ifdef CONFIG_LPS22HH_TRIGGER_OWN_THREAD
static void lps22hh_thread(struct lps22hh_data *lps22hh)
{
while (1) {
k_sem_take(&lps22hh->gpio_sem, K_FOREVER);
k_sem_take(&lps22hh->intr_sem, K_FOREVER);
lps22hh_handle_interrupt(lps22hh->dev);
}
}
@ -129,6 +144,21 @@ static void lps22hh_work_cb(struct k_work *work)
}
#endif /* CONFIG_LPS22HH_TRIGGER_GLOBAL_THREAD */
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
static int lps22hh_ibi_cb(struct i3c_device_desc *target,
struct i3c_ibi_payload *payload)
{
const struct device *dev = target->dev;
struct lps22hh_data *lps22hh = dev->data;
ARG_UNUSED(payload);
lps22hh_intr_callback(lps22hh);
return 0;
}
#endif
int lps22hh_init_interrupt(const struct device *dev)
{
struct lps22hh_data *lps22hh = dev->data;
@ -137,7 +167,11 @@ int lps22hh_init_interrupt(const struct device *dev)
int ret;
/* setup data ready gpio interrupt */
if (!device_is_ready(cfg->gpio_int.port)) {
if (!device_is_ready(cfg->gpio_int.port)
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
&& (cfg->i3c.bus == NULL)
#endif
) {
if (cfg->gpio_int.port) {
LOG_ERR("%s: device %s is not ready", dev->name,
cfg->gpio_int.port->name);
@ -151,7 +185,7 @@ int lps22hh_init_interrupt(const struct device *dev)
lps22hh->dev = dev;
#if defined(CONFIG_LPS22HH_TRIGGER_OWN_THREAD)
k_sem_init(&lps22hh->gpio_sem, 0, K_SEM_MAX_LIMIT);
k_sem_init(&lps22hh->intr_sem, 0, K_SEM_MAX_LIMIT);
k_thread_create(&lps22hh->thread, lps22hh->thread_stack,
CONFIG_LPS22HH_THREAD_STACK_SIZE,
@ -162,23 +196,28 @@ int lps22hh_init_interrupt(const struct device *dev)
lps22hh->work.handler = lps22hh_work_cb;
#endif /* CONFIG_LPS22HH_TRIGGER_OWN_THREAD */
ret = gpio_pin_configure_dt(&cfg->gpio_int, GPIO_INPUT);
if (ret < 0) {
LOG_ERR("Could not configure gpio");
return ret;
}
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
if (cfg->i3c.bus == NULL)
#endif
{
ret = gpio_pin_configure_dt(&cfg->gpio_int, GPIO_INPUT);
if (ret < 0) {
LOG_ERR("Could not configure gpio");
return ret;
}
LOG_INF("%s: int on %s.%02u", dev->name, cfg->gpio_int.port->name,
cfg->gpio_int.pin);
LOG_INF("%s: int on %s.%02u", dev->name, cfg->gpio_int.port->name,
cfg->gpio_int.pin);
gpio_init_callback(&lps22hh->gpio_cb,
lps22hh_gpio_callback,
BIT(cfg->gpio_int.pin));
gpio_init_callback(&lps22hh->gpio_cb,
lps22hh_gpio_callback,
BIT(cfg->gpio_int.pin));
ret = gpio_add_callback(cfg->gpio_int.port, &lps22hh->gpio_cb);
if (ret < 0) {
LOG_ERR("Could not set gpio callback");
return ret;
ret = gpio_add_callback(cfg->gpio_int.port, &lps22hh->gpio_cb);
if (ret < 0) {
LOG_ERR("Could not set gpio callback");
return ret;
}
}
/* enable interrupt in pulse mode */
@ -186,6 +225,20 @@ int lps22hh_init_interrupt(const struct device *dev)
return -EIO;
}
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i3c)
if (cfg->i3c.bus != NULL) {
/* I3C IBI does not utilize GPIO interrupt. */
lps22hh->i3c_dev->ibi_cb = lps22hh_ibi_cb;
if (i3c_ibi_enable(lps22hh->i3c_dev) != 0) {
LOG_DBG("Could not enable I3C IBI");
return -EIO;
}
return 0;
}
#endif
return gpio_pin_interrupt_configure_dt(&cfg->gpio_int,
GPIO_INT_EDGE_TO_ACTIVE);
}