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 <hal/nrf_gpio.h>
11
12 #include <drivers/pwm.h>
13 #include <nrf_peripherals.h>
14
15 #define LOG_LEVEL CONFIG_PWM_LOG_LEVEL
16 #include <logging/log.h>
17 LOG_MODULE_REGISTER(pwm_nrf5_sw);
18
19 #define GENERATOR_NODE DT_PHANDLE(DT_DRV_INST(0), generator)
20 #define GENERATOR_CC_NUM DT_PROP(GENERATOR_NODE, cc_num)
21
22 #if DT_NODE_HAS_COMPAT(GENERATOR_NODE, nordic_nrf_rtc)
23 #define USE_RTC 1
24 #define GENERATOR_ADDR ((NRF_RTC_Type *) DT_REG_ADDR(GENERATOR_NODE))
25 BUILD_ASSERT(DT_INST_PROP(0, clock_prescaler) == 0,
26 "Only clock-prescaler = <0> is supported when used with RTC");
27 #else
28 #define USE_RTC 0
29 #define GENERATOR_ADDR ((NRF_TIMER_Type *) DT_REG_ADDR(GENERATOR_NODE))
30 #endif
31
32 /* One compare channel is needed to set the PWM period, hence +1. */
33 #if ((DT_INST_PROP(0, channel_count) + 1) > GENERATOR_CC_NUM)
34 #error "Invalid number of PWM channels configured."
35 #endif
36 #define PWM_0_MAP_SIZE DT_INST_PROP(0, channel_count)
37
38 struct pwm_config {
39 union {
40 NRF_RTC_Type *rtc;
41 NRF_TIMER_Type *timer;
42 };
43 uint8_t gpiote_base;
44 uint8_t ppi_base;
45 uint8_t map_size;
46 uint8_t prescaler;
47 };
48
49 struct chan_map {
50 uint32_t pwm;
51 uint32_t pulse_cycles;
52 };
53
54 struct pwm_data {
55 uint32_t period_cycles;
56 struct chan_map map[PWM_0_MAP_SIZE];
57 };
58
pwm_config_rtc(const struct pwm_config * config)59 static inline NRF_RTC_Type *pwm_config_rtc(const struct pwm_config *config)
60 {
61 #if USE_RTC
62 return config->rtc;
63 #else
64 return NULL;
65 #endif
66 }
67
pwm_config_timer(const struct pwm_config * config)68 static inline NRF_TIMER_Type *pwm_config_timer(const struct pwm_config *config)
69 {
70 #if !USE_RTC
71 return config->timer;
72 #else
73 return NULL;
74 #endif
75 }
76
pwm_period_check(struct pwm_data * data,uint8_t map_size,uint32_t pwm,uint32_t period_cycles,uint32_t pulse_cycles)77 static uint32_t pwm_period_check(struct pwm_data *data, uint8_t map_size,
78 uint32_t pwm, uint32_t period_cycles,
79 uint32_t pulse_cycles)
80 {
81 uint8_t i;
82
83 /* allow 0% and 100% duty cycle, as it does not use PWM. */
84 if ((pulse_cycles == 0U) || (pulse_cycles == period_cycles)) {
85 return 0;
86 }
87
88 /* fail if requested period does not match already running period */
89 for (i = 0U; i < map_size; i++) {
90 if ((data->map[i].pwm != pwm) &&
91 (data->map[i].pulse_cycles != 0U) &&
92 (period_cycles != data->period_cycles)) {
93 return -EINVAL;
94 }
95 }
96
97 return 0;
98 }
99
pwm_channel_map(struct pwm_data * data,uint8_t map_size,uint32_t pwm)100 static uint8_t pwm_channel_map(struct pwm_data *data, uint8_t map_size,
101 uint32_t pwm)
102 {
103 uint8_t i;
104
105 /* find pin, if already present */
106 for (i = 0U; i < map_size; i++) {
107 if (pwm == data->map[i].pwm) {
108 return i;
109 }
110 }
111
112 /* find a free entry */
113 i = map_size;
114 while (i--) {
115 if (data->map[i].pulse_cycles == 0U) {
116 break;
117 }
118 }
119
120 return i;
121 }
122
pwm_nrf5_sw_pin_set(const struct device * dev,uint32_t pwm,uint32_t period_cycles,uint32_t pulse_cycles,pwm_flags_t flags)123 static int pwm_nrf5_sw_pin_set(const struct device *dev, uint32_t pwm,
124 uint32_t period_cycles, uint32_t pulse_cycles,
125 pwm_flags_t flags)
126 {
127 const struct pwm_config *config = dev->config;
128 NRF_TIMER_Type *timer = pwm_config_timer(config);
129 NRF_RTC_Type *rtc = pwm_config_rtc(config);
130 struct pwm_data *data = dev->data;
131 uint8_t ppi_index;
132 uint32_t ppi_mask;
133 uint8_t channel;
134 uint32_t ret;
135
136 if (flags) {
137 /* PWM polarity not supported (yet?) */
138 return -ENOTSUP;
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, pwm, 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 /* TODO: if the assigned NRF_TIMER supports higher bit
159 * resolution, use that info in config struct.
160 */
161 if (period_cycles > UINT16_MAX) {
162 LOG_ERR("Too long period (%u), adjust pwm prescaler!",
163 period_cycles);
164 return -EINVAL;
165 }
166 }
167
168 /* map pwm pin to GPIOTE config/channel */
169 channel = pwm_channel_map(data, config->map_size, pwm);
170 if (channel >= config->map_size) {
171 LOG_ERR("No more channels available");
172 return -ENOMEM;
173 }
174
175 LOG_DBG("PWM %d, period %u, pulse %u", pwm,
176 period_cycles, pulse_cycles);
177
178 /* clear GPIOTE config */
179 NRF_GPIOTE->CONFIG[config->gpiote_base + channel] = 0;
180
181 /* clear PPI used */
182 if (USE_RTC) {
183 ppi_index = config->ppi_base + (channel * 3);
184 ppi_mask = BIT(ppi_index) | BIT(ppi_index + 1) |
185 BIT(ppi_index + 2);
186 } else {
187 ppi_index = config->ppi_base + (channel * 2);
188 ppi_mask = BIT(ppi_index) | BIT(ppi_index + 1);
189 }
190 NRF_PPI->CHENCLR = ppi_mask;
191
192 /* configure GPIO pin as output */
193 nrf_gpio_cfg_output(pwm);
194 if (pulse_cycles == 0U) {
195 /* 0% duty cycle, keep pin low */
196 nrf_gpio_pin_clear(pwm);
197
198 goto pin_set_pwm_off;
199 } else if (pulse_cycles == period_cycles) {
200 /* 100% duty cycle, keep pin high */
201 nrf_gpio_pin_set(pwm);
202
203 goto pin_set_pwm_off;
204 } else {
205 /* x% duty cycle, start PWM with pin low */
206 nrf_gpio_pin_clear(pwm);
207 }
208
209 /* configure RTC / TIMER */
210 if (USE_RTC) {
211 rtc->EVENTS_COMPARE[channel] = 0;
212 rtc->EVENTS_COMPARE[config->map_size] = 0;
213
214 /*
215 * '- 1' adjusts pulse and period cycles to the fact that CLEAR
216 * task event is generated always one LFCLK cycle after period
217 * COMPARE value is reached.
218 */
219 rtc->CC[channel] = pulse_cycles - 1;
220 rtc->CC[config->map_size] = period_cycles - 1;
221 rtc->TASKS_CLEAR = 1;
222 } else {
223 timer->EVENTS_COMPARE[channel] = 0;
224 timer->EVENTS_COMPARE[config->map_size] = 0;
225
226 timer->CC[channel] = pulse_cycles;
227 timer->CC[config->map_size] = period_cycles;
228 timer->TASKS_CLEAR = 1;
229 }
230
231 /* configure GPIOTE, toggle with initialise output high */
232 NRF_GPIOTE->CONFIG[config->gpiote_base + channel] = 0x00130003 |
233 (pwm << 8);
234
235 /* setup PPI */
236 if (USE_RTC) {
237 NRF_PPI->CH[ppi_index].EEP =
238 (uint32_t) &(rtc->EVENTS_COMPARE[channel]);
239 NRF_PPI->CH[ppi_index].TEP =
240 (uint32_t) &(NRF_GPIOTE->TASKS_OUT[channel]);
241 NRF_PPI->CH[ppi_index + 1].EEP =
242 (uint32_t) &(rtc->EVENTS_COMPARE[config->map_size]);
243 NRF_PPI->CH[ppi_index + 1].TEP =
244 (uint32_t) &(NRF_GPIOTE->TASKS_OUT[channel]);
245 NRF_PPI->CH[ppi_index + 2].EEP =
246 (uint32_t) &(rtc->EVENTS_COMPARE[config->map_size]);
247 NRF_PPI->CH[ppi_index + 2].TEP =
248 (uint32_t) &(rtc->TASKS_CLEAR);
249 } else {
250 NRF_PPI->CH[ppi_index].EEP =
251 (uint32_t) &(timer->EVENTS_COMPARE[channel]);
252 NRF_PPI->CH[ppi_index].TEP =
253 (uint32_t) &(NRF_GPIOTE->TASKS_OUT[channel]);
254 NRF_PPI->CH[ppi_index + 1].EEP =
255 (uint32_t) &(timer->EVENTS_COMPARE[config->map_size]);
256 NRF_PPI->CH[ppi_index + 1].TEP =
257 (uint32_t) &(NRF_GPIOTE->TASKS_OUT[channel]);
258 }
259 NRF_PPI->CHENSET = ppi_mask;
260
261 /* start timer, hence PWM */
262 if (USE_RTC) {
263 rtc->TASKS_START = 1;
264 } else {
265 timer->TASKS_START = 1;
266 }
267
268 /* store the pwm/pin and its param */
269 data->period_cycles = period_cycles;
270 data->map[channel].pwm = pwm;
271 data->map[channel].pulse_cycles = pulse_cycles;
272
273 return 0;
274
275 pin_set_pwm_off:
276 data->map[channel].pulse_cycles = 0U;
277 bool pwm_active = false;
278
279 /* stop timer if all channels are inactive */
280 for (channel = 0U; channel < config->map_size; channel++) {
281 if (data->map[channel].pulse_cycles) {
282 pwm_active = true;
283 break;
284 }
285 }
286
287 if (!pwm_active) {
288 /* No active PWM, stop timer */
289 if (USE_RTC) {
290 rtc->TASKS_STOP = 1;
291 } else {
292 timer->TASKS_STOP = 1;
293 }
294 }
295
296 return 0;
297 }
298
pwm_nrf5_sw_get_cycles_per_sec(const struct device * dev,uint32_t pwm,uint64_t * cycles)299 static int pwm_nrf5_sw_get_cycles_per_sec(const struct device *dev,
300 uint32_t pwm,
301 uint64_t *cycles)
302 {
303 const struct pwm_config *config = dev->config;
304
305 if (USE_RTC) {
306 /*
307 * RTC frequency is derived from 32768Hz source without any
308 * prescaler
309 */
310 *cycles = 32768UL;
311 } else {
312 /*
313 * HF timer frequency is derived from 16MHz source with a
314 * prescaler
315 */
316 *cycles = 16000000UL / BIT(config->prescaler);
317 }
318
319 return 0;
320 }
321
322 static const struct pwm_driver_api pwm_nrf5_sw_drv_api_funcs = {
323 .pin_set = pwm_nrf5_sw_pin_set,
324 .get_cycles_per_sec = pwm_nrf5_sw_get_cycles_per_sec,
325 };
326
pwm_nrf5_sw_init(const struct device * dev)327 static int pwm_nrf5_sw_init(const struct device *dev)
328 {
329 const struct pwm_config *config = dev->config;
330 NRF_TIMER_Type *timer = pwm_config_timer(config);
331 NRF_RTC_Type *rtc = pwm_config_rtc(config);
332
333 if (USE_RTC) {
334 /* setup RTC */
335 rtc->PRESCALER = 0;
336
337 /*
338 * TODO: set EVTEN to map_size if not 3, i.e. if RTC supports
339 * less than 4 compares, then less channels can be supported.
340 */
341 rtc->EVTENSET = (RTC_EVTENSET_COMPARE0_Msk |
342 RTC_EVTENSET_COMPARE1_Msk |
343 RTC_EVTENSET_COMPARE2_Msk |
344 RTC_EVTENSET_COMPARE3_Msk);
345 } else {
346 /* setup HF timer */
347 timer->MODE = TIMER_MODE_MODE_Timer;
348 timer->PRESCALER = config->prescaler;
349 timer->BITMODE = TIMER_BITMODE_BITMODE_16Bit;
350
351 /*
352 * TODO: set shorts according to map_size if not 3, i.e. if
353 * NRF_TIMER supports more than 4 compares, then more channels
354 * can be supported.
355 */
356 timer->SHORTS = TIMER_SHORTS_COMPARE3_CLEAR_Msk;
357 }
358
359 return 0;
360 }
361
362 static const struct pwm_config pwm_nrf5_sw_0_config = {
363 COND_CODE_1(USE_RTC, (.rtc), (.timer)) = GENERATOR_ADDR,
364 .ppi_base = DT_INST_PROP(0, ppi_base),
365 .gpiote_base = DT_INST_PROP(0, gpiote_base),
366 .map_size = PWM_0_MAP_SIZE,
367 .prescaler = DT_INST_PROP(0, clock_prescaler),
368 };
369
370 static struct pwm_data pwm_nrf5_sw_0_data;
371
372 DEVICE_DT_INST_DEFINE(0,
373 pwm_nrf5_sw_init,
374 NULL,
375 &pwm_nrf5_sw_0_data,
376 &pwm_nrf5_sw_0_config,
377 POST_KERNEL,
378 CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
379 &pwm_nrf5_sw_drv_api_funcs);
380