Skip to content

Commit

Permalink
drivers: pwm: nrfx: Improve runtime PM
Browse files Browse the repository at this point in the history
Rework PM handling to use pm_device_driver_init(). Shim is not using
put and get internally as there is no api that disables or stops
pwm so it is hard to determine when to put the device. There are cases
when PWM peripheral is stopped but PWM is still active because
duty cycle is 100% or 0% and pin is driven by GPIO and not PWM.

If user want to use runtime PM with PWM it is possible and getting
the device will initialize internal data and putting will suspend
by forcing PWM stop if used and setting pins to sleep state. However,
from power consumption perspective it is enough to set 0% or 100%
duty cycle on all channels.

Signed-off-by: Krzysztof Chruściński <[email protected]>
  • Loading branch information
nordic-krch committed Oct 1, 2024
1 parent 0aafdd5 commit 31c5043
Showing 1 changed file with 42 additions and 34 deletions.
76 changes: 42 additions & 34 deletions drivers/pwm/pwm_nrfx.c
Original file line number Diff line number Diff line change
Expand Up @@ -262,16 +262,13 @@ static const struct pwm_driver_api pwm_nrfx_drv_api_funcs = {
.get_cycles_per_sec = pwm_nrfx_get_cycles_per_sec,
};

static int pwm_nrfx_init(const struct device *dev)
static int pwm_resume(const struct device *dev)
{
const struct pwm_nrfx_config *config = dev->config;
uint8_t initially_inverted = 0;
nrfx_err_t result;

int ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);

ANOMALY_109_EGU_IRQ_CONNECT(NRFX_PWM_NRF52_ANOMALY_109_EGU_INSTANCE);

if (ret < 0) {
return ret;
}
Expand All @@ -295,60 +292,69 @@ static int pwm_nrfx_init(const struct device *dev)
seq_values_ptr_get(dev)[i] = PWM_NRFX_CH_VALUE(0, inverted);
}

result = nrfx_pwm_init(&config->pwm, &config->initial_config, pwm_handler, dev->data);
if (result != NRFX_SUCCESS) {
LOG_ERR("Failed to initialize device: %s", dev->name);
return -EBUSY;
}

return 0;
}

#ifdef CONFIG_PM_DEVICE
static void pwm_nrfx_uninit(const struct device *dev)
static int pwm_suspend(const struct device *dev, bool do_pinctrl)
{
const struct pwm_nrfx_config *config = dev->config;
struct pwm_nrfx_data *data = dev->data;

nrfx_pwm_uninit(&config->pwm);
if (data->active) {
/* PWM is still in use. Force stopping. */
data->stop_requested = true;
nrfx_pwm_stop(&config->pwm, false);
while (data->stop_requested) {
}
}

memset(dev->data, 0, sizeof(struct pwm_nrfx_data));

if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) {
return pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP);
}

return 0;
}

static int pwm_nrfx_pm_action(const struct device *dev,
enum pm_device_action action)
{
const struct pwm_nrfx_config *config = dev->config;
int ret = 0;
int ret = -ENOTSUP;

switch (action) {
case PM_DEVICE_ACTION_RESUME:
ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
if (ret < 0) {
return ret;
}
ret = pwm_nrfx_init(dev);
break;

case PM_DEVICE_ACTION_SUSPEND:
pwm_nrfx_uninit(dev);

ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP);
if (ret < 0) {
return ret;
}
ret = pwm_suspend(dev, true);
break;
case PM_DEVICE_ACTION_RESUME:
ret = pwm_resume(dev);
break;

default:
return -ENOTSUP;
break;
}

return ret;
}
#else

#define pwm_nrfx_pm_action NULL
static int pwm_nrfx_init(const struct device *dev)
{
const struct pwm_nrfx_config *config = dev->config;
nrfx_err_t err;
int ret;

err = nrfx_pwm_init(&config->pwm, &config->initial_config, pwm_handler, dev->data);
if (err != NRFX_SUCCESS) {
LOG_ERR("Failed to initialize device: %s", dev->name);
return -EBUSY;
}

#endif /* CONFIG_PM_DEVICE */
ret = pwm_suspend(dev);
if (ret != 0) {
return ret;
}

return pm_device_driver_init(dev, pwm_nrfx_pm_action);
}

#define PWM(dev_idx) DT_NODELABEL(pwm##dev_idx)
#define PWM_PROP(dev_idx, prop) DT_PROP(PWM(dev_idx), prop)
Expand Down Expand Up @@ -387,6 +393,8 @@ static int pwm_nrfx_pm_action(const struct device *dev,
{ \
IRQ_CONNECT(DT_IRQN(PWM(idx)), DT_IRQ(PWM(idx), priority), \
nrfx_isr, nrfx_pwm_##idx##_irq_handler, 0); \
ANOMALY_109_EGU_IRQ_CONNECT( \
NRFX_PWM_NRF52_ANOMALY_109_EGU_INSTANCE); \
return pwm_nrfx_init(dev); \
}; \
PM_DEVICE_DT_DEFINE(PWM(idx), pwm_nrfx_pm_action); \
Expand Down

0 comments on commit 31c5043

Please sign in to comment.