1 /*
2 * Copyright (c) 2017 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT nordic_nrf_sw_pwm
8
9 #include <soc.h>
10 #include <zephyr/drivers/pwm.h>
11 #include <zephyr/dt-bindings/gpio/gpio.h>
12 #include <nrfx_gpiote.h>
13 #include <helpers/nrfx_gppi.h>
14 #include <hal/nrf_gpio.h>
15 #include <hal/nrf_rtc.h>
16 #include <hal/nrf_timer.h>
17
18 #include <zephyr/logging/log.h>
19
20 LOG_MODULE_REGISTER(pwm_nrf_sw, CONFIG_PWM_LOG_LEVEL);
21
22 #define GENERATOR_NODE DT_INST_PHANDLE(0, generator)
23 #define GENERATOR_CC_NUM DT_PROP(GENERATOR_NODE, cc_num)
24
25 #if DT_NODE_HAS_COMPAT(GENERATOR_NODE, nordic_nrf_rtc)
26 #define USE_RTC 1
27 #define GENERATOR_ADDR ((NRF_RTC_Type *) DT_REG_ADDR(GENERATOR_NODE))
28 #define GENERATOR_BITS 24
29 BUILD_ASSERT(DT_INST_PROP(0, clock_prescaler) == 0,
30 "Only clock-prescaler = <0> is supported when used with RTC");
31 #else
32 #define USE_RTC 0
33 #define GENERATOR_ADDR ((NRF_TIMER_Type *) DT_REG_ADDR(GENERATOR_NODE))
34 #define GENERATOR_BITS DT_PROP(GENERATOR_NODE, max_bit_width)
35 #endif
36
37 #define PWM_0_MAP_SIZE DT_INST_PROP_LEN(0, channel_gpios)
38
39 /* One compare channel is needed to set the PWM period, hence +1. */
40 #if ((PWM_0_MAP_SIZE + 1) > GENERATOR_CC_NUM)
41 #error "Invalid number of PWM channels configured."
42 #endif
43
44 #if defined(PPI_FEATURE_FORKS_PRESENT) || defined(DPPI_PRESENT)
45 #define PPI_FORK_AVAILABLE 1
46 #else
47 #define PPI_FORK_AVAILABLE 0
48 #endif
49
50 /* When RTC is used, one more PPI task endpoint is required for clearing
51 * the counter, so when FORK feature is not available, one more PPI channel
52 * needs to be used.
53 */
54 #if USE_RTC && !PPI_FORK_AVAILABLE
55 #define PPI_PER_CH 3
56 #else
57 #define PPI_PER_CH 2
58 #endif
59
60 struct pwm_config {
61 union {
62 NRF_RTC_Type *rtc;
63 NRF_TIMER_Type *timer;
64 };
65 nrfx_gpiote_t gpiote[PWM_0_MAP_SIZE];
66 uint8_t psel_ch[PWM_0_MAP_SIZE];
67 uint8_t initially_inverted;
68 uint8_t map_size;
69 uint8_t prescaler;
70 };
71
72 struct pwm_data {
73 uint32_t period_cycles;
74 uint32_t pulse_cycles[PWM_0_MAP_SIZE];
75 uint8_t ppi_ch[PWM_0_MAP_SIZE][PPI_PER_CH];
76 uint8_t gpiote_ch[PWM_0_MAP_SIZE];
77 };
78
pwm_config_rtc(const struct pwm_config * config)79 static inline NRF_RTC_Type *pwm_config_rtc(const struct pwm_config *config)
80 {
81 #if USE_RTC
82 return config->rtc;
83 #else
84 return NULL;
85 #endif
86 }
87
pwm_config_timer(const struct pwm_config * config)88 static inline NRF_TIMER_Type *pwm_config_timer(const struct pwm_config *config)
89 {
90 #if !USE_RTC
91 return config->timer;
92 #else
93 return NULL;
94 #endif
95 }
96
pwm_period_check(struct pwm_data * data,uint8_t map_size,uint32_t channel,uint32_t period_cycles,uint32_t pulse_cycles)97 static uint32_t pwm_period_check(struct pwm_data *data, uint8_t map_size,
98 uint32_t channel, uint32_t period_cycles,
99 uint32_t pulse_cycles)
100 {
101 uint8_t i;
102
103 /* allow 0% and 100% duty cycle, as it does not use PWM. */
104 if ((pulse_cycles == 0U) || (pulse_cycles == period_cycles)) {
105 return 0;
106 }
107
108 /* fail if requested period does not match already running period */
109 for (i = 0U; i < map_size; i++) {
110 if ((i != channel) &&
111 (data->pulse_cycles[i] != 0U) &&
112 (period_cycles != data->period_cycles)) {
113 return -EINVAL;
114 }
115 }
116
117 return 0;
118 }
119
pwm_nrf_sw_set_cycles(const struct device * dev,uint32_t channel,uint32_t period_cycles,uint32_t pulse_cycles,pwm_flags_t flags)120 static int pwm_nrf_sw_set_cycles(const struct device *dev, uint32_t channel,
121 uint32_t period_cycles, uint32_t pulse_cycles,
122 pwm_flags_t flags)
123 {
124 const struct pwm_config *config = dev->config;
125 NRF_TIMER_Type *timer = pwm_config_timer(config);
126 NRF_RTC_Type *rtc = pwm_config_rtc(config);
127 NRF_GPIOTE_Type *gpiote;
128 struct pwm_data *data = dev->data;
129 uint32_t ppi_mask;
130 uint8_t active_level;
131 uint8_t psel_ch;
132 uint8_t gpiote_ch;
133 const uint8_t *ppi_chs;
134 int ret;
135
136 if (channel >= config->map_size) {
137 LOG_ERR("Invalid channel: %u.", channel);
138 return -EINVAL;
139 }
140
141 /* check if requested period is allowed while other channels are
142 * active.
143 */
144 ret = pwm_period_check(data, config->map_size, channel, period_cycles,
145 pulse_cycles);
146 if (ret) {
147 LOG_ERR("Incompatible period");
148 return ret;
149 }
150
151 if (USE_RTC) {
152 /* pulse_cycles - 1 is written to 24-bit CC */
153 if (period_cycles > BIT_MASK(24) + 1) {
154 LOG_ERR("Too long period (%u)!", period_cycles);
155 return -EINVAL;
156 }
157 } else {
158 if (GENERATOR_BITS < 32 &&
159 period_cycles > BIT_MASK(GENERATOR_BITS)) {
160 LOG_ERR("Too long period (%u), adjust PWM prescaler!",
161 period_cycles);
162 return -EINVAL;
163 }
164 }
165
166 gpiote = config->gpiote[channel].p_reg;
167 psel_ch = config->psel_ch[channel];
168 gpiote_ch = data->gpiote_ch[channel];
169 ppi_chs = data->ppi_ch[channel];
170
171 LOG_DBG("channel %u, period %u, pulse %u",
172 channel, period_cycles, pulse_cycles);
173
174 /* clear PPI used */
175 ppi_mask = BIT(ppi_chs[0]) | BIT(ppi_chs[1]) |
176 (PPI_PER_CH > 2 ? BIT(ppi_chs[2]) : 0);
177 nrfx_gppi_channels_disable(ppi_mask);
178
179 active_level = (flags & PWM_POLARITY_INVERTED) ? 0 : 1;
180
181 /*
182 * If the duty cycle is 0% or 100%, there is no need to generate
183 * the PWM signal, just keep the output pin in inactive or active
184 * state, respectively.
185 */
186 if (pulse_cycles == 0 || pulse_cycles == period_cycles) {
187 nrf_gpio_pin_write(psel_ch,
188 pulse_cycles == 0 ? !active_level
189 : active_level);
190
191 /* clear GPIOTE config */
192 nrf_gpiote_te_default(gpiote, gpiote_ch);
193
194 /* No PWM generation for this channel. */
195 data->pulse_cycles[channel] = 0U;
196
197 /* Check if PWM signal is generated on any channel. */
198 for (uint8_t i = 0; i < config->map_size; i++) {
199 if (data->pulse_cycles[i]) {
200 return 0;
201 }
202 }
203
204 /* No PWM generation needed, stop the timer. */
205 if (USE_RTC) {
206 nrf_rtc_task_trigger(rtc, NRF_RTC_TASK_STOP);
207 } else {
208 nrf_timer_task_trigger(timer, NRF_TIMER_TASK_STOP);
209 }
210
211 return 0;
212 }
213
214 /* configure RTC / TIMER */
215 if (USE_RTC) {
216 nrf_rtc_event_clear(rtc,
217 nrf_rtc_compare_event_get(1 + channel));
218 nrf_rtc_event_clear(rtc,
219 nrf_rtc_compare_event_get(0));
220
221 /*
222 * '- 1' adjusts pulse and period cycles to the fact that CLEAR
223 * task event is generated always one LFCLK cycle after period
224 * COMPARE value is reached.
225 */
226 nrf_rtc_cc_set(rtc, 1 + channel, pulse_cycles - 1);
227 nrf_rtc_cc_set(rtc, 0, period_cycles - 1);
228 nrf_rtc_task_trigger(rtc, NRF_RTC_TASK_CLEAR);
229 } else {
230 nrf_timer_event_clear(timer,
231 nrf_timer_compare_event_get(1 + channel));
232 nrf_timer_event_clear(timer,
233 nrf_timer_compare_event_get(0));
234
235 nrf_timer_cc_set(timer, 1 + channel, pulse_cycles);
236 nrf_timer_cc_set(timer, 0, period_cycles);
237 nrf_timer_task_trigger(timer, NRF_TIMER_TASK_CLEAR);
238 }
239
240 /* Configure GPIOTE - toggle task with proper initial output value. */
241 gpiote->CONFIG[gpiote_ch] =
242 (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) |
243 ((uint32_t)psel_ch << 8) |
244 (GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos) |
245 ((uint32_t)active_level << GPIOTE_CONFIG_OUTINIT_Pos);
246
247 /* setup PPI */
248 uint32_t pulse_end_event_address, period_end_event_address;
249 nrf_gpiote_task_t pulse_end_task, period_end_task;
250 #if defined(GPIOTE_FEATURE_SET_PRESENT) && defined(GPIOTE_FEATURE_CLR_PRESENT)
251 if (active_level == 0) {
252 pulse_end_task = nrf_gpiote_set_task_get(gpiote_ch);
253 period_end_task = nrf_gpiote_clr_task_get(gpiote_ch);
254 } else {
255 pulse_end_task = nrf_gpiote_clr_task_get(gpiote_ch);
256 period_end_task = nrf_gpiote_set_task_get(gpiote_ch);
257 }
258 #else
259 pulse_end_task = period_end_task = nrf_gpiote_out_task_get(gpiote_ch);
260 #endif
261 uint32_t pulse_end_task_address =
262 nrf_gpiote_task_address_get(gpiote, pulse_end_task);
263 uint32_t period_end_task_address =
264 nrf_gpiote_task_address_get(gpiote, period_end_task);
265
266 if (USE_RTC) {
267 uint32_t clear_task_address =
268 nrf_rtc_event_address_get(rtc, NRF_RTC_TASK_CLEAR);
269
270 pulse_end_event_address =
271 nrf_rtc_event_address_get(rtc,
272 nrf_rtc_compare_event_get(1 + channel));
273 period_end_event_address =
274 nrf_rtc_event_address_get(rtc,
275 nrf_rtc_compare_event_get(0));
276
277 #if PPI_FORK_AVAILABLE
278 nrfx_gppi_fork_endpoint_setup(ppi_chs[1],
279 clear_task_address);
280 #else
281 nrfx_gppi_channel_endpoints_setup(ppi_chs[2],
282 period_end_event_address,
283 clear_task_address);
284 #endif
285 } else {
286 pulse_end_event_address =
287 nrf_timer_event_address_get(timer,
288 nrf_timer_compare_event_get(1 + channel));
289 period_end_event_address =
290 nrf_timer_event_address_get(timer,
291 nrf_timer_compare_event_get(0));
292 }
293
294 nrfx_gppi_channel_endpoints_setup(ppi_chs[0],
295 pulse_end_event_address,
296 pulse_end_task_address);
297 nrfx_gppi_channel_endpoints_setup(ppi_chs[1],
298 period_end_event_address,
299 period_end_task_address);
300 nrfx_gppi_channels_enable(ppi_mask);
301
302 /* start timer, hence PWM */
303 if (USE_RTC) {
304 nrf_rtc_task_trigger(rtc, NRF_RTC_TASK_START);
305 } else {
306 nrf_timer_task_trigger(timer, NRF_TIMER_TASK_START);
307 }
308
309 /* store the period and pulse cycles */
310 data->period_cycles = period_cycles;
311 data->pulse_cycles[channel] = pulse_cycles;
312
313 return 0;
314 }
315
pwm_nrf_sw_get_cycles_per_sec(const struct device * dev,uint32_t channel,uint64_t * cycles)316 static int pwm_nrf_sw_get_cycles_per_sec(const struct device *dev,
317 uint32_t channel, uint64_t *cycles)
318 {
319 const struct pwm_config *config = dev->config;
320
321 if (USE_RTC) {
322 /*
323 * RTC frequency is derived from 32768Hz source without any
324 * prescaler
325 */
326 *cycles = 32768UL;
327 } else {
328 /*
329 * HF timer frequency is derived from 16MHz source with a
330 * prescaler
331 */
332 *cycles = 16000000UL / BIT(config->prescaler);
333 }
334
335 return 0;
336 }
337
338 static const struct pwm_driver_api pwm_nrf_sw_drv_api_funcs = {
339 .set_cycles = pwm_nrf_sw_set_cycles,
340 .get_cycles_per_sec = pwm_nrf_sw_get_cycles_per_sec,
341 };
342
pwm_nrf_sw_init(const struct device * dev)343 static int pwm_nrf_sw_init(const struct device *dev)
344 {
345 const struct pwm_config *config = dev->config;
346 struct pwm_data *data = dev->data;
347 NRF_TIMER_Type *timer = pwm_config_timer(config);
348 NRF_RTC_Type *rtc = pwm_config_rtc(config);
349
350 for (uint32_t i = 0; i < config->map_size; i++) {
351 nrfx_err_t err;
352
353 /* Allocate resources. */
354 for (uint32_t j = 0; j < PPI_PER_CH; j++) {
355 err = nrfx_gppi_channel_alloc(&data->ppi_ch[i][j]);
356 if (err != NRFX_SUCCESS) {
357 /* Do not free allocated resource. It is a fatal condition,
358 * system requires reconfiguration.
359 */
360 LOG_ERR("Failed to allocate PPI channel");
361 return -ENOMEM;
362 }
363 }
364
365 err = nrfx_gpiote_channel_alloc(&config->gpiote[i],
366 &data->gpiote_ch[i]);
367 if (err != NRFX_SUCCESS) {
368 /* Do not free allocated resource. It is a fatal condition,
369 * system requires reconfiguration.
370 */
371 LOG_ERR("Failed to allocate GPIOTE channel");
372 return -ENOMEM;
373 }
374
375 /* Set initial state of the output pins. */
376 nrf_gpio_pin_write(config->psel_ch[i],
377 (config->initially_inverted & BIT(i)) ? 1 : 0);
378 nrf_gpio_cfg_output(config->psel_ch[i]);
379 }
380
381 if (USE_RTC) {
382 /* setup RTC */
383 nrf_rtc_prescaler_set(rtc, 0);
384 nrf_rtc_event_enable(rtc, NRF_RTC_INT_COMPARE0_MASK |
385 NRF_RTC_INT_COMPARE1_MASK |
386 NRF_RTC_INT_COMPARE2_MASK |
387 NRF_RTC_INT_COMPARE3_MASK);
388 } else {
389 /* setup HF timer */
390 nrf_timer_mode_set(timer, NRF_TIMER_MODE_TIMER);
391 nrf_timer_prescaler_set(timer, config->prescaler);
392 nrf_timer_bit_width_set(timer,
393 GENERATOR_BITS == 32 ? NRF_TIMER_BIT_WIDTH_32
394 : NRF_TIMER_BIT_WIDTH_16);
395 nrf_timer_shorts_enable(timer,
396 NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK);
397 }
398
399 return 0;
400 }
401
402 #define PSEL_AND_COMMA(_node_id, _prop, _idx) \
403 NRF_DT_GPIOS_TO_PSEL_BY_IDX(_node_id, _prop, _idx),
404
405 #define ACTIVE_LOW_BITS(_node_id, _prop, _idx) \
406 ((DT_GPIO_FLAGS_BY_IDX(_node_id, _prop, _idx) & GPIO_ACTIVE_LOW) \
407 ? BIT(_idx) : 0) |
408
409 #define GPIOTE_AND_COMMA(_node_id, _prop, _idx) \
410 NRFX_GPIOTE_INSTANCE(NRF_DT_GPIOTE_INST_BY_IDX(_node_id, _prop, _idx)),
411
412 static const struct pwm_config pwm_nrf_sw_0_config = {
413 COND_CODE_1(USE_RTC, (.rtc), (.timer)) = GENERATOR_ADDR,
414 .gpiote = {
415 DT_INST_FOREACH_PROP_ELEM(0, channel_gpios, GPIOTE_AND_COMMA)
416 },
417 .psel_ch = {
418 DT_INST_FOREACH_PROP_ELEM(0, channel_gpios, PSEL_AND_COMMA)
419 },
420 .initially_inverted =
421 DT_INST_FOREACH_PROP_ELEM(0, channel_gpios, ACTIVE_LOW_BITS) 0,
422 .map_size = PWM_0_MAP_SIZE,
423 .prescaler = DT_INST_PROP(0, clock_prescaler),
424 };
425
426 static struct pwm_data pwm_nrf_sw_0_data;
427
428 DEVICE_DT_INST_DEFINE(0,
429 pwm_nrf_sw_init,
430 NULL,
431 &pwm_nrf_sw_0_data,
432 &pwm_nrf_sw_0_config,
433 POST_KERNEL,
434 CONFIG_PWM_INIT_PRIORITY,
435 &pwm_nrf_sw_drv_api_funcs);
436