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