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