1 /*
2 * Copyright (c) 2018, Cue Health Inc
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <nrfx_pwm.h>
7 #include <zephyr/drivers/pwm.h>
8 #include <zephyr/pm/device.h>
9 #include <zephyr/drivers/pinctrl.h>
10 #include <soc.h>
11 #include <hal/nrf_gpio.h>
12 #include <stdbool.h>
13 #include <zephyr/linker/devicetree_regions.h>
14 #include <zephyr/cache.h>
15 #include <zephyr/mem_mgmt/mem_attr.h>
16 #include <zephyr/drivers/clock_control/nrf_clock_control.h>
17 #ifdef CONFIG_SOC_NRF54H20_GPD
18 #include <nrf/gpd.h>
19 #endif
20
21 #include <zephyr/logging/log.h>
22
23 LOG_MODULE_REGISTER(pwm_nrfx, CONFIG_PWM_LOG_LEVEL);
24
25 /* NRFX_PWM_NRF52_ANOMALY_109_WORKAROUND_ENABLED can be undefined or defined
26 * to 0 or 1, hence the use of #if IS_ENABLED().
27 */
28 #if IS_ENABLED(NRFX_PWM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
29 #define ANOMALY_109_EGU_IRQ_CONNECT(idx) _EGU_IRQ_CONNECT(idx)
30 #define _EGU_IRQ_CONNECT(idx) \
31 extern void nrfx_egu_##idx##_irq_handler(void); \
32 IRQ_CONNECT(DT_IRQN(DT_NODELABEL(egu##idx)), \
33 DT_IRQ(DT_NODELABEL(egu##idx), priority), \
34 nrfx_isr, nrfx_egu_##idx##_irq_handler, 0)
35 #else
36 #define ANOMALY_109_EGU_IRQ_CONNECT(idx)
37 #endif
38
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 #define PWM_NRFX_FAST_PRESENT 1
51 #endif
52
53 #if defined(PWM_NRFX_FAST_PRESENT) && CONFIG_CLOCK_CONTROL_NRF2_GLOBAL_HSFLL
54 #define PWM_NRFX_USE_CLOCK_CONTROL 1
55 #endif
56
57 #define PWM_NRFX_CH_POLARITY_MASK BIT(15)
58 #define PWM_NRFX_CH_COMPARE_MASK BIT_MASK(15)
59 #define PWM_NRFX_CH_VALUE(compare_value, inverted) \
60 (compare_value | (inverted ? 0 : PWM_NRFX_CH_POLARITY_MASK))
61
62 struct pwm_nrfx_config {
63 nrfx_pwm_t pwm;
64 nrfx_pwm_config_t initial_config;
65 nrf_pwm_sequence_t seq;
66 const struct pinctrl_dev_config *pcfg;
67 uint32_t clock_freq;
68 #ifdef CONFIG_DCACHE
69 uint32_t mem_attr;
70 #endif
71 #ifdef PWM_NRFX_USE_CLOCK_CONTROL
72 const struct device *clk_dev;
73 struct nrf_clock_spec clk_spec;
74 #endif
75 };
76
77 struct pwm_nrfx_data {
78 uint32_t period_cycles;
79 /* Bit mask indicating channels that need the PWM generation. */
80 uint8_t pwm_needed;
81 uint8_t prescaler;
82 bool stop_requested;
83 #ifdef PWM_NRFX_USE_CLOCK_CONTROL
84 bool clock_requested;
85 #endif
86 };
87 /* Ensure the pwm_needed bit mask can accommodate all available channels. */
88 #if (NRF_PWM_CHANNEL_COUNT > 8)
89 #error "Current implementation supports maximum 8 channels."
90 #endif
91
92 #ifdef PWM_NRFX_FAST_PRESENT
pwm_is_fast(const struct pwm_nrfx_config * config)93 static bool pwm_is_fast(const struct pwm_nrfx_config *config)
94 {
95 return config->clock_freq > MHZ(16);
96 }
97 #else
pwm_is_fast(const struct pwm_nrfx_config * config)98 static bool pwm_is_fast(const struct pwm_nrfx_config *config)
99 {
100 return false;
101 }
102 #endif
103
seq_values_ptr_get(const struct device * dev)104 static uint16_t *seq_values_ptr_get(const struct device *dev)
105 {
106 const struct pwm_nrfx_config *config = dev->config;
107
108 return (uint16_t *)config->seq.values.p_raw;
109 }
110
pwm_handler(nrfx_pwm_evt_type_t event_type,void * p_context)111 static void pwm_handler(nrfx_pwm_evt_type_t event_type, void *p_context)
112 {
113 ARG_UNUSED(event_type);
114 ARG_UNUSED(p_context);
115 }
116
pwm_period_check_and_set(const struct device * dev,uint32_t channel,uint32_t period_cycles)117 static bool pwm_period_check_and_set(const struct device *dev,
118 uint32_t channel, uint32_t period_cycles)
119 {
120 const struct pwm_nrfx_config *config = dev->config;
121 struct pwm_nrfx_data *data = dev->data;
122 uint8_t prescaler;
123 uint32_t countertop;
124
125 /* If the currently configured period matches the requested one,
126 * nothing more needs to be done.
127 */
128 if (period_cycles == data->period_cycles) {
129 return true;
130 }
131
132 /* If any other channel is driven by the PWM peripheral, the period
133 * that is currently set cannot be changed, as this would influence
134 * the output for that channel.
135 */
136 if ((data->pwm_needed & ~BIT(channel)) != 0) {
137 LOG_ERR("Incompatible period.");
138 return false;
139 }
140
141 /* Try to find a prescaler that will allow setting the requested period
142 * after prescaling as the countertop value for the PWM peripheral.
143 */
144 prescaler = 0;
145 countertop = period_cycles;
146 do {
147 if (countertop <= PWM_COUNTERTOP_COUNTERTOP_Msk) {
148 data->period_cycles = period_cycles;
149 data->prescaler = prescaler;
150
151 nrf_pwm_configure(config->pwm.p_reg,
152 data->prescaler,
153 config->initial_config.count_mode,
154 (uint16_t)countertop);
155 return true;
156 }
157
158 countertop >>= 1;
159 ++prescaler;
160 } while (prescaler <= PWM_PRESCALER_PRESCALER_Msk);
161
162 LOG_ERR("Prescaler for period_cycles %u not found.", period_cycles);
163 return false;
164 }
165
channel_psel_get(uint32_t channel,uint32_t * psel,const struct pwm_nrfx_config * config)166 static bool channel_psel_get(uint32_t channel, uint32_t *psel,
167 const struct pwm_nrfx_config *config)
168 {
169 *psel = nrf_pwm_pin_get(config->pwm.p_reg, (uint8_t)channel);
170
171 return (((*psel & PWM_PSEL_OUT_CONNECT_Msk) >> PWM_PSEL_OUT_CONNECT_Pos)
172 == PWM_PSEL_OUT_CONNECT_Connected);
173 }
174
stop_pwm(const struct device * dev)175 static int stop_pwm(const struct device *dev)
176 {
177 const struct pwm_nrfx_config *config = dev->config;
178
179 /* Don't wait here for the peripheral to actually stop. Instead,
180 * ensure it is stopped before starting the next playback.
181 */
182 nrfx_pwm_stop(&config->pwm, false);
183
184 #if PWM_NRFX_USE_CLOCK_CONTROL
185 struct pwm_nrfx_data *data = dev->data;
186
187 if (data->clock_requested) {
188 int ret = nrf_clock_control_release(config->clk_dev, &config->clk_spec);
189
190 if (ret < 0) {
191 LOG_ERR("Global HSFLL release failed: %d", ret);
192 return ret;
193 }
194
195 data->clock_requested = false;
196 }
197 #endif
198
199 return 0;
200 }
201
pwm_nrfx_set_cycles(const struct device * dev,uint32_t channel,uint32_t period_cycles,uint32_t pulse_cycles,pwm_flags_t flags)202 static int pwm_nrfx_set_cycles(const struct device *dev, uint32_t channel,
203 uint32_t period_cycles, uint32_t pulse_cycles,
204 pwm_flags_t flags)
205 {
206 /* We assume here that period_cycles will always be 16MHz
207 * peripheral clock. Since pwm_nrfx_get_cycles_per_sec() function might
208 * be removed, see ISSUE #6958.
209 * TODO: Remove this comment when issue has been resolved.
210 */
211 const struct pwm_nrfx_config *config = dev->config;
212 struct pwm_nrfx_data *data = dev->data;
213 uint16_t compare_value;
214 bool inverted = (flags & PWM_POLARITY_INVERTED);
215 bool needs_pwm = false;
216
217 if (channel >= NRF_PWM_CHANNEL_COUNT) {
218 LOG_ERR("Invalid channel: %u.", channel);
219 return -EINVAL;
220 }
221
222 /* If this PWM is in center-aligned mode, pulse and period lengths
223 * are effectively doubled by the up-down count, so halve them here
224 * to compensate.
225 */
226 if (config->initial_config.count_mode == NRF_PWM_MODE_UP_AND_DOWN) {
227 period_cycles /= 2;
228 pulse_cycles /= 2;
229 }
230
231 if (pulse_cycles == 0) {
232 /* Constantly inactive (duty 0%). */
233 compare_value = 0;
234 } else if (pulse_cycles >= period_cycles) {
235 /* Constantly active (duty 100%). */
236 /* This value is always greater than or equal to COUNTERTOP. */
237 compare_value = PWM_NRFX_CH_COMPARE_MASK;
238 } else {
239 /* PWM generation needed. Check if the requested period matches
240 * the one that is currently set, or the PWM peripheral can be
241 * reconfigured accordingly.
242 */
243 if (!pwm_period_check_and_set(dev, channel, period_cycles)) {
244 return -EINVAL;
245 }
246
247 compare_value = (uint16_t)(pulse_cycles >> data->prescaler);
248 needs_pwm = true;
249 }
250
251 seq_values_ptr_get(dev)[channel] = PWM_NRFX_CH_VALUE(compare_value, inverted);
252
253 #ifdef CONFIG_DCACHE
254 if (config->mem_attr & DT_MEM_CACHEABLE) {
255 sys_cache_data_flush_range(seq_values_ptr_get(dev), config->seq.length);
256 }
257 #endif
258
259 LOG_DBG("channel %u, pulse %u, period %u, prescaler: %u.",
260 channel, pulse_cycles, period_cycles, data->prescaler);
261
262 /* If this channel does not need to be driven by the PWM peripheral
263 * because its state is to be constant (duty 0% or 100%), set properly
264 * the GPIO configuration for its output pin. This will provide
265 * the correct output state for this channel when the PWM peripheral
266 * is stopped.
267 */
268 if (!needs_pwm) {
269 uint32_t psel;
270
271 if (channel_psel_get(channel, &psel, config)) {
272 uint32_t out_level = (pulse_cycles == 0) ? 0 : 1;
273
274 if (inverted) {
275 out_level ^= 1;
276 }
277 /* Output of fast PWM instance is directly connected to GPIO pads,
278 * thus it cannot controlled by GPIO. Use regular 0%/100% duty cycle
279 * playback instead.
280 */
281 #ifdef PWM_NRFX_FAST_PRESENT
282 if (pwm_is_fast(config)) {
283 nrfx_pwm_simple_playback(&config->pwm, &config->seq, 1,
284 NRFX_PWM_FLAG_NO_EVT_FINISHED);
285 } else {
286 #else
287 {
288 #endif
289 nrf_gpio_pin_write(psel, out_level);
290 }
291 }
292
293 data->pwm_needed &= ~BIT(channel);
294 } else {
295 data->pwm_needed |= BIT(channel);
296 }
297
298 /* If the PWM generation is not needed for any channel (all are set
299 * to constant inactive or active state), stop the PWM peripheral.
300 * Otherwise, request a playback of the defined sequence so that
301 * the PWM peripheral loads `seq_values` into its internal compare
302 * registers and drives its outputs accordingly.
303 */
304 if (data->pwm_needed == 0) {
305 if (pwm_is_fast(config)) {
306 #if PWM_NRFX_USE_CLOCK_CONTROL
307 if (data->clock_requested) {
308 int ret = nrf_clock_control_release(config->clk_dev,
309 &config->clk_spec);
310
311 if (ret < 0) {
312 LOG_ERR("Global HSFLL release failed: %d", ret);
313 return ret;
314 }
315
316 data->clock_requested = false;
317 }
318 #endif
319 return 0;
320 }
321 int ret = stop_pwm(dev);
322
323 if (ret < 0) {
324 LOG_ERR("PWM stop failed: %d", ret);
325 return ret;
326 }
327
328 data->stop_requested = true;
329 } else {
330 if (data->stop_requested) {
331 data->stop_requested = false;
332
333 /* After a stop is requested, the PWM peripheral stops
334 * pulse generation at the end of the current period,
335 * and till that moment, it ignores any start requests,
336 * so ensure here that it is stopped.
337 */
338 while (!nrfx_pwm_stopped_check(&config->pwm)) {
339 }
340 }
341
342 /* It is sufficient to play the sequence once without looping.
343 * The PWM generation will continue with the loaded values
344 * until another playback is requested (new values will be
345 * loaded then) or the PWM peripheral is stopped.
346 */
347 #if PWM_NRFX_USE_CLOCK_CONTROL
348 if (config->clk_dev && !data->clock_requested) {
349 int ret = nrf_clock_control_request_sync(config->clk_dev,
350 &config->clk_spec,
351 K_FOREVER);
352
353 if (ret < 0) {
354 LOG_ERR("Global HSFLL request failed: %d", ret);
355 return ret;
356 }
357
358 data->clock_requested = true;
359 }
360 #endif
361 nrfx_pwm_simple_playback(&config->pwm, &config->seq, 1,
362 NRFX_PWM_FLAG_NO_EVT_FINISHED);
363 }
364
365 return 0;
366 }
367
368 static int pwm_nrfx_get_cycles_per_sec(const struct device *dev, uint32_t channel,
369 uint64_t *cycles)
370 {
371 const struct pwm_nrfx_config *config = dev->config;
372
373 *cycles = config->clock_freq;
374
375 return 0;
376 }
377
378 static DEVICE_API(pwm, pwm_nrfx_drv_api_funcs) = {
379 .set_cycles = pwm_nrfx_set_cycles,
380 .get_cycles_per_sec = pwm_nrfx_get_cycles_per_sec,
381 };
382
383 static int pwm_resume(const struct device *dev)
384 {
385 const struct pwm_nrfx_config *config = dev->config;
386 uint8_t initially_inverted = 0;
387
388 (void)pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
389
390 #ifdef CONFIG_SOC_NRF54H20_GPD
391 nrf_gpd_retain_pins_set(config->pcfg, false);
392 #endif
393
394 for (size_t i = 0; i < NRF_PWM_CHANNEL_COUNT; i++) {
395 uint32_t psel;
396
397 if (channel_psel_get(i, &psel, config)) {
398 /* Mark channels as inverted according to what initial
399 * state of their outputs has been set by pinctrl (high
400 * idle state means that the channel is inverted).
401 */
402 initially_inverted |= nrf_gpio_pin_out_read(psel) ?
403 BIT(i) : 0;
404 }
405 }
406
407 for (size_t i = 0; i < NRF_PWM_CHANNEL_COUNT; i++) {
408 bool inverted = initially_inverted & BIT(i);
409
410 seq_values_ptr_get(dev)[i] = PWM_NRFX_CH_VALUE(0, inverted);
411 }
412
413 return 0;
414 }
415
416 static int pwm_suspend(const struct device *dev)
417 {
418 const struct pwm_nrfx_config *config = dev->config;
419
420 int ret = stop_pwm(dev);
421
422 if (ret < 0) {
423 LOG_ERR("PWM stop failed: %d", ret);
424 return ret;
425 }
426
427 while (!nrfx_pwm_stopped_check(&config->pwm)) {
428 }
429
430 #ifdef CONFIG_SOC_NRF54H20_GPD
431 nrf_gpd_retain_pins_set(config->pcfg, true);
432 #endif
433
434 memset(dev->data, 0, sizeof(struct pwm_nrfx_data));
435 (void)pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP);
436
437 return 0;
438 }
439
440 static int pwm_nrfx_pm_action(const struct device *dev,
441 enum pm_device_action action)
442 {
443 if (action == PM_DEVICE_ACTION_RESUME) {
444 return pwm_resume(dev);
445 } else if (IS_ENABLED(CONFIG_PM_DEVICE) && (action == PM_DEVICE_ACTION_SUSPEND)) {
446 return pwm_suspend(dev);
447 } else {
448 return -ENOTSUP;
449 }
450
451 return 0;
452 }
453
454 static int pwm_nrfx_init(const struct device *dev)
455 {
456 const struct pwm_nrfx_config *config = dev->config;
457 nrfx_err_t err;
458
459 ANOMALY_109_EGU_IRQ_CONNECT(NRFX_PWM_NRF52_ANOMALY_109_EGU_INSTANCE);
460
461 if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) {
462 (void)pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP);
463 }
464
465 err = nrfx_pwm_init(&config->pwm, &config->initial_config, pwm_handler, dev->data);
466 if (err != NRFX_SUCCESS) {
467 LOG_ERR("Failed to initialize device: %s", dev->name);
468 return -EBUSY;
469 }
470
471 return pm_device_driver_init(dev, pwm_nrfx_pm_action);
472 }
473
474 #define PWM_MEM_REGION(idx) DT_PHANDLE(PWM(idx), memory_regions)
475
476 #define PWM_MEMORY_SECTION(idx) \
477 COND_CODE_1(PWM_HAS_PROP(idx, memory_regions), \
478 (__attribute__((__section__(LINKER_DT_NODE_REGION_NAME( \
479 PWM_MEM_REGION(idx)))))), \
480 ())
481
482 #define PWM_GET_MEM_ATTR(idx) \
483 COND_CODE_1(PWM_HAS_PROP(idx, memory_regions), \
484 (DT_PROP_OR(PWM_MEM_REGION(idx), zephyr_memory_attr, 0)), (0))
485
486 /* Fast instances depend on the global HSFLL clock controller (as they need
487 * to request the highest frequency from it to operate correctly), so they
488 * must be initialized after that controller driver, hence the default PWM
489 * initialization priority may be too early for them.
490 */
491 #if defined(CONFIG_CLOCK_CONTROL_NRF2_GLOBAL_HSFLL_INIT_PRIORITY) && \
492 CONFIG_PWM_INIT_PRIORITY < CONFIG_CLOCK_CONTROL_NRF2_GLOBAL_HSFLL_INIT_PRIORITY
493 #define PWM_INIT_PRIORITY(idx) \
494 COND_CODE_1(PWM_NRFX_IS_FAST(_, /*empty*/, idx, _), \
495 (UTIL_INC(CONFIG_CLOCK_CONTROL_NRF2_GLOBAL_HSFLL_INIT_PRIORITY)), \
496 (CONFIG_PWM_INIT_PRIORITY))
497 #else
498 #define PWM_INIT_PRIORITY(idx) CONFIG_PWM_INIT_PRIORITY
499 #endif
500
501 #define PWM_NRFX_DEVICE(idx) \
502 NRF_DT_CHECK_NODE_HAS_PINCTRL_SLEEP(PWM(idx)); \
503 static struct pwm_nrfx_data pwm_nrfx_##idx##_data; \
504 static uint16_t pwm_##idx##_seq_values[NRF_PWM_CHANNEL_COUNT] \
505 PWM_MEMORY_SECTION(idx); \
506 PINCTRL_DT_DEFINE(PWM(idx)); \
507 static const struct pwm_nrfx_config pwm_nrfx_##idx##_config = { \
508 .pwm = NRFX_PWM_INSTANCE(idx), \
509 .initial_config = { \
510 .skip_gpio_cfg = true, \
511 .skip_psel_cfg = true, \
512 .base_clock = NRF_PWM_CLK_1MHz, \
513 .count_mode = (PWM_PROP(idx, center_aligned) \
514 ? NRF_PWM_MODE_UP_AND_DOWN \
515 : NRF_PWM_MODE_UP), \
516 .top_value = 1000, \
517 .load_mode = NRF_PWM_LOAD_INDIVIDUAL, \
518 .step_mode = NRF_PWM_STEP_TRIGGERED, \
519 }, \
520 .seq.values.p_raw = pwm_##idx##_seq_values, \
521 .seq.length = NRF_PWM_CHANNEL_COUNT, \
522 .pcfg = PINCTRL_DT_DEV_CONFIG_GET(PWM(idx)), \
523 .clock_freq = COND_CODE_1(DT_CLOCKS_HAS_IDX(PWM(idx), 0), \
524 (DT_PROP(DT_CLOCKS_CTLR(PWM(idx)), clock_frequency)), \
525 (16ul * 1000ul * 1000ul)), \
526 IF_ENABLED(CONFIG_DCACHE, \
527 (.mem_attr = PWM_GET_MEM_ATTR(idx),)) \
528 IF_ENABLED(PWM_NRFX_USE_CLOCK_CONTROL, \
529 (.clk_dev = PWM_NRFX_IS_FAST(_, /*empty*/, idx, _) \
530 ? DEVICE_DT_GET(DT_CLOCKS_CTLR(PWM(idx))) \
531 : NULL, \
532 .clk_spec = { \
533 .frequency = \
534 NRF_PERIPH_GET_FREQUENCY(PWM(idx)), \
535 },)) \
536 }; \
537 static int pwm_nrfx_init##idx(const struct device *dev) \
538 { \
539 IRQ_CONNECT(DT_IRQN(PWM(idx)), DT_IRQ(PWM(idx), priority), \
540 nrfx_isr, nrfx_pwm_##idx##_irq_handler, 0); \
541 return pwm_nrfx_init(dev); \
542 }; \
543 PM_DEVICE_DT_DEFINE(PWM(idx), pwm_nrfx_pm_action); \
544 DEVICE_DT_DEFINE(PWM(idx), \
545 pwm_nrfx_init##idx, PM_DEVICE_DT_GET(PWM(idx)), \
546 &pwm_nrfx_##idx##_data, \
547 &pwm_nrfx_##idx##_config, \
548 POST_KERNEL, PWM_INIT_PRIORITY(idx), \
549 &pwm_nrfx_drv_api_funcs)
550
551 #define COND_PWM_NRFX_DEVICE(unused, prefix, i, _) \
552 IF_ENABLED(CONFIG_HAS_HW_NRF_PWM##prefix##i, (PWM_NRFX_DEVICE(prefix##i);))
553
554 NRFX_FOREACH_PRESENT(PWM, COND_PWM_NRFX_DEVICE, (), (), _)
555