1 /*
2 * Copyright (c) 2017 Vitor Massaru Iha <vitor@massaru.org>
3 * Copyright (c) 2025 Espressif Systems (Shanghai) Co., Ltd.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #define DT_DRV_COMPAT espressif_esp32_ledc
9
10 #include <hal/ledc_hal.h>
11 #include <hal/ledc_types.h>
12 #include <esp_clk_tree.h>
13
14 #include <soc.h>
15 #include <errno.h>
16 #include <string.h>
17 #include <zephyr/drivers/pwm.h>
18 #include <zephyr/kernel.h>
19 #include <zephyr/drivers/pinctrl.h>
20 #include <zephyr/drivers/clock_control.h>
21
22 #include <zephyr/logging/log.h>
23 LOG_MODULE_REGISTER(pwm_ledc_esp32, CONFIG_PWM_LOG_LEVEL);
24
25 static const int global_clks[] = LEDC_LL_GLOBAL_CLOCKS;
26 #if SOC_LEDC_HAS_TIMER_SPECIFIC_MUX
27 static const int timer_specific_clks[] = LEDC_LL_TIMER_SPECIFIC_CLOCKS;
28 static int lowspd_clks[ARRAY_SIZE(global_clks) + ARRAY_SIZE(timer_specific_clks)];
29 #endif
30 #if SOC_LEDC_SUPPORT_HS_MODE
31 static const int highspd_clks[] = {LEDC_APB_CLK, LEDC_REF_TICK};
32 #endif
33
34 struct pwm_ledc_esp32_data {
35 ledc_hal_context_t hal;
36 struct k_sem cmd_sem;
37 };
38
39 struct pwm_ledc_esp32_channel_config {
40 const uint8_t idx;
41 const uint8_t channel_num;
42 const uint8_t timer_num;
43 uint32_t freq;
44 const ledc_mode_t speed_mode;
45 uint8_t resolution;
46 ledc_clk_src_t clock_src;
47 uint32_t clock_src_hz;
48 uint32_t duty_val;
49 bool inverted;
50 };
51
52 struct pwm_ledc_esp32_config {
53 const struct pinctrl_dev_config *pincfg;
54 const struct device *clock_dev;
55 const clock_control_subsys_t clock_subsys;
56 struct pwm_ledc_esp32_channel_config *channel_config;
57 const int channel_len;
58 };
59
get_channel_config(const struct device * dev,int channel_id)60 static struct pwm_ledc_esp32_channel_config *get_channel_config(const struct device *dev,
61 int channel_id)
62 {
63 struct pwm_ledc_esp32_config *config = (struct pwm_ledc_esp32_config *)dev->config;
64
65 for (uint8_t i = 0; i < config->channel_len; i++) {
66 if (config->channel_config[i].idx == channel_id) {
67 return &config->channel_config[i];
68 }
69 }
70 return NULL;
71 }
72
pwm_led_esp32_start(struct pwm_ledc_esp32_data * data,struct pwm_ledc_esp32_channel_config * channel)73 static void pwm_led_esp32_start(struct pwm_ledc_esp32_data *data,
74 struct pwm_ledc_esp32_channel_config *channel)
75 {
76 ledc_hal_set_sig_out_en(&data->hal, channel->channel_num, true);
77 ledc_hal_set_duty_start(&data->hal, channel->channel_num, true);
78
79 if (channel->speed_mode == LEDC_LOW_SPEED_MODE) {
80 ledc_hal_ls_channel_update(&data->hal, channel->channel_num);
81 }
82 }
83
pwm_led_esp32_stop(struct pwm_ledc_esp32_data * data,struct pwm_ledc_esp32_channel_config * channel,bool idle_level)84 static void pwm_led_esp32_stop(struct pwm_ledc_esp32_data *data,
85 struct pwm_ledc_esp32_channel_config *channel, bool idle_level)
86 {
87 ledc_hal_set_idle_level(&data->hal, channel->channel_num, idle_level);
88 ledc_hal_set_sig_out_en(&data->hal, channel->channel_num, false);
89 ledc_hal_set_duty_start(&data->hal, channel->channel_num, false);
90
91 if (channel->speed_mode == LEDC_LOW_SPEED_MODE) {
92 ledc_hal_ls_channel_update(&data->hal, channel->channel_num);
93 }
94 }
95
pwm_led_esp32_duty_set(const struct device * dev,struct pwm_ledc_esp32_channel_config * channel)96 static void pwm_led_esp32_duty_set(const struct device *dev,
97 struct pwm_ledc_esp32_channel_config *channel)
98 {
99 struct pwm_ledc_esp32_data *data = (struct pwm_ledc_esp32_data *const)(dev)->data;
100
101 ledc_hal_set_hpoint(&data->hal, channel->channel_num, 0);
102 ledc_hal_set_duty_int_part(&data->hal, channel->channel_num, channel->duty_val);
103 ledc_hal_set_duty_direction(&data->hal, channel->channel_num, 1);
104 ledc_hal_set_duty_num(&data->hal, channel->channel_num, 1);
105 ledc_hal_set_duty_cycle(&data->hal, channel->channel_num, 1);
106 ledc_hal_set_duty_scale(&data->hal, channel->channel_num, 0);
107 }
108
pwm_led_esp32_calculate_max_resolution(struct pwm_ledc_esp32_channel_config * channel)109 static int pwm_led_esp32_calculate_max_resolution(struct pwm_ledc_esp32_channel_config *channel)
110 {
111 /**
112 * Max duty resolution can be obtained with
113 * max_res = log2(CLK_FREQ/FREQ)
114 */
115 uint32_t max_precision_n = channel->clock_src_hz / channel->freq;
116
117 for (uint8_t i = 0; i <= SOC_LEDC_TIMER_BIT_WIDTH; i++) {
118 max_precision_n /= 2;
119 if (!max_precision_n) {
120 channel->resolution = i;
121 return 0;
122 }
123 }
124 return -EINVAL;
125 }
126
pwm_led_esp32_timer_config(struct pwm_ledc_esp32_channel_config * channel)127 static int pwm_led_esp32_timer_config(struct pwm_ledc_esp32_channel_config *channel)
128 {
129 const int *clock_src;
130 int clock_src_num;
131
132 if (channel->speed_mode == LEDC_LOW_SPEED_MODE) {
133 #ifdef SOC_LEDC_HAS_TIMER_SPECIFIC_MUX
134 clock_src = lowspd_clks;
135 clock_src_num = ARRAY_SIZE(lowspd_clks);
136 #else
137 clock_src = global_clks;
138 clock_src_num = ARRAY_SIZE(global_clks);
139 #endif
140 }
141 #ifdef SOC_LEDC_SUPPORT_HS_MODE
142 else {
143 clock_src = highspd_clks;
144 clock_src_num = ARRAY_SIZE(highspd_clks);
145 }
146 #endif
147
148 /**
149 * Calculate max resolution based on the given frequency and the pwm clock.
150 * Try each clock source available depending on the device and channel type.
151 */
152 for (int i = 0; i < clock_src_num; i++) {
153 channel->clock_src = clock_src[i];
154 esp_clk_tree_src_get_freq_hz(channel->clock_src,
155 ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED,
156 &channel->clock_src_hz);
157 if (!pwm_led_esp32_calculate_max_resolution(channel)) {
158 return 0;
159 }
160 }
161
162 /* Frequency is too low for this device, so even though best precision can't
163 * be achieved we can set max resolution and consider that the previous
164 * loop selects clock from fastest to slowest, so this is the best
165 * configuration achievable.
166 */
167 channel->resolution = SOC_LEDC_TIMER_BIT_WIDTH;
168
169 return 0;
170 }
171
pwm_led_esp32_timer_set(const struct device * dev,struct pwm_ledc_esp32_channel_config * channel)172 static int pwm_led_esp32_timer_set(const struct device *dev,
173 struct pwm_ledc_esp32_channel_config *channel)
174 {
175 int prescaler = 0;
176 uint32_t precision = (0x1 << channel->resolution);
177 struct pwm_ledc_esp32_data *data = (struct pwm_ledc_esp32_data *const)(dev)->data;
178
179 __ASSERT_NO_MSG(channel->freq > 0);
180
181 prescaler = ((uint64_t)channel->clock_src_hz << 8) / channel->freq / precision;
182
183 if (prescaler < 0x100 || prescaler > 0x3FFFF) {
184 LOG_ERR("Prescaler out of range: %#X", prescaler);
185 return -EINVAL;
186 }
187
188 if (channel->speed_mode == LEDC_LOW_SPEED_MODE) {
189 ledc_hal_set_slow_clk_sel(&data->hal, channel->clock_src);
190 }
191
192 ledc_hal_set_clock_divider(&data->hal, channel->timer_num, prescaler);
193 ledc_hal_set_duty_resolution(&data->hal, channel->timer_num, channel->resolution);
194 ledc_hal_set_clock_source(&data->hal, channel->timer_num, channel->clock_src);
195
196 if (channel->speed_mode == LEDC_LOW_SPEED_MODE) {
197 ledc_hal_ls_timer_update(&data->hal, channel->timer_num);
198 }
199
200 LOG_DBG("channel_num=%d, speed_mode=%d, timer_num=%d, clock_src=%d, prescaler=%d, "
201 "resolution=%d\n",
202 channel->channel_num, channel->speed_mode, channel->timer_num, channel->clock_src,
203 prescaler, channel->resolution);
204
205 return 0;
206 }
207
pwm_led_esp32_get_cycles_per_sec(const struct device * dev,uint32_t channel_idx,uint64_t * cycles)208 static int pwm_led_esp32_get_cycles_per_sec(const struct device *dev, uint32_t channel_idx,
209 uint64_t *cycles)
210 {
211 struct pwm_ledc_esp32_channel_config *channel = get_channel_config(dev, channel_idx);
212
213 if (!channel) {
214 LOG_ERR("Error getting channel %d", channel_idx);
215 return -EINVAL;
216 }
217
218 *cycles = (uint64_t)channel->clock_src_hz;
219
220 return 0;
221 }
222
pwm_led_esp32_channel_update_frequency(const struct device * dev,struct pwm_ledc_esp32_channel_config * channel,uint32_t period_cycles)223 static int pwm_led_esp32_channel_update_frequency(const struct device *dev,
224 struct pwm_ledc_esp32_channel_config *channel,
225 uint32_t period_cycles)
226 {
227 const struct pwm_ledc_esp32_config *config = dev->config;
228 uint32_t current_freq = channel->freq;
229 uint64_t clk_freq;
230 int ret;
231
232 ret = pwm_led_esp32_get_cycles_per_sec(dev, channel->idx, &clk_freq);
233
234 if (ret < 0) {
235 return ret;
236 }
237
238 channel->freq = (uint32_t)(clk_freq / period_cycles);
239
240 if (!channel->freq) {
241 channel->freq = 1;
242 }
243
244 if (channel->freq == current_freq) {
245 /* No need to reconfigure timer */
246 return 0;
247 }
248
249 /* Check whether another channel is using the same timer.
250 * Timers can only be shared if the same frequency is used, so
251 * first set operation will take precedence.
252 */
253 for (int i = 0; i < config->channel_len; ++i) {
254 struct pwm_ledc_esp32_channel_config *ch = &config->channel_config[i];
255
256 if (ch->freq && (channel->channel_num != ch->channel_num) &&
257 (channel->timer_num == ch->timer_num) &&
258 (channel->speed_mode == ch->speed_mode) &&
259 (channel->freq != ch->freq)) {
260 LOG_ERR("Timer can't be shared and different frequency be "
261 "requested");
262 channel->freq = 0;
263 return -EINVAL;
264 }
265 }
266
267 pwm_led_esp32_timer_config(channel);
268
269 ret = pwm_led_esp32_timer_set(dev, channel);
270
271 if (ret < 0) {
272 LOG_ERR("Error setting timer for channel %d", channel->idx);
273 return ret;
274 }
275
276 return 0;
277 }
278
pwm_led_esp32_set_cycles(const struct device * dev,uint32_t channel_idx,uint32_t period_cycles,uint32_t pulse_cycles,pwm_flags_t flags)279 static int pwm_led_esp32_set_cycles(const struct device *dev, uint32_t channel_idx,
280 uint32_t period_cycles, uint32_t pulse_cycles,
281 pwm_flags_t flags)
282 {
283 struct pwm_ledc_esp32_data *data = (struct pwm_ledc_esp32_data *const)(dev)->data;
284 struct pwm_ledc_esp32_channel_config *channel = get_channel_config(dev, channel_idx);
285 int ret = 0;
286
287 if (!channel) {
288 LOG_ERR("Error getting channel %d", channel_idx);
289 return -EINVAL;
290 }
291
292 k_sem_take(&data->cmd_sem, K_FOREVER);
293
294 if (flags & PWM_POLARITY_INVERTED) {
295 pulse_cycles = period_cycles - pulse_cycles;
296 channel->inverted = true;
297 } else {
298 channel->inverted = false;
299 }
300
301 ledc_hal_init(&data->hal, channel->speed_mode);
302
303 if ((pulse_cycles == period_cycles) || (pulse_cycles == 0)) {
304 /* For duty 0% and 100% stop PWM, set output level and return */
305 pwm_led_esp32_stop(data, channel, (pulse_cycles == period_cycles));
306 goto sem_give;
307 }
308
309 ret = pwm_led_esp32_channel_update_frequency(dev, channel, period_cycles);
310
311 if (ret < 0) {
312 LOG_ERR("Error updating frequency of channel %d", channel_idx);
313 goto sem_give;
314 }
315
316 /* Update PWM duty */
317
318 double duty_cycle = (double)pulse_cycles / (double)period_cycles;
319
320 channel->duty_val = (uint32_t)((double)(1 << channel->resolution) * duty_cycle);
321
322 pwm_led_esp32_duty_set(dev, channel);
323
324 pwm_led_esp32_start(data, channel);
325
326 sem_give:
327 k_sem_give(&data->cmd_sem);
328
329 return ret;
330 }
331
pwm_led_esp32_init(const struct device * dev)332 int pwm_led_esp32_init(const struct device *dev)
333 {
334 const struct pwm_ledc_esp32_config *config = dev->config;
335 struct pwm_ledc_esp32_data *data = dev->data;
336 struct pwm_ledc_esp32_channel_config *channel;
337 int ret = 0;
338
339 if (!device_is_ready(config->clock_dev)) {
340 LOG_ERR("clock control device not ready");
341 return -ENODEV;
342 }
343
344 /* Enable peripheral */
345 clock_control_on(config->clock_dev, config->clock_subsys);
346
347 #if SOC_LEDC_HAS_TIMER_SPECIFIC_MUX
348 /* Combine clock sources to include timer specific sources */
349 memcpy(lowspd_clks, global_clks, sizeof(global_clks));
350 memcpy(&lowspd_clks[ARRAY_SIZE(global_clks)], timer_specific_clks,
351 sizeof(timer_specific_clks));
352 #endif
353
354 for (int i = 0; i < config->channel_len; ++i) {
355 channel = &config->channel_config[i];
356
357 ledc_hal_init(&data->hal, channel->speed_mode);
358
359 if (channel->speed_mode == LEDC_LOW_SPEED_MODE) {
360 channel->clock_src = global_clks[0];
361 ledc_hal_set_slow_clk_sel(&data->hal, channel->clock_src);
362 }
363 #ifdef SOC_LEDC_SUPPORT_HS_MODE
364 else {
365 channel->clock_src = highspd_clks[0];
366 }
367 #endif
368 ledc_hal_set_clock_source(&data->hal, channel->timer_num, channel->clock_src);
369
370 esp_clk_tree_src_get_freq_hz(channel->clock_src,
371 ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED,
372 &channel->clock_src_hz);
373
374 ledc_hal_bind_channel_timer(&data->hal, channel->channel_num, channel->timer_num);
375 pwm_led_esp32_stop(data, channel, channel->inverted);
376 ledc_hal_timer_rst(&data->hal, channel->timer_num);
377 }
378
379 ret = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
380
381 if (ret < 0) {
382 LOG_ERR("PWM pinctrl setup failed (%d)", ret);
383 return ret;
384 }
385
386 return 0;
387 }
388
389 static DEVICE_API(pwm, pwm_led_esp32_api) = {
390 .set_cycles = pwm_led_esp32_set_cycles,
391 .get_cycles_per_sec = pwm_led_esp32_get_cycles_per_sec,
392 };
393
394 PINCTRL_DT_INST_DEFINE(0);
395
396 #define CHANNEL_CONFIG(node_id) \
397 { \
398 .idx = DT_REG_ADDR(node_id), \
399 .channel_num = DT_REG_ADDR(node_id) % 8, \
400 .timer_num = DT_PROP(node_id, timer), \
401 .speed_mode = DT_REG_ADDR(node_id) < SOC_LEDC_CHANNEL_NUM ? LEDC_LOW_SPEED_MODE \
402 : !LEDC_LOW_SPEED_MODE, \
403 .inverted = DT_PROP(node_id, inverted), \
404 },
405
406 static struct pwm_ledc_esp32_channel_config channel_config[] = {
407 DT_INST_FOREACH_CHILD(0, CHANNEL_CONFIG)};
408
409 static struct pwm_ledc_esp32_config pwm_ledc_esp32_config = {
410 .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0),
411 .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(0)),
412 .clock_subsys = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(0, offset),
413 .channel_config = channel_config,
414 .channel_len = ARRAY_SIZE(channel_config),
415 };
416
417 static struct pwm_ledc_esp32_data pwm_ledc_esp32_data = {
418 .hal = {
419 .dev = (ledc_dev_t *) DT_INST_REG_ADDR(0),
420 },
421 .cmd_sem = Z_SEM_INITIALIZER(pwm_ledc_esp32_data.cmd_sem, 1, 1),
422 };
423
424 DEVICE_DT_INST_DEFINE(0, &pwm_led_esp32_init, NULL, &pwm_ledc_esp32_data, &pwm_ledc_esp32_config,
425 POST_KERNEL, CONFIG_PWM_INIT_PRIORITY, &pwm_led_esp32_api);
426