zephyr/drivers/sensor/fdc2x1x/fdc2x1x_trigger.c
Gerard Marull-Paretas c2cf1ad203 pm: device: remove usage of local states
The device PM subsystem already holds the device state, so there is no
need to keep duplicates inside the device. The pm_device_state_get has
been refactored to just return the device state. Note that this is still
not safe, but the same applied to the previous implementation. This
problem will be addressed later.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
2021-08-04 08:23:01 -04:00

174 lines
4.0 KiB
C

/*
* Copyright (c) 2020 arithmetics.io
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT ti_fdc2x1x
#include <device.h>
#include <drivers/gpio.h>
#include <sys/util.h>
#include <kernel.h>
#include <drivers/sensor.h>
#include "fdc2x1x.h"
#include <stdio.h>
#include <logging/log.h>
LOG_MODULE_DECLARE(FDC2X1X, CONFIG_SENSOR_LOG_LEVEL);
static void fdc2x1x_thread_cb(const struct device *dev)
{
struct fdc2x1x_data *drv_data = dev->data;
uint16_t status;
#ifdef CONFIG_PM_DEVICE
enum pm_device_state state;
/* INTB asserts after exiting shutdown mode. Drop this interrupt */
(void)pm_device_state_get(dev, &state);
if (state == PM_DEVICE_STATE_OFF) {
return;
}
#endif
/* Clear the status */
if (fdc2x1x_get_status(dev, &status) < 0) {
LOG_ERR("Unable to get status.");
return;
}
k_mutex_lock(&drv_data->trigger_mutex, K_FOREVER);
if ((drv_data->drdy_handler != NULL) && FDC2X1X_STATUS_DRDY(status)) {
drv_data->drdy_handler(dev, &drv_data->drdy_trigger);
}
k_mutex_unlock(&drv_data->trigger_mutex);
}
static void fdc2x1x_gpio_callback(const struct device *dev,
struct gpio_callback *cb, uint32_t pins)
{
struct fdc2x1x_data *drv_data =
CONTAINER_OF(cb, struct fdc2x1x_data, gpio_cb);
#ifdef CONFIG_FDC2X1X_TRIGGER_OWN_THREAD
k_sem_give(&drv_data->gpio_sem);
#elif CONFIG_FDC2X1X_TRIGGER_GLOBAL_THREAD
k_work_submit(&drv_data->work);
#endif
}
#ifdef CONFIG_FDC2X1X_TRIGGER_OWN_THREAD
static void fdc2x1x_thread(struct fdc2x1x_data *drv_data)
{
while (true) {
k_sem_take(&drv_data->gpio_sem, K_FOREVER);
fdc2x1x_thread_cb(drv_data->dev);
}
}
#elif CONFIG_FDC2X1X_TRIGGER_GLOBAL_THREAD
static void fdc2x1x_work_cb(struct k_work *work)
{
struct fdc2x1x_data *drv_data =
CONTAINER_OF(work, struct fdc2x1x_data, work);
fdc2x1x_thread_cb(drv_data->dev);
}
#endif
int fdc2x1x_trigger_set(const struct device *dev,
const struct sensor_trigger *trig,
sensor_trigger_handler_t handler)
{
struct fdc2x1x_data *drv_data = dev->data;
const struct fdc2x1x_config *cfg = dev->config;
uint16_t status, int_mask, int_en;
int ret;
gpio_pin_interrupt_configure(cfg->intb_gpio, cfg->intb_pin,
GPIO_INT_DISABLE);
switch (trig->type) {
case SENSOR_TRIG_DATA_READY:
k_mutex_lock(&drv_data->trigger_mutex, K_FOREVER);
drv_data->drdy_handler = handler;
drv_data->drdy_trigger = *trig;
k_mutex_unlock(&drv_data->trigger_mutex);
int_mask = FDC2X1X_ERROR_CONFIG_DRDY_2INT_MSK;
break;
default:
LOG_ERR("Unsupported sensor trigger");
ret = -ENOTSUP;
goto out;
}
if (handler) {
int_en = int_mask;
drv_data->int_config |= int_mask;
} else {
int_en = 0U;
}
ret = fdc2x1x_reg_write_mask(dev,
FDC2X1X_ERROR_CONFIG, int_mask, int_en);
/* Clear INTB pin by reading STATUS register */
fdc2x1x_get_status(dev, &status);
out:
gpio_pin_interrupt_configure(cfg->intb_gpio, cfg->intb_pin,
GPIO_INT_EDGE_TO_ACTIVE);
return ret;
}
int fdc2x1x_init_interrupt(const struct device *dev)
{
struct fdc2x1x_data *drv_data = dev->data;
const struct fdc2x1x_config *cfg = dev->config;
int ret;
k_mutex_init(&drv_data->trigger_mutex);
if (!device_is_ready(cfg->intb_gpio)) {
LOG_ERR("%s: intb_gpio device not ready", cfg->intb_gpio->name);
return -ENODEV;
}
ret = fdc2x1x_set_interrupt_pin(dev, true);
if (ret) {
return ret;
}
gpio_pin_configure(cfg->intb_gpio, cfg->intb_pin,
GPIO_INPUT | cfg->intb_flags);
gpio_init_callback(&drv_data->gpio_cb,
fdc2x1x_gpio_callback,
BIT(cfg->intb_pin));
if (gpio_add_callback(cfg->intb_gpio, &drv_data->gpio_cb) < 0) {
LOG_ERR("Failed to set gpio callback!");
return -EIO;
}
drv_data->dev = dev;
#ifdef CONFIG_FDC2X1X_TRIGGER_OWN_THREAD
k_sem_init(&drv_data->gpio_sem, 0, UINT_MAX);
k_thread_create(&drv_data->thread, drv_data->thread_stack,
CONFIG_FDC2X1X_THREAD_STACK_SIZE,
(k_thread_entry_t)fdc2x1x_thread,
drv_data, 0, NULL,
K_PRIO_COOP(CONFIG_FDC2X1X_THREAD_PRIORITY),
0, K_NO_WAIT);
#elif CONFIG_FDC2X1X_TRIGGER_GLOBAL_THREAD
drv_data->work.handler = fdc2x1x_work_cb;
#endif
return 0;
}