Skip to content

Commit a9a0b33

Browse files
committed
[nrf fromlist] drivers: pwm: nrfx: Disable PWM peripheral when not used
Shim was not correctly disabling PWM when it was not used. Task STOP was triggered but PWM->ENABLE remained set which caused increased current. Added interrupt and enabled event handler in the nrfx driver to allow disabling PWM on STOPPED event. Upstream PR: zephyrproject-rtos/zephyr#78759 Signed-off-by: Krzysztof Chruściński <[email protected]>
1 parent 188aece commit a9a0b33

File tree

1 file changed

+28
-23
lines changed

1 file changed

+28
-23
lines changed

drivers/pwm/pwm_nrfx.c

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,13 @@ LOG_MODULE_REGISTER(pwm_nrfx, CONFIG_PWM_LOG_LEVEL);
2020
* to 0 or 1, hence the use of #if IS_ENABLED().
2121
*/
2222
#if IS_ENABLED(NRFX_PWM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
23-
#define ANOMALY_109_IRQ_CONNECT(...) IRQ_CONNECT(__VA_ARGS__)
2423
#define ANOMALY_109_EGU_IRQ_CONNECT(idx) _EGU_IRQ_CONNECT(idx)
2524
#define _EGU_IRQ_CONNECT(idx) \
2625
extern void nrfx_egu_##idx##_irq_handler(void); \
2726
IRQ_CONNECT(DT_IRQN(DT_NODELABEL(egu##idx)), \
2827
DT_IRQ(DT_NODELABEL(egu##idx), priority), \
2928
nrfx_isr, nrfx_egu_##idx##_irq_handler, 0)
3029
#else
31-
#define ANOMALY_109_IRQ_CONNECT(...)
3230
#define ANOMALY_109_EGU_IRQ_CONNECT(idx)
3331
#endif
3432

@@ -49,7 +47,8 @@ struct pwm_nrfx_data {
4947
/* Bit mask indicating channels that need the PWM generation. */
5048
uint8_t pwm_needed;
5149
uint8_t prescaler;
52-
bool stop_requested;
50+
volatile bool stop_requested;
51+
volatile bool active;
5352
};
5453
/* Ensure the pwm_needed bit mask can accommodate all available channels. */
5554
#if (NRF_PWM_CHANNEL_COUNT > 8)
@@ -63,6 +62,15 @@ static uint16_t *seq_values_ptr_get(const struct device *dev)
6362
return (uint16_t *)config->seq.values.p_raw;
6463
}
6564

65+
static void pwm_handler(nrfx_pwm_evt_type_t event_type, void *p_context)
66+
{
67+
__ASSERT_NO_MSG(event_type == NRFX_PWM_EVT_STOPPED);
68+
struct pwm_nrfx_data *data = p_context;
69+
70+
data->stop_requested = false;
71+
data->active = false;
72+
}
73+
6674
static bool pwm_period_check_and_set(const struct device *dev,
6775
uint32_t channel, uint32_t period_cycles)
6876
{
@@ -209,27 +217,27 @@ static int pwm_nrfx_set_cycles(const struct device *dev, uint32_t channel,
209217
/* Don't wait here for the peripheral to actually stop. Instead,
210218
* ensure it is stopped before starting the next playback.
211219
*/
212-
nrfx_pwm_stop(&config->pwm, false);
213-
data->stop_requested = true;
220+
if (data->active && !data->stop_requested) {
221+
data->stop_requested = true;
222+
nrfx_pwm_stop(&config->pwm, false);
223+
}
214224
} else {
215-
if (data->stop_requested) {
216-
data->stop_requested = false;
217-
218-
/* After a stop is requested, the PWM peripheral stops
219-
* pulse generation at the end of the current period,
220-
* and till that moment, it ignores any start requests,
221-
* so ensure here that it is stopped.
222-
*/
223-
while (!nrfx_pwm_stopped_check(&config->pwm)) {
224-
}
225+
/* After a stop is requested, the PWM peripheral stops
226+
* pulse generation at the end of the current period,
227+
* and till that moment, it ignores any start requests,
228+
* so ensure here that it is stopped.
229+
*/
230+
while (data->stop_requested) {
225231
}
226232

227233
/* It is sufficient to play the sequence once without looping.
228234
* The PWM generation will continue with the loaded values
229235
* until another playback is requested (new values will be
230236
* loaded then) or the PWM peripheral is stopped.
231237
*/
232-
nrfx_pwm_simple_playback(&config->pwm, &config->seq, 1, 0);
238+
data->active = true;
239+
nrfx_pwm_simple_playback(&config->pwm, &config->seq, 1,
240+
NRFX_PWM_FLAG_NO_EVT_FINISHED);
233241
}
234242

235243
return 0;
@@ -256,6 +264,7 @@ static int pwm_nrfx_init(const struct device *dev)
256264
{
257265
const struct pwm_nrfx_config *config = dev->config;
258266
uint8_t initially_inverted = 0;
267+
nrfx_err_t result;
259268

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

@@ -284,10 +293,7 @@ static int pwm_nrfx_init(const struct device *dev)
284293
seq_values_ptr_get(dev)[i] = PWM_NRFX_CH_VALUE(0, inverted);
285294
}
286295

287-
nrfx_err_t result = nrfx_pwm_init(&config->pwm,
288-
&config->initial_config,
289-
NULL,
290-
NULL);
296+
result = nrfx_pwm_init(&config->pwm, &config->initial_config, pwm_handler, dev->data);
291297
if (result != NRFX_SUCCESS) {
292298
LOG_ERR("Failed to initialize device: %s", dev->name);
293299
return -EBUSY;
@@ -377,9 +383,8 @@ static int pwm_nrfx_pm_action(const struct device *dev,
377383
}; \
378384
static int pwm_nrfx_init##idx(const struct device *dev) \
379385
{ \
380-
ANOMALY_109_IRQ_CONNECT( \
381-
DT_IRQN(PWM(idx)), DT_IRQ(PWM(idx), priority), \
382-
nrfx_isr, nrfx_pwm_##idx##_irq_handler, 0); \
386+
IRQ_CONNECT(DT_IRQN(PWM(idx)), DT_IRQ(PWM(idx), priority), \
387+
nrfx_isr, nrfx_pwm_##idx##_irq_handler, 0); \
383388
return pwm_nrfx_init(dev); \
384389
}; \
385390
PM_DEVICE_DT_DEFINE(PWM(idx), pwm_nrfx_pm_action); \

0 commit comments

Comments
 (0)