drivers: sensors: add MC3419 accel sensor support
add basic sensor support for 3-axis accelerometer, currently this driver support data acquisition and motion detection features. Signed-off-by: Karthikeyan Krishnasamy <karthikeyan@linumiz.com>
This commit is contained in:
parent
18d6919092
commit
f5ed51c179
|
@ -89,6 +89,7 @@ add_subdirectory_ifdef(CONFIG_MAX31865 max31865)
|
|||
add_subdirectory_ifdef(CONFIG_MAX31875 max31875)
|
||||
add_subdirectory_ifdef(CONFIG_MAX44009 max44009)
|
||||
add_subdirectory_ifdef(CONFIG_MAX6675 max6675)
|
||||
add_subdirectory_ifdef(CONFIG_MC3419 mc3419)
|
||||
add_subdirectory_ifdef(CONFIG_MCP9600 mcp9600)
|
||||
add_subdirectory_ifdef(CONFIG_MCP970X mcp970x)
|
||||
add_subdirectory_ifdef(CONFIG_MCP9808 mcp9808)
|
||||
|
|
|
@ -145,6 +145,7 @@ source "drivers/sensor/max31865/Kconfig"
|
|||
source "drivers/sensor/max31875/Kconfig"
|
||||
source "drivers/sensor/max44009/Kconfig"
|
||||
source "drivers/sensor/max6675/Kconfig"
|
||||
source "drivers/sensor/mc3419/Kconfig"
|
||||
source "drivers/sensor/mchp_tach_xec/Kconfig"
|
||||
source "drivers/sensor/mcp9600/Kconfig"
|
||||
source "drivers/sensor/mcp970x/Kconfig"
|
||||
|
|
8
drivers/sensor/mc3419/CMakeLists.txt
Normal file
8
drivers/sensor/mc3419/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Copyright (c) 2023 Linumiz
|
||||
|
||||
zephyr_library()
|
||||
|
||||
zephyr_library_sources(mc3419.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_MC3419_TRIGGER mc3419_trigger.c)
|
48
drivers/sensor/mc3419/Kconfig
Normal file
48
drivers/sensor/mc3419/Kconfig
Normal file
|
@ -0,0 +1,48 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Copyright (c) 2023 Linumiz
|
||||
|
||||
menuconfig MC3419
|
||||
bool "MC3419 acclerometer driver"
|
||||
default y
|
||||
depends on DT_HAS_MEMSIC_MC3419_ENABLED
|
||||
select I2C if $(dt_compat_on_bus,$(DT_COMPAT_MEMSIC_MC3419),i2c)
|
||||
help
|
||||
Enable driver for MC3419 acclerometer.
|
||||
|
||||
if MC3419
|
||||
|
||||
config MC3419_TRIGGER
|
||||
bool "Trigger mode"
|
||||
|
||||
if MC3419_TRIGGER
|
||||
|
||||
config MC3419_TRIGGER_OWN_THREAD
|
||||
bool "Use own thread"
|
||||
help
|
||||
Enable trigger to run in own thread. By
|
||||
default it is global thread mode.
|
||||
|
||||
config MC3419_THREAD_PRIORITY
|
||||
int "Own thread priority"
|
||||
depends on MC3419_TRIGGER_OWN_THREAD
|
||||
default 10
|
||||
|
||||
config MC3419_THREAD_STACK_SIZE
|
||||
int "Own thread stask size"
|
||||
depends on MC3419_TRIGGER_OWN_THREAD
|
||||
default 1024
|
||||
|
||||
endif # MC3419_TRIGGER
|
||||
|
||||
config MC3419_DECIMATION_RATE
|
||||
int "Enable decimation rate"
|
||||
range 0 15
|
||||
default 15
|
||||
help
|
||||
This helps in producing slower interrupt. Internal Data
|
||||
Rate is divide by this decimation rate. If decimation rate
|
||||
is 0 then internal data rate is equal to output data rate,
|
||||
then it produce interrupt floods.
|
||||
|
||||
endif # MC3419
|
314
drivers/sensor/mc3419/mc3419.c
Normal file
314
drivers/sensor/mc3419/mc3419.c
Normal file
|
@ -0,0 +1,314 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Copyright (c) 2023 Linumiz
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT memsic_mc3419
|
||||
|
||||
#include <zephyr/init.h>
|
||||
#include <zephyr/drivers/sensor.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include "mc3419.h"
|
||||
|
||||
LOG_MODULE_REGISTER(MC3419, CONFIG_SENSOR_LOG_LEVEL);
|
||||
|
||||
static const uint16_t mc3419_accel_sense_map[] = {1, 2, 4, 8, 6};
|
||||
static struct mc3419_odr_map odr_map_table[] = {
|
||||
{25}, {50}, {62, 500}, {100},
|
||||
{125}, {250}, {500}, {1000}
|
||||
};
|
||||
|
||||
static int mc3419_get_odr_value(uint16_t freq, uint16_t m_freq)
|
||||
{
|
||||
for (int i = 0; i < ARRAY_SIZE(odr_map_table); i++) {
|
||||
if (odr_map_table[i].freq == freq &&
|
||||
odr_map_table[i].mfreq == m_freq) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int mc3419_set_op_mode(const struct mc3419_config *cfg,
|
||||
enum mc3419_op_mode mode)
|
||||
{
|
||||
return i2c_reg_write_byte_dt(&cfg->i2c, MC3419_REG_OP_MODE, mode);
|
||||
}
|
||||
|
||||
static int mc3419_sample_fetch(const struct device *dev,
|
||||
enum sensor_channel chan)
|
||||
{
|
||||
int ret = 0;
|
||||
const struct mc3419_config *cfg = dev->config;
|
||||
struct mc3419_driver_data *data = dev->data;
|
||||
|
||||
k_sem_take(&data->sem, K_FOREVER);
|
||||
ret = i2c_burst_read_dt(&cfg->i2c, MC3419_REG_XOUT_L,
|
||||
(uint8_t *)data->samples,
|
||||
MC3419_SAMPLE_READ_SIZE);
|
||||
k_sem_give(&data->sem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mc3419_to_sensor_value(double sensitivity, int16_t *raw_data,
|
||||
struct sensor_value *val)
|
||||
{
|
||||
double value = sys_le16_to_cpu(*raw_data);
|
||||
|
||||
value *= sensitivity * SENSOR_GRAVITY_DOUBLE / 1000;
|
||||
|
||||
return sensor_value_from_double(val, value);
|
||||
}
|
||||
|
||||
static int mc3419_channel_get(const struct device *dev,
|
||||
enum sensor_channel chan,
|
||||
struct sensor_value *val)
|
||||
{
|
||||
int ret = 0;
|
||||
struct mc3419_driver_data *data = dev->data;
|
||||
|
||||
k_sem_take(&data->sem, K_FOREVER);
|
||||
switch (chan) {
|
||||
case SENSOR_CHAN_ACCEL_X:
|
||||
ret = mc3419_to_sensor_value(data->sensitivity, &data->samples[0], val);
|
||||
break;
|
||||
case SENSOR_CHAN_ACCEL_Y:
|
||||
ret = mc3419_to_sensor_value(data->sensitivity, &data->samples[1], val);
|
||||
break;
|
||||
case SENSOR_CHAN_ACCEL_Z:
|
||||
ret = mc3419_to_sensor_value(data->sensitivity, &data->samples[2], val);
|
||||
break;
|
||||
case SENSOR_CHAN_ACCEL_XYZ:
|
||||
ret = mc3419_to_sensor_value(data->sensitivity, &data->samples[0], &val[0]);
|
||||
ret |= mc3419_to_sensor_value(data->sensitivity, &data->samples[1], &val[1]);
|
||||
ret |= mc3419_to_sensor_value(data->sensitivity, &data->samples[2], &val[2]);
|
||||
break;
|
||||
default:
|
||||
LOG_ERR("Unsupported channel");
|
||||
ret = -ENOTSUP;
|
||||
}
|
||||
|
||||
k_sem_give(&data->sem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mc3419_set_accel_range(const struct device *dev, uint8_t range)
|
||||
{
|
||||
int ret = 0;
|
||||
const struct mc3419_config *cfg = dev->config;
|
||||
struct mc3419_driver_data *data = dev->data;
|
||||
|
||||
if (range >= MC3419_ACCL_RANGE_END) {
|
||||
LOG_ERR("Accel resolution is out of range");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = i2c_reg_update_byte_dt(&cfg->i2c, MC3419_REG_RANGE_SELECT_CTRL,
|
||||
MC3419_RANGE_MASK, range << 4);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to set resolution (%d)", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
data->sensitivity = (double)(mc3419_accel_sense_map[range] *
|
||||
SENSOR_GRAIN_VALUE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mc3419_set_odr(const struct device *dev,
|
||||
const struct sensor_value *val)
|
||||
{
|
||||
int ret = 0;
|
||||
int data_rate = 0;
|
||||
const struct mc3419_config *cfg = dev->config;
|
||||
|
||||
ret = mc3419_get_odr_value(val->val1, val->val2);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to get odr value from odr map (%d)", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
data_rate = MC3419_BASE_ODR_VAL + ret;
|
||||
|
||||
ret = i2c_reg_write_byte_dt(&cfg->i2c, MC3419_REG_SAMPLE_RATE,
|
||||
data_rate);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to set ODR (%d)", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
LOG_DBG("Set ODR Rate to 0x%x", data_rate);
|
||||
ret = i2c_reg_write_byte_dt(&cfg->i2c, MC3419_REG_SAMPLE_RATE_2,
|
||||
CONFIG_MC3419_DECIMATION_RATE);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to set decimation rate (%d)", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_MC3419_TRIGGER)
|
||||
static int mc3419_set_anymotion_threshold(const struct device *dev,
|
||||
const struct sensor_value *val)
|
||||
{
|
||||
int ret = 0;
|
||||
const struct mc3419_config *cfg = dev->config;
|
||||
uint8_t buf[3] = {0};
|
||||
|
||||
if (val->val1 > MC3419_ANY_MOTION_THRESH_MAX) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
buf[0] = MC3419_REG_ANY_MOTION_THRES;
|
||||
sys_put_le16((uint16_t)val->val1, &buf[1]);
|
||||
|
||||
ret = i2c_write_dt(&cfg->i2c, buf, sizeof(buf));
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to set anymotion threshold (%d)", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mc3419_trigger_set(const struct device *dev,
|
||||
const struct sensor_trigger *trig,
|
||||
sensor_trigger_handler_t handler)
|
||||
{
|
||||
int ret = 0;
|
||||
const struct mc3419_config *cfg = dev->config;
|
||||
struct mc3419_driver_data *data = dev->data;
|
||||
|
||||
k_sem_take(&data->sem, K_FOREVER);
|
||||
ret = mc3419_set_op_mode(cfg, MC3419_MODE_STANDBY);
|
||||
if (ret < 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = mc3419_configure_trigger(dev, trig, handler);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to set trigger (%d)", ret);
|
||||
}
|
||||
|
||||
exit:
|
||||
mc3419_set_op_mode(cfg, MC3419_MODE_WAKE);
|
||||
|
||||
k_sem_give(&data->sem);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int mc3419_attr_set(const struct device *dev,
|
||||
enum sensor_channel chan,
|
||||
enum sensor_attribute attr,
|
||||
const struct sensor_value *val)
|
||||
{
|
||||
int ret = 0;
|
||||
struct mc3419_driver_data *data = dev->data;
|
||||
|
||||
if (chan != SENSOR_CHAN_ACCEL_X &&
|
||||
chan != SENSOR_CHAN_ACCEL_Y &&
|
||||
chan != SENSOR_CHAN_ACCEL_Z &&
|
||||
chan != SENSOR_CHAN_ACCEL_XYZ) {
|
||||
LOG_ERR("Not supported on this channel.");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
k_sem_take(&data->sem, K_FOREVER);
|
||||
ret = mc3419_set_op_mode(dev->config, MC3419_MODE_STANDBY);
|
||||
if (ret < 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
switch (attr) {
|
||||
case SENSOR_ATTR_FULL_SCALE:
|
||||
ret = mc3419_set_accel_range(dev, val->val1);
|
||||
break;
|
||||
case SENSOR_ATTR_SAMPLING_FREQUENCY:
|
||||
ret = mc3419_set_odr(dev, val);
|
||||
break;
|
||||
#if defined(CONFIG_MC3419_TRIGGER)
|
||||
case SENSOR_ATTR_SLOPE_TH:
|
||||
ret = mc3419_set_anymotion_threshold(dev, val);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
LOG_ERR("ACCEL attribute is not supported");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
exit:
|
||||
mc3419_set_op_mode(dev->config, MC3419_MODE_WAKE);
|
||||
|
||||
k_sem_give(&data->sem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mc3419_init(const struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct mc3419_driver_data *data = dev->data;
|
||||
const struct mc3419_config *cfg = dev->config;
|
||||
|
||||
if (!(i2c_is_ready_dt(&cfg->i2c))) {
|
||||
LOG_ERR("Bus device is not ready");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
k_sem_init(&data->sem, 1, 1);
|
||||
|
||||
#if defined(CONFIG_MC3419_TRIGGER)
|
||||
ret = mc3419_trigger_init(dev);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Could not initialize interrupts");
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Leave the sensor in default power on state, will be
|
||||
* enabled by configure attr or setting trigger.
|
||||
*/
|
||||
|
||||
LOG_INF("MC3419 Initialized");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct sensor_driver_api mc3419_api = {
|
||||
.attr_set = mc3419_attr_set,
|
||||
#if defined(CONFIG_MC3419_TRIGGER)
|
||||
.trigger_set = mc3419_trigger_set,
|
||||
#endif
|
||||
.sample_fetch = mc3419_sample_fetch,
|
||||
.channel_get = mc3419_channel_get,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_MC3419_TRIGGER)
|
||||
#define MC3419_CFG_IRQ(idx) \
|
||||
.int_gpio = GPIO_DT_SPEC_INST_GET_OR(idx, int_gpios, { 0 }), \
|
||||
.int_cfg = DT_INST_PROP(idx, int_pin2),
|
||||
#else
|
||||
#define MC3419_CFG_IRQ(idx)
|
||||
#endif
|
||||
|
||||
#define MC3419_DEFINE(idx) \
|
||||
static const struct mc3419_config mc3419_config_##idx = { \
|
||||
.i2c = I2C_DT_SPEC_INST_GET(idx), \
|
||||
MC3419_CFG_IRQ(idx) \
|
||||
}; \
|
||||
static struct mc3419_driver_data mc3419_data_##idx; \
|
||||
SENSOR_DEVICE_DT_INST_DEFINE(idx, \
|
||||
mc3419_init, NULL, \
|
||||
&mc3419_data_##idx, \
|
||||
&mc3419_config_##idx, \
|
||||
POST_KERNEL, \
|
||||
CONFIG_SENSOR_INIT_PRIORITY, \
|
||||
&mc3419_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(MC3419_DEFINE)
|
102
drivers/sensor/mc3419/mc3419.h
Normal file
102
drivers/sensor/mc3419/mc3419.h
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Copyright (c) 2023 Linumiz
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_DRIVERS_SENSOR_MC3419_H_
|
||||
#define ZEPHYR_DRIVERS_SENSOR_MC3419_H_
|
||||
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
#include <zephyr/drivers/i2c.h>
|
||||
#include <zephyr/drivers/sensor.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
/* Registers */
|
||||
#define MC3419_REG_INT_CTRL 0x06
|
||||
#define MC3419_REG_OP_MODE 0x07
|
||||
#define MC3419_REG_SAMPLE_RATE 0x08
|
||||
#define MC3419_REG_MOTION_CTRL 0x09
|
||||
#define MC3419_REG_XOUT_L 0x0D
|
||||
#define MC3419_REG_YOUT_L 0x0F
|
||||
#define MC3419_REG_ZOUT_L 0x11
|
||||
#define MC3419_REG_STATUS 0x13
|
||||
#define MC3419_REG_INT_STATUS 0x14
|
||||
#define MC3419_REG_RANGE_SELECT_CTRL 0x20
|
||||
#define MC3419_REG_SAMPLE_RATE_2 0x30
|
||||
#define MC3419_REG_COMM_CTRL 0x31
|
||||
#define MC3419_REG_ANY_MOTION_THRES 0x43
|
||||
|
||||
#define MC3419_RANGE_MASK GENMASK(6, 4)
|
||||
#define MC3419_DATA_READY_MASK BIT(7)
|
||||
#define MC3419_ANY_MOTION_MASK BIT(2)
|
||||
#define MC3419_INT_CLEAR 0x00
|
||||
#define MC3419_INT_ROUTE 0x10
|
||||
|
||||
#define MC3419_ANY_MOTION_THRESH_MAX 0x7FFF
|
||||
#define MC3419_SAMPLE_SIZE 3
|
||||
#define MC3419_SAMPLE_READ_SIZE (MC3419_SAMPLE_SIZE * (sizeof(int16_t)))
|
||||
|
||||
#define SENSOR_GRAIN_VALUE (61LL / 1000.0)
|
||||
#define SENSOR_GRAVITY_DOUBLE (SENSOR_G / 1000000.0)
|
||||
#define MC3419_BASE_ODR_VAL 0x10
|
||||
|
||||
#define MC3419_TRIG_DATA_READY 0
|
||||
#define MC3419_TRIG_ANY_MOTION 1
|
||||
#define MC3419_TRIG_SIZE 2
|
||||
|
||||
enum mc3419_op_mode {
|
||||
MC3419_MODE_STANDBY = 0x00,
|
||||
MC3419_MODE_WAKE = 0x01
|
||||
};
|
||||
|
||||
struct mc3419_odr_map {
|
||||
int16_t freq;
|
||||
int16_t mfreq;
|
||||
};
|
||||
|
||||
enum mc3419_accl_range {
|
||||
MC3419_ACCl_RANGE_2G,
|
||||
MC3419_ACCl_RANGE_4G,
|
||||
MC3419_ACCl_RANGE_8G,
|
||||
MC3419_ACCl_RANGE_16G,
|
||||
MC3419_ACCl_RANGE_12G,
|
||||
MC3419_ACCL_RANGE_END
|
||||
};
|
||||
|
||||
struct mc3419_config {
|
||||
struct i2c_dt_spec i2c;
|
||||
#if defined(CONFIG_MC3419_TRIGGER)
|
||||
struct gpio_dt_spec int_gpio;
|
||||
bool int_cfg;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct mc3419_driver_data {
|
||||
double sensitivity;
|
||||
struct k_sem sem;
|
||||
int16_t samples[MC3419_SAMPLE_SIZE];
|
||||
#if defined(CONFIG_MC3419_TRIGGER)
|
||||
const struct device *gpio_dev;
|
||||
struct gpio_callback gpio_cb;
|
||||
sensor_trigger_handler_t handler[MC3419_TRIG_SIZE];
|
||||
const struct sensor_trigger *trigger[MC3419_TRIG_SIZE];
|
||||
#if defined(CONFIG_MC3419_TRIGGER_OWN_THREAD)
|
||||
K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_MC3419_THREAD_STACK_SIZE);
|
||||
struct k_thread thread;
|
||||
struct k_sem trig_sem;
|
||||
#else
|
||||
struct k_work work;
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(CONFIG_MC3419_TRIGGER)
|
||||
int mc3419_trigger_init(const struct device *dev);
|
||||
int mc3419_configure_trigger(const struct device *dev,
|
||||
const struct sensor_trigger *trig,
|
||||
sensor_trigger_handler_t handler);
|
||||
#endif
|
||||
|
||||
#endif
|
178
drivers/sensor/mc3419/mc3419_trigger.c
Normal file
178
drivers/sensor/mc3419/mc3419_trigger.c
Normal file
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Copyright (c) 2023 Linumiz
|
||||
*/
|
||||
|
||||
#include "mc3419.h"
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_DECLARE(MC3419, CONFIG_SENSOR_LOG_LEVEL);
|
||||
|
||||
static void mc3419_gpio_callback(const struct device *dev,
|
||||
struct gpio_callback *cb,
|
||||
uint32_t pin_mask)
|
||||
{
|
||||
struct mc3419_driver_data *data = CONTAINER_OF(cb,
|
||||
struct mc3419_driver_data, gpio_cb);
|
||||
|
||||
const struct mc3419_config *cfg = data->gpio_dev->config;
|
||||
|
||||
if ((pin_mask & BIT(cfg->int_gpio.pin)) == 0U) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_MC3419_TRIGGER_OWN_THREAD)
|
||||
k_sem_give(&data->trig_sem);
|
||||
#else
|
||||
k_work_submit(&data->work);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void mc3419_process_int(const struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
const struct mc3419_config *cfg = dev->config;
|
||||
const struct mc3419_driver_data *data = dev->data;
|
||||
uint8_t int_source = 0;
|
||||
|
||||
ret = i2c_reg_read_byte_dt(&cfg->i2c, MC3419_REG_INT_STATUS, &int_source);
|
||||
if (ret < 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (int_source & MC3419_DATA_READY_MASK) {
|
||||
if (data->handler[MC3419_TRIG_DATA_READY]) {
|
||||
data->handler[MC3419_TRIG_DATA_READY](dev,
|
||||
data->trigger[MC3419_TRIG_DATA_READY]);
|
||||
}
|
||||
}
|
||||
|
||||
if (int_source & MC3419_ANY_MOTION_MASK) {
|
||||
if (data->handler[MC3419_TRIG_ANY_MOTION]) {
|
||||
data->handler[MC3419_TRIG_ANY_MOTION](dev,
|
||||
data->trigger[MC3419_TRIG_ANY_MOTION]);
|
||||
}
|
||||
}
|
||||
exit:
|
||||
ret = i2c_reg_write_byte_dt(&cfg->i2c, MC3419_REG_INT_STATUS,
|
||||
MC3419_INT_CLEAR);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to clear interrupt (%d)", ret);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_MC3419_TRIGGER_OWN_THREAD)
|
||||
static void mc3419_thread(struct mc3419_driver_data *data)
|
||||
{
|
||||
while (1) {
|
||||
k_sem_take(&data->trig_sem, K_FOREVER);
|
||||
mc3419_process_int(data->gpio_dev);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void mc3419_work_cb(struct k_work *work)
|
||||
{
|
||||
struct mc3419_driver_data *data = CONTAINER_OF(work,
|
||||
struct mc3419_driver_data, work);
|
||||
|
||||
mc3419_process_int(data->gpio_dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
int mc3419_configure_trigger(const struct device *dev,
|
||||
const struct sensor_trigger *trig,
|
||||
sensor_trigger_handler_t handler)
|
||||
{
|
||||
int ret = 0;
|
||||
uint8_t buf = 0;
|
||||
const struct mc3419_config *cfg = dev->config;
|
||||
struct mc3419_driver_data *data = dev->data;
|
||||
|
||||
if (!(trig->type & SENSOR_TRIG_DATA_READY) &&
|
||||
!(trig->type & SENSOR_TRIG_MOTION)) {
|
||||
LOG_ERR("Unsupported sensor trigger");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (trig->type & SENSOR_TRIG_DATA_READY) {
|
||||
data->handler[MC3419_TRIG_DATA_READY] = handler;
|
||||
data->trigger[MC3419_TRIG_DATA_READY] = trig;
|
||||
buf |= MC3419_DATA_READY_MASK;
|
||||
}
|
||||
|
||||
if (trig->type & SENSOR_TRIG_MOTION) {
|
||||
uint8_t int_mask = MC3419_ANY_MOTION_MASK;
|
||||
|
||||
buf |= MC3419_ANY_MOTION_MASK;
|
||||
data->handler[MC3419_TRIG_ANY_MOTION] = handler;
|
||||
data->trigger[MC3419_TRIG_ANY_MOTION] = trig;
|
||||
|
||||
ret = i2c_reg_update_byte_dt(&cfg->i2c, MC3419_REG_MOTION_CTRL,
|
||||
int_mask, handler ? int_mask : 0);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to configure motion interrupt (%d)", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = i2c_reg_update_byte_dt(&cfg->i2c, MC3419_REG_INT_CTRL,
|
||||
buf, buf);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to configure interrupt (%d)", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpio_pin_interrupt_configure_dt(&cfg->int_gpio, GPIO_INT_EDGE_FALLING);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mc3419_trigger_init(const struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct mc3419_driver_data *data = dev->data;
|
||||
const struct mc3419_config *cfg = dev->config;
|
||||
|
||||
if (!gpio_is_ready_dt(&cfg->int_gpio)) {
|
||||
LOG_ERR("GPIO port %s not ready", cfg->int_gpio.port->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = gpio_pin_configure_dt(&cfg->int_gpio, GPIO_INPUT);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to configure interrupt gpio");
|
||||
return ret;
|
||||
}
|
||||
|
||||
data->gpio_dev = dev;
|
||||
|
||||
#if defined(CONFIG_MC3419_TRIGGER_OWN_THREAD)
|
||||
k_sem_init(&data->trig_sem, 0, 1);
|
||||
k_thread_create(&data->thread, data->thread_stack,
|
||||
CONFIG_MC3419_THREAD_STACK_SIZE,
|
||||
(k_thread_entry_t)mc3419_thread, data, NULL,
|
||||
NULL, K_PRIO_COOP(CONFIG_MC3419_THREAD_PRIORITY), 0,
|
||||
K_NO_WAIT);
|
||||
#else
|
||||
k_work_init(&data->work, mc3419_work_cb);
|
||||
#endif
|
||||
gpio_init_callback(&data->gpio_cb, mc3419_gpio_callback,
|
||||
BIT(cfg->int_gpio.pin));
|
||||
ret = gpio_add_callback(cfg->int_gpio.port, &data->gpio_cb);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to set int callback");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (cfg->int_cfg) {
|
||||
ret = i2c_reg_write_byte_dt(&cfg->i2c, MC3419_REG_COMM_CTRL,
|
||||
MC3419_INT_ROUTE);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Failed to route the interrupt to INT2 pin (%d)", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
23
dts/bindings/sensor/memsic,mc3419.yaml
Normal file
23
dts/bindings/sensor/memsic,mc3419.yaml
Normal file
|
@ -0,0 +1,23 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
# Copyright (c) 2023 Linumiz
|
||||
|
||||
description: MC3419 3-axis accel sensor
|
||||
|
||||
compatible: "memsic,mc3419"
|
||||
|
||||
include: [sensor-device.yaml, i2c-device.yaml]
|
||||
|
||||
properties:
|
||||
int-gpios:
|
||||
type: phandle-array
|
||||
description: |
|
||||
This property specifies the connection for INT, this pin
|
||||
defaults to active low when sample produce interrupt.
|
||||
|
||||
int-pin2:
|
||||
type: boolean
|
||||
description: |
|
||||
This property is used for interrupt routing.The sensor
|
||||
has two interrupt pins.By default the interrupt are routed
|
||||
to interrupt pin 1, by enabled this property interrupt are
|
||||
routed to interrupt pin 2.
|
Loading…
Reference in a new issue