1 /*
2 * Copyright (c) 2023 Analog Devices Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT adi_adxl367
8
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/gpio.h>
11 #include <zephyr/sys/util.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/drivers/sensor.h>
14 #include "adxl367.h"
15
16 #include <zephyr/logging/log.h>
17 LOG_MODULE_DECLARE(ADXL367, CONFIG_SENSOR_LOG_LEVEL);
18
adxl367_thread_cb(const struct device * dev)19 static void adxl367_thread_cb(const struct device *dev)
20 {
21 const struct adxl367_dev_config *cfg = dev->config;
22 struct adxl367_data *drv_data = dev->data;
23 uint8_t status;
24 int ret;
25
26 /* Clear the status */
27 ret = drv_data->hw_tf->read_reg(dev, ADXL367_STATUS, &status);
28 if (ret != 0) {
29 return;
30 }
31
32 if (drv_data->th_handler != NULL) {
33 if (((FIELD_GET(ADXL367_STATUS_INACT, status)) != 0) ||
34 (FIELD_GET(ADXL367_STATUS_ACT, status)) != 0) {
35 drv_data->th_handler(dev, drv_data->th_trigger);
36 }
37 }
38
39 if ((drv_data->drdy_handler != NULL) &&
40 (FIELD_GET(ADXL367_STATUS_DATA_RDY, status) != 0)) {
41 drv_data->drdy_handler(dev, drv_data->drdy_trigger);
42 }
43
44 ret = gpio_pin_interrupt_configure_dt(&cfg->interrupt,
45 GPIO_INT_EDGE_TO_ACTIVE);
46 __ASSERT(ret == 0, "Interrupt configuration failed");
47 }
48
adxl367_gpio_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)49 static void adxl367_gpio_callback(const struct device *dev,
50 struct gpio_callback *cb, uint32_t pins)
51 {
52 struct adxl367_data *drv_data =
53 CONTAINER_OF(cb, struct adxl367_data, gpio_cb);
54 const struct adxl367_dev_config *cfg = drv_data->dev->config;
55
56 gpio_pin_interrupt_configure_dt(&cfg->interrupt, GPIO_INT_DISABLE);
57
58 #if defined(CONFIG_ADXL367_TRIGGER_OWN_THREAD)
59 k_sem_give(&drv_data->gpio_sem);
60 #elif defined(CONFIG_ADXL367_TRIGGER_GLOBAL_THREAD)
61 k_work_submit(&drv_data->work);
62 #endif
63 }
64
65 #if defined(CONFIG_ADXL367_TRIGGER_OWN_THREAD)
adxl367_thread(struct adxl367_data * drv_data)66 static void adxl367_thread(struct adxl367_data *drv_data)
67 {
68 while (true) {
69 k_sem_take(&drv_data->gpio_sem, K_FOREVER);
70 adxl367_thread_cb(drv_data->dev);
71 }
72 }
73
74 #elif defined(CONFIG_ADXL367_TRIGGER_GLOBAL_THREAD)
adxl367_work_cb(struct k_work * work)75 static void adxl367_work_cb(struct k_work *work)
76 {
77 struct adxl367_data *drv_data =
78 CONTAINER_OF(work, struct adxl367_data, work);
79
80 adxl367_thread_cb(drv_data->dev);
81 }
82 #endif
83
adxl367_trigger_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)84 int adxl367_trigger_set(const struct device *dev,
85 const struct sensor_trigger *trig,
86 sensor_trigger_handler_t handler)
87 {
88 const struct adxl367_dev_config *cfg = dev->config;
89 struct adxl367_data *drv_data = dev->data;
90 uint8_t int_mask, int_en, status;
91 int ret;
92
93 ret = gpio_pin_interrupt_configure_dt(&cfg->interrupt,
94 GPIO_INT_DISABLE);
95 if (ret != 0) {
96 return ret;
97 }
98
99 switch (trig->type) {
100 case SENSOR_TRIG_THRESHOLD:
101 drv_data->th_handler = handler;
102 drv_data->th_trigger = trig;
103 int_mask = ADXL367_ACT_INT | ADXL367_INACT_INT;
104 break;
105 case SENSOR_TRIG_DATA_READY:
106 drv_data->drdy_handler = handler;
107 drv_data->drdy_trigger = trig;
108 int_mask = ADXL367_DATA_RDY;
109 break;
110 default:
111 LOG_ERR("Unsupported sensor trigger");
112 return -ENOTSUP;
113 }
114
115 if (handler != NULL) {
116 int_en = int_mask;
117 } else {
118 int_en = 0U;
119 }
120
121 ret = drv_data->hw_tf->write_reg_mask(dev, ADXL367_INTMAP1_LOWER, int_mask, int_en);
122 if (ret != 0) {
123 return ret;
124 }
125
126 /* Clear status */
127 ret = drv_data->hw_tf->read_reg(dev, ADXL367_STATUS, &status);
128 if (ret != 0) {
129 return ret;
130 }
131
132 ret = gpio_pin_interrupt_configure_dt(&cfg->interrupt,
133 GPIO_INT_EDGE_TO_ACTIVE);
134 if (ret != 0) {
135 return ret;
136 }
137
138 return 0;
139 }
140
adxl367_init_interrupt(const struct device * dev)141 int adxl367_init_interrupt(const struct device *dev)
142 {
143 const struct adxl367_dev_config *cfg = dev->config;
144 struct adxl367_data *drv_data = dev->data;
145 int ret;
146
147 if (!gpio_is_ready_dt(&cfg->interrupt)) {
148 LOG_ERR("GPIO port %s not ready", cfg->interrupt.port->name);
149 return -EINVAL;
150 }
151
152 ret = gpio_pin_configure_dt(&cfg->interrupt, GPIO_INPUT);
153 if (ret != 0) {
154 return ret;
155 }
156
157 gpio_init_callback(&drv_data->gpio_cb,
158 adxl367_gpio_callback,
159 BIT(cfg->interrupt.pin));
160
161 ret = gpio_add_callback(cfg->interrupt.port, &drv_data->gpio_cb);
162 if (ret != 0) {
163 LOG_ERR("Failed to set gpio callback!");
164 return ret;
165 }
166
167 drv_data->dev = dev;
168
169 #if defined(CONFIG_ADXL367_TRIGGER_OWN_THREAD)
170 k_sem_init(&drv_data->gpio_sem, 0, K_SEM_MAX_LIMIT);
171
172 k_thread_create(&drv_data->thread, drv_data->thread_stack,
173 CONFIG_ADXL367_THREAD_STACK_SIZE,
174 (k_thread_entry_t)adxl367_thread, drv_data,
175 NULL, NULL, K_PRIO_COOP(CONFIG_ADXL367_THREAD_PRIORITY),
176 0, K_NO_WAIT);
177 #elif defined(CONFIG_ADXL367_TRIGGER_GLOBAL_THREAD)
178 drv_data->work.handler = adxl367_work_cb;
179 #endif
180
181 return 0;
182 }
183