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