Skip to content

Commit 0d813fb

Browse files
nordic-krchhenrikbrixandersen
authored andcommitted
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 <[email protected]>
1 parent 6971447 commit 0d813fb

File tree

1 file changed

+102
-27
lines changed

1 file changed

+102
-27
lines changed

drivers/gpio/gpio_nrfx.c

Lines changed: 102 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,26 @@
2222
#define GPIO_HAS_PAD_GROUP 0
2323
#endif
2424

25+
#define GPIOTE_PHANDLE(id) DT_INST_PHANDLE(id, gpiote_instance)
26+
#define GPIOTE_PROP(idx, prop) DT_PROP(GPIOTE(idx), prop)
27+
28+
#define IS_NO_PORT_INSTANCE(id) DT_PROP_OR(GPIOTE_PHANDLE(id), no_port_event, 0) ||
29+
#define IS_FIXED_CH_INSTANCE(id) DT_PROP_OR(GPIOTE_PHANDLE(id), fixed_channels_supported, 0) ||
30+
31+
#if DT_INST_FOREACH_STATUS_OKAY(IS_NO_PORT_INSTANCE) 0
32+
#define GPIOTE_NO_PORT_EVT_SUPPORT 1
33+
#endif
34+
35+
#if DT_INST_FOREACH_STATUS_OKAY(IS_FIXED_CH_INSTANCE) 0
36+
#define GPIOTE_FIXED_CH_SUPPORT 1
37+
#endif
38+
39+
#if defined(GPIOTE_NO_PORT_EVT_SUPPORT) || defined(GPIOTE_FIXED_CH_SUPPORT)
40+
#define GPIOTE_FEATURE_FLAG 1
41+
#define GPIOTE_FLAG_NO_PORT_EVT BIT(0)
42+
#define GPIOTE_FLAG_FIXED_CHAN BIT(1)
43+
#endif
44+
2545
struct gpio_nrfx_data {
2646
/* gpio_driver_data needs to be first */
2747
struct gpio_driver_data common;
@@ -38,6 +58,9 @@ struct gpio_nrfx_cfg {
3858
#if GPIO_HAS_PAD_GROUP
3959
const struct device *pad_group;
4060
#endif
61+
#if defined(GPIOTE_FEATURE_FLAG)
62+
uint32_t flags;
63+
#endif
4164
};
4265

4366
static inline struct gpio_nrfx_data *get_port_data(const struct device *port)
@@ -77,6 +100,7 @@ static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin,
77100
nrfx_gpiote_pin_t abs_pin = NRF_GPIO_PIN_MAP(cfg->port_num, pin);
78101
nrf_gpio_pin_pull_t pull = get_pull(flags);
79102
nrf_gpio_pin_drive_t drive;
103+
int pm_ret;
80104

81105
switch (flags & (NRF_GPIO_DRIVE_MSK | GPIO_OPEN_DRAIN)) {
82106
case NRF_GPIO_DRIVE_S0S1:
@@ -156,6 +180,7 @@ static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin,
156180
abs_pin, &input_pin_config);
157181
if (err != NRFX_SUCCESS) {
158182
ret = -EINVAL;
183+
159184
goto end;
160185
}
161186
}
@@ -187,12 +212,20 @@ static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin,
187212
}
188213

189214
if (IS_ENABLED(CONFIG_GPIO_NRFX_INTERRUPT) && free_ch) {
215+
#ifdef GPIOTE_FEATURE_FLAG
216+
/* Fixed channel was used, no need to free. */
217+
if (cfg->flags & GPIOTE_FLAG_FIXED_CHAN) {
218+
goto end;
219+
}
220+
#endif
190221
err = nrfx_gpiote_channel_free(&cfg->gpiote, ch);
191222
__ASSERT_NO_MSG(err == NRFX_SUCCESS);
192223
}
193224

194225
end:
195-
return pm_device_runtime_put(port);
226+
pm_ret = pm_device_runtime_put(port);
227+
228+
return (ret != 0) ? ret : pm_ret;
196229
}
197230

198231
#ifdef CONFIG_GPIO_GET_CONFIG
@@ -360,6 +393,37 @@ static nrfx_gpiote_trigger_t get_trigger(enum gpio_int_mode mode,
360393
NRFX_GPIOTE_TRIGGER_LOTOHI;
361394
}
362395

396+
static nrfx_err_t chan_alloc(const struct gpio_nrfx_cfg *cfg, gpio_pin_t pin, uint8_t *ch)
397+
{
398+
#ifdef GPIOTE_FEATURE_FLAG
399+
if (cfg->flags & GPIOTE_FLAG_FIXED_CHAN) {
400+
/* Currently fixed channel relation is only present in one instance (GPIOTE0 on
401+
* cpurad). The rules are following:
402+
* - GPIOTE0 can only be used with P1 (pins 4-11) and P2 (pins (0-11))
403+
* - P1: channel => pin - 4, e.g. P1.4 => channel 0, P1.5 => channel 1
404+
* - P2: channel => pin % 8, e.g. P2.0 => channel 0, P2.8 => channel 0
405+
*/
406+
nrfx_err_t err = NRFX_SUCCESS;
407+
408+
if (cfg->port_num == 1) {
409+
if (pin < 4) {
410+
err = NRFX_ERROR_INVALID_PARAM;
411+
} else {
412+
*ch = pin - 4;
413+
}
414+
} else if (cfg->port_num == 2) {
415+
*ch = pin & 0x7;
416+
} else {
417+
err = NRFX_ERROR_INVALID_PARAM;
418+
}
419+
420+
return err;
421+
}
422+
#endif
423+
424+
return nrfx_gpiote_channel_alloc(&cfg->gpiote, ch);
425+
}
426+
363427
static int gpio_nrfx_pin_interrupt_configure(const struct device *port,
364428
gpio_pin_t pin,
365429
enum gpio_int_mode mode,
@@ -395,14 +459,19 @@ static int gpio_nrfx_pin_interrupt_configure(const struct device *port,
395459
(nrf_gpio_pin_dir_get(abs_pin) == NRF_GPIO_PIN_DIR_INPUT)) {
396460
err = nrfx_gpiote_channel_get(&cfg->gpiote, abs_pin, &ch);
397461
if (err == NRFX_ERROR_INVALID_PARAM) {
398-
err = nrfx_gpiote_channel_alloc(&cfg->gpiote, &ch);
462+
err = chan_alloc(cfg, pin, &ch);
399463
if (err != NRFX_SUCCESS) {
400464
return -ENOMEM;
401465
}
402466
}
403467

404468
trigger_config.p_in_channel = &ch;
405469
} else {
470+
#ifdef GPIOTE_FEATURE_FLAG
471+
if (cfg->flags & GPIOTE_FLAG_NO_PORT_EVT) {
472+
return -ENOTSUP;
473+
}
474+
#endif
406475
/* If edge mode with channel was previously used and we are changing to sense or
407476
* level triggered, we must free the channel.
408477
*/
@@ -600,7 +669,6 @@ static DEVICE_API(gpio, gpio_nrfx_drv_api_funcs) = {
600669
#endif
601670
};
602671

603-
#define GPIOTE_PHANDLE(id) DT_INST_PHANDLE(id, gpiote_instance)
604672
#define GPIOTE_INST(id) DT_PROP(GPIOTE_PHANDLE(id), instance)
605673

606674
#define GPIOTE_INSTANCE(id) \
@@ -626,30 +694,37 @@ static DEVICE_API(gpio, gpio_nrfx_drv_api_funcs) = {
626694
#define GPIO_NRF_PAD_GROUP_INIT(id)
627695
#endif
628696

629-
#define GPIO_NRF_DEVICE(id) \
630-
GPIOTE_CHECK(id); \
631-
static const struct gpio_nrfx_cfg gpio_nrfx_p##id##_cfg = { \
632-
.common = { \
633-
.port_pin_mask = \
634-
GPIO_PORT_PIN_MASK_FROM_DT_INST(id), \
635-
}, \
636-
.port = _CONCAT(NRF_P, DT_INST_PROP(id, port)), \
637-
.port_num = DT_INST_PROP(id, port), \
638-
.edge_sense = DT_INST_PROP_OR(id, sense_edge_mask, 0), \
639-
.gpiote = GPIOTE_INSTANCE(id), \
640-
GPIO_NRF_PAD_GROUP_INIT(id) \
641-
}; \
642-
\
643-
static struct gpio_nrfx_data gpio_nrfx_p##id##_data; \
644-
\
645-
PM_DEVICE_DT_INST_DEFINE(id, gpio_nrfx_pm_hook); \
646-
\
647-
DEVICE_DT_INST_DEFINE(id, gpio_nrfx_init, \
648-
PM_DEVICE_DT_INST_GET(id), \
649-
&gpio_nrfx_p##id##_data, \
650-
&gpio_nrfx_p##id##_cfg, \
651-
PRE_KERNEL_1, \
652-
CONFIG_GPIO_INIT_PRIORITY, \
697+
#define GPIO_NRF_DEVICE(id) \
698+
GPIOTE_CHECK(id); \
699+
static const struct gpio_nrfx_cfg gpio_nrfx_p##id##_cfg = { \
700+
.common = { \
701+
.port_pin_mask = \
702+
GPIO_PORT_PIN_MASK_FROM_DT_INST(id), \
703+
}, \
704+
.port = _CONCAT(NRF_P, DT_INST_PROP(id, port)), \
705+
.port_num = DT_INST_PROP(id, port), \
706+
.edge_sense = DT_INST_PROP_OR(id, sense_edge_mask, 0), \
707+
.gpiote = GPIOTE_INSTANCE(id), \
708+
GPIO_NRF_PAD_GROUP_INIT(id) \
709+
IF_ENABLED(GPIOTE_FEATURE_FLAG, \
710+
(.flags = \
711+
(DT_PROP_OR(GPIOTE_PHANDLE(id), no_port_event, 0) ? \
712+
GPIOTE_FLAG_NO_PORT_EVT : 0) | \
713+
(DT_PROP_OR(GPIOTE_PHANDLE(id), fixed_channels_supported, 0) ? \
714+
GPIOTE_FLAG_FIXED_CHAN : 0),) \
715+
) \
716+
}; \
717+
\
718+
static struct gpio_nrfx_data gpio_nrfx_p##id##_data; \
719+
\
720+
PM_DEVICE_DT_INST_DEFINE(id, gpio_nrfx_pm_hook); \
721+
\
722+
DEVICE_DT_INST_DEFINE(id, gpio_nrfx_init, \
723+
PM_DEVICE_DT_INST_GET(id), \
724+
&gpio_nrfx_p##id##_data, \
725+
&gpio_nrfx_p##id##_cfg, \
726+
PRE_KERNEL_1, \
727+
CONFIG_GPIO_INIT_PRIORITY, \
653728
&gpio_nrfx_drv_api_funcs);
654729

655730
DT_INST_FOREACH_STATUS_OKAY(GPIO_NRF_DEVICE)

0 commit comments

Comments
 (0)