Skip to content

Commit eeef86d

Browse files
committed
drivers: gpio: nrfx: Add support for GPIOTE0 on cpurad
Add support for special GPIOTE0 instance on nrf54h20/cpurad. This instance requires special handling because: - there is no support for PORT event (level interrupts) - TE channels are fixed to the pin Signed-off-by: Krzysztof Chruściński <krzysztof.chruscinski@nordicsemi.no>
1 parent 815b385 commit eeef86d

File tree

1 file changed

+101
-27
lines changed

1 file changed

+101
-27
lines changed

drivers/gpio/gpio_nrfx.c

Lines changed: 101 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,26 @@
2020
#include <nrf/gpd.h>
2121
#endif
2222

23+
#define GPIOTE_PHANDLE(id) DT_INST_PHANDLE(id, gpiote_instance)
24+
#define GPIOTE_PROP(idx, prop) DT_PROP(GPIOTE(idx), prop)
25+
26+
#define IS_NO_PORT_INSTANCE(id) DT_PROP_OR(GPIOTE_PHANDLE(id), no_port_event, 0) ||
27+
#define IS_FIXED_CH_INSTANCE(id) DT_PROP_OR(GPIOTE_PHANDLE(id), fixed_channels_supported, 0) ||
28+
29+
#if DT_INST_FOREACH_STATUS_OKAY(IS_NO_PORT_INSTANCE) 0
30+
#define GPIOTE_NO_PORT_EVT_SUPPORT 1
31+
#endif
32+
33+
#if DT_INST_FOREACH_STATUS_OKAY(IS_FIXED_CH_INSTANCE) 0
34+
#define GPIOTE_FIXED_CH_SUPPORT 1
35+
#endif
36+
37+
#if defined(GPIOTE_NO_PORT_EVT_SUPPORT) || defined(GPIOTE_FIXED_CH_SUPPORT)
38+
#define GPIOTE_FEATURE_FLAG 1
39+
#define GPIOTE_FLAG_NO_PORT_EVT BIT(0)
40+
#define GPIOTE_FLAG_FIXED_CHAN BIT(1)
41+
#endif
42+
2343
struct gpio_nrfx_data {
2444
/* gpio_driver_data needs to be first */
2545
struct gpio_driver_data common;
@@ -33,6 +53,9 @@ struct gpio_nrfx_cfg {
3353
uint32_t edge_sense;
3454
uint8_t port_num;
3555
nrfx_gpiote_t gpiote;
56+
#if defined(GPIOTE_FEATURE_FLAG)
57+
uint32_t flags;
58+
#endif
3659
#ifdef CONFIG_SOC_NRF54H20_GPD
3760
uint8_t pad_pd;
3861
#endif
@@ -180,6 +203,7 @@ static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin,
180203
abs_pin, &input_pin_config);
181204
if (err != NRFX_SUCCESS) {
182205
ret = -EINVAL;
206+
183207
goto end;
184208
}
185209
}
@@ -211,13 +235,21 @@ static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin,
211235
}
212236

213237
if (IS_ENABLED(CONFIG_GPIO_NRFX_INTERRUPT) && free_ch) {
238+
#ifdef GPIOTE_FEATURE_FLAG
239+
/* Fixed channel was used, no need to free. */
240+
if (cfg->flags & GPIOTE_FLAG_FIXED_CHAN) {
241+
goto end;
242+
}
243+
#endif
214244
err = nrfx_gpiote_channel_free(&cfg->gpiote, ch);
215245
__ASSERT_NO_MSG(err == NRFX_SUCCESS);
216246
}
217247

218248
end:
219249
gpio_nrfx_gpd_retain_set(port, BIT(pin));
220-
return pm_device_runtime_put(port);
250+
int pm_ret = pm_device_runtime_put(port);
251+
252+
return (ret != 0) ? ret : pm_ret;
221253
}
222254

223255
#ifdef CONFIG_GPIO_GET_CONFIG
@@ -393,6 +425,37 @@ static nrfx_gpiote_trigger_t get_trigger(enum gpio_int_mode mode,
393425
NRFX_GPIOTE_TRIGGER_LOTOHI;
394426
}
395427

428+
static nrfx_err_t chan_alloc(const struct gpio_nrfx_cfg *cfg, gpio_pin_t pin, uint8_t *ch)
429+
{
430+
#ifdef GPIOTE_FEATURE_FLAG
431+
if (cfg->flags & GPIOTE_FLAG_FIXED_CHAN) {
432+
/* Currently fixed channel relation is only present in one instance (GPIOTE0 on
433+
* cpurad). The rules are following:
434+
* - GPIOTE0 can only be used with P1 (pins 4-11) and P2 (pins (0-11))
435+
* - P1: channel => pin - 4, e.g. P1.4 => channel 0, P1.5 => channel 1
436+
* - P2: channel => pin % 8, e.g. P2.0 => channel 0, P2.8 => channel 0
437+
*/
438+
nrfx_err_t err = NRFX_SUCCESS;
439+
440+
if (cfg->port_num == 1) {
441+
if (pin < 4) {
442+
err = NRFX_ERROR_INVALID_PARAM;
443+
} else {
444+
*ch = pin - 4;
445+
}
446+
} else if (cfg->port_num == 2) {
447+
*ch = pin & 0x7;
448+
} else {
449+
err = NRFX_ERROR_INVALID_PARAM;
450+
}
451+
452+
return err;
453+
}
454+
#endif
455+
456+
return nrfx_gpiote_channel_alloc(&cfg->gpiote, ch);
457+
}
458+
396459
static int gpio_nrfx_pin_interrupt_configure(const struct device *port,
397460
gpio_pin_t pin,
398461
enum gpio_int_mode mode,
@@ -428,14 +491,19 @@ static int gpio_nrfx_pin_interrupt_configure(const struct device *port,
428491
(nrf_gpio_pin_dir_get(abs_pin) == NRF_GPIO_PIN_DIR_INPUT)) {
429492
err = nrfx_gpiote_channel_get(&cfg->gpiote, abs_pin, &ch);
430493
if (err == NRFX_ERROR_INVALID_PARAM) {
431-
err = nrfx_gpiote_channel_alloc(&cfg->gpiote, &ch);
494+
err = chan_alloc(cfg, pin, &ch);
432495
if (err != NRFX_SUCCESS) {
433496
return -ENOMEM;
434497
}
435498
}
436499

437500
trigger_config.p_in_channel = &ch;
438501
} else {
502+
#ifdef GPIOTE_FEATURE_FLAG
503+
if (cfg->flags & GPIOTE_FLAG_NO_PORT_EVT) {
504+
return -ENOTSUP;
505+
}
506+
#endif
439507
/* If edge mode with channel was previously used and we are changing to sense or
440508
* level triggered, we must free the channel.
441509
*/
@@ -641,7 +709,6 @@ static DEVICE_API(gpio, gpio_nrfx_drv_api_funcs) = {
641709
#endif
642710
};
643711

644-
#define GPIOTE_PHANDLE(id) DT_INST_PHANDLE(id, gpiote_instance)
645712
#define GPIOTE_INST(id) DT_PROP(GPIOTE_PHANDLE(id), instance)
646713

647714
#define GPIOTE_INSTANCE(id) \
@@ -668,30 +735,37 @@ static DEVICE_API(gpio, gpio_nrfx_drv_api_funcs) = {
668735
#define PAD_PD(inst)
669736
#endif
670737

671-
#define GPIO_NRF_DEVICE(id) \
672-
GPIOTE_CHECK(id); \
673-
static const struct gpio_nrfx_cfg gpio_nrfx_p##id##_cfg = { \
674-
.common = { \
675-
.port_pin_mask = \
676-
GPIO_PORT_PIN_MASK_FROM_DT_INST(id), \
677-
}, \
678-
.port = _CONCAT(NRF_P, DT_INST_PROP(id, port)), \
679-
.port_num = DT_INST_PROP(id, port), \
680-
.edge_sense = DT_INST_PROP_OR(id, sense_edge_mask, 0), \
681-
.gpiote = GPIOTE_INSTANCE(id), \
682-
PAD_PD(id) \
683-
}; \
684-
\
685-
static struct gpio_nrfx_data gpio_nrfx_p##id##_data; \
686-
\
687-
PM_DEVICE_DT_INST_DEFINE(id, gpio_nrfx_pm_hook); \
688-
\
689-
DEVICE_DT_INST_DEFINE(id, gpio_nrfx_init, \
690-
PM_DEVICE_DT_INST_GET(id), \
691-
&gpio_nrfx_p##id##_data, \
692-
&gpio_nrfx_p##id##_cfg, \
693-
PRE_KERNEL_1, \
694-
CONFIG_GPIO_INIT_PRIORITY, \
738+
#define GPIO_NRF_DEVICE(id) \
739+
GPIOTE_CHECK(id); \
740+
static const struct gpio_nrfx_cfg gpio_nrfx_p##id##_cfg = { \
741+
.common = { \
742+
.port_pin_mask = \
743+
GPIO_PORT_PIN_MASK_FROM_DT_INST(id), \
744+
}, \
745+
.port = _CONCAT(NRF_P, DT_INST_PROP(id, port)), \
746+
.port_num = DT_INST_PROP(id, port), \
747+
.edge_sense = DT_INST_PROP_OR(id, sense_edge_mask, 0), \
748+
.gpiote = GPIOTE_INSTANCE(id), \
749+
IF_ENABLED(GPIOTE_FEATURE_FLAG, \
750+
(.flags = \
751+
(DT_PROP_OR(GPIOTE_PHANDLE(id), no_port_event, 0) ? \
752+
GPIOTE_FLAG_NO_PORT_EVT : 0) | \
753+
(DT_PROP_OR(GPIOTE_PHANDLE(id), fixed_channels_supported, 0) ? \
754+
GPIOTE_FLAG_FIXED_CHAN : 0),) \
755+
) \
756+
PAD_PD(id) \
757+
}; \
758+
\
759+
static struct gpio_nrfx_data gpio_nrfx_p##id##_data; \
760+
\
761+
PM_DEVICE_DT_INST_DEFINE(id, gpio_nrfx_pm_hook); \
762+
\
763+
DEVICE_DT_INST_DEFINE(id, gpio_nrfx_init, \
764+
PM_DEVICE_DT_INST_GET(id), \
765+
&gpio_nrfx_p##id##_data, \
766+
&gpio_nrfx_p##id##_cfg, \
767+
PRE_KERNEL_1, \
768+
CONFIG_GPIO_INIT_PRIORITY, \
695769
&gpio_nrfx_drv_api_funcs);
696770

697771
DT_INST_FOREACH_STATUS_OKAY(GPIO_NRF_DEVICE)

0 commit comments

Comments
 (0)