Skip to content

Commit c1546c1

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 6dc6618 commit c1546c1

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
@@ -189,6 +212,7 @@ static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin,
189212
abs_pin, &input_pin_config);
190213
if (err != NRFX_SUCCESS) {
191214
ret = -EINVAL;
215+
192216
goto end;
193217
}
194218
}
@@ -220,13 +244,21 @@ static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin,
220244
}
221245

222246
if (IS_ENABLED(CONFIG_GPIO_NRFX_INTERRUPT) && free_ch) {
247+
#ifdef GPIOTE_FEATURE_FLAG
248+
/* Fixed channel was used, no need to free. */
249+
if (cfg->flags & GPIOTE_FLAG_FIXED_CHAN) {
250+
goto end;
251+
}
252+
#endif
223253
err = nrfx_gpiote_channel_free(&cfg->gpiote, ch);
224254
__ASSERT_NO_MSG(err == NRFX_SUCCESS);
225255
}
226256

227257
end:
228258
gpio_nrfx_gpd_retain_set(port, BIT(pin), flags);
229-
return pm_device_runtime_put(port);
259+
int pm_ret = pm_device_runtime_put(port);
260+
261+
return (ret != 0) ? ret : pm_ret;
230262
}
231263

232264
#ifdef CONFIG_GPIO_GET_CONFIG
@@ -402,6 +434,37 @@ static nrfx_gpiote_trigger_t get_trigger(enum gpio_int_mode mode,
402434
NRFX_GPIOTE_TRIGGER_LOTOHI;
403435
}
404436

437+
static nrfx_err_t chan_alloc(const struct gpio_nrfx_cfg *cfg, gpio_pin_t pin, uint8_t *ch)
438+
{
439+
#ifdef GPIOTE_FEATURE_FLAG
440+
if (cfg->flags & GPIOTE_FLAG_FIXED_CHAN) {
441+
/* Currently fixed channel relation is only present in one instance (GPIOTE0 on
442+
* cpurad). The rules are following:
443+
* - GPIOTE0 can only be used with P1 (pins 4-11) and P2 (pins (0-11))
444+
* - P1: channel => pin - 4, e.g. P1.4 => channel 0, P1.5 => channel 1
445+
* - P2: channel => pin % 8, e.g. P2.0 => channel 0, P2.8 => channel 0
446+
*/
447+
nrfx_err_t err = NRFX_SUCCESS;
448+
449+
if (cfg->port_num == 1) {
450+
if (pin < 4) {
451+
err = NRFX_ERROR_INVALID_PARAM;
452+
} else {
453+
*ch = pin - 4;
454+
}
455+
} else if (cfg->port_num == 2) {
456+
*ch = pin & 0x7;
457+
} else {
458+
err = NRFX_ERROR_INVALID_PARAM;
459+
}
460+
461+
return err;
462+
}
463+
#endif
464+
465+
return nrfx_gpiote_channel_alloc(&cfg->gpiote, ch);
466+
}
467+
405468
static int gpio_nrfx_pin_interrupt_configure(const struct device *port,
406469
gpio_pin_t pin,
407470
enum gpio_int_mode mode,
@@ -437,14 +500,19 @@ static int gpio_nrfx_pin_interrupt_configure(const struct device *port,
437500
(nrf_gpio_pin_dir_get(abs_pin) == NRF_GPIO_PIN_DIR_INPUT)) {
438501
err = nrfx_gpiote_channel_get(&cfg->gpiote, abs_pin, &ch);
439502
if (err == NRFX_ERROR_INVALID_PARAM) {
440-
err = nrfx_gpiote_channel_alloc(&cfg->gpiote, &ch);
503+
err = chan_alloc(cfg, pin, &ch);
441504
if (err != NRFX_SUCCESS) {
442505
return -ENOMEM;
443506
}
444507
}
445508

446509
trigger_config.p_in_channel = &ch;
447510
} else {
511+
#ifdef GPIOTE_FEATURE_FLAG
512+
if (cfg->flags & GPIOTE_FLAG_NO_PORT_EVT) {
513+
return -ENOTSUP;
514+
}
515+
#endif
448516
/* If edge mode with channel was previously used and we are changing to sense or
449517
* level triggered, we must free the channel.
450518
*/
@@ -650,7 +718,6 @@ static DEVICE_API(gpio, gpio_nrfx_drv_api_funcs) = {
650718
#endif
651719
};
652720

653-
#define GPIOTE_PHANDLE(id) DT_INST_PHANDLE(id, gpiote_instance)
654721
#define GPIOTE_INST(id) DT_PROP(GPIOTE_PHANDLE(id), instance)
655722

656723
#define GPIOTE_INSTANCE(id) \
@@ -677,30 +744,37 @@ static DEVICE_API(gpio, gpio_nrfx_drv_api_funcs) = {
677744
#define PAD_PD(inst)
678745
#endif
679746

680-
#define GPIO_NRF_DEVICE(id) \
681-
GPIOTE_CHECK(id); \
682-
static const struct gpio_nrfx_cfg gpio_nrfx_p##id##_cfg = { \
683-
.common = { \
684-
.port_pin_mask = \
685-
GPIO_PORT_PIN_MASK_FROM_DT_INST(id), \
686-
}, \
687-
.port = _CONCAT(NRF_P, DT_INST_PROP(id, port)), \
688-
.port_num = DT_INST_PROP(id, port), \
689-
.edge_sense = DT_INST_PROP_OR(id, sense_edge_mask, 0), \
690-
.gpiote = GPIOTE_INSTANCE(id), \
691-
PAD_PD(id) \
692-
}; \
693-
\
694-
static struct gpio_nrfx_data gpio_nrfx_p##id##_data; \
695-
\
696-
PM_DEVICE_DT_INST_DEFINE(id, gpio_nrfx_pm_hook); \
697-
\
698-
DEVICE_DT_INST_DEFINE(id, gpio_nrfx_init, \
699-
PM_DEVICE_DT_INST_GET(id), \
700-
&gpio_nrfx_p##id##_data, \
701-
&gpio_nrfx_p##id##_cfg, \
702-
PRE_KERNEL_1, \
703-
CONFIG_GPIO_INIT_PRIORITY, \
747+
#define GPIO_NRF_DEVICE(id) \
748+
GPIOTE_CHECK(id); \
749+
static const struct gpio_nrfx_cfg gpio_nrfx_p##id##_cfg = { \
750+
.common = { \
751+
.port_pin_mask = \
752+
GPIO_PORT_PIN_MASK_FROM_DT_INST(id), \
753+
}, \
754+
.port = _CONCAT(NRF_P, DT_INST_PROP(id, port)), \
755+
.port_num = DT_INST_PROP(id, port), \
756+
.edge_sense = DT_INST_PROP_OR(id, sense_edge_mask, 0), \
757+
.gpiote = GPIOTE_INSTANCE(id), \
758+
IF_ENABLED(GPIOTE_FEATURE_FLAG, \
759+
(.flags = \
760+
(DT_PROP_OR(GPIOTE_PHANDLE(id), no_port_event, 0) ? \
761+
GPIOTE_FLAG_NO_PORT_EVT : 0) | \
762+
(DT_PROP_OR(GPIOTE_PHANDLE(id), fixed_channels_supported, 0) ? \
763+
GPIOTE_FLAG_FIXED_CHAN : 0),) \
764+
) \
765+
PAD_PD(id) \
766+
}; \
767+
\
768+
static struct gpio_nrfx_data gpio_nrfx_p##id##_data; \
769+
\
770+
PM_DEVICE_DT_INST_DEFINE(id, gpio_nrfx_pm_hook); \
771+
\
772+
DEVICE_DT_INST_DEFINE(id, gpio_nrfx_init, \
773+
PM_DEVICE_DT_INST_GET(id), \
774+
&gpio_nrfx_p##id##_data, \
775+
&gpio_nrfx_p##id##_cfg, \
776+
PRE_KERNEL_1, \
777+
CONFIG_GPIO_INIT_PRIORITY, \
704778
&gpio_nrfx_drv_api_funcs);
705779

706780
DT_INST_FOREACH_STATUS_OKAY(GPIO_NRF_DEVICE)

0 commit comments

Comments
 (0)