drivers: pwm: nrfx: Improve runtime PM

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>
This commit is contained in:
Krzysztof Chruściński 2024-09-20 13:17:19 +02:00 committed by Anas Nashif
parent c3a33cfd3e
commit e11d050b23

View file

@ -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;
@ -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;
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;
}
break;
default:
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;
}
return ret;
return 0;
}
#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;
#endif /* CONFIG_PM_DEVICE */
ANOMALY_109_EGU_IRQ_CONNECT(NRFX_PWM_NRF52_ANOMALY_109_EGU_INSTANCE);
if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) {
(void)pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP);
}
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;
}
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)