Skip to content

Commit 06d88a4

Browse files
drivers: pwm: nrfx: add global hsfll request for fast PWM
Added clock control api for global hsfll used in fast PWM120 driver. Signed-off-by: Michał Stasiak <[email protected]>
1 parent be25c94 commit 06d88a4

File tree

1 file changed

+110
-13
lines changed

1 file changed

+110
-13
lines changed

drivers/pwm/pwm_nrfx.c

Lines changed: 110 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <zephyr/linker/devicetree_regions.h>
1414
#include <zephyr/cache.h>
1515
#include <zephyr/mem_mgmt/mem_attr.h>
16+
#include <zephyr/drivers/clock_control/nrf_clock_control.h>
1617
#ifdef CONFIG_SOC_NRF54H20_GPD
1718
#include <nrf/gpd.h>
1819
#endif
@@ -35,6 +36,21 @@ LOG_MODULE_REGISTER(pwm_nrfx, CONFIG_PWM_LOG_LEVEL);
3536
#define ANOMALY_109_EGU_IRQ_CONNECT(idx)
3637
#endif
3738

39+
#define PWM(dev_idx) DT_NODELABEL(pwm##dev_idx)
40+
#define PWM_PROP(dev_idx, prop) DT_PROP(PWM(dev_idx), prop)
41+
#define PWM_HAS_PROP(idx, prop) DT_NODE_HAS_PROP(PWM(idx), prop)
42+
43+
#define PWM_NRFX_IS_FAST(unused, prefix, idx, _) \
44+
COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(PWM(idx)), \
45+
(COND_CODE_1(PWM_HAS_PROP(idx, power_domains), \
46+
(IS_EQ(DT_PHA(PWM(idx), power_domains, id), NRF_GPD_FAST_ACTIVE1)), \
47+
(0))), (0))
48+
49+
#if (NRFX_FOREACH_PRESENT(PWM, PWM_NRFX_IS_FAST, (||), (0))) && \
50+
CONFIG_CLOCK_CONTROL_NRF2_GLOBAL_HSFLL
51+
#define PWM_NRFX_USE_CLOCK_CONTROL 1
52+
#endif
53+
3854
#define PWM_NRFX_CH_POLARITY_MASK BIT(15)
3955
#define PWM_NRFX_CH_COMPARE_MASK BIT_MASK(15)
4056
#define PWM_NRFX_CH_VALUE(compare_value, inverted) \
@@ -49,6 +65,10 @@ struct pwm_nrfx_config {
4965
#ifdef CONFIG_DCACHE
5066
uint32_t mem_attr;
5167
#endif
68+
#ifdef PWM_NRFX_USE_CLOCK_CONTROL
69+
const struct device *clk_dev;
70+
struct nrf_clock_spec clk_spec;
71+
#endif
5272
};
5373

5474
struct pwm_nrfx_data {
@@ -57,6 +77,9 @@ struct pwm_nrfx_data {
5777
uint8_t pwm_needed;
5878
uint8_t prescaler;
5979
bool stop_requested;
80+
#ifdef PWM_NRFX_USE_CLOCK_CONTROL
81+
bool clock_requested;
82+
#endif
6083
};
6184
/* Ensure the pwm_needed bit mask can accommodate all available channels. */
6285
#if (NRF_PWM_CHANNEL_COUNT > 8)
@@ -134,6 +157,33 @@ static bool channel_psel_get(uint32_t channel, uint32_t *psel,
134157
== PWM_PSEL_OUT_CONNECT_Connected);
135158
}
136159

160+
static int stop_pwm(const struct device *dev)
161+
{
162+
const struct pwm_nrfx_config *config = dev->config;
163+
164+
/* Don't wait here for the peripheral to actually stop. Instead,
165+
* ensure it is stopped before starting the next playback.
166+
*/
167+
nrfx_pwm_stop(&config->pwm, false);
168+
169+
#if PWM_NRFX_USE_CLOCK_CONTROL
170+
struct pwm_nrfx_data *data = dev->data;
171+
172+
if (data->clock_requested) {
173+
int ret = nrf_clock_control_release(config->clk_dev, &config->clk_spec);
174+
175+
if (ret < 0) {
176+
LOG_ERR("Global HSFLL release failed: %d", ret);
177+
return ret;
178+
}
179+
180+
data->clock_requested = false;
181+
}
182+
#endif
183+
184+
return 0;
185+
}
186+
137187
static int pwm_nrfx_set_cycles(const struct device *dev, uint32_t channel,
138188
uint32_t period_cycles, uint32_t pulse_cycles,
139189
pwm_flags_t flags)
@@ -225,10 +275,13 @@ static int pwm_nrfx_set_cycles(const struct device *dev, uint32_t channel,
225275
* registers and drives its outputs accordingly.
226276
*/
227277
if (data->pwm_needed == 0) {
228-
/* Don't wait here for the peripheral to actually stop. Instead,
229-
* ensure it is stopped before starting the next playback.
230-
*/
231-
nrfx_pwm_stop(&config->pwm, false);
278+
int ret = stop_pwm(dev);
279+
280+
if (ret < 0) {
281+
LOG_ERR("PWM stop failed: %d", ret);
282+
return ret;
283+
}
284+
232285
data->stop_requested = true;
233286
} else {
234287
if (data->stop_requested) {
@@ -248,6 +301,20 @@ static int pwm_nrfx_set_cycles(const struct device *dev, uint32_t channel,
248301
* until another playback is requested (new values will be
249302
* loaded then) or the PWM peripheral is stopped.
250303
*/
304+
#if PWM_NRFX_USE_CLOCK_CONTROL
305+
if (config->clk_dev && !data->clock_requested) {
306+
int ret = nrf_clock_control_request_sync(config->clk_dev,
307+
&config->clk_spec,
308+
K_FOREVER);
309+
310+
if (ret < 0) {
311+
LOG_ERR("Global HSFLL request failed: %d", ret);
312+
return ret;
313+
}
314+
315+
data->clock_requested = true;
316+
}
317+
#endif
251318
nrfx_pwm_simple_playback(&config->pwm, &config->seq, 1,
252319
NRFX_PWM_FLAG_NO_EVT_FINISHED);
253320
}
@@ -270,7 +337,7 @@ static DEVICE_API(pwm, pwm_nrfx_drv_api_funcs) = {
270337
.get_cycles_per_sec = pwm_nrfx_get_cycles_per_sec,
271338
};
272339

273-
static void pwm_resume(const struct device *dev)
340+
static int pwm_resume(const struct device *dev)
274341
{
275342
const struct pwm_nrfx_config *config = dev->config;
276343
uint8_t initially_inverted = 0;
@@ -299,13 +366,21 @@ static void pwm_resume(const struct device *dev)
299366

300367
seq_values_ptr_get(dev)[i] = PWM_NRFX_CH_VALUE(0, inverted);
301368
}
369+
370+
return 0;
302371
}
303372

304-
static void pwm_suspend(const struct device *dev)
373+
static int pwm_suspend(const struct device *dev)
305374
{
306375
const struct pwm_nrfx_config *config = dev->config;
307376

308-
nrfx_pwm_stop(&config->pwm, false);
377+
int ret = stop_pwm(dev);
378+
379+
if (ret < 0) {
380+
LOG_ERR("PWM stop failed: %d", ret);
381+
return ret;
382+
}
383+
309384
while (!nrfx_pwm_stopped_check(&config->pwm)) {
310385
}
311386

@@ -315,15 +390,17 @@ static void pwm_suspend(const struct device *dev)
315390

316391
memset(dev->data, 0, sizeof(struct pwm_nrfx_data));
317392
(void)pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP);
393+
394+
return 0;
318395
}
319396

320397
static int pwm_nrfx_pm_action(const struct device *dev,
321398
enum pm_device_action action)
322399
{
323400
if (action == PM_DEVICE_ACTION_RESUME) {
324-
pwm_resume(dev);
401+
return pwm_resume(dev);
325402
} else if (IS_ENABLED(CONFIG_PM_DEVICE) && (action == PM_DEVICE_ACTION_SUSPEND)) {
326-
pwm_suspend(dev);
403+
return pwm_suspend(dev);
327404
} else {
328405
return -ENOTSUP;
329406
}
@@ -351,9 +428,6 @@ static int pwm_nrfx_init(const struct device *dev)
351428
return pm_device_driver_init(dev, pwm_nrfx_pm_action);
352429
}
353430

354-
#define PWM(dev_idx) DT_NODELABEL(pwm##dev_idx)
355-
#define PWM_PROP(dev_idx, prop) DT_PROP(PWM(dev_idx), prop)
356-
#define PWM_HAS_PROP(idx, prop) DT_NODE_HAS_PROP(PWM(idx), prop)
357431
#define PWM_MEM_REGION(idx) DT_PHANDLE(PWM(idx), memory_regions)
358432

359433
#define PWM_MEMORY_SECTION(idx) \
@@ -366,6 +440,21 @@ static int pwm_nrfx_init(const struct device *dev)
366440
COND_CODE_1(PWM_HAS_PROP(idx, memory_regions), \
367441
(DT_PROP_OR(PWM_MEM_REGION(idx), zephyr_memory_attr, 0)), (0))
368442

443+
/* Fast instances depend on the global HSFLL clock controller (as they need
444+
* to request the highest frequency from it to operate correctly), so they
445+
* must be initialized after that controller driver, hence the default PWM
446+
* initialization priority may be too early for them.
447+
*/
448+
#if defined(CONFIG_CLOCK_CONTROL_NRF2_GLOBAL_HSFLL_INIT_PRIORITY) && \
449+
CONFIG_PWM_INIT_PRIORITY < CONFIG_CLOCK_CONTROL_NRF2_GLOBAL_HSFLL_INIT_PRIORITY
450+
#define PWM_INIT_PRIORITY(idx) \
451+
COND_CODE_1(PWM_NRFX_IS_FAST(_, /*empty*/, idx, _), \
452+
(UTIL_INC(CONFIG_CLOCK_CONTROL_NRF2_GLOBAL_HSFLL_INIT_PRIORITY)), \
453+
(CONFIG_PWM_INIT_PRIORITY))
454+
#else
455+
#define PWM_INIT_PRIORITY(idx) CONFIG_PWM_INIT_PRIORITY
456+
#endif
457+
369458
#define PWM_NRFX_DEVICE(idx) \
370459
NRF_DT_CHECK_NODE_HAS_PINCTRL_SLEEP(PWM(idx)); \
371460
static struct pwm_nrfx_data pwm_nrfx_##idx##_data; \
@@ -393,6 +482,14 @@ static int pwm_nrfx_init(const struct device *dev)
393482
(16ul * 1000ul * 1000ul)), \
394483
IF_ENABLED(CONFIG_DCACHE, \
395484
(.mem_attr = PWM_GET_MEM_ATTR(idx),)) \
485+
IF_ENABLED(PWM_NRFX_USE_CLOCK_CONTROL, \
486+
(.clk_dev = PWM_NRFX_IS_FAST(_, /*empty*/, idx, _) \
487+
? DEVICE_DT_GET(DT_CLOCKS_CTLR(PWM(idx))) \
488+
: NULL, \
489+
.clk_spec = { \
490+
.frequency = \
491+
NRF_PERIPH_GET_FREQUENCY(PWM(idx)), \
492+
},)) \
396493
}; \
397494
static int pwm_nrfx_init##idx(const struct device *dev) \
398495
{ \
@@ -405,7 +502,7 @@ static int pwm_nrfx_init(const struct device *dev)
405502
pwm_nrfx_init##idx, PM_DEVICE_DT_GET(PWM(idx)), \
406503
&pwm_nrfx_##idx##_data, \
407504
&pwm_nrfx_##idx##_config, \
408-
POST_KERNEL, CONFIG_PWM_INIT_PRIORITY, \
505+
POST_KERNEL, PWM_INIT_PRIORITY(idx), \
409506
&pwm_nrfx_drv_api_funcs)
410507

411508
#define COND_PWM_NRFX_DEVICE(unused, prefix, i, _) \

0 commit comments

Comments
 (0)