Skip to content
Merged
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
136 changes: 91 additions & 45 deletions drivers/gpio/gpio_nrfx.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include <zephyr/drivers/gpio.h>
#include <zephyr/dt-bindings/gpio/nordic-nrf-gpio.h>
#include <zephyr/irq.h>
#include <zephyr/pm/device.h>
#include <zephyr/pm/device_runtime.h>

#include <zephyr/drivers/gpio/gpio_utils.h>

Expand Down Expand Up @@ -62,53 +64,37 @@ 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)
static void 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) {
nrf_gpio_port_retain_enable(cfg->port, mask);
}

ret = nrf_gpd_release(NRF_GPD_FAST_ACTIVE1);
if (ret < 0) {
return ret;
}
if (cfg->pad_pd != NRF_GPD_FAST_ACTIVE1 || !(flags & GPIO_OUTPUT)) {
return;
}

nrf_gpio_port_retain_enable(cfg->port, mask);
#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)
static void 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;
}

nrf_gpio_port_retain_disable(cfg->port, mask);
if (cfg->pad_pd != NRF_GPD_FAST_ACTIVE1) {
return;
}

nrf_gpio_port_retain_disable(cfg->port, 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,
Expand Down Expand Up @@ -152,11 +138,13 @@ 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));
ret = pm_device_runtime_get(port);
if (ret < 0) {
return ret;
}

gpio_nrfx_gpd_retain_clear(port, BIT(pin));

if (flags & GPIO_OUTPUT_INIT_HIGH) {
nrf_gpio_port_out_set(cfg->port, BIT(pin));
} else if (flags & GPIO_OUTPUT_INIT_LOW) {
Expand Down Expand Up @@ -237,8 +225,8 @@ static int gpio_nrfx_pin_configure(const struct device *port, gpio_pin_t pin,
}

end:
(void)gpio_nrfx_gpd_retain_set(port, BIT(pin), flags);
return ret;
gpio_nrfx_gpd_retain_set(port, BIT(pin), flags);
return pm_device_runtime_put(port);
}

#ifdef CONFIG_GPIO_GET_CONFIG
Expand Down Expand Up @@ -328,15 +316,16 @@ static int gpio_nrfx_port_set_masked_raw(const struct device *port,
const uint32_t set_mask = value & mask;
const uint32_t clear_mask = (~set_mask) & mask;

ret = gpio_nrfx_gpd_retain_clear(port, mask);
ret = pm_device_runtime_get(port);
if (ret < 0) {
return ret;
}

gpio_nrfx_gpd_retain_clear(port, mask);
nrf_gpio_port_out_set(reg, set_mask);
nrf_gpio_port_out_clear(reg, clear_mask);

return gpio_nrfx_gpd_retain_set(port, mask, GPIO_OUTPUT);
gpio_nrfx_gpd_retain_set(port, mask, GPIO_OUTPUT);
return pm_device_runtime_put(port);
}

static int gpio_nrfx_port_set_bits_raw(const struct device *port,
Expand All @@ -345,14 +334,15 @@ static int gpio_nrfx_port_set_bits_raw(const struct device *port,
NRF_GPIO_Type *reg = get_port_cfg(port)->port;
int ret;

ret = gpio_nrfx_gpd_retain_clear(port, mask);
ret = pm_device_runtime_get(port);
if (ret < 0) {
return ret;
}

gpio_nrfx_gpd_retain_clear(port, mask);
nrf_gpio_port_out_set(reg, mask);

return gpio_nrfx_gpd_retain_set(port, mask, GPIO_OUTPUT);
gpio_nrfx_gpd_retain_set(port, mask, GPIO_OUTPUT);
return pm_device_runtime_put(port);
}

static int gpio_nrfx_port_clear_bits_raw(const struct device *port,
Expand All @@ -361,14 +351,15 @@ static int gpio_nrfx_port_clear_bits_raw(const struct device *port,
NRF_GPIO_Type *reg = get_port_cfg(port)->port;
int ret;

ret = gpio_nrfx_gpd_retain_clear(port, mask);
ret = pm_device_runtime_get(port);
if (ret < 0) {
return ret;
}

gpio_nrfx_gpd_retain_clear(port, mask);
nrf_gpio_port_out_clear(reg, mask);

return gpio_nrfx_gpd_retain_set(port, mask, GPIO_OUTPUT);
gpio_nrfx_gpd_retain_set(port, mask, GPIO_OUTPUT);
return pm_device_runtime_put(port);
}

static int gpio_nrfx_port_toggle_bits(const struct device *port,
Expand All @@ -380,15 +371,16 @@ static int gpio_nrfx_port_toggle_bits(const struct device *port,
const uint32_t clear_mask = (~value) & mask;
int ret;

ret = gpio_nrfx_gpd_retain_clear(port, mask);
ret = pm_device_runtime_get(port);
if (ret < 0) {
return ret;
}

gpio_nrfx_gpd_retain_clear(port, mask);
nrf_gpio_port_out_set(reg, set_mask);
nrf_gpio_port_out_clear(reg, clear_mask);

return gpio_nrfx_gpd_retain_set(port, mask, GPIO_OUTPUT);
gpio_nrfx_gpd_retain_set(port, mask, GPIO_OUTPUT);
return pm_device_runtime_put(port);
}

#ifdef CONFIG_GPIO_NRFX_INTERRUPT
Expand Down Expand Up @@ -547,17 +539,68 @@ static void nrfx_gpio_handler(nrfx_gpiote_pin_t abs_pin,
IRQ_CONNECT(DT_IRQN(node_id), DT_IRQ(node_id, priority), nrfx_isr, \
NRFX_CONCAT(nrfx_gpiote_, DT_PROP(node_id, instance), _irq_handler), 0);

static int gpio_nrfx_pm_suspend(const struct device *port)
{
#ifdef CONFIG_SOC_NRF54H20_GPD
const struct gpio_nrfx_cfg *cfg = get_port_cfg(port);

if (cfg->pad_pd != NRF_GPD_FAST_ACTIVE1) {
return 0;
}

return nrf_gpd_release(NRF_GPD_FAST_ACTIVE1);
#else
ARG_UNUSED(port);
return 0;
#endif
}

static int gpio_nrfx_pm_resume(const struct device *port)
{
#ifdef CONFIG_SOC_NRF54H20_GPD
const struct gpio_nrfx_cfg *cfg = get_port_cfg(port);

if (cfg->pad_pd != NRF_GPD_FAST_ACTIVE1) {
return 0;
}

return nrf_gpd_request(NRF_GPD_FAST_ACTIVE1);
#else
ARG_UNUSED(port);
return 0;
#endif
}

static int gpio_nrfx_pm_hook(const struct device *port, enum pm_device_action action)
{
int ret;

switch (action) {
case PM_DEVICE_ACTION_SUSPEND:
ret = gpio_nrfx_pm_suspend(port);
break;
case PM_DEVICE_ACTION_RESUME:
ret = gpio_nrfx_pm_resume(port);
break;
default:
ret = -ENOTSUP;
break;
}

return ret;
}

static int gpio_nrfx_init(const struct device *port)
{
const struct gpio_nrfx_cfg *cfg = get_port_cfg(port);
nrfx_err_t err;

if (!has_gpiote(cfg)) {
return 0;
goto pm_init;
}

if (nrfx_gpiote_init_check(&cfg->gpiote)) {
return 0;
goto pm_init;
}

err = nrfx_gpiote_init(&cfg->gpiote, 0 /*not used*/);
Expand All @@ -570,7 +613,8 @@ static int gpio_nrfx_init(const struct device *port)
DT_FOREACH_STATUS_OKAY(nordic_nrf_gpiote, GPIOTE_IRQ_HANDLER_CONNECT);
#endif /* CONFIG_GPIO_NRFX_INTERRUPT */

return 0;
pm_init:
return pm_device_driver_init(port, gpio_nrfx_pm_hook);
}

static DEVICE_API(gpio, gpio_nrfx_drv_api_funcs) = {
Expand Down Expand Up @@ -635,8 +679,10 @@ static DEVICE_API(gpio, gpio_nrfx_drv_api_funcs) = {
\
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, \
NULL, \
PM_DEVICE_DT_INST_GET(id), \
&gpio_nrfx_p##id##_data, \
&gpio_nrfx_p##id##_cfg, \
PRE_KERNEL_1, \
Expand Down
40 changes: 40 additions & 0 deletions drivers/spi/spi_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/kernel.h>
#include <zephyr/pm/device_runtime.h>

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -274,6 +275,45 @@ static inline int spi_context_cs_configure_all(struct spi_context *ctx)
return 0;
}

/* Helper function to power manage the GPIO CS pins, not meant to be used directly by drivers */
static inline int _spi_context_cs_pm_all(struct spi_context *ctx, bool get)
{
const struct gpio_dt_spec *cs_gpio;
int ret;

for (cs_gpio = ctx->cs_gpios; cs_gpio < &ctx->cs_gpios[ctx->num_cs_gpios]; cs_gpio++) {
if (get) {
ret = pm_device_runtime_get(cs_gpio->port);
} else {
ret = pm_device_runtime_put(cs_gpio->port);
}

if (ret < 0) {
return ret;
}
}

return 0;
}

/* This function should be called by drivers to pm get all the chip select lines in
* master mode in the case of any CS being a GPIO. This should be called from the
* drivers pm action hook on pm resume.
*/
static inline int spi_context_cs_get_all(struct spi_context *ctx)
{
return _spi_context_cs_pm_all(ctx, true);
}

/* This function should be called by drivers to pm put all the chip select lines in
* master mode in the case of any CS being a GPIO. This should be called from the
* drivers pm action hook on pm suspend.
*/
static inline int spi_context_cs_put_all(struct spi_context *ctx)
{
return _spi_context_cs_pm_all(ctx, false);
}

/* Helper function to control the GPIO CS, not meant to be used directly by drivers */
static inline void _spi_context_cs_control(struct spi_context *ctx,
bool on, bool force_off)
Expand Down
16 changes: 13 additions & 3 deletions drivers/spi/spi_nrfx_spim.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,12 @@ static inline void finalize_spi_transaction(const struct device *dev, bool deact
void *reg = dev_config->spim.p_reg;

if (deactivate_cs) {
/*
* We may suspend SPI only if we don't have to keep CS asserted, as we
* need to keep the CS GPIO port resumed until spi_release() in this case.
*/
spi_context_cs_control(&dev_data->ctx, false);
pm_device_runtime_put_async(dev, K_NO_WAIT);
}

if (NRF_SPIM_IS_320MHZ_SPIM(reg) && !(dev_data->ctx.config->operation & SPI_HOLD_ON_CS)) {
Expand All @@ -163,8 +168,6 @@ static inline void finalize_spi_transaction(const struct device *dev, bool deact
if (!IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) {
release_clock(dev);
}

pm_device_runtime_put_async(dev, K_NO_WAIT);
}

static inline uint32_t get_nrf_spim_frequency(uint32_t frequency)
Expand Down Expand Up @@ -402,7 +405,7 @@ static void finish_transaction(const struct device *dev, int error)
spi_context_complete(ctx, dev, error);
dev_data->busy = false;

finalize_spi_transaction(dev, true);
finalize_spi_transaction(dev, (dev_data->ctx.config->operation & SPI_HOLD_ON_CS) > 0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes related to pm_device_runtime_put_async() should be done in a separate commit, with some explanation in the commit message.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deal, I already forgot exactly why it was moved here :D

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved to separate commit and added comment to driver

}

static void transfer_next_chunk(const struct device *dev)
Expand Down Expand Up @@ -661,12 +664,17 @@ static DEVICE_API(spi, spi_nrfx_driver_api) = {
static int spim_resume(const struct device *dev)
{
const struct spi_nrfx_config *dev_config = dev->config;
struct spi_nrfx_data *dev_data = dev->data;

(void)pinctrl_apply_state(dev_config->pcfg, PINCTRL_STATE_DEFAULT);
/* nrfx_spim_init() will be called at configuration before
* the next transfer.
*/

if (spi_context_cs_get_all(&dev_data->ctx)) {
return -EAGAIN;
}

#ifdef CONFIG_SOC_NRF54H20_GPD
nrf_gpd_retain_pins_set(dev_config->pcfg, false);
#endif
Expand All @@ -688,6 +696,8 @@ static void spim_suspend(const struct device *dev)
release_clock(dev);
}

spi_context_cs_put_all(&dev_data->ctx);

#ifdef CONFIG_SOC_NRF54H20_GPD
nrf_gpd_retain_pins_set(dev_config->pcfg, true);
#endif
Expand Down
Loading