Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2021, Nordic Semiconductor ASA
3 : : *
4 : : * SPDX-License-Identifier: Apache-2.0
5 : : */
6 : : #define DT_DRV_COMPAT nordic_nrf_gpio
7 : :
8 : : #include <nrfx_gpiote.h>
9 : : #include <string.h>
10 : : #include <drivers/gpio.h>
11 : : #include <dt-bindings/gpio/nordic-nrf-gpio.h>
12 : : #include "gpio_utils.h"
13 : :
14 : : struct gpio_nrfx_data {
15 : : /* gpio_driver_data needs to be first */
16 : : struct gpio_driver_data common;
17 : : sys_slist_t callbacks;
18 : : };
19 : :
20 : : struct gpio_nrfx_cfg {
21 : : /* gpio_driver_config needs to be first */
22 : : struct gpio_driver_config common;
23 : : NRF_GPIO_Type *port;
24 : : uint32_t edge_sense;
25 : : uint8_t port_num;
26 : : };
27 : :
28 : 0 : static inline struct gpio_nrfx_data *get_port_data(const struct device *port)
29 : : {
30 : 0 : return port->data;
31 : : }
32 : :
33 : 0 : static inline const struct gpio_nrfx_cfg *get_port_cfg(const struct device *port)
34 : : {
35 : 0 : return port->config;
36 : : }
37 : :
38 : 0 : static int get_drive(gpio_flags_t flags, nrf_gpio_pin_drive_t *drive)
39 : : {
40 : 0 : int err = 0;
41 : :
42 [ # # # # : 0 : switch (flags & (NRF_GPIO_DS_LOW_MASK | NRF_GPIO_DS_HIGH_MASK |
# # # #
# ]
43 : : GPIO_OPEN_DRAIN)) {
44 : 0 : case NRF_GPIO_DS_DFLT:
45 : 0 : *drive = NRF_GPIO_PIN_S0S1;
46 : 0 : break;
47 : 0 : case NRF_GPIO_DS_DFLT_LOW | NRF_GPIO_DS_ALT_HIGH:
48 : 0 : *drive = NRF_GPIO_PIN_S0H1;
49 : 0 : break;
50 : 0 : case NRF_GPIO_DS_DFLT_LOW | GPIO_OPEN_DRAIN:
51 : 0 : *drive = NRF_GPIO_PIN_S0D1;
52 : 0 : break;
53 : :
54 : 0 : case NRF_GPIO_DS_ALT_LOW | NRF_GPIO_DS_DFLT_HIGH:
55 : 0 : *drive = NRF_GPIO_PIN_H0S1;
56 : 0 : break;
57 : 0 : case NRF_GPIO_DS_ALT:
58 : 0 : *drive = NRF_GPIO_PIN_H0H1;
59 : 0 : break;
60 : 0 : case NRF_GPIO_DS_ALT_LOW | GPIO_OPEN_DRAIN:
61 : 0 : *drive = NRF_GPIO_PIN_H0D1;
62 : 0 : break;
63 : :
64 : 0 : case NRF_GPIO_DS_DFLT_HIGH | GPIO_OPEN_SOURCE:
65 : 0 : *drive = NRF_GPIO_PIN_D0S1;
66 : 0 : break;
67 : 0 : case NRF_GPIO_DS_ALT_HIGH | GPIO_OPEN_SOURCE:
68 : 0 : *drive = NRF_GPIO_PIN_D0H1;
69 : 0 : break;
70 : :
71 : 0 : default:
72 : 0 : err = -EINVAL;
73 : 0 : break;
74 : : }
75 : :
76 : 0 : return err;
77 : : }
78 : :
79 : 0 : static nrf_gpio_pin_pull_t get_pull(gpio_flags_t flags)
80 : : {
81 [ # # ]: 0 : if (flags & GPIO_PULL_UP) {
82 : 0 : return NRF_GPIO_PIN_PULLUP;
83 [ # # ]: 0 : } else if (flags & GPIO_PULL_DOWN) {
84 : 0 : return NRF_GPIO_PIN_PULLDOWN;
85 : : }
86 : :
87 : 0 : return NRF_GPIO_PIN_NOPULL;
88 : : }
89 : :
90 : 0 : static int pin_uninit(nrfx_gpiote_pin_t pin)
91 : : {
92 : : uint8_t ch;
93 : : nrfx_err_t err;
94 : : bool free_ch;
95 : :
96 : 0 : err = nrfx_gpiote_channel_get(pin, &ch);
97 : 0 : free_ch = (err == NRFX_SUCCESS);
98 : :
99 : 0 : err = nrfx_gpiote_pin_uninit(pin);
100 [ # # ]: 0 : if (err != NRFX_SUCCESS) {
101 : 0 : return -EIO;
102 : : }
103 : :
104 [ # # ]: 0 : if (free_ch) {
105 : 0 : err = nrfx_gpiote_channel_free(ch);
106 : : }
107 : :
108 [ # # ]: 0 : return (err != NRFX_SUCCESS) ? -EIO : 0;
109 : : }
110 : :
111 : 0 : static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin,
112 : : gpio_flags_t flags)
113 : : {
114 : : nrfx_err_t err;
115 : : uint8_t ch;
116 : : bool free_ch;
117 : 0 : const struct gpio_nrfx_cfg *cfg = get_port_cfg(port);
118 : 0 : nrfx_gpiote_pin_t abs_pin = NRF_GPIO_PIN_MAP(cfg->port_num, pin);
119 : :
120 [ # # ]: 0 : if (flags == GPIO_DISCONNECTED) {
121 : 0 : return pin_uninit(abs_pin);
122 : : }
123 : :
124 : 0 : nrfx_gpiote_trigger_config_t trigger_config = {
125 : : .trigger = NRFX_GPIOTE_TRIGGER_NONE
126 : : };
127 : :
128 : 0 : err = nrfx_gpiote_channel_get(pin, &ch);
129 : 0 : free_ch = (err == NRFX_SUCCESS);
130 : :
131 : : /* Remove previously configured trigger when pin is reconfigured. */
132 : 0 : err = nrfx_gpiote_input_configure(abs_pin, NULL, &trigger_config, NULL);
133 [ # # ]: 0 : if (err != NRFX_SUCCESS) {
134 : 0 : return -EINVAL;
135 : : }
136 : :
137 [ # # ]: 0 : if (free_ch) {
138 : 0 : err = nrfx_gpiote_channel_free(ch);
139 : : }
140 : :
141 [ # # ]: 0 : if (flags & GPIO_OUTPUT) {
142 : : nrf_gpio_pin_drive_t drive;
143 : 0 : int rv = get_drive(flags, &drive);
144 : :
145 [ # # ]: 0 : if (rv != 0) {
146 : 0 : return rv;
147 : : }
148 : :
149 : 0 : nrfx_gpiote_output_config_t output_config = {
150 : : .drive = drive,
151 : 0 : .input_connect = (flags & GPIO_INPUT) ?
152 : 0 : NRF_GPIO_PIN_INPUT_CONNECT :
153 : : NRF_GPIO_PIN_INPUT_DISCONNECT,
154 : 0 : .pull = get_pull(flags)
155 : : };
156 : :
157 : :
158 [ # # ]: 0 : if (flags & GPIO_OUTPUT_INIT_HIGH) {
159 : 0 : nrf_gpio_port_out_set(cfg->port, BIT(pin));
160 [ # # ]: 0 : } else if (flags & GPIO_OUTPUT_INIT_LOW) {
161 : 0 : nrf_gpio_port_out_clear(cfg->port, BIT(pin));
162 : : }
163 : :
164 : 0 : err = nrfx_gpiote_output_configure(abs_pin, &output_config, NULL);
165 [ # # ]: 0 : return (err != NRFX_SUCCESS) ? -EINVAL : 0;
166 : : }
167 : :
168 : 0 : nrfx_gpiote_input_config_t input_config = {
169 : 0 : .pull = get_pull(flags)
170 : : };
171 : :
172 : 0 : err = nrfx_gpiote_input_configure(abs_pin, &input_config, NULL, NULL);
173 : :
174 [ # # ]: 0 : return (err != NRFX_SUCCESS) ? -EINVAL : 0;
175 : : }
176 : :
177 : 0 : static int gpio_nrfx_port_get_raw(const struct device *port,
178 : : gpio_port_value_t *value)
179 : : {
180 : 0 : NRF_GPIO_Type *reg = get_port_cfg(port)->port;
181 : :
182 : 0 : *value = nrf_gpio_port_in_read(reg);
183 : :
184 : 0 : return 0;
185 : : }
186 : :
187 : 0 : static int gpio_nrfx_port_set_masked_raw(const struct device *port,
188 : : gpio_port_pins_t mask,
189 : : gpio_port_value_t value)
190 : : {
191 : 0 : NRF_GPIO_Type *reg = get_port_cfg(port)->port;
192 : : uint32_t value_tmp;
193 : :
194 : 0 : value_tmp = nrf_gpio_port_out_read(reg) & ~mask;
195 : 0 : nrf_gpio_port_out_write(reg, value_tmp | (mask & value));
196 : :
197 : 0 : return 0;
198 : : }
199 : :
200 : 0 : static int gpio_nrfx_port_set_bits_raw(const struct device *port,
201 : : gpio_port_pins_t mask)
202 : : {
203 : 0 : NRF_GPIO_Type *reg = get_port_cfg(port)->port;
204 : :
205 : 0 : nrf_gpio_port_out_set(reg, mask);
206 : :
207 : 0 : return 0;
208 : : }
209 : :
210 : 0 : static int gpio_nrfx_port_clear_bits_raw(const struct device *port,
211 : : gpio_port_pins_t mask)
212 : : {
213 : 0 : NRF_GPIO_Type *reg = get_port_cfg(port)->port;
214 : :
215 : 0 : nrf_gpio_port_out_clear(reg, mask);
216 : :
217 : 0 : return 0;
218 : : }
219 : :
220 : 0 : static int gpio_nrfx_port_toggle_bits(const struct device *port,
221 : : gpio_port_pins_t mask)
222 : : {
223 : 0 : NRF_GPIO_Type *reg = get_port_cfg(port)->port;
224 : : uint32_t value;
225 : :
226 : 0 : value = nrf_gpio_port_out_read(reg);
227 : 0 : nrf_gpio_port_out_write(reg, value ^ mask);
228 : :
229 : 0 : return 0;
230 : : }
231 : :
232 : 0 : static nrfx_gpiote_trigger_t get_trigger(enum gpio_int_mode mode,
233 : : enum gpio_int_trig trig)
234 : : {
235 [ # # ]: 0 : if (mode == GPIO_INT_MODE_LEVEL) {
236 [ # # ]: 0 : return trig == GPIO_INT_TRIG_LOW ? NRFX_GPIOTE_TRIGGER_LOW :
237 : : NRFX_GPIOTE_TRIGGER_HIGH;
238 : : }
239 : :
240 [ # # # # ]: 0 : return trig == GPIO_INT_TRIG_BOTH ? NRFX_GPIOTE_TRIGGER_TOGGLE :
241 : : trig == GPIO_INT_TRIG_LOW ? NRFX_GPIOTE_TRIGGER_HITOLO :
242 : : NRFX_GPIOTE_TRIGGER_LOTOHI;
243 : : }
244 : :
245 : 0 : static int gpio_nrfx_pin_interrupt_configure(const struct device *port,
246 : : gpio_pin_t pin,
247 : : enum gpio_int_mode mode,
248 : : enum gpio_int_trig trig)
249 : : {
250 : 0 : uint32_t abs_pin = NRF_GPIO_PIN_MAP(get_port_cfg(port)->port_num, pin);
251 : : nrfx_err_t err;
252 : :
253 [ # # ]: 0 : if (mode == GPIO_INT_MODE_DISABLED) {
254 : 0 : nrfx_gpiote_trigger_disable(abs_pin);
255 : :
256 : 0 : return 0;
257 : : }
258 : :
259 : 0 : nrfx_gpiote_trigger_config_t trigger_config = {
260 : 0 : .trigger = get_trigger(mode, trig),
261 : : };
262 : :
263 : : /* If edge mode is to be used and pin is not configured to use sense for
264 : : * edge use IN event.
265 : : */
266 [ # # # # ]: 0 : if (!(BIT(pin) & get_port_cfg(port)->edge_sense) &&
267 [ # # ]: 0 : (mode == GPIO_INT_MODE_EDGE) &&
268 : 0 : (nrf_gpio_pin_dir_get(abs_pin) == NRF_GPIO_PIN_DIR_INPUT)) {
269 : : uint8_t ch;
270 : :
271 : 0 : err = nrfx_gpiote_channel_get(abs_pin, &ch);
272 [ # # ]: 0 : if (err == NRFX_ERROR_INVALID_PARAM) {
273 : 0 : err = nrfx_gpiote_channel_alloc(&ch);
274 [ # # ]: 0 : if (err != NRFX_SUCCESS) {
275 : 0 : return -ENOMEM;
276 : : }
277 : : }
278 : :
279 : 0 : trigger_config.p_in_channel = &ch;
280 : : }
281 : :
282 : 0 : err = nrfx_gpiote_input_configure(abs_pin, NULL, &trigger_config, NULL);
283 [ # # ]: 0 : if (err != NRFX_SUCCESS) {
284 : 0 : return -EIO;
285 : : }
286 : :
287 : 0 : nrfx_gpiote_trigger_enable(abs_pin, true);
288 : :
289 : 0 : return 0;
290 : : }
291 : :
292 : 0 : static int gpio_nrfx_manage_callback(const struct device *port,
293 : : struct gpio_callback *callback,
294 : : bool set)
295 : : {
296 : 0 : return gpio_manage_callback(&get_port_data(port)->callbacks,
297 : : callback, set);
298 : : }
299 : :
300 : : /* Get port device from port id. */
301 : 0 : static const struct device *get_dev(uint32_t port_id)
302 : : {
303 : 0 : const struct device *dev = NULL;
304 : :
305 : : #define GPIO_NRF_GET_DEV(i) \
306 : : else if (DT_INST_PROP(i, port) == port_id) { \
307 : : dev = DEVICE_DT_INST_GET(i); \
308 : : }
309 : :
310 : : if (0) {
311 : : } /* Followed by else if from FOREACH macro. Done to avoid return statement in macro. */
312 [ # # # # ]: 0 : DT_INST_FOREACH_STATUS_OKAY(GPIO_NRF_GET_DEV)
313 : : #undef GPIO_NRF_GET_DEV
314 : :
315 : 0 : return dev;
316 : : }
317 : :
318 : 0 : static void nrfx_gpio_handler(nrfx_gpiote_pin_t abs_pin,
319 : : nrfx_gpiote_trigger_t trigger,
320 : : void *context)
321 : : {
322 : 0 : uint32_t pin = abs_pin;
323 : 0 : uint32_t port_id = nrf_gpio_pin_port_number_extract(&pin);
324 : 0 : const struct device *port = get_dev(port_id);
325 : :
326 : : /* If given port is handled directly by nrfx driver it might not be enabled in DT. */
327 [ # # ]: 0 : if (port == NULL) {
328 : 0 : return;
329 : : }
330 : :
331 : 0 : struct gpio_nrfx_data *data = get_port_data(port);
332 : 0 : sys_slist_t *list = &data->callbacks;
333 : :
334 : 0 : gpio_fire_callbacks(list, port, BIT(pin));
335 : : }
336 : :
337 : : #define GPIOTE_NODE DT_INST(0, nordic_nrf_gpiote)
338 : :
339 : 2 : static int gpio_nrfx_init(const struct device *port)
340 : : {
341 : : nrfx_err_t err;
342 : :
343 [ + + ]: 2 : if (nrfx_gpiote_is_init()) {
344 : 1 : return 0;
345 : : }
346 : :
347 : 1 : err = nrfx_gpiote_init(0/*not used*/);
348 [ - + ]: 1 : if (err != NRFX_SUCCESS) {
349 : 0 : return -EIO;
350 : : }
351 : :
352 : 1 : nrfx_gpiote_global_callback_set(nrfx_gpio_handler, NULL);
353 : :
354 : 1 : IRQ_CONNECT(DT_IRQN(GPIOTE_NODE), DT_IRQ(GPIOTE_NODE, priority),
355 : : nrfx_isr, nrfx_gpiote_irq_handler, 0);
356 : :
357 : 1 : return 0;
358 : : }
359 : :
360 : : static const struct gpio_driver_api gpio_nrfx_drv_api_funcs = {
361 : : .pin_configure = gpio_nrfx_pin_configure,
362 : : .port_get_raw = gpio_nrfx_port_get_raw,
363 : : .port_set_masked_raw = gpio_nrfx_port_set_masked_raw,
364 : : .port_set_bits_raw = gpio_nrfx_port_set_bits_raw,
365 : : .port_clear_bits_raw = gpio_nrfx_port_clear_bits_raw,
366 : : .port_toggle_bits = gpio_nrfx_port_toggle_bits,
367 : : .pin_interrupt_configure = gpio_nrfx_pin_interrupt_configure,
368 : : .manage_callback = gpio_nrfx_manage_callback,
369 : : };
370 : :
371 : : /* Device instantiation is done with node labels because 'port_num' is
372 : : * the peripheral number by SoC numbering. We therefore cannot use
373 : : * DT_INST APIs here without wider changes.
374 : : */
375 : :
376 : : #define GPIO_NRF_DEVICE(id) \
377 : : static const struct gpio_nrfx_cfg gpio_nrfx_p##id##_cfg = { \
378 : : .common = { \
379 : : .port_pin_mask = \
380 : : GPIO_PORT_PIN_MASK_FROM_DT_INST(id), \
381 : : }, \
382 : : .port = (NRF_GPIO_Type *)DT_INST_REG_ADDR(id), \
383 : : .port_num = DT_INST_PROP(id, port), \
384 : : .edge_sense = DT_INST_PROP_OR(id, sense_edge_mask, 0) \
385 : : }; \
386 : : \
387 : : static struct gpio_nrfx_data gpio_nrfx_p##id##_data; \
388 : : \
389 : : DEVICE_DT_INST_DEFINE(id, gpio_nrfx_init, \
390 : : NULL, \
391 : : &gpio_nrfx_p##id##_data, \
392 : : &gpio_nrfx_p##id##_cfg, \
393 : : PRE_KERNEL_1, \
394 : : CONFIG_GPIO_INIT_PRIORITY, \
395 : : &gpio_nrfx_drv_api_funcs);
396 : :
397 : : DT_INST_FOREACH_STATUS_OKAY(GPIO_NRF_DEVICE)
|