drivers: gpio: nrfx: add support for ports with pad on FAST_ACTIVE1

This patch allows to _safely_ configure GPIO ports that have their pad
on FAST_ACTIVE1 domain.

Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>
This commit is contained in:
Gerard Marull-Paretas 2024-10-10 15:58:41 +02:00 committed by Mahesh Mahadevan
parent 0b18f31246
commit 56c5b1e2da

View file

@ -14,6 +14,10 @@
#include <zephyr/drivers/gpio/gpio_utils.h>
#ifdef CONFIG_SOC_NRF54H20_GPD
#include <nrf/gpd.h>
#endif
struct gpio_nrfx_data {
/* gpio_driver_data needs to be first */
struct gpio_driver_data common;
@ -27,6 +31,9 @@ struct gpio_nrfx_cfg {
uint32_t edge_sense;
uint8_t port_num;
nrfx_gpiote_t gpiote;
#ifdef CONFIG_SOC_NRF54H20_GPD
uint8_t pad_pd;
#endif
};
static inline struct gpio_nrfx_data *get_port_data(const struct device *port)
@ -55,9 +62,59 @@ static nrf_gpio_pin_pull_t get_pull(gpio_flags_t flags)
return NRF_GPIO_PIN_NOPULL;
}
static int gpio_nrfx_gpd_retain_set(const struct device *port, uint32_t mask, gpio_flags_t flags)
{
#ifdef CONFIG_SOC_NRF54H20_GPD
const struct gpio_nrfx_cfg *cfg = get_port_cfg(port);
if (cfg->pad_pd == NRF_GPD_FAST_ACTIVE1) {
int ret;
if (flags & GPIO_OUTPUT) {
cfg->port->RETAINSET = mask;
}
ret = nrf_gpd_release(NRF_GPD_FAST_ACTIVE1);
if (ret < 0) {
return ret;
}
}
#else
ARG_UNUSED(port);
ARG_UNUSED(mask);
ARG_UNUSED(flags);
#endif
return 0;
}
static int gpio_nrfx_gpd_retain_clear(const struct device *port, uint32_t mask)
{
#ifdef CONFIG_SOC_NRF54H20_GPD
const struct gpio_nrfx_cfg *cfg = get_port_cfg(port);
if (cfg->pad_pd == NRF_GPD_FAST_ACTIVE1) {
int ret;
ret = nrf_gpd_request(NRF_GPD_FAST_ACTIVE1);
if (ret < 0) {
return ret;
}
cfg->port->RETAINCLR = mask;
}
#else
ARG_UNUSED(port);
ARG_UNUSED(mask);
#endif
return 0;
}
static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin,
gpio_flags_t flags)
{
int ret = 0;
nrfx_err_t err = NRFX_SUCCESS;
uint8_t ch;
bool free_ch = false;
@ -95,6 +152,11 @@ static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin,
return -EINVAL;
}
ret = gpio_nrfx_gpd_retain_clear(port, BIT(pin));
if (ret < 0) {
return ret;
}
if (flags & GPIO_OUTPUT_INIT_HIGH) {
nrf_gpio_port_out_set(cfg->port, BIT(pin));
} else if (flags & GPIO_OUTPUT_INIT_LOW) {
@ -110,7 +172,8 @@ static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin,
: NRF_GPIO_PIN_INPUT_DISCONNECT;
nrf_gpio_reconfigure(abs_pin, &dir, &input, &pull, &drive, NULL);
return 0;
goto end;
}
/* Get the GPIOTE channel associated with this pin, if any. It needs
@ -137,7 +200,8 @@ static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin,
err = nrfx_gpiote_input_configure(&cfg->gpiote,
abs_pin, &input_pin_config);
if (err != NRFX_SUCCESS) {
return -EINVAL;
ret = -EINVAL;
goto end;
}
}
@ -162,7 +226,8 @@ static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin,
}
if (err != NRFX_SUCCESS) {
return -EINVAL;
ret = -EINVAL;
goto end;
}
}
@ -171,7 +236,9 @@ static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin,
__ASSERT_NO_MSG(err == NRFX_SUCCESS);
}
return 0;
end:
(void)gpio_nrfx_gpd_retain_set(port, BIT(pin), flags);
return ret;
}
static int gpio_nrfx_port_get_raw(const struct device *port,
@ -189,34 +256,52 @@ static int gpio_nrfx_port_set_masked_raw(const struct device *port,
gpio_port_value_t value)
{
NRF_GPIO_Type *reg = get_port_cfg(port)->port;
int ret;
const uint32_t set_mask = value & mask;
const uint32_t clear_mask = (~set_mask) & mask;
ret = gpio_nrfx_gpd_retain_clear(port, mask);
if (ret < 0) {
return ret;
}
nrf_gpio_port_out_set(reg, set_mask);
nrf_gpio_port_out_clear(reg, clear_mask);
return 0;
return gpio_nrfx_gpd_retain_set(port, mask, GPIO_OUTPUT);
}
static int gpio_nrfx_port_set_bits_raw(const struct device *port,
gpio_port_pins_t mask)
{
NRF_GPIO_Type *reg = get_port_cfg(port)->port;
int ret;
ret = gpio_nrfx_gpd_retain_clear(port, mask);
if (ret < 0) {
return ret;
}
nrf_gpio_port_out_set(reg, mask);
return 0;
return gpio_nrfx_gpd_retain_set(port, mask, GPIO_OUTPUT);
}
static int gpio_nrfx_port_clear_bits_raw(const struct device *port,
gpio_port_pins_t mask)
{
NRF_GPIO_Type *reg = get_port_cfg(port)->port;
int ret;
ret = gpio_nrfx_gpd_retain_clear(port, mask);
if (ret < 0) {
return ret;
}
nrf_gpio_port_out_clear(reg, mask);
return 0;
return gpio_nrfx_gpd_retain_set(port, mask, GPIO_OUTPUT);
}
static int gpio_nrfx_port_toggle_bits(const struct device *port,
@ -226,11 +311,17 @@ static int gpio_nrfx_port_toggle_bits(const struct device *port,
const uint32_t value = nrf_gpio_port_out_read(reg) ^ mask;
const uint32_t set_mask = value & mask;
const uint32_t clear_mask = (~value) & mask;
int ret;
ret = gpio_nrfx_gpd_retain_clear(port, mask);
if (ret < 0) {
return ret;
}
nrf_gpio_port_out_set(reg, set_mask);
nrf_gpio_port_out_clear(reg, clear_mask);
return 0;
return gpio_nrfx_gpd_retain_set(port, mask, GPIO_OUTPUT);
}
#ifdef CONFIG_GPIO_NRFX_INTERRUPT
@ -450,6 +541,14 @@ static const struct gpio_driver_api gpio_nrfx_drv_api_funcs = {
"Please enable GPIOTE instance for used GPIO port!")), \
())
#ifdef CONFIG_SOC_NRF54H20_GPD
#define PAD_PD(inst) \
.pad_pd = DT_INST_PHA_BY_NAME_OR(inst, power_domains, pad, id, \
NRF_GPD_SLOW_MAIN),
#else
#define PAD_PD(inst)
#endif
#define GPIO_NRF_DEVICE(id) \
GPIOTE_CHECK(id); \
static const struct gpio_nrfx_cfg gpio_nrfx_p##id##_cfg = { \
@ -461,6 +560,7 @@ static const struct gpio_driver_api gpio_nrfx_drv_api_funcs = {
.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; \