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
5474struct 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+
137187static 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
320397static 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