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