Put all the devicetree configuration data into a config structure in flash, which removes some ultra-long identifiers from the code and makes it more readable, and prepares for multiple instance support. Consistently use the interrupt signal datasheet name for all objects that are specific to that signal, including configuration structure tags and function names. Update the trigger idiom for setup/handle/process stages. Signed-off-by: Peter Bigot <peter.bigot@nordicsemi.no>
171 lines
3.9 KiB
C
171 lines
3.9 KiB
C
/*
|
|
* Copyright (c) 2016 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <device.h>
|
|
#include <drivers/i2c.h>
|
|
#include <sys/__assert.h>
|
|
#include <sys/util.h>
|
|
#include <kernel.h>
|
|
#include <drivers/sensor.h>
|
|
#include <logging/log.h>
|
|
#include "hts221.h"
|
|
|
|
LOG_MODULE_DECLARE(HTS221, CONFIG_SENSOR_LOG_LEVEL);
|
|
|
|
static inline void setup_drdy(struct device *dev,
|
|
bool enable)
|
|
{
|
|
struct hts221_data *data = dev->driver_data;
|
|
const struct hts221_config *cfg = dev->config->config_info;
|
|
unsigned int flags = enable
|
|
? GPIO_INT_EDGE_TO_ACTIVE
|
|
: GPIO_INT_DISABLE;
|
|
|
|
gpio_pin_interrupt_configure(data->drdy_dev, cfg->drdy_pin, flags);
|
|
}
|
|
|
|
static inline void handle_drdy(struct device *dev)
|
|
{
|
|
struct hts221_data *data = dev->driver_data;
|
|
|
|
setup_drdy(dev, false);
|
|
|
|
#if defined(CONFIG_HTS221_TRIGGER_OWN_THREAD)
|
|
k_sem_give(&data->drdy_sem);
|
|
#elif defined(CONFIG_HTS221_TRIGGER_GLOBAL_THREAD)
|
|
k_work_submit(&data->work);
|
|
#endif
|
|
}
|
|
|
|
static void process_drdy(struct device *dev)
|
|
{
|
|
struct hts221_data *data = dev->driver_data;
|
|
|
|
if (data->data_ready_handler != NULL) {
|
|
data->data_ready_handler(dev, &data->data_ready_trigger);
|
|
}
|
|
|
|
if (data->data_ready_handler != NULL) {
|
|
setup_drdy(dev, true);
|
|
}
|
|
}
|
|
|
|
int hts221_trigger_set(struct device *dev,
|
|
const struct sensor_trigger *trig,
|
|
sensor_trigger_handler_t handler)
|
|
{
|
|
struct hts221_data *data = dev->driver_data;
|
|
const struct hts221_config *cfg = dev->config->config_info;
|
|
|
|
__ASSERT_NO_MSG(trig->type == SENSOR_TRIG_DATA_READY);
|
|
|
|
setup_drdy(dev, false);
|
|
|
|
data->data_ready_handler = handler;
|
|
if (handler == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
data->data_ready_trigger = *trig;
|
|
|
|
setup_drdy(dev, true);
|
|
|
|
/* If DRDY is active we probably won't get the rising edge, so
|
|
* invoke the callback manually.
|
|
*/
|
|
if (gpio_pin_get(data->drdy_dev, cfg->drdy_pin) > 0) {
|
|
handle_drdy(dev);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void hts221_drdy_callback(struct device *dev,
|
|
struct gpio_callback *cb, u32_t pins)
|
|
{
|
|
struct hts221_data *data =
|
|
CONTAINER_OF(cb, struct hts221_data, drdy_cb);
|
|
|
|
ARG_UNUSED(pins);
|
|
|
|
handle_drdy(data->dev);
|
|
}
|
|
|
|
#ifdef CONFIG_HTS221_TRIGGER_OWN_THREAD
|
|
static void hts221_thread(int dev_ptr, int unused)
|
|
{
|
|
struct device *dev = INT_TO_POINTER(dev_ptr);
|
|
struct hts221_data *data = dev->driver_data;
|
|
|
|
ARG_UNUSED(unused);
|
|
|
|
while (1) {
|
|
k_sem_take(&data->drdy_sem, K_FOREVER);
|
|
process_drdy(dev);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_HTS221_TRIGGER_GLOBAL_THREAD
|
|
static void hts221_work_cb(struct k_work *work)
|
|
{
|
|
struct hts221_data *data =
|
|
CONTAINER_OF(work, struct hts221_data, work);
|
|
|
|
process_drdy(data->dev);
|
|
}
|
|
#endif
|
|
|
|
int hts221_init_interrupt(struct device *dev)
|
|
{
|
|
struct hts221_data *data = dev->driver_data;
|
|
const struct hts221_config *cfg = dev->config->config_info;
|
|
|
|
data->dev = dev;
|
|
|
|
/* setup data ready gpio interrupt */
|
|
data->drdy_dev = device_get_binding(cfg->drdy_controller);
|
|
if (data->drdy_dev == NULL) {
|
|
LOG_ERR("Cannot get pointer to %s device.",
|
|
cfg->drdy_controller);
|
|
return -EINVAL;
|
|
}
|
|
|
|
gpio_pin_configure(data->drdy_dev, cfg->drdy_pin,
|
|
GPIO_INPUT | cfg->drdy_flags);
|
|
|
|
gpio_init_callback(&data->drdy_cb, hts221_drdy_callback,
|
|
BIT(cfg->drdy_pin));
|
|
|
|
if (gpio_add_callback(data->drdy_dev, &data->drdy_cb) < 0) {
|
|
LOG_ERR("Could not set gpio callback.");
|
|
return -EIO;
|
|
}
|
|
|
|
/* enable data-ready interrupt */
|
|
if (i2c_reg_write_byte(data->i2c, cfg->i2c_addr,
|
|
HTS221_REG_CTRL3, HTS221_DRDY_EN) < 0) {
|
|
LOG_ERR("Could not enable data-ready interrupt.");
|
|
return -EIO;
|
|
}
|
|
|
|
#if defined(CONFIG_HTS221_TRIGGER_OWN_THREAD)
|
|
k_sem_init(&data->drdy_sem, 0, UINT_MAX);
|
|
|
|
k_thread_create(&data->thread, data->thread_stack,
|
|
CONFIG_HTS221_THREAD_STACK_SIZE,
|
|
(k_thread_entry_t)hts221_thread, dev,
|
|
0, NULL, K_PRIO_COOP(CONFIG_HTS221_THREAD_PRIORITY),
|
|
0, K_NO_WAIT);
|
|
#elif defined(CONFIG_HTS221_TRIGGER_GLOBAL_THREAD)
|
|
data->work.handler = hts221_work_cb;
|
|
#endif
|
|
|
|
setup_drdy(dev, true);
|
|
|
|
return 0;
|
|
}
|