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