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