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