1 /*
2 * Copyright (c) 2018, Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/drivers/sensor.h>
8 #include <zephyr/pm/device.h>
9 #include <zephyr/drivers/pinctrl.h>
10 #include <soc.h>
11
12 #include <nrfx_qdec.h>
13 #include <hal/nrf_gpio.h>
14
15 #include <zephyr/logging/log.h>
16 #include <zephyr/irq.h>
17 LOG_MODULE_REGISTER(qdec_nrfx, CONFIG_SENSOR_LOG_LEVEL);
18
19 #define DT_DRV_COMPAT nordic_nrf_qdec
20
21 #define FULL_ANGLE 360
22
23 /* limit range to avoid overflow when converting steps to degrees */
24 #define ACC_MAX (INT_MAX / FULL_ANGLE)
25 #define ACC_MIN (INT_MIN / FULL_ANGLE)
26
27
28 struct qdec_nrfx_data {
29 int32_t fetched_acc;
30 int32_t acc;
31 bool overflow;
32 sensor_trigger_handler_t data_ready_handler;
33 const struct sensor_trigger *data_ready_trigger;
34 };
35
36 struct qdec_nrfx_config {
37 nrfx_qdec_t qdec;
38 nrfx_qdec_config_t config;
39 void (*irq_connect)(void);
40 const struct pinctrl_dev_config *pcfg;
41 uint32_t enable_pin;
42 int32_t steps;
43 };
44
accumulate(struct qdec_nrfx_data * data,int32_t acc)45 static void accumulate(struct qdec_nrfx_data *data, int32_t acc)
46 {
47 unsigned int key = irq_lock();
48
49 bool overflow = ((acc > 0) && (ACC_MAX - acc < data->acc)) ||
50 ((acc < 0) && (ACC_MIN - acc > data->acc));
51
52 if (!overflow) {
53 data->acc += acc;
54 } else {
55 data->overflow = true;
56 }
57
58 irq_unlock(key);
59 }
60
qdec_nrfx_sample_fetch(const struct device * dev,enum sensor_channel chan)61 static int qdec_nrfx_sample_fetch(const struct device *dev,
62 enum sensor_channel chan)
63 {
64 const struct qdec_nrfx_config *config = dev->config;
65 struct qdec_nrfx_data *data = dev->data;
66 int32_t acc;
67 uint32_t accdbl;
68
69 if ((chan != SENSOR_CHAN_ALL) && (chan != SENSOR_CHAN_ROTATION)) {
70 return -ENOTSUP;
71 }
72
73 nrfx_qdec_accumulators_read(&config->qdec, &acc, &accdbl);
74
75 accumulate(data, acc);
76
77 unsigned int key = irq_lock();
78
79 data->fetched_acc = data->acc;
80 data->acc = 0;
81
82 irq_unlock(key);
83
84 if (data->overflow) {
85 data->overflow = false;
86 return -EOVERFLOW;
87 }
88
89 return 0;
90 }
91
qdec_nrfx_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)92 static int qdec_nrfx_channel_get(const struct device *dev,
93 enum sensor_channel chan,
94 struct sensor_value *val)
95 {
96 struct qdec_nrfx_data *data = dev->data;
97 const struct qdec_nrfx_config *config = dev->config;
98 unsigned int key;
99 int32_t acc;
100
101 if (chan != SENSOR_CHAN_ROTATION) {
102 return -ENOTSUP;
103 }
104
105 key = irq_lock();
106 acc = data->fetched_acc;
107 irq_unlock(key);
108
109 val->val1 = (acc * FULL_ANGLE) / config->steps;
110 val->val2 = (acc * FULL_ANGLE) - (val->val1 * config->steps);
111 if (val->val2 != 0) {
112 val->val2 *= 1000000;
113 val->val2 /= config->steps;
114 }
115
116 return 0;
117 }
118
qdec_nrfx_trigger_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)119 static int qdec_nrfx_trigger_set(const struct device *dev,
120 const struct sensor_trigger *trig,
121 sensor_trigger_handler_t handler)
122 {
123 struct qdec_nrfx_data *data = dev->data;
124 unsigned int key;
125
126 if (trig->type != SENSOR_TRIG_DATA_READY) {
127 return -ENOTSUP;
128 }
129
130 if ((trig->chan != SENSOR_CHAN_ALL) &&
131 (trig->chan != SENSOR_CHAN_ROTATION)) {
132 return -ENOTSUP;
133 }
134
135 key = irq_lock();
136 data->data_ready_handler = handler;
137 data->data_ready_trigger = trig;
138 irq_unlock(key);
139
140 return 0;
141 }
142
qdec_nrfx_event_handler(nrfx_qdec_event_t event,void * p_context)143 static void qdec_nrfx_event_handler(nrfx_qdec_event_t event, void *p_context)
144 {
145 const struct device *dev = p_context;
146 struct qdec_nrfx_data *dev_data = dev->data;
147
148 sensor_trigger_handler_t handler;
149 const struct sensor_trigger *trig;
150 unsigned int key;
151
152 switch (event.type) {
153 case NRF_QDEC_EVENT_REPORTRDY:
154 accumulate(dev_data, event.data.report.acc);
155
156 key = irq_lock();
157 handler = dev_data->data_ready_handler;
158 trig = dev_data->data_ready_trigger;
159 irq_unlock(key);
160
161 if (handler) {
162 handler(dev, trig);
163 }
164 break;
165
166 case NRF_QDEC_EVENT_ACCOF:
167 dev_data->overflow = true;
168 break;
169
170 default:
171 LOG_ERR("unhandled event (0x%x)", event.type);
172 break;
173 }
174 }
175
qdec_nrfx_gpio_ctrl(const struct device * dev,bool enable)176 static void qdec_nrfx_gpio_ctrl(const struct device *dev, bool enable)
177 {
178 const struct qdec_nrfx_config *config = dev->config;
179
180 if (config->enable_pin != NRF_QDEC_PIN_NOT_CONNECTED) {
181
182 uint32_t val = (enable)?(0):(1);
183
184 nrf_gpio_pin_write(config->enable_pin, val);
185 nrf_gpio_cfg_output(config->enable_pin);
186 }
187 }
188
189 static DEVICE_API(sensor, qdec_nrfx_driver_api) = {
190 .sample_fetch = qdec_nrfx_sample_fetch,
191 .channel_get = qdec_nrfx_channel_get,
192 .trigger_set = qdec_nrfx_trigger_set,
193 };
194
qdec_pm_suspend(const struct device * dev)195 static void qdec_pm_suspend(const struct device *dev)
196 {
197 const struct qdec_nrfx_config *config = dev->config;
198
199 nrfx_qdec_disable(&config->qdec);
200 qdec_nrfx_gpio_ctrl(dev, false);
201
202 (void)pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP);
203 }
204
qdec_pm_resume(const struct device * dev)205 static void qdec_pm_resume(const struct device *dev)
206 {
207 const struct qdec_nrfx_config *config = dev->config;
208
209 (void)pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
210 qdec_nrfx_gpio_ctrl(dev, true);
211 nrfx_qdec_enable(&config->qdec);
212 }
213
qdec_nrfx_pm_action(const struct device * dev,enum pm_device_action action)214 static int qdec_nrfx_pm_action(const struct device *dev, enum pm_device_action action)
215 {
216 switch (action) {
217 case PM_DEVICE_ACTION_RESUME:
218 qdec_pm_resume(dev);
219 break;
220
221 case PM_DEVICE_ACTION_SUSPEND:
222 if (IS_ENABLED(CONFIG_PM_DEVICE)) {
223 qdec_pm_suspend(dev);
224 }
225 break;
226 default:
227 return -ENOTSUP;
228 break;
229 }
230
231 return 0;
232 }
233
qdec_nrfx_init(const struct device * dev)234 static int qdec_nrfx_init(const struct device *dev)
235 {
236 const struct qdec_nrfx_config *config = dev->config;
237 nrfx_err_t nerr;
238
239 config->irq_connect();
240
241 nerr = nrfx_qdec_init(&config->qdec, &config->config, qdec_nrfx_event_handler, (void *)dev);
242 if (nerr != NRFX_SUCCESS) {
243 return (nerr == NRFX_ERROR_INVALID_STATE) ? -EBUSY : -EFAULT;
244 }
245
246 /* End up in suspend state. */
247 qdec_nrfx_gpio_ctrl(dev, false);
248 if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) {
249 (void)pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP);
250 }
251
252 return pm_device_driver_init(dev, qdec_nrfx_pm_action);
253 }
254
255 #define QDEC(idx) DT_NODELABEL(qdec##idx)
256 #define QDEC_PROP(idx, prop) DT_PROP(QDEC(idx), prop)
257
258 #define SENSOR_NRFX_QDEC_DEVICE(idx) \
259 NRF_DT_CHECK_NODE_HAS_PINCTRL_SLEEP(QDEC(idx)); \
260 BUILD_ASSERT(QDEC_PROP(idx, steps) > 0, \
261 "Wrong QDEC"#idx" steps setting in dts. Only positive number valid"); \
262 BUILD_ASSERT(QDEC_PROP(idx, steps) <= 2048, \
263 "Wrong QDEC"#idx" steps setting in dts. Overflow possible"); \
264 static void irq_connect##idx(void) \
265 { \
266 IRQ_CONNECT(DT_IRQN(QDEC(idx)), DT_IRQ(QDEC(idx), priority), \
267 nrfx_isr, nrfx_qdec_##idx##_irq_handler, 0); \
268 } \
269 static struct qdec_nrfx_data qdec_##idx##_data; \
270 PINCTRL_DT_DEFINE(QDEC(idx)); \
271 static struct qdec_nrfx_config qdec_##idx##_config = { \
272 .qdec = NRFX_QDEC_INSTANCE(idx), \
273 .config = { \
274 .reportper = NRF_QDEC_REPORTPER_40, \
275 .sampleper = NRF_QDEC_SAMPLEPER_2048US, \
276 .skip_gpio_cfg = true, \
277 .skip_psel_cfg = true, \
278 .ledpre = QDEC_PROP(idx, led_pre), \
279 .ledpol = NRF_QDEC_LEPOL_ACTIVE_HIGH, \
280 .reportper_inten = true, \
281 }, \
282 .irq_connect = irq_connect##idx, \
283 .pcfg = PINCTRL_DT_DEV_CONFIG_GET(QDEC(idx)), \
284 .enable_pin = DT_PROP_OR(QDEC(idx), enable_pin, NRF_QDEC_PIN_NOT_CONNECTED), \
285 .steps = QDEC_PROP(idx, steps), \
286 }; \
287 PM_DEVICE_DT_DEFINE(QDEC(idx), qdec_nrfx_pm_action, PM_DEVICE_ISR_SAFE); \
288 SENSOR_DEVICE_DT_DEFINE(QDEC(idx), \
289 qdec_nrfx_init, \
290 PM_DEVICE_DT_GET(QDEC(idx)), \
291 &qdec_##idx##_data, \
292 &qdec_##idx##_config, \
293 POST_KERNEL, \
294 CONFIG_SENSOR_INIT_PRIORITY, \
295 &qdec_nrfx_driver_api)
296
297 #ifdef CONFIG_HAS_HW_NRF_QDEC0
298 SENSOR_NRFX_QDEC_DEVICE(0);
299 #endif
300
301 #ifdef CONFIG_HAS_HW_NRF_QDEC1
302 SENSOR_NRFX_QDEC_DEVICE(1);
303 #endif
304
305 #ifdef CONFIG_HAS_HW_NRF_QDEC20
306 SENSOR_NRFX_QDEC_DEVICE(20);
307 #endif
308
309 #ifdef CONFIG_HAS_HW_NRF_QDEC21
310 SENSOR_NRFX_QDEC_DEVICE(21);
311 #endif
312
313 #ifdef CONFIG_HAS_HW_NRF_QDEC130
314 SENSOR_NRFX_QDEC_DEVICE(130);
315 #endif
316
317 #ifdef CONFIG_HAS_HW_NRF_QDEC131
318 SENSOR_NRFX_QDEC_DEVICE(131);
319 #endif
320