Skip to content

drivers: gpio: nrfx: Add support for GPIOTE0 on nrf54h20 cpurad #91041

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 102 additions & 27 deletions drivers/gpio/gpio_nrfx.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,26 @@
#include <nrf/gpd.h>
#endif

#define GPIOTE_PHANDLE(id) DT_INST_PHANDLE(id, gpiote_instance)
#define GPIOTE_PROP(idx, prop) DT_PROP(GPIOTE(idx), prop)

#define IS_NO_PORT_INSTANCE(id) DT_PROP_OR(GPIOTE_PHANDLE(id), no_port_event, 0) ||
#define IS_FIXED_CH_INSTANCE(id) DT_PROP_OR(GPIOTE_PHANDLE(id), fixed_channels_supported, 0) ||

#if DT_INST_FOREACH_STATUS_OKAY(IS_NO_PORT_INSTANCE) 0
#define GPIOTE_NO_PORT_EVT_SUPPORT 1
#endif

#if DT_INST_FOREACH_STATUS_OKAY(IS_FIXED_CH_INSTANCE) 0
#define GPIOTE_FIXED_CH_SUPPORT 1
#endif

#if defined(GPIOTE_NO_PORT_EVT_SUPPORT) || defined(GPIOTE_FIXED_CH_SUPPORT)
#define GPIOTE_FEATURE_FLAG 1
#define GPIOTE_FLAG_NO_PORT_EVT BIT(0)
#define GPIOTE_FLAG_FIXED_CHAN BIT(1)
#endif

struct gpio_nrfx_data {
/* gpio_driver_data needs to be first */
struct gpio_driver_data common;
Expand All @@ -33,6 +53,9 @@ struct gpio_nrfx_cfg {
uint32_t edge_sense;
uint8_t port_num;
nrfx_gpiote_t gpiote;
#if defined(GPIOTE_FEATURE_FLAG)
uint32_t flags;
#endif
#ifdef CONFIG_SOC_NRF54H20_GPD
uint8_t pad_pd;
#endif
Expand Down Expand Up @@ -189,6 +212,7 @@ static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin,
abs_pin, &input_pin_config);
if (err != NRFX_SUCCESS) {
ret = -EINVAL;

goto end;
}
}
Expand Down Expand Up @@ -220,13 +244,21 @@ static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin,
}

if (IS_ENABLED(CONFIG_GPIO_NRFX_INTERRUPT) && free_ch) {
#ifdef GPIOTE_FEATURE_FLAG
/* Fixed channel was used, no need to free. */
if (cfg->flags & GPIOTE_FLAG_FIXED_CHAN) {
goto end;
}
#endif
err = nrfx_gpiote_channel_free(&cfg->gpiote, ch);
__ASSERT_NO_MSG(err == NRFX_SUCCESS);
}

end:
gpio_nrfx_gpd_retain_set(port, BIT(pin), flags);
return pm_device_runtime_put(port);
int pm_ret = pm_device_runtime_put(port);

return (ret != 0) ? ret : pm_ret;
}

#ifdef CONFIG_GPIO_GET_CONFIG
Expand Down Expand Up @@ -402,6 +434,37 @@ static nrfx_gpiote_trigger_t get_trigger(enum gpio_int_mode mode,
NRFX_GPIOTE_TRIGGER_LOTOHI;
}

static nrfx_err_t chan_alloc(const struct gpio_nrfx_cfg *cfg, gpio_pin_t pin, uint8_t *ch)
{
#ifdef GPIOTE_FEATURE_FLAG
if (cfg->flags & GPIOTE_FLAG_FIXED_CHAN) {
/* Currently fixed channel relation is only present in one instance (GPIOTE0 on
* cpurad). The rules are following:
* - GPIOTE0 can only be used with P1 (pins 4-11) and P2 (pins (0-11))
* - P1: channel => pin - 4, e.g. P1.4 => channel 0, P1.5 => channel 1
* - P2: channel => pin % 8, e.g. P2.0 => channel 0, P2.8 => channel 0
*/
nrfx_err_t err = NRFX_SUCCESS;

if (cfg->port_num == 1) {
if (pin < 4) {
err = NRFX_ERROR_INVALID_PARAM;
} else {
*ch = pin - 4;
}
} else if (cfg->port_num == 2) {
*ch = pin & 0x7;
} else {
err = NRFX_ERROR_INVALID_PARAM;
}

return err;
}
#endif

return nrfx_gpiote_channel_alloc(&cfg->gpiote, ch);
}

static int gpio_nrfx_pin_interrupt_configure(const struct device *port,
gpio_pin_t pin,
enum gpio_int_mode mode,
Expand Down Expand Up @@ -437,13 +500,19 @@ static int gpio_nrfx_pin_interrupt_configure(const struct device *port,
(nrf_gpio_pin_dir_get(abs_pin) == NRF_GPIO_PIN_DIR_INPUT)) {
err = nrfx_gpiote_channel_get(&cfg->gpiote, abs_pin, &ch);
if (err == NRFX_ERROR_INVALID_PARAM) {
err = nrfx_gpiote_channel_alloc(&cfg->gpiote, &ch);
err = chan_alloc(cfg, pin, &ch);
if (err != NRFX_SUCCESS) {
return -ENOMEM;
}
}

trigger_config.p_in_channel = &ch;
} else {
#ifdef GPIOTE_FEATURE_FLAG
if (cfg->flags & GPIOTE_FLAG_NO_PORT_EVT) {
return -ENOTSUP;
}
#endif
}

err = nrfx_gpiote_input_configure(&cfg->gpiote, abs_pin, &input_pin_config);
Expand Down Expand Up @@ -641,7 +710,6 @@ static DEVICE_API(gpio, gpio_nrfx_drv_api_funcs) = {
#endif
};

#define GPIOTE_PHANDLE(id) DT_INST_PHANDLE(id, gpiote_instance)
#define GPIOTE_INST(id) DT_PROP(GPIOTE_PHANDLE(id), instance)

#define GPIOTE_INSTANCE(id) \
Expand All @@ -668,30 +736,37 @@ static DEVICE_API(gpio, gpio_nrfx_drv_api_funcs) = {
#define PAD_PD(inst)
#endif

#define GPIO_NRF_DEVICE(id) \
GPIOTE_CHECK(id); \
static const struct gpio_nrfx_cfg gpio_nrfx_p##id##_cfg = { \
.common = { \
.port_pin_mask = \
GPIO_PORT_PIN_MASK_FROM_DT_INST(id), \
}, \
.port = _CONCAT(NRF_P, DT_INST_PROP(id, port)), \
.port_num = DT_INST_PROP(id, port), \
.edge_sense = DT_INST_PROP_OR(id, sense_edge_mask, 0), \
.gpiote = GPIOTE_INSTANCE(id), \
PAD_PD(id) \
}; \
\
static struct gpio_nrfx_data gpio_nrfx_p##id##_data; \
\
PM_DEVICE_DT_INST_DEFINE(id, gpio_nrfx_pm_hook); \
\
DEVICE_DT_INST_DEFINE(id, gpio_nrfx_init, \
PM_DEVICE_DT_INST_GET(id), \
&gpio_nrfx_p##id##_data, \
&gpio_nrfx_p##id##_cfg, \
PRE_KERNEL_1, \
CONFIG_GPIO_INIT_PRIORITY, \
#define GPIO_NRF_DEVICE(id) \
GPIOTE_CHECK(id); \
static const struct gpio_nrfx_cfg gpio_nrfx_p##id##_cfg = { \
.common = { \
.port_pin_mask = \
GPIO_PORT_PIN_MASK_FROM_DT_INST(id), \
}, \
.port = _CONCAT(NRF_P, DT_INST_PROP(id, port)), \
.port_num = DT_INST_PROP(id, port), \
.edge_sense = DT_INST_PROP_OR(id, sense_edge_mask, 0), \
.gpiote = GPIOTE_INSTANCE(id), \
IF_ENABLED(GPIOTE_FEATURE_FLAG, \
(.flags = \
(DT_PROP_OR(GPIOTE_PHANDLE(id), no_port_event, 0) ? \
GPIOTE_FLAG_NO_PORT_EVT : 0) | \
(DT_PROP_OR(GPIOTE_PHANDLE(id), fixed_channels_supported, 0) ? \
GPIOTE_FLAG_FIXED_CHAN : 0),) \
) \
PAD_PD(id) \
}; \
\
static struct gpio_nrfx_data gpio_nrfx_p##id##_data; \
\
PM_DEVICE_DT_INST_DEFINE(id, gpio_nrfx_pm_hook); \
\
DEVICE_DT_INST_DEFINE(id, gpio_nrfx_init, \
PM_DEVICE_DT_INST_GET(id), \
&gpio_nrfx_p##id##_data, \
&gpio_nrfx_p##id##_cfg, \
PRE_KERNEL_1, \
CONFIG_GPIO_INIT_PRIORITY, \
&gpio_nrfx_drv_api_funcs);

DT_INST_FOREACH_STATUS_OKAY(GPIO_NRF_DEVICE)
12 changes: 12 additions & 0 deletions dts/bindings/gpio/nordic,nrf-gpiote.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ compatible: "nordic,nrf-gpiote"
include:
- base.yaml
- nordic,split-channels.yaml
- pinctrl-device.yaml

properties:
reg:
Expand All @@ -16,6 +17,17 @@ properties:
interrupts:
required: true

no-port-event:
type: boolean
description: |
Indicates that the GPIOTE instance does not support PORT event.

fixed-channels-supported:
type: boolean
description: |
Indicates that the GPIOTE instance has fixed connection between pins and TE channels.
It means that a specific TE channel must be used for a given pin.

instance:
type: int
required: true
Expand Down
10 changes: 10 additions & 0 deletions dts/vendor/nordic/nrf54h20.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,16 @@
interrupts = <37 NRF_DEFAULT_IRQ_PRIORITY>;
};

gpiote0: gpiote@27000 {
compatible = "nordic,nrf-gpiote";
reg = <0x27000 0x1000>;
status = "disabled";
interrupts = <39 NRF_DEFAULT_IRQ_PRIORITY>;
instance = <0>;
no-port-event;
fixed-channels-supported;
};

timer020: timer@28000 {
compatible = "nordic,nrf-timer";
reg = <0x28000 0x1000>;
Expand Down
4 changes: 4 additions & 0 deletions modules/hal_nordic/nrfx/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,10 @@ config NRFX_GPIOTE131
depends on $(dt_nodelabel_exists,gpiote131)
select NRFX_GPIOTE

config NRFX_GPIOTE_VAR_FEATURE_SUPPORT
def_bool $(dt_nodelabel_enabled,gpiote0)
depends on $(dt_nodelabel_bool_prop,gpiote0,fixed-channels-supported)

config NRFX_GPIOTE_NUM_OF_EVT_HANDLERS
int "Number of event handlers"
depends on NRFX_GPIOTE
Expand Down
3 changes: 3 additions & 0 deletions modules/hal_nordic/nrfx/nrfx_kconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,9 @@
#ifdef CONFIG_NRFX_GPIOTE131
#define NRFX_GPIOTE131_ENABLED 1
#endif
#ifdef CONFIG_NRFX_GPIOTE_VAR_FEATURE_SUPPORT
#define NRFX_GPIOTE_VAR_FEATURE_SUPPORT 1
#endif

#ifdef CONFIG_NRFX_GPIOTE_NUM_OF_EVT_HANDLERS
#define NRFX_GPIOTE_CONFIG_NUM_OF_EVT_HANDLERS CONFIG_NRFX_GPIOTE_NUM_OF_EVT_HANDLERS
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: Apache-2.0 */

&pinctrl {
gpiote0_default_alt: gpiote0_default_alt {
group1 {
psels = <NRF_PSEL(SPIM_SCK, 1, 4)>;
};
};
};

/ {
resources {
compatible = "test-gpio-basic-api";
out-gpios = <&gpio1 5 0>;
in-gpios = <&gpio1 4 0>;
};
};

&gpio1 {
status = "okay";
gpiote-instance = <&gpiote0>;
};

&gpiote0 {
status = "okay";
pinctrl-0 = <&gpiote0_default_alt>;
pinctrl-names = "default";
};
7 changes: 5 additions & 2 deletions tests/drivers/gpio/gpio_basic_api/src/test_callback_manage.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,19 @@ static int init_callback(const struct device *dev_in, const struct device *dev_o
static void trigger_callback(const struct device *dev_in, const struct device *dev_out,
int enable_cb)
{
int rc;

gpio_pin_set(dev_out, PIN_OUT, 0);
k_sleep(K_MSEC(100));

cb_cnt[0] = 0;
cb_cnt[1] = 0;
if (enable_cb == 1) {
gpio_pin_interrupt_configure(dev_in, PIN_IN, GPIO_INT_EDGE_RISING);
rc = gpio_pin_interrupt_configure(dev_in, PIN_IN, GPIO_INT_EDGE_RISING);
} else {
gpio_pin_interrupt_configure(dev_in, PIN_IN, GPIO_INT_DISABLE);
rc = gpio_pin_interrupt_configure(dev_in, PIN_IN, GPIO_INT_DISABLE);
}
zassert_equal(rc, 0);
k_sleep(K_MSEC(100));
gpio_pin_set(dev_out, PIN_OUT, 1);
k_sleep(K_MSEC(1000));
Expand Down
6 changes: 6 additions & 0 deletions tests/drivers/gpio/gpio_basic_api/src/test_config_trigger.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ ZTEST(after_flash_gpio_config_trigger, test_gpio_config_twice_trigger)
k_sleep(K_MSEC(10));
zassert_between_inclusive(cb_cnt, 0, 1, "Got %d interrupts", cb_cnt);

ret = gpio_pin_interrupt_configure(dev_in, PIN_IN, GPIO_INT_DISABLE);
zassert_ok(ret, "interrupt disabling failed");

gpio_remove_callback(dev_in, &drv_data->gpio_cb);
}

Expand Down Expand Up @@ -115,5 +118,8 @@ ZTEST(after_flash_gpio_config_trigger, test_gpio_config_trigger)
k_sleep(K_MSEC(10));
zassert_between_inclusive(cb_cnt, 0, 1, "Got %d interrupts", cb_cnt);

ret = gpio_pin_interrupt_configure(dev_in, PIN_IN, GPIO_INT_DISABLE);
zassert_ok(ret, "interrupt disabling failed");

gpio_remove_callback(dev_in, &drv_data->gpio_cb);
}
7 changes: 7 additions & 0 deletions tests/drivers/gpio/gpio_basic_api/testcase.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,10 @@ tests:
platform_allow:
- siwx917_rb4338a
extra_args: "DTC_OVERLAY_FILE=boards/siwx917_rb4338a-uulp.overlay"
drivers.gpio.2pin.nrf54h20_cpurad_gpiote0:
harness_config:
fixture: i2s_loopback # Loopback includes the pin pair needed for that test
platform_allow:
- nrf54h20dk/nrf54h20/cpurad
extra_args:
- DTC_OVERLAY_FILE="boards/nrf54h20dk_nrf54h20_cpurad_gpiote0.overlay"
2 changes: 1 addition & 1 deletion west.yml
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ manifest:
groups:
- hal
- name: hal_nordic
revision: 1f169d927e367eb1e161972e9504da5aa1f10c42
revision: pull/298/head
path: modules/hal/nordic
groups:
- hal
Expand Down
Loading