Skip to content

Commit

Permalink
[nrf fromtree] 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 <krzysztof.chruscinski@nordicsemi.no>
(cherry picked from commit e11d050)
  • Loading branch information
nordic-krch committed Oct 21, 2024
1 parent e578365 commit b432b61
Showing 1 changed file with 30 additions and 45 deletions.
75 changes: 30 additions & 45 deletions drivers/pwm/pwm_nrfx.c
Original file line number Diff line number Diff line change
Expand Up @@ -257,19 +257,12 @@ 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 void 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;
}
(void)pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);

for (size_t i = 0; i < NRF_PWM_CHANNEL_COUNT; i++) {
uint32_t psel;
Expand All @@ -289,61 +282,53 @@ 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 void pwm_suspend(const struct device *dev)
{
const struct pwm_nrfx_config *config = dev->config;

nrfx_pwm_uninit(&config->pwm);
nrfx_pwm_stop(&config->pwm, false);
while (!nrfx_pwm_stopped_check(&config->pwm)) {
}

memset(dev->data, 0, sizeof(struct pwm_nrfx_data));
(void)pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP);
}

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;
if (action == PM_DEVICE_ACTION_RESUME) {
pwm_resume(dev);
} else if (IS_ENABLED(CONFIG_PM_DEVICE) && (action == PM_DEVICE_ACTION_SUSPEND)) {
pwm_suspend(dev);
} else {
return -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;
return 0;
}

case PM_DEVICE_ACTION_SUSPEND:
pwm_nrfx_uninit(dev);
static int pwm_nrfx_init(const struct device *dev)
{
const struct pwm_nrfx_config *config = dev->config;
nrfx_err_t err;

ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP);
if (ret < 0) {
return ret;
}
break;
ANOMALY_109_EGU_IRQ_CONNECT(NRFX_PWM_NRF52_ANOMALY_109_EGU_INSTANCE);

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

return ret;
}
#else

#define pwm_nrfx_pm_action NULL
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 */
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

0 comments on commit b432b61

Please sign in to comment.