1 /*
2 * Copyright (c) 2024 TDK Invensense
3 * Copyright (c) 2022 Esco Medical ApS
4 * Copyright (c) 2016 TDK Invensense
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/sensor.h>
11 #include <zephyr/sys/util.h>
12 #include "icm42670.h"
13 #include "icm42670_trigger.h"
14
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_DECLARE(ICM42670, CONFIG_SENSOR_LOG_LEVEL);
17
icm42670_gpio_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)18 static void icm42670_gpio_callback(const struct device *dev, struct gpio_callback *cb,
19 uint32_t pins)
20 {
21 ARG_UNUSED(dev);
22 ARG_UNUSED(pins);
23
24 struct icm42670_data *data = CONTAINER_OF(cb, struct icm42670_data, gpio_cb);
25
26 #if defined(CONFIG_ICM42670_TRIGGER_OWN_THREAD)
27 k_sem_give(&data->gpio_sem);
28 #elif defined(CONFIG_ICM42670_TRIGGER_GLOBAL_THREAD)
29 k_work_submit(&data->work);
30 #endif
31 }
32
icm42670_thread_cb(const struct device * dev)33 static void icm42670_thread_cb(const struct device *dev)
34 {
35 struct icm42670_data *data = dev->data;
36 const struct icm42670_config *cfg = dev->config;
37
38 icm42670_lock(dev);
39 gpio_pin_interrupt_configure_dt(&cfg->gpio_int, GPIO_INT_DISABLE);
40
41 if (data->data_ready_handler) {
42 data->data_ready_handler(dev, data->data_ready_trigger);
43 }
44
45 gpio_pin_interrupt_configure_dt(&cfg->gpio_int, GPIO_INT_EDGE_TO_ACTIVE);
46 icm42670_unlock(dev);
47 }
48
49 #if defined(CONFIG_ICM42670_TRIGGER_OWN_THREAD)
50
icm42670_thread(void * p1,void * p2,void * p3)51 static void icm42670_thread(void *p1, void *p2, void *p3)
52 {
53 ARG_UNUSED(p2);
54 ARG_UNUSED(p3);
55
56 struct icm42670_data *data = p1;
57
58 while (1) {
59 k_sem_take(&data->gpio_sem, K_FOREVER);
60 icm42670_thread_cb(data->dev);
61 }
62 }
63 #elif defined(CONFIG_ICM42670_TRIGGER_GLOBAL_THREAD)
64
icm42670_work_handler(struct k_work * work)65 static void icm42670_work_handler(struct k_work *work)
66 {
67 struct icm42670_data *data = CONTAINER_OF(work, struct icm42670_data, work);
68
69 icm42670_thread_cb(data->dev);
70 }
71
72 #endif
73
icm42670_trigger_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)74 int icm42670_trigger_set(const struct device *dev, const struct sensor_trigger *trig,
75 sensor_trigger_handler_t handler)
76 {
77 struct icm42670_data *data = dev->data;
78 const struct icm42670_config *cfg = dev->config;
79
80 if (!handler) {
81 return -EINVAL;
82 }
83
84 icm42670_lock(dev);
85 gpio_pin_interrupt_configure_dt(&cfg->gpio_int, GPIO_INT_DISABLE);
86
87 if (trig->type == SENSOR_TRIG_DATA_READY) {
88 data->data_ready_handler = handler;
89 data->data_ready_trigger = trig;
90 #ifdef CONFIG_TDK_APEX
91 } else if (trig->type == SENSOR_TRIG_MOTION) {
92 data->data_ready_handler = handler;
93 data->data_ready_trigger = trig;
94 #endif
95 } else {
96 return -ENOTSUP;
97 }
98
99 icm42670_unlock(dev);
100 gpio_pin_interrupt_configure_dt(&cfg->gpio_int, GPIO_INT_EDGE_TO_ACTIVE);
101
102 return 0;
103 }
104
icm42670_trigger_init(const struct device * dev)105 int icm42670_trigger_init(const struct device *dev)
106 {
107 struct icm42670_data *data = dev->data;
108 const struct icm42670_config *cfg = dev->config;
109 int res = 0;
110
111 if (!cfg->gpio_int.port) {
112 LOG_ERR("trigger enabled but no interrupt gpio supplied");
113 return -ENODEV;
114 }
115
116 if (!gpio_is_ready_dt(&cfg->gpio_int)) {
117 LOG_ERR("gpio_int gpio not ready");
118 return -ENODEV;
119 }
120
121 data->dev = dev;
122 gpio_pin_configure_dt(&cfg->gpio_int, GPIO_INPUT);
123 gpio_init_callback(&data->gpio_cb, icm42670_gpio_callback, BIT(cfg->gpio_int.pin));
124 res = gpio_add_callback(cfg->gpio_int.port, &data->gpio_cb);
125
126 if (res < 0) {
127 LOG_ERR("Failed to set gpio callback");
128 return res;
129 }
130
131 k_mutex_init(&data->mutex);
132
133 #if defined(CONFIG_ICM42670_TRIGGER_OWN_THREAD)
134 k_sem_init(&data->gpio_sem, 0, K_SEM_MAX_LIMIT);
135 k_thread_create(&data->thread, data->thread_stack, CONFIG_ICM42670_THREAD_STACK_SIZE,
136 icm42670_thread, data, NULL, NULL,
137 K_PRIO_COOP(CONFIG_ICM42670_THREAD_PRIORITY), 0, K_NO_WAIT);
138 #elif defined(CONFIG_ICM42670_TRIGGER_GLOBAL_THREAD)
139 data->work.handler = icm42670_work_handler;
140 #endif
141
142 return gpio_pin_interrupt_configure_dt(&cfg->gpio_int, GPIO_INT_EDGE_TO_INACTIVE);
143 }
144
icm42670_trigger_enable_interrupt(const struct device * dev)145 int icm42670_trigger_enable_interrupt(const struct device *dev)
146 {
147 struct icm42670_data *data = dev->data;
148 int err = 0;
149 inv_imu_int1_pin_config_t int1_pin_config;
150 inv_imu_interrupt_parameter_t config_int = {(inv_imu_interrupt_value)0};
151
152 /* Set interrupt config */
153 int1_pin_config.int_polarity = INT_CONFIG_INT1_POLARITY_HIGH;
154 int1_pin_config.int_mode = INT_CONFIG_INT1_MODE_PULSED;
155 int1_pin_config.int_drive = INT_CONFIG_INT1_DRIVE_CIRCUIT_PP;
156 err |= inv_imu_set_pin_config_int1(&data->driver, &int1_pin_config);
157
158 config_int.INV_FIFO_THS = INV_IMU_ENABLE;
159 err |= inv_imu_set_config_int1(&data->driver, &config_int);
160
161 return err;
162 }
163
icm42670_lock(const struct device * dev)164 void icm42670_lock(const struct device *dev)
165 {
166 struct icm42670_data *data = dev->data;
167
168 k_mutex_lock(&data->mutex, K_FOREVER);
169 }
170
icm42670_unlock(const struct device * dev)171 void icm42670_unlock(const struct device *dev)
172 {
173 struct icm42670_data *data = dev->data;
174
175 k_mutex_unlock(&data->mutex);
176 }
177