Skip to content

Commit

Permalink
sensor: lps22hh: extend to support being on I3C bus
Browse files Browse the repository at this point in the history
This extends the lps22hh driver to support being on I3C bus.

Signed-off-by: Daniel Leung <[email protected]>
  • Loading branch information
dcpleung authored and nashif committed Sep 9, 2022
1 parent 6034714 commit 34ccd88
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 24 deletions.
1 change: 1 addition & 0 deletions drivers/sensor/lps22hh/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
70 changes: 69 additions & 1 deletion drivers/sensor/lps22hh/lps22hh.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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.
Expand All @@ -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);
Expand Down
20 changes: 19 additions & 1 deletion drivers/sensor/lps22hh/lps22hh.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand All @@ -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
Expand Down
97 changes: 75 additions & 22 deletions drivers/sensor/lps22hh/lps22hh_trigger.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,32 @@ 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) {
LOG_ERR("%s: Not able to configure pin_int", dev->name);
}
}

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)
{
Expand All @@ -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);
}
}
Expand All @@ -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;
Expand All @@ -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);
Expand All @@ -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,
Expand All @@ -162,30 +196,49 @@ 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 */
if (lps22hh_int_notification_set(ctx, LPS22HH_INT_PULSED) < 0) {
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);
}

0 comments on commit 34ccd88

Please sign in to comment.