1 /*
2 * Copyright (c) 2022 Intel Corporation
3 * Copyright (c) 2023 Google LLC
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/device.h>
8 #include <zephyr/drivers/sensor.h>
9 #include <zephyr/drivers/gpio.h>
10 #include <zephyr/logging/log.h>
11 #include <zephyr/sys/util.h>
12
13 #include "icm42688.h"
14 #include "icm42688_reg.h"
15 #include "icm42688_rtio.h"
16 #include "icm42688_spi.h"
17 #include "icm42688_trigger.h"
18
19 LOG_MODULE_DECLARE(ICM42688, CONFIG_SENSOR_LOG_LEVEL);
20
icm42688_gpio_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)21 static void icm42688_gpio_callback(const struct device *dev, struct gpio_callback *cb,
22 uint32_t pins)
23 {
24 struct icm42688_dev_data *data = CONTAINER_OF(cb, struct icm42688_dev_data, gpio_cb);
25
26 ARG_UNUSED(dev);
27 ARG_UNUSED(pins);
28
29 #if defined(CONFIG_ICM42688_TRIGGER_OWN_THREAD)
30 k_sem_give(&data->gpio_sem);
31 #elif defined(CONFIG_ICM42688_TRIGGER_GLOBAL_THREAD)
32 k_work_submit(&data->work);
33 #endif
34 if (IS_ENABLED(CONFIG_ICM42688_STREAM)) {
35 icm42688_fifo_event(data->dev);
36 }
37 }
38
39 #if defined(CONFIG_ICM42688_TRIGGER_OWN_THREAD) || defined(CONFIG_ICM42688_TRIGGER_GLOBAL_THREAD)
icm42688_thread_cb(const struct device * dev)40 static void icm42688_thread_cb(const struct device *dev)
41 {
42 struct icm42688_dev_data *data = dev->data;
43
44 icm42688_lock(dev);
45
46 if (data->data_ready_handler != NULL) {
47 data->data_ready_handler(dev, data->data_ready_trigger);
48 }
49
50 icm42688_unlock(dev);
51 }
52 #endif
53
54 #ifdef CONFIG_ICM42688_TRIGGER_OWN_THREAD
55
icm42688_thread(void * p1,void * p2,void * p3)56 static void icm42688_thread(void *p1, void *p2, void *p3)
57 {
58 ARG_UNUSED(p2);
59 ARG_UNUSED(p3);
60
61 struct icm42688_dev_data *data = p1;
62
63 while (1) {
64 k_sem_take(&data->gpio_sem, K_FOREVER);
65 icm42688_thread_cb(data->dev);
66 }
67 }
68
69 #elif defined(CONFIG_ICM42688_TRIGGER_GLOBAL_THREAD)
70
icm42688_work_handler(struct k_work * work)71 static void icm42688_work_handler(struct k_work *work)
72 {
73 struct icm42688_dev_data *data = CONTAINER_OF(work, struct icm42688_dev_data, work);
74
75 icm42688_thread_cb(data->dev);
76 }
77
78 #endif
79
icm42688_trigger_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)80 int icm42688_trigger_set(const struct device *dev, const struct sensor_trigger *trig,
81 sensor_trigger_handler_t handler)
82 {
83 struct icm42688_dev_data *data = dev->data;
84 const struct icm42688_dev_cfg *cfg = dev->config;
85 uint8_t status;
86 int res = 0;
87
88 if (trig == NULL || handler == NULL) {
89 return -EINVAL;
90 }
91
92 icm42688_lock(dev);
93 gpio_pin_interrupt_configure_dt(&cfg->gpio_int1, GPIO_INT_DISABLE);
94
95 switch (trig->type) {
96 case SENSOR_TRIG_DATA_READY:
97 case SENSOR_TRIG_FIFO_WATERMARK:
98 case SENSOR_TRIG_FIFO_FULL:
99 data->data_ready_handler = handler;
100 data->data_ready_trigger = trig;
101
102 res = icm42688_spi_read(&cfg->spi, REG_INT_STATUS, &status, 1);
103 break;
104 default:
105 res = -ENOTSUP;
106 break;
107 }
108
109 icm42688_unlock(dev);
110 gpio_pin_interrupt_configure_dt(&cfg->gpio_int1, GPIO_INT_EDGE_TO_ACTIVE);
111
112 return res;
113 }
114
icm42688_trigger_init(const struct device * dev)115 int icm42688_trigger_init(const struct device *dev)
116 {
117 struct icm42688_dev_data *data = dev->data;
118 const struct icm42688_dev_cfg *cfg = dev->config;
119 int res = 0;
120
121 if (!cfg->gpio_int1.port) {
122 LOG_ERR("trigger enabled but no interrupt gpio supplied");
123 return -ENODEV;
124 }
125
126 if (!gpio_is_ready_dt(&cfg->gpio_int1)) {
127 LOG_ERR("gpio_int1 not ready");
128 return -ENODEV;
129 }
130
131 data->dev = dev;
132 gpio_pin_configure_dt(&cfg->gpio_int1, GPIO_INPUT);
133 gpio_init_callback(&data->gpio_cb, icm42688_gpio_callback, BIT(cfg->gpio_int1.pin));
134 res = gpio_add_callback(cfg->gpio_int1.port, &data->gpio_cb);
135
136 if (res < 0) {
137 LOG_ERR("Failed to set gpio callback");
138 return res;
139 }
140
141 k_mutex_init(&data->mutex);
142 #if defined(CONFIG_ICM42688_TRIGGER_OWN_THREAD)
143 k_sem_init(&data->gpio_sem, 0, K_SEM_MAX_LIMIT);
144 k_thread_create(&data->thread, data->thread_stack, CONFIG_ICM42688_THREAD_STACK_SIZE,
145 icm42688_thread, data, NULL, NULL,
146 K_PRIO_COOP(CONFIG_ICM42688_THREAD_PRIORITY), 0, K_NO_WAIT);
147 #elif defined(CONFIG_ICM42688_TRIGGER_GLOBAL_THREAD)
148 data->work.handler = icm42688_work_handler;
149 #endif
150 return gpio_pin_interrupt_configure_dt(&cfg->gpio_int1, GPIO_INT_EDGE_TO_ACTIVE);
151 }
152
icm42688_trigger_enable_interrupt(const struct device * dev,struct icm42688_cfg * new_cfg)153 int icm42688_trigger_enable_interrupt(const struct device *dev, struct icm42688_cfg *new_cfg)
154 {
155 int res;
156 const struct icm42688_dev_cfg *cfg = dev->config;
157
158 /* pulse-mode (auto clearing), push-pull and active-high */
159 res = icm42688_spi_single_write(&cfg->spi, REG_INT_CONFIG,
160 BIT_INT1_DRIVE_CIRCUIT | BIT_INT1_POLARITY);
161 if (res != 0) {
162 return res;
163 }
164
165 /* Deassert async reset for proper INT pin operation, see datasheet 14.50 */
166 res = icm42688_spi_single_write(&cfg->spi, REG_INT_CONFIG1, 0);
167 if (res != 0) {
168 return res;
169 }
170
171 /* enable interrupts on INT1 pin */
172 uint8_t value = 0;
173
174 if (new_cfg->interrupt1_drdy) {
175 value |= FIELD_PREP(BIT_UI_DRDY_INT1_EN, 1);
176 }
177 if (new_cfg->interrupt1_fifo_ths) {
178 value |= FIELD_PREP(BIT_FIFO_THS_INT1_EN, 1);
179 }
180 if (new_cfg->interrupt1_fifo_full) {
181 value |= FIELD_PREP(BIT_FIFO_FULL_INT1_EN, 1);
182 }
183 return icm42688_spi_single_write(&cfg->spi, REG_INT_SOURCE0, value);
184 }
185
icm42688_lock(const struct device * dev)186 void icm42688_lock(const struct device *dev)
187 {
188 struct icm42688_dev_data *data = dev->data;
189
190 k_mutex_lock(&data->mutex, K_FOREVER);
191 }
192
icm42688_unlock(const struct device * dev)193 void icm42688_unlock(const struct device *dev)
194 {
195 struct icm42688_dev_data *data = dev->data;
196
197 k_mutex_unlock(&data->mutex);
198 }
199