1 /*
2  * Copyright (c) 2017 Vitor Massaru Iha <vitor@massaru.org>
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT espressif_esp32_gpio
8 
9 /* Include esp-idf headers first to avoid redefining BIT() macro */
10 #include <esp_intr_alloc.h>
11 #include <soc/dport_reg.h>
12 #include <esp32/rom/gpio.h>
13 #include <soc/gpio_sig_map.h>
14 #include <soc/ledc_reg.h>
15 
16 #include <soc.h>
17 #include <errno.h>
18 #include <drivers/pwm.h>
19 #include <kernel.h>
20 #include <drivers/gpio.h>
21 #include <string.h>
22 
23 #define PWM_ESP32_HSCH_HPOINT(i) (LEDC_HSCH0_HPOINT_REG + (0x14 * i))
24 #define PWM_ESP32_HSCH_DUTY(i) (LEDC_HSCH0_DUTY_REG + (0x14 * i))
25 #define PWM_ESP32_HSCH_CONF0(i) (LEDC_HSCH0_CONF0_REG + (0x14 * i))
26 #define PWM_ESP32_HSCH_CONF1(i) (LEDC_HSCH0_CONF1_REG + (0x14 * i))
27 #define PWM_ESP32_HSTIMER(i) (LEDC_HSTIMER0_CONF_REG + (0x8 * i))
28 
29 #define PWM_ESP32_LSCH_HPOINT(i) (LEDC_LSCH0_HPOINT_REG + (0x14 * i))
30 #define PWM_ESP32_LSCH_DUTY(i) (LEDC_LSCH0_DUTY_REG + (0x14 * i))
31 #define PWM_ESP32_LSCH_CONF0(i) (LEDC_LSCH0_CONF0_REG + (0x14 * i))
32 #define PWM_ESP32_LSCH_CONF1(i) (LEDC_LSCH0_CONF1_REG + (0x14 * i))
33 #define PWM_ESP32_LSTIMER(i) (LEDC_LSTIMER0_CONF_REG + (0x8 * i))
34 
35 enum {
36 	PWM_LED_ESP32_REF_TICK_FREQ,
37 	PWM_LED_ESP32_APB_CLK_FREQ,
38 };
39 
40 enum {
41 	PWM_LED_ESP32_HIGH_SPEED,
42 	PWM_LED_ESP32_LOW_SPEED
43 };
44 
45 struct pwm_led_esp32_timer {
46 	int freq;
47 	uint8_t bit_num;
48 } __attribute__ ((__packed__));
49 
50 struct pwm_led_esp32_channel {
51 	uint8_t timer : 2;
52 	uint8_t gpio : 6;
53 };
54 
55 union pwm_led_esp32_duty {
56 	struct {
57 		uint32_t start: 1;
58 		uint32_t direction: 1;
59 		uint32_t num: 3;
60 		uint32_t cycle: 3;
61 		uint32_t scale: 3;
62 	};
63 	uint32_t val;
64 };
65 
66 struct pwm_led_esp32_config {
67 	/* Speed mode
68 	 * 0: High speed mode
69 	 * 1: Low speed mode
70 	 *
71 	 * Timers
72 	 * 0 - 3: 4 timers
73 	 */
74 
75 	struct pwm_led_esp32_channel ch_cfg[16];
76 
77 	struct pwm_led_esp32_timer timer_cfg[2][4];
78 };
79 
80 /* TODO: Remove these functions after this PR:
81  * https://github.com/zephyrproject-rtos/zephyr/pull/5113
82  */
set_mask32(uint32_t v,uint32_t mem_addr)83 static inline void set_mask32(uint32_t v, uint32_t mem_addr)
84 {
85 	sys_write32(sys_read32(mem_addr) | v, mem_addr);
86 }
87 
clear_mask32(uint32_t v,uint32_t mem_addr)88 static inline void clear_mask32(uint32_t v, uint32_t mem_addr)
89 {
90 	sys_write32(sys_read32(mem_addr) & ~v, mem_addr);
91 }
92 
esp32_get_gpio_for_pin(int pin)93 static const char *esp32_get_gpio_for_pin(int pin)
94 {
95 	if (pin < 32) {
96 #if defined(CONFIG_GPIO_ESP32_0)
97 		return DT_INST_LABEL(0);
98 #else
99 		return NULL;
100 #endif /* CONFIG_GPIO_ESP32_0 */
101 	}
102 
103 #if defined(CONFIG_GPIO_ESP32_1)
104 	return DT_INST_LABEL(1);
105 #else
106 	return NULL;
107 #endif /* CONFIG_GPIO_ESP32_1 */
108 }
109 /* end Remove after PR 5113 */
110 
pwm_led_esp32_get_gpio_config(uint8_t pin,const struct pwm_led_esp32_channel * ch_cfg)111 static uint8_t pwm_led_esp32_get_gpio_config(uint8_t pin,
112 		const struct pwm_led_esp32_channel *ch_cfg)
113 {
114 	uint8_t i;
115 
116 	for (i = 0U; i < 16; i++) {
117 		if (ch_cfg[i].gpio == pin) {
118 			return i;
119 		}
120 	}
121 	return -EINVAL;
122 }
123 
pwm_led_esp32_low_speed_update(int speed_mode,int channel)124 static void pwm_led_esp32_low_speed_update(int speed_mode, int channel)
125 {
126 	uint32_t reg_addr;
127 
128 	if (speed_mode == PWM_LED_ESP32_LOW_SPEED) {
129 		reg_addr = PWM_ESP32_LSCH_CONF0(channel);
130 		sys_set_bit(reg_addr, LEDC_PARA_UP_LSCH0_S);
131 	}
132 }
133 
pwm_led_esp32_update_duty(int speed_mode,int channel)134 static void pwm_led_esp32_update_duty(int speed_mode, int channel)
135 {
136 	uint32_t conf0_addr;
137 	uint32_t conf1_addr;
138 
139 	if (speed_mode == PWM_LED_ESP32_HIGH_SPEED) {
140 		conf0_addr = PWM_ESP32_HSCH_CONF0(channel);
141 		conf1_addr = PWM_ESP32_HSCH_CONF1(channel);
142 	} else {
143 		conf0_addr = PWM_ESP32_LSCH_CONF0(channel);
144 		conf1_addr = PWM_ESP32_LSCH_CONF1(channel);
145 	}
146 
147 	sys_set_bit(conf0_addr, LEDC_SIG_OUT_EN_LSCH0_S);
148 	sys_set_bit(conf1_addr, LEDC_DUTY_START_LSCH0_S);
149 
150 	pwm_led_esp32_low_speed_update(speed_mode, channel);
151 }
152 
pwm_led_esp32_duty_config(int speed_mode,int channel,int duty_val,union pwm_led_esp32_duty duty)153 static void pwm_led_esp32_duty_config(int speed_mode,
154 				      int channel,
155 				      int duty_val,
156 				      union pwm_led_esp32_duty duty)
157 {
158 	volatile uint32_t hpoint_addr;
159 	volatile uint32_t duty_addr;
160 	volatile uint32_t conf1_addr;
161 	volatile uint32_t conf1_val;
162 
163 	if (speed_mode == PWM_LED_ESP32_HIGH_SPEED) {
164 		hpoint_addr = PWM_ESP32_HSCH_HPOINT(channel);
165 		duty_addr = PWM_ESP32_HSCH_DUTY(channel);
166 		conf1_addr = PWM_ESP32_HSCH_CONF1(channel);
167 
168 	} else {
169 		hpoint_addr = PWM_ESP32_LSCH_HPOINT(channel);
170 		duty_addr = PWM_ESP32_LSCH_DUTY(channel);
171 		conf1_addr = PWM_ESP32_LSCH_CONF1(channel);
172 	}
173 
174 	sys_write32(0, hpoint_addr);
175 	sys_write32(duty_val, duty_addr);
176 	sys_write32(duty.val, conf1_addr);
177 
178 	pwm_led_esp32_low_speed_update(speed_mode, channel);
179 }
180 
pwm_led_esp32_duty_set(int speed_mode,int channel,int duty_val)181 static void pwm_led_esp32_duty_set(int speed_mode, int channel, int duty_val)
182 {
183 	union pwm_led_esp32_duty duty;
184 
185 	duty.start = 0U;
186 	duty.direction = 1U;
187 	duty.cycle = 1U;
188 	duty.scale = 0U;
189 
190 	pwm_led_esp32_duty_config(speed_mode, channel, duty_val << 4, duty);
191 }
192 
pwm_led_esp32_bind_channel_timer(int speed_mode,int channel,int timer)193 static void pwm_led_esp32_bind_channel_timer(int speed_mode,
194 					     int channel,
195 					     int timer)
196 {
197 	volatile uint32_t timer_addr;
198 
199 	if (speed_mode == PWM_LED_ESP32_HIGH_SPEED) {
200 		timer_addr = PWM_ESP32_HSCH_CONF0(channel);
201 	} else {
202 		timer_addr = PWM_ESP32_LSCH_CONF0(channel);
203 	}
204 
205 	set_mask32(timer, timer_addr);
206 
207 	pwm_led_esp32_low_speed_update(speed_mode, channel);
208 }
209 
pwm_led_esp32_channel_set(int pin,bool speed_mode,int channel,int duty,int timer)210 static int pwm_led_esp32_channel_set(int pin, bool speed_mode, int channel,
211 				     int duty, int timer)
212 {
213 	const int pin_mode = GPIO_OUTPUT;
214 
215 	const char *device_name;
216 	const struct device *gpio;
217 	int ret;
218 	uint32_t sig_out_idx;
219 
220 	/* Set duty cycle */
221 	pwm_led_esp32_duty_set(speed_mode, channel, duty);
222 
223 	pwm_led_esp32_update_duty(speed_mode, channel);
224 
225 	pwm_led_esp32_bind_channel_timer(speed_mode, channel, timer);
226 
227 	/* Set pin */
228 	device_name = esp32_get_gpio_for_pin(pin);
229 	if (!device_name) {
230 		return -EINVAL;
231 	}
232 
233 	gpio = device_get_binding(device_name);
234 	if (!gpio) {
235 		return -EINVAL;
236 	}
237 
238 	ret = gpio_pin_configure(gpio, pin, pin_mode);
239 	if (ret < 0) {
240 		return ret;
241 	}
242 
243 	if (speed_mode == PWM_LED_ESP32_HIGH_SPEED) {
244 		sig_out_idx = LEDC_HS_SIG_OUT0_IDX + channel;
245 	} else {
246 		sig_out_idx = LEDC_LS_SIG_OUT0_IDX + channel;
247 	}
248 	esp32_rom_gpio_matrix_out(pin, sig_out_idx, 0, 0);
249 
250 	return 0;
251 }
252 
pwm_led_esp32_timer_set(int speed_mode,int timer,int bit_num,int frequency)253 static int pwm_led_esp32_timer_set(int speed_mode, int timer,
254 				   int bit_num, int frequency)
255 {
256 	uint32_t timer_addr;
257 	uint64_t div_num;
258 	int tick_sel = PWM_LED_ESP32_APB_CLK_FREQ;
259 	uint32_t precision = (0x1 << bit_num);
260 
261 	__ASSERT_NO_MSG(frequency > 0);
262 
263 	/* This expression comes from ESP32 Espressif's Technical Reference
264 	 * Manual chapter 13.2.2 Timers.
265 	 * div_num is a fixed point value (Q10.8).
266 	 */
267 	div_num = ((uint64_t) APB_CLK_FREQ << 8) / frequency / precision;
268 
269 	if (div_num < 0x100) {
270 		/* Since Q10.8 is a fixed point value, then div_num < 0x100
271 		 *  means divisor is too low.
272 		 */
273 		return -EINVAL;
274 	}
275 
276 	if (div_num > 0x3FFFF) {
277 		/* Since Q10.8 is a fixed point value, then div_num > 0x3FFFF
278 		 * means divisor is too high. We can try to use the REF_TICK.
279 		 */
280 		div_num = ((uint64_t) 1000000 << 8) / frequency / precision;
281 		if (div_num < 0x100 || div_num > 0x3FFFF) {
282 			return -EINVAL;
283 		}
284 		tick_sel = PWM_LED_ESP32_REF_TICK_FREQ;
285 	} else {
286 		if (speed_mode) {
287 			sys_set_bit(LEDC_CONF_REG, LEDC_APB_CLK_SEL_S);
288 		}
289 	}
290 
291 	if (speed_mode == PWM_LED_ESP32_HIGH_SPEED) {
292 		timer_addr = PWM_ESP32_HSTIMER(timer);
293 	} else {
294 		timer_addr = PWM_ESP32_LSTIMER(timer);
295 	}
296 
297 	set_mask32(div_num << LEDC_DIV_NUM_LSTIMER0_S, timer_addr);
298 	set_mask32(tick_sel << LEDC_TICK_SEL_LSTIMER0_S, timer_addr);
299 	set_mask32(bit_num & LEDC_LSTIMER0_LIM_M, timer_addr);
300 
301 	if (speed_mode) {
302 		/* update div_num and bit_num */
303 		sys_set_bit(timer_addr, LEDC_LSTIMER0_PARA_UP_S);
304 	}
305 
306 	/* reset low speed timer */
307 	sys_set_bit(timer_addr, LEDC_LSTIMER0_RST_S);
308 	sys_clear_bit(timer_addr, LEDC_LSTIMER0_RST_S);
309 
310 	return 0;
311 }
312 
313 /* period_cycles is not used, set frequency on menuconfig instead. */
pwm_led_esp32_pin_set_cycles(const struct device * dev,uint32_t pwm,uint32_t period_cycles,uint32_t pulse_cycles,pwm_flags_t flags)314 static int pwm_led_esp32_pin_set_cycles(const struct device *dev,
315 					uint32_t pwm, uint32_t period_cycles,
316 					uint32_t pulse_cycles, pwm_flags_t flags)
317 {
318 	int speed_mode;
319 	int channel;
320 	int timer;
321 	int ret;
322 	const struct pwm_led_esp32_config * const config =
323 		(const struct pwm_led_esp32_config *) dev->config;
324 
325 	ARG_UNUSED(period_cycles);
326 
327 	if (flags) {
328 		/* PWM polarity not supported (yet?) */
329 		return -ENOTSUP;
330 	}
331 
332 	channel = pwm_led_esp32_get_gpio_config(pwm, config->ch_cfg);
333 	if (channel < 0) {
334 		return -EINVAL;
335 	}
336 	speed_mode = channel < 8 ? PWM_LED_ESP32_HIGH_SPEED :
337 				   PWM_LED_ESP32_LOW_SPEED;
338 
339 	timer = config->ch_cfg[channel].timer;
340 	/* Now we know which speed_mode and timer is set, then we will convert
341 	 * the channel number from (0 - 15) to (0 - 7).
342 	 */
343 	channel %= 8;
344 
345 	/* Enable peripheral */
346 	set_mask32(DPORT_LEDC_CLK_EN, DPORT_PERIP_CLK_EN_REG);
347 	clear_mask32(DPORT_LEDC_RST, DPORT_PERIP_RST_EN_REG);
348 
349 	/* Set timer */
350 	ret = pwm_led_esp32_timer_set(speed_mode, timer,
351 			config->timer_cfg[speed_mode][timer].bit_num,
352 			config->timer_cfg[speed_mode][timer].freq);
353 	if (ret < 0) {
354 		return ret;
355 	}
356 
357 	/* Set channel */
358 	ret = pwm_led_esp32_channel_set(pwm, speed_mode, channel, 0, timer);
359 	if (ret < 0) {
360 		return ret;
361 	}
362 	pwm_led_esp32_duty_set(speed_mode, channel, pulse_cycles);
363 	pwm_led_esp32_update_duty(speed_mode, channel);
364 
365 	return ret;
366 }
367 
pwm_led_esp32_get_cycles_per_sec(const struct device * dev,uint32_t pwm,uint64_t * cycles)368 static int pwm_led_esp32_get_cycles_per_sec(const struct device *dev,
369 					    uint32_t pwm,
370 					    uint64_t *cycles)
371 {
372 	const struct pwm_led_esp32_config *config;
373 	int channel;
374 	int timer;
375 	int speed_mode;
376 
377 	config = (const struct pwm_led_esp32_config *) dev->config;
378 
379 	channel = pwm_led_esp32_get_gpio_config(pwm, config->ch_cfg);
380 	if (channel < 0) {
381 		return -EINVAL;
382 	}
383 	speed_mode = channel < 8 ? PWM_LED_ESP32_HIGH_SPEED :
384 				   PWM_LED_ESP32_LOW_SPEED;
385 
386 	timer = config->ch_cfg[channel].timer;
387 
388 	*cycles = config->timer_cfg[speed_mode][timer].freq;
389 
390 	return 0;
391 }
392 
393 static const struct pwm_driver_api pwm_led_esp32_api = {
394 	.pin_set = pwm_led_esp32_pin_set_cycles,
395 	.get_cycles_per_sec = pwm_led_esp32_get_cycles_per_sec,
396 };
397 
pwm_led_esp32_init(const struct device * dev)398 int pwm_led_esp32_init(const struct device *dev)
399 {
400 	return 0;
401 }
402 
403 /* Initialization for PWM_LED_ESP32 */
404 #include <device.h>
405 #include <init.h>
406 
407 DEVICE_DECLARE(pwm_led_esp32_0);
408 
409 #define CH_HS_TIMER(i) ((CONFIG_PWM_LED_ESP32_HS_CH ## i ## _TIMER) & 0x2)
410 #define CH_HS_GPIO(i) ((CONFIG_PWM_LED_ESP32_HS_CH ## i ## _GPIO) & 0xfff)
411 #define CH_LS_TIMER(i) ((CONFIG_PWM_LED_ESP32_LS_CH ## i ## _TIMER) & 0x2)
412 #define CH_LS_GPIO(i) ((CONFIG_PWM_LED_ESP32_LS_CH ## i ## _GPIO) & 0xfff)
413 
414 #define TIMER_HS_FREQ(i) (CONFIG_PWM_LED_ESP32_HS_TIMER ## i ## _FREQ)
415 #define TIMER_LS_FREQ(i) (CONFIG_PWM_LED_ESP32_LS_TIMER ## i ## _FREQ)
416 #define TIMER_HS_BIT_NUM(i) (CONFIG_PWM_LED_ESP32_HS_TIMER ## i ## _BIT_NUM)
417 #define TIMER_LS_BIT_NUM(i) (CONFIG_PWM_LED_ESP32_LS_TIMER ## i ## _BIT_NUM)
418 
419 const static struct pwm_led_esp32_config pwm_led_esp32_config = {
420 	.timer_cfg[PWM_LED_ESP32_HIGH_SPEED][0] = {
421 		.bit_num = TIMER_HS_BIT_NUM(0),
422 		.freq = TIMER_HS_FREQ(0),
423 	},
424 	.timer_cfg[PWM_LED_ESP32_HIGH_SPEED][1] = {
425 		.bit_num = TIMER_HS_BIT_NUM(1),
426 		.freq = TIMER_HS_FREQ(1),
427 	},
428 	.timer_cfg[PWM_LED_ESP32_HIGH_SPEED][2] = {
429 		.bit_num = TIMER_HS_BIT_NUM(2),
430 		.freq = TIMER_HS_FREQ(2),
431 	},
432 	.timer_cfg[PWM_LED_ESP32_HIGH_SPEED][2] = {
433 		.bit_num = TIMER_HS_BIT_NUM(2),
434 		.freq = TIMER_HS_FREQ(2),
435 	},
436 	.timer_cfg[PWM_LED_ESP32_HIGH_SPEED][3] = {
437 		.bit_num = TIMER_HS_BIT_NUM(3),
438 		.freq = TIMER_HS_FREQ(3),
439 	},
440 	.timer_cfg[PWM_LED_ESP32_LOW_SPEED][0] = {
441 		.bit_num = TIMER_LS_BIT_NUM(0),
442 		.freq = TIMER_LS_FREQ(0),
443 	},
444 	.timer_cfg[PWM_LED_ESP32_LOW_SPEED][1] = {
445 		.bit_num = TIMER_LS_BIT_NUM(1),
446 		.freq = TIMER_LS_FREQ(1),
447 	},
448 	.timer_cfg[PWM_LED_ESP32_LOW_SPEED][2] = {
449 		.bit_num = TIMER_LS_BIT_NUM(2),
450 		.freq = TIMER_LS_FREQ(2),
451 	},
452 	.timer_cfg[PWM_LED_ESP32_LOW_SPEED][3] = {
453 		.bit_num = TIMER_LS_BIT_NUM(3),
454 		.freq = TIMER_LS_FREQ(3),
455 	},
456 	.ch_cfg[0] = {
457 		.timer = CH_HS_TIMER(0),
458 		.gpio = CH_HS_GPIO(0),
459 	},
460 	.ch_cfg[1] = {
461 		.timer = CH_HS_TIMER(1),
462 		.gpio = CH_HS_GPIO(1),
463 	},
464 	.ch_cfg[2] = {
465 		.timer = CH_HS_TIMER(2),
466 		.gpio = CH_HS_GPIO(2),
467 	},
468 	.ch_cfg[3] = {
469 		.timer = CH_HS_TIMER(3),
470 		.gpio = CH_HS_GPIO(3),
471 	},
472 	.ch_cfg[4] = {
473 		.timer = CH_HS_TIMER(4),
474 		.gpio = CH_HS_GPIO(4),
475 	},
476 	.ch_cfg[5] = {
477 		.timer = CH_HS_TIMER(5),
478 		.gpio = CH_HS_GPIO(5),
479 	},
480 	.ch_cfg[6] = {
481 		.timer = CH_HS_TIMER(6),
482 		.gpio = CH_HS_GPIO(6),
483 	},
484 	.ch_cfg[7] = {
485 		.timer = CH_HS_TIMER(7),
486 		.gpio = CH_HS_GPIO(7),
487 	},
488 	.ch_cfg[8] = {
489 		.timer = CH_LS_TIMER(0),
490 		.gpio = CH_LS_GPIO(0),
491 	},
492 	.ch_cfg[9] = {
493 		.timer = CH_LS_TIMER(1),
494 		.gpio = CH_LS_GPIO(1),
495 	},
496 	.ch_cfg[10] = {
497 		.timer = CH_LS_TIMER(2),
498 		.gpio = CH_LS_GPIO(2),
499 	},
500 	.ch_cfg[11] = {
501 		.timer = CH_LS_TIMER(3),
502 		.gpio = CH_LS_GPIO(3),
503 	},
504 	.ch_cfg[12] = {
505 		.timer = CH_LS_TIMER(4),
506 		.gpio = CH_LS_GPIO(4),
507 	},
508 	.ch_cfg[13] = {
509 		.timer = CH_LS_TIMER(5),
510 		.gpio = CH_LS_GPIO(5),
511 	},
512 	.ch_cfg[14] = {
513 		.timer = CH_LS_TIMER(6),
514 		.gpio = CH_LS_GPIO(6),
515 	},
516 	.ch_cfg[15] = {
517 		.timer = CH_LS_TIMER(7),
518 		.gpio = CH_LS_GPIO(7),
519 	},
520 };
521 
522 DEVICE_DEFINE(pwm_led_esp32_0, CONFIG_PWM_LED_ESP32_DEV_NAME_0,
523 		pwm_led_esp32_init, NULL, NULL,
524 		&pwm_led_esp32_config, POST_KERNEL,
525 		CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &pwm_led_esp32_api);
526