This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 5991a8c4cc xtensa/espressif: Change LEDC implementation to common for 
Xtensa based Espressif chips
5991a8c4cc is described below

commit 5991a8c4cc1152039e1167d6f6bfb25346f1c387
Author: Eren Terzioglu <eren.terzio...@espressif.com>
AuthorDate: Tue Jun 10 13:59:35 2025 +0200

    xtensa/espressif: Change LEDC implementation to common for Xtensa based 
Espressif chips
    
    Change LEDC implementation to common one for esp32[-s2|-s3]
    
    Signed-off-by: Eren Terzioglu <eren.terzio...@espressif.com>
---
 arch/xtensa/src/common/espressif/Kconfig           |  168 ++
 arch/xtensa/src/common/espressif/Make.defs         |    4 +
 arch/xtensa/src/common/espressif/esp_ledc.c        | 1787 ++++++++++++++++++++
 .../esp32s2_ledc.h => common/espressif/esp_ledc.h} |   16 +-
 arch/xtensa/src/esp32s2/Kconfig                    |    1 +
 arch/xtensa/src/esp32s2/Make.defs                  |    4 -
 arch/xtensa/src/esp32s2/esp32s2_ledc.c             |  810 ---------
 arch/xtensa/src/esp32s3/Kconfig                    |    1 +
 arch/xtensa/src/esp32s3/Make.defs                  |    4 -
 arch/xtensa/src/esp32s3/esp32s3_ledc.c             |  865 ----------
 arch/xtensa/src/esp32s3/esp32s3_ledc.h             |   52 -
 .../esp32s2/esp32s2-saola-1/configs/pwm/defconfig  |   10 +-
 .../esp32s2/esp32s2-saola-1/src/esp32s2-saola-1.h  |    2 +-
 .../esp32s2/esp32s2-saola-1/src/esp32s2_bringup.c  |    8 +-
 .../esp32s2/esp32s2-saola-1/src/esp32s2_ledc.c     |   18 +-
 .../esp32s3/common/include/esp32s3_board_ledc.h    |    2 +-
 boards/xtensa/esp32s3/common/src/Make.defs         |    2 +-
 .../xtensa/esp32s3/common/src/esp32s3_board_ledc.c |   18 +-
 .../esp32s3/esp32s3-devkit/configs/pwm/defconfig   |   10 +-
 .../esp32s3/esp32s3-devkit/src/esp32s3_bringup.c   |    6 +-
 .../esp32s3/esp32s3-korvo-2/src/esp32s3_bringup.c  |    6 +-
 .../lckfb-szpi-esp32s3/configs/lcd/defconfig       |    7 +-
 .../lckfb-szpi-esp32s3/configs/lvgl/defconfig      |    7 +-
 .../lckfb-szpi-esp32s3/configs/pwm/defconfig       |    7 +-
 .../lckfb-szpi-esp32s3/src/esp32s3_bringup.c       |    4 +-
 25 files changed, 2022 insertions(+), 1797 deletions(-)

diff --git a/arch/xtensa/src/common/espressif/Kconfig 
b/arch/xtensa/src/common/espressif/Kconfig
index 6a39ad19e3..d0f9085433 100644
--- a/arch/xtensa/src/common/espressif/Kconfig
+++ b/arch/xtensa/src/common/espressif/Kconfig
@@ -54,6 +54,13 @@ config ESP_SDM
        select ANALOG
        select DAC
 
+config ESPRESSIF_LEDC
+       bool "LEDC (PWM)"
+       default n
+       depends on ARCH_CHIP_ESP32S2 || ARCH_CHIP_ESP32S3
+       select PWM
+       select ARCH_HAVE_PWM_MULTICHAN
+
 config ESPRESSIF_I2S
        bool
        default n
@@ -153,6 +160,167 @@ config ESPRESSIF_DEDICATED_GPIO_IRQ
        ---help---
                Enable dedicated GPIO IRQ support
 
+menu "LEDC configuration"
+       depends on ESPRESSIF_LEDC
+
+config ESPRESSIF_LEDC_HPOINT
+       hex "LEDC hpoint value"
+       default 0x0000
+       range 0x0 1048575
+       ---help---
+               This value sets the start point of the pulse within each timer 
period,
+               measured in timer ticks. It allows adjusting the phase of the 
signal.
+
+menuconfig ESPRESSIF_LEDC_TIMER0
+       bool "Timer 0"
+       default n
+
+if ESPRESSIF_LEDC_TIMER0
+
+config ESPRESSIF_LEDC_TIMER0_CHANNELS
+       int "Number of Timer 0 channels"
+       default 2 if PWM_MULTICHAN && PWM_NCHANNELS > 1
+       default 1 if !PWM_MULTICHAN || PWM_NCHANNELS = 1
+       range 0 6
+
+config ESPRESSIF_LEDC_TIMER0_RESOLUTION
+       int "Timer 0 resolution"
+       default 12
+       range 1 14
+       ---help---
+               Timer resolution in bits. The resolution is the number of bits 
used to by the timer
+               counter to generate the PWM signal. The duty cycle provided by 
the upper layers
+               will be scaled to fit the resolution.
+
+endif # ESPRESSIF_LEDC_TIMER0
+
+menuconfig ESPRESSIF_LEDC_TIMER1
+       bool "Timer 1"
+       default n
+
+if ESPRESSIF_LEDC_TIMER1
+
+config ESPRESSIF_LEDC_TIMER1_CHANNELS
+       int "Number of Timer 1 channels"
+       default 2 if PWM_MULTICHAN && PWM_NCHANNELS > 1
+       default 1 if !PWM_MULTICHAN || PWM_NCHANNELS = 1
+       range 0 6
+
+config ESPRESSIF_LEDC_TIMER1_RESOLUTION
+       int "Timer 1 resolution"
+       default 12
+       range 1 14
+       ---help---
+               Timer resolution in bits. The resolution is the number of bits 
used to by the timer
+               counter to generate the PWM signal. The duty cycle provided by 
the upper layers
+               will be scaled to fit the resolution.
+
+endif # ESPRESSIF_LEDC_TIMER1
+
+menuconfig ESPRESSIF_LEDC_TIMER2
+       bool "Timer 2"
+       default n
+
+if ESPRESSIF_LEDC_TIMER2
+
+config ESPRESSIF_LEDC_TIMER2_CHANNELS
+       int "Number of Timer 2 channels"
+       default 2 if PWM_MULTICHAN && PWM_NCHANNELS > 1
+       default 1 if !PWM_MULTICHAN || PWM_NCHANNELS = 1
+       range 0 6
+
+config ESPRESSIF_LEDC_TIMER2_RESOLUTION
+       int "Timer 2 resolution"
+       default 12
+       range 1 14
+       ---help---
+               Timer resolution in bits. The resolution is the number of bits 
used to by the timer
+               counter to generate the PWM signal. The duty cycle provided by 
the upper layers
+               will be scaled to fit the resolution.
+
+endif # ESPRESSIF_LEDC_TIMER2
+
+menuconfig ESPRESSIF_LEDC_TIMER3
+       bool "Timer 3"
+       default n
+
+if ESPRESSIF_LEDC_TIMER3
+
+config ESPRESSIF_LEDC_TIMER3_CHANNELS
+       int "Number of Timer 3 channels"
+       default 2 if PWM_MULTICHAN && PWM_NCHANNELS > 1
+       default 1 if !PWM_MULTICHAN || PWM_NCHANNELS = 1
+       range 0 6
+
+config ESPRESSIF_LEDC_TIMER3_RESOLUTION
+       int "Timer 3 resolution"
+       default 12
+       range 1 14
+       ---help---
+               Timer resolution in bits. The resolution is the number of bits 
used to by the timer
+               counter to generate the PWM signal. The duty cycle provided by 
the upper layers
+               will be scaled to fit the resolution.
+
+endif # ESPRESSIF_LEDC_TIMER3
+
+if !ESP32S2_LEDC && !ESP32S3_LEDC
+
+config ESPRESSIF_LEDC_CHANNEL0_PIN
+       int "Channel 0 pin"
+       default 2
+       range 0 48 if ARCH_CHIP_ESP32S3
+       range 0 46 if ARCH_CHIP_ESP32S2
+
+config ESPRESSIF_LEDC_CHANNEL1_PIN
+       int "Channel 1 pin"
+       default 3
+       range 0 48 if ARCH_CHIP_ESP32S3
+       range 0 46 if ARCH_CHIP_ESP32S2
+
+config ESPRESSIF_LEDC_CHANNEL2_PIN
+       int "Channel 2 pin"
+       default 4
+       range 0 48 if ARCH_CHIP_ESP32S3
+       range 0 46 if ARCH_CHIP_ESP32S2
+
+config ESPRESSIF_LEDC_CHANNEL3_PIN
+       int "Channel 3 pin"
+       default 5
+       range 0 48 if ARCH_CHIP_ESP32S3
+       range 0 46 if ARCH_CHIP_ESP32S2
+
+if PWM_MULTICHAN && PWM_NCHANNELS > 1
+
+config ESPRESSIF_LEDC_CHANNEL4_PIN
+       int "Channel 4 pin"
+       default 6
+       range 0 48 if ARCH_CHIP_ESP32S3
+       range 0 46 if ARCH_CHIP_ESP32S2
+
+config ESPRESSIF_LEDC_CHANNEL5_PIN
+       int "Channel 5 pin"
+       default 7
+       range 0 48 if ARCH_CHIP_ESP32S3
+       range 0 46 if ARCH_CHIP_ESP32S2
+
+config ESPRESSIF_LEDC_CHANNEL6_PIN
+       int "Channel 6 pin"
+       default 8
+       range 0 48 if ARCH_CHIP_ESP32S3
+       range 0 46 if ARCH_CHIP_ESP32S2
+
+config ESPRESSIF_LEDC_CHANNEL7_PIN
+       int "Channel 7 pin"
+       default 9
+       range 0 48 if ARCH_CHIP_ESP32S3
+       range 0 46 if ARCH_CHIP_ESP32S2
+
+endif # PWM_MULTICHAN && PWM_NCHANNELS > 1
+
+endif # !ESP32_LEDC && !ESP32S2_LEDC && !ESP32S3_LEDC
+
+endmenu # LEDC configuration
+
 menu "Bootloader and Image Configuration"
 
 config ESPRESSIF_BOOTLOADER_MCUBOOT
diff --git a/arch/xtensa/src/common/espressif/Make.defs 
b/arch/xtensa/src/common/espressif/Make.defs
index 225726f4e7..97165af073 100644
--- a/arch/xtensa/src/common/espressif/Make.defs
+++ b/arch/xtensa/src/common/espressif/Make.defs
@@ -65,6 +65,10 @@ CHIP_CSRCS += esp_qencoder.c
 endif
 endif
 
+ifeq ($(CONFIG_ESPRESSIF_LEDC),y)
+CHIP_CSRCS += esp_ledc.c
+endif
+
 ifeq ($(CONFIG_ESPRESSIF_SPIFLASH),y)
 CHIP_CSRCS += esp_spiflash.c
 ifeq ($(CONFIG_ESPRESSIF_MTD),y)
diff --git a/arch/xtensa/src/common/espressif/esp_ledc.c 
b/arch/xtensa/src/common/espressif/esp_ledc.c
new file mode 100644
index 0000000000..172d89936f
--- /dev/null
+++ b/arch/xtensa/src/common/espressif/esp_ledc.c
@@ -0,0 +1,1787 @@
+/****************************************************************************
+ * arch/xtensa/src/common/espressif/esp_ledc.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/param.h>
+#include <debug.h>
+#include <errno.h>
+
+#include <nuttx/kmalloc.h>
+
+#include "esp_ledc.h"
+#include "xtensa.h"
+#if defined(CONFIG_ARCH_CHIP_ESP32S3)
+#include "esp32s3_gpio.h"
+#include "hardware/esp32s3_gpio_sigmap.h"
+#elif defined(CONFIG_ARCH_CHIP_ESP32S2)
+#include "esp32s2_gpio.h"
+#include "hardware/esp32s2_gpio_sigmap.h"
+#else
+#include "esp32_gpio.h"
+#include "hardware/esp32_gpio_sigmap.h"
+#endif
+
+#include "esp_private/periph_ctrl.h"
+#include "hal/ledc_hal.h"
+#include "hal/ledc_types.h"
+#include "soc/soc_caps.h"
+#include "clk_ctrl_os.h"
+#include "esp_clk_tree.h"
+#include "esp_attr.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if defined(CONFIG_ARCH_CHIP_ESP32S3)
+#  define esp_configgpio            esp32s3_configgpio
+#  define esp_gpio_matrix_out       esp32s3_gpio_matrix_out
+#  ifdef CONFIG_ESP32S3_LEDC
+#    define CONFIG_ESPRESSIF_LEDC_CHANNEL0_PIN CONFIG_ESP32S3_LEDC_CHANNEL0_PIN
+#    define CONFIG_ESPRESSIF_LEDC_CHANNEL1_PIN CONFIG_ESP32S3_LEDC_CHANNEL1_PIN
+#    define CONFIG_ESPRESSIF_LEDC_CHANNEL2_PIN CONFIG_ESP32S3_LEDC_CHANNEL2_PIN
+#    define CONFIG_ESPRESSIF_LEDC_CHANNEL3_PIN CONFIG_ESP32S3_LEDC_CHANNEL3_PIN
+#    define CONFIG_ESPRESSIF_LEDC_CHANNEL4_PIN CONFIG_ESP32S3_LEDC_CHANNEL4_PIN
+#    define CONFIG_ESPRESSIF_LEDC_CHANNEL5_PIN CONFIG_ESP32S3_LEDC_CHANNEL5_PIN
+#    define CONFIG_ESPRESSIF_LEDC_CHANNEL6_PIN CONFIG_ESP32S3_LEDC_CHANNEL6_PIN
+#    define CONFIG_ESPRESSIF_LEDC_CHANNEL7_PIN CONFIG_ESP32S3_LEDC_CHANNEL7_PIN
+#    ifdef CONFIG_ESP32S3_LEDC_TIM0
+#      define CONFIG_ESPRESSIF_LEDC_TIMER0_CHANNELS 
CONFIG_ESP32S3_LEDC_TIM0_CHANNELS
+#      define CONFIG_ESPRESSIF_LEDC_TIMER0 1
+#      define CONFIG_ESPRESSIF_LEDC_TIMER0_RESOLUTION 12
+#    endif /* CONFIG_ESP32S3_LEDC_TIM0 */
+#    ifdef CONFIG_ESP32S3_LEDC_TIM1
+#      define CONFIG_ESPRESSIF_LEDC_TIMER1_CHANNELS 
CONFIG_ESP32S3_LEDC_TIM1_CHANNELS
+#      define CONFIG_ESPRESSIF_LEDC_TIMER1 1
+#      define CONFIG_ESPRESSIF_LEDC_TIMER1_RESOLUTION 12
+#    endif /* CONFIG_ESP32S3_LEDC_TIM1 */
+#    ifdef CONFIG_ESP32S3_LEDC_TIM2
+#      define CONFIG_ESPRESSIF_LEDC_TIMER2_CHANNELS 
CONFIG_ESP32S3_LEDC_TIM2_CHANNELS
+#      define CONFIG_ESPRESSIF_LEDC_TIMER2 1
+#      define CONFIG_ESPRESSIF_LEDC_TIMER2_RESOLUTION 12
+#    endif /* CONFIG_ESP32S3_LEDC_TIM2 */
+#    ifdef CONFIG_ESP32S3_LEDC_TIM3
+#      define CONFIG_ESPRESSIF_LEDC_TIMER3_CHANNELS 
CONFIG_ESP32S3_LEDC_TIM3_CHANNELS
+#      define CONFIG_ESPRESSIF_LEDC_TIMER3 1
+#      define CONFIG_ESPRESSIF_LEDC_TIMER3_RESOLUTION 12
+#    endif /* CONFIG_ESP32S3_LEDC_TIM3 */
+#  endif /* CONFIG_ESP32S3_LEDC */
+#elif defined(CONFIG_ARCH_CHIP_ESP32S2)
+#  define esp_configgpio            esp32s2_configgpio
+#  define esp_gpio_matrix_out       esp32s2_gpio_matrix_out
+#  ifdef CONFIG_ESP32S2_LEDC
+#    define CONFIG_ESPRESSIF_LEDC_CHANNEL0_PIN CONFIG_ESP32S2_LEDC_CHANNEL0_PIN
+#    define CONFIG_ESPRESSIF_LEDC_CHANNEL1_PIN CONFIG_ESP32S2_LEDC_CHANNEL1_PIN
+#    define CONFIG_ESPRESSIF_LEDC_CHANNEL2_PIN CONFIG_ESP32S2_LEDC_CHANNEL2_PIN
+#    define CONFIG_ESPRESSIF_LEDC_CHANNEL3_PIN CONFIG_ESP32S2_LEDC_CHANNEL3_PIN
+#    define CONFIG_ESPRESSIF_LEDC_CHANNEL4_PIN CONFIG_ESP32S2_LEDC_CHANNEL4_PIN
+#    define CONFIG_ESPRESSIF_LEDC_CHANNEL5_PIN CONFIG_ESP32S2_LEDC_CHANNEL5_PIN
+#    define CONFIG_ESPRESSIF_LEDC_CHANNEL6_PIN CONFIG_ESP32S2_LEDC_CHANNEL6_PIN
+#    define CONFIG_ESPRESSIF_LEDC_CHANNEL7_PIN CONFIG_ESP32S2_LEDC_CHANNEL7_PIN
+#    ifdef CONFIG_ESP32S2_LEDC_TIM0
+#      define CONFIG_ESPRESSIF_LEDC_TIMER0_CHANNELS 
CONFIG_ESP32S2_LEDC_TIM0_CHANNELS
+#      define CONFIG_ESPRESSIF_LEDC_TIMER0 1
+#      define CONFIG_ESPRESSIF_LEDC_TIMER0_RESOLUTION 12
+#    endif /* CONFIG_ESP32S2_LEDC_TIM0 */
+#    ifdef CONFIG_ESP32S2_LEDC_TIM1
+#      define CONFIG_ESPRESSIF_LEDC_TIMER1_CHANNELS 
CONFIG_ESP32S2_LEDC_TIM1_CHANNELS
+#      define CONFIG_ESPRESSIF_LEDC_TIMER1 1
+#      define CONFIG_ESPRESSIF_LEDC_TIMER1_RESOLUTION 12
+#    endif /* CONFIG_ESP32S2_LEDC_TIM1 */
+#    ifdef CONFIG_ESP32S2_LEDC_TIM2
+#      define CONFIG_ESPRESSIF_LEDC_TIMER2_CHANNELS 
CONFIG_ESP32S2_LEDC_TIM2_CHANNELS
+#      define CONFIG_ESPRESSIF_LEDC_TIMER2 1
+#      define CONFIG_ESPRESSIF_LEDC_TIMER2_RESOLUTION 12
+#    endif /* CONFIG_ESP32S2_LEDC_TIM2 */
+#    ifdef CONFIG_ESP32S2_LEDC_TIM3
+#      define CONFIG_ESPRESSIF_LEDC_TIMER3_CHANNELS 
CONFIG_ESP32S2_LEDC_TIM3_CHANNELS
+#      define CONFIG_ESPRESSIF_LEDC_TIMER3 1
+#      define CONFIG_ESPRESSIF_LEDC_TIMER3_RESOLUTION 12
+#    endif /* CONFIG_ESP32S2_LEDC_TIM3 */
+#  endif /* CONFIG_ESP32S2_LEDC */
+#endif
+
+#if defined(CONFIG_ESP32S2_LEDC) || defined(CONFIG_ESP32S3_LEDC)
+#  define LEGACY_CONFIG 1
+#endif
+
+#define LEDC_TIMER_DIV_NUM_MAX    (0x3FFFF)
+
+#define LEDC_IS_DIV_INVALID(div)  ((div) <= LEDC_LL_FRACTIONAL_MAX || \
+                                   (div) > LEDC_TIMER_DIV_NUM_MAX)
+
+/* Precision degree only affects RC_FAST, other clock sources' frequencies
+ * are fixed values. For targets that do not support RC_FAST calibration,
+ * can only use its approximate value.
+ */
+
+#if SOC_CLK_RC_FAST_SUPPORT_CALIBRATION
+#  define LEDC_CLK_SRC_FREQ_PRECISION ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED
+#else
+#  define LEDC_CLK_SRC_FREQ_PRECISION ESP_CLK_TREE_SRC_FREQ_PRECISION_APPROX
+#endif
+
+#if !SOC_RCC_IS_INDEPENDENT
+#  define LEDC_BUS_CLOCK_ATOMIC() PERIPH_RCC_ATOMIC()
+#else
+#  define LEDC_BUS_CLOCK_ATOMIC()
+#endif
+
+#if SOC_PERIPH_CLK_CTRL_SHARED
+#  define LEDC_FUNC_CLOCK_ATOMIC() PERIPH_RCC_ATOMIC()
+#else
+#  define LEDC_FUNC_CLOCK_ATOMIC()
+#endif
+
+/* All chips have 4 internal timers */
+
+#define LEDC_TIMERS               (4)
+
+/* If PWM multi-channel is disabled, then only one channel is supported per
+ * timer. Thus, the number of channels is the same as the number of timers.
+ * Note that we only support the maximum of 6 PWM channels.
+ */
+
+#if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS > 1
+#  define LEDC_CHANNELS           SOC_LEDC_CHANNEL_NUM
+#else
+#  define LEDC_CHANNELS           LEDC_TIMERS
+#endif
+
+/* LEDC timer0 channels and offset */
+
+#ifdef CONFIG_ESPRESSIF_LEDC_TIMER0
+#  if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS > 1
+#    define LEDC_TIM0_CHANS       CONFIG_ESPRESSIF_LEDC_TIMER0_CHANNELS
+#  else
+#    define LEDC_TIM0_CHANS       (1)
+#  endif
+#  define LEDC_TIM0_CHANS_OFF     (0)
+#endif
+
+/* LEDC timer1 channels and offset */
+
+#ifdef CONFIG_ESPRESSIF_LEDC_TIMER1
+#  if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS > 1
+#    define LEDC_TIM1_CHANS       CONFIG_ESPRESSIF_LEDC_TIMER1_CHANNELS
+#  else
+#    define LEDC_TIM1_CHANS       (1)
+#  endif
+#  define LEDC_TIM1_CHANS_OFF     (LEDC_TIM0_CHANS_OFF + LEDC_TIM0_CHANS)
+#endif
+
+/* LEDC timer2 channels and offset */
+
+#ifdef CONFIG_ESPRESSIF_LEDC_TIMER2
+#  if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS > 1
+#    define LEDC_TIM2_CHANS       CONFIG_ESPRESSIF_LEDC_TIMER2_CHANNELS
+#  else
+#    define LEDC_TIM2_CHANS       (1)
+#  endif
+#  define LEDC_TIM2_CHANS_OFF     (LEDC_TIM1_CHANS_OFF + LEDC_TIM1_CHANS)
+#endif
+
+/* LEDC timer3 channels and offset */
+
+#ifdef CONFIG_ESPRESSIF_LEDC_TIMER3
+#  if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS > 1
+#    define LEDC_TIM3_CHANS       CONFIG_ESPRESSIF_LEDC_TIMER3_CHANNELS
+#  else
+#    define LEDC_TIM3_CHANS       (1)
+#  endif
+#  define LEDC_TIM3_CHANS_OFF     (LEDC_TIM2_CHANS_OFF + LEDC_TIM2_CHANS)
+#endif
+
+/* Uninitialized LEDC timer clock */
+
+#define LEDC_SLOW_CLK_UNINIT      (-1)
+
+/* Clock not found */
+
+#define LEDC_CLK_NOT_FOUND        (0)
+
+/* LEDC keep config */
+
+#define LEDC_VAL_NO_CHANGE        (-1)
+
+/* LEDC Timer default frequency */
+
+#define LEDC_DEFAULT_FREQ         (1000)
+
+/* Check max LEDC channels number */
+
+#ifndef LEGACY_CONFIG
+#  if CONFIG_ESPRESSIF_LEDC_TIMER0_CHANNELS + \
+      CONFIG_ESPRESSIF_LEDC_TIMER1_CHANNELS + \
+      CONFIG_ESPRESSIF_LEDC_TIMER2_CHANNELS + \
+      CONFIG_ESPRESSIF_LEDC_TIMER3_CHANNELS > LEDC_CHANNELS
+#    error "Too many LEDC channels. The maximum number of channels used " \
+           "by all timers is 6 when multi-channel PWM is enabled and "    \
+           "4 when multi-channel PWM is disabled."
+#endif
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* LEDC timer channel configuration */
+
+struct esp_ledc_chan_s
+{
+  const uint8_t num;                    /* PWM channel ID */
+  const uint8_t pin;                    /* PWM channel GPIO pin number */
+
+  uint32_t duty;                        /* PWM channel current duty */
+};
+
+/* This structure represents the state of one LEDC timer */
+
+struct esp_ledc_s
+{
+  const struct pwm_ops_s *ops;          /* PWM operations */
+
+  const uint8_t timer;                  /* Timer ID */
+
+  const uint8_t channels;               /* Timer channels number */
+  struct esp_ledc_chan_s *chans;        /* Timer channels pointer */
+
+  ledc_timer_bit_t duty_resolution;     /* Timer duty resolution */
+  ledc_clk_cfg_t clk_cfg;               /* Timer clock configuration */
+  uint32_t frequency;                   /* Timer current frequency */
+  uint32_t reload;                      /* Timer current reload */
+};
+
+struct ledc_obj_s
+{
+  ledc_hal_context_t ledc_hal;               /* LEDC hal context */
+  ledc_slow_clk_sel_t glb_clk;               /* LEDC global clock selection */
+  bool timer_is_stopped[LEDC_TIMER_MAX];     /* Indicates whether each timer 
has been stopped */
+  bool glb_clk_is_acquired[LEDC_TIMER_MAX];  /* Tracks whether the global 
clock is being acquired by each timer */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+#if 0 /* Should be added when sleep is supported */
+extern void esp_sleep_periph_use_8m(bool use_or_not);
+#endif
+
+static bool ledc_ctx_create(void);
+static bool ledc_slow_clk_calibrate(void);
+static uint32_t ledc_calculate_divisor(uint32_t src_clk_freq,
+                                       int freq_hz,
+                                       uint32_t precision);
+static uint32_t ledc_auto_global_clk_div(int freq_hz,
+                                         uint32_t precision,
+                                         ledc_slow_clk_sel_t *clk_target);
+static uint32_t ledc_auto_clk_divisor(int freq_hz,
+                                      uint32_t precision,
+                                      ledc_clk_src_t *clk_source,
+                                      ledc_slow_clk_sel_t *clk_target);
+static int ledc_timer_set(ledc_timer_t timer_sel,
+                          uint32_t clock_divider,
+                          uint32_t duty_resolution,
+                          ledc_clk_src_t clk_src);
+static int ledc_set_timer_div(ledc_timer_t timer_num,
+                              ledc_clk_cfg_t clk_cfg,
+                              int freq_hz,
+                              int duty_resolution);
+static int ledc_timer_resume(ledc_timer_t timer_sel);
+static int ledc_timer_rst(ledc_timer_t timer_sel);
+static int ledc_timer_pause(ledc_timer_t timer_sel);
+static int setup_timer(struct esp_ledc_s *priv);
+static int ledc_duty_config(ledc_channel_t channel,
+                            int hpoint_val,
+                            int duty_val,
+                            ledc_duty_direction_t duty_direction,
+                            uint32_t duty_num,
+                            uint32_t duty_cycle,
+                            uint32_t duty_scale);
+static int ledc_set_duty_with_hpoint(ledc_channel_t channel,
+                                     uint32_t duty,
+                                     uint32_t hpoint);
+static int ledc_channel_output_enable(ledc_channel_t channel);
+static int ledc_channel_output_disable(ledc_channel_t channel);
+static int ledc_update_duty(ledc_channel_t channel);
+static uint32_t ledc_duty_bin_conversion(uint16_t nuttx_duty,
+                                         uint32_t duty_resolution);
+static int ledc_bind_channel_timer(ledc_channel_t channel,
+                                   ledc_timer_t timer_sel);
+static void setup_channel(struct esp_ledc_s *priv, int cn);
+static int pwm_setup(struct pwm_lowerhalf_s *dev);
+static int pwm_shutdown(struct pwm_lowerhalf_s *dev);
+static int pwm_start(struct pwm_lowerhalf_s *dev,
+                     const struct pwm_info_s *info);
+static int pwm_stop(struct pwm_lowerhalf_s *dev);
+static int pwm_ioctl(struct pwm_lowerhalf_s *dev, int cmd,
+                     unsigned long arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* LEDC context */
+
+static struct ledc_obj_s *p_ledc_obj = NULL;
+
+/* LEDC available timer global clocks */
+
+static const ledc_slow_clk_sel_t s_glb_clks[] = LEDC_LL_GLOBAL_CLOCKS;
+
+/* Current RC_FAST frequency */
+
+static uint32_t s_ledc_slow_clk_rc_fast_freq = 0;
+
+/* LEDC PWM operations */
+
+static const struct pwm_ops_s g_pwmops =
+{
+  .setup       = pwm_setup,
+  .shutdown    = pwm_shutdown,
+  .start       = pwm_start,
+  .stop        = pwm_stop,
+  .ioctl       = pwm_ioctl
+};
+
+/* LEDC channels table */
+
+static struct esp_ledc_chan_s g_ledc_chans[LEDC_CHANNELS] =
+{
+  {
+    .num       = 0,
+    .pin       = CONFIG_ESPRESSIF_LEDC_CHANNEL0_PIN
+  },
+  {
+    .num       = 1,
+    .pin       = CONFIG_ESPRESSIF_LEDC_CHANNEL1_PIN
+  },
+  {
+    .num       = 2,
+    .pin       = CONFIG_ESPRESSIF_LEDC_CHANNEL2_PIN
+  },
+  {
+    .num       = 3,
+    .pin       = CONFIG_ESPRESSIF_LEDC_CHANNEL3_PIN
+  },
+#if LEDC_CHANNELS > 4
+  {
+    .num       = 4,
+    .pin       = CONFIG_ESPRESSIF_LEDC_CHANNEL4_PIN
+  },
+  {
+    .num       = 5,
+    .pin       = CONFIG_ESPRESSIF_LEDC_CHANNEL5_PIN
+  },
+  {
+    .num       = 6,
+    .pin       = CONFIG_ESPRESSIF_LEDC_CHANNEL6_PIN
+  },
+  {
+    .num       = 7,
+    .pin       = CONFIG_ESPRESSIF_LEDC_CHANNEL7_PIN
+  }
+#endif
+};
+
+/* LEDC timer0 private data */
+
+#ifdef CONFIG_ESPRESSIF_LEDC_TIMER0
+
+#  if CONFIG_ESPRESSIF_LEDC_TIMER0_RESOLUTION > SOC_LEDC_TIMER_BIT_WIDTH
+#    error "Invalid PWM Timer 0 resolution."
+#  endif
+
+static struct esp_ledc_s g_pwm0dev =
+{
+  .ops             = &g_pwmops,
+  .timer           = 0,
+  .channels        = LEDC_TIM0_CHANS,
+  .chans           = &g_ledc_chans[LEDC_TIM0_CHANS_OFF],
+  .duty_resolution = CONFIG_ESPRESSIF_LEDC_TIMER0_RESOLUTION,
+  .clk_cfg         = LEDC_AUTO_CLK,
+  .frequency       = LEDC_DEFAULT_FREQ
+};
+#endif /* CONFIG_ESPRESSIF_LEDC_TIMER0 */
+
+/* LEDC timer1 private data */
+
+#ifdef CONFIG_ESPRESSIF_LEDC_TIMER1
+
+#  if CONFIG_ESPRESSIF_LEDC_TIMER1_RESOLUTION > SOC_LEDC_TIMER_BIT_WIDTH
+#    error "Invalid PWM Timer 1 resolution."
+#  endif
+
+static struct esp_ledc_s g_pwm1dev =
+{
+  .ops             = &g_pwmops,
+  .timer           = 1,
+  .channels        = LEDC_TIM1_CHANS,
+  .chans           = &g_ledc_chans[LEDC_TIM1_CHANS_OFF],
+  .duty_resolution = CONFIG_ESPRESSIF_LEDC_TIMER1_RESOLUTION,
+  .clk_cfg         = LEDC_AUTO_CLK,
+  .frequency       = LEDC_DEFAULT_FREQ
+};
+#endif /* CONFIG_ESPRESSIF_LEDC_TIMER1 */
+
+/* LEDC timer2 private data */
+
+#ifdef CONFIG_ESPRESSIF_LEDC_TIMER2
+
+#  if CONFIG_ESPRESSIF_LEDC_TIMER2_RESOLUTION > SOC_LEDC_TIMER_BIT_WIDTH
+#    error "Invalid PWM Timer 2 resolution."
+#  endif
+
+static struct esp_ledc_s g_pwm2dev =
+{
+  .ops             = &g_pwmops,
+  .timer           = 2,
+  .channels        = LEDC_TIM2_CHANS,
+  .chans           = &g_ledc_chans[LEDC_TIM2_CHANS_OFF],
+  .duty_resolution = CONFIG_ESPRESSIF_LEDC_TIMER2_RESOLUTION,
+  .clk_cfg         = LEDC_AUTO_CLK,
+  .frequency       = LEDC_DEFAULT_FREQ
+};
+#endif /* CONFIG_ESPRESSIF_LEDC_TIMER2 */
+
+/* LEDC timer3 private data */
+
+#ifdef CONFIG_ESPRESSIF_LEDC_TIMER3
+
+#  if CONFIG_ESPRESSIF_LEDC_TIMER3_RESOLUTION > SOC_LEDC_TIMER_BIT_WIDTH
+#    error "Invalid PWM Timer 3 resolution."
+#  endif
+
+static struct esp_ledc_s g_pwm3dev =
+{
+  .ops             = &g_pwmops,
+  .timer           = 3,
+  .channels        = LEDC_TIM3_CHANS,
+  .chans           = &g_ledc_chans[LEDC_TIM3_CHANS_OFF],
+  .duty_resolution = CONFIG_ESPRESSIF_LEDC_TIMER3_RESOLUTION,
+  .clk_cfg         = LEDC_AUTO_CLK,
+  .frequency       = LEDC_DEFAULT_FREQ
+};
+#endif /* CONFIG_ESPRESSIF_LEDC_TIMER3 */
+
+/****************************************************************************
+ * Private functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: ledc_ctx_create
+ *
+ * Description:
+ *   Create LEDC context.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   True if context was created, false otherwise.
+ *
+ ****************************************************************************/
+
+static bool ledc_ctx_create(void)
+{
+  bool new_ctx = false;
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  if (!p_ledc_obj)
+    {
+      struct ledc_obj_s *ledc_new_mode_obj;
+      ledc_new_mode_obj = (struct ledc_obj_s *)
+        kmm_calloc(1, sizeof(struct ledc_obj_s));
+      if (ledc_new_mode_obj)
+        {
+          new_ctx = true;
+
+          LEDC_BUS_CLOCK_ATOMIC()
+            {
+              ledc_ll_enable_bus_clock(true);
+              ledc_ll_enable_reset_reg(false);
+            }
+
+          LEDC_FUNC_CLOCK_ATOMIC()
+            {
+              ledc_ll_enable_clock(LEDC_LL_GET_HW(), true);
+            }
+
+          ledc_hal_init(&(ledc_new_mode_obj->ledc_hal), LEDC_LOW_SPEED_MODE);
+          ledc_new_mode_obj->glb_clk = LEDC_SLOW_CLK_UNINIT;
+          p_ledc_obj = ledc_new_mode_obj;
+          periph_module_enable(PERIPH_LEDC_MODULE);
+      }
+  }
+
+  leave_critical_section(flags);
+
+  return new_ctx;
+}
+
+/****************************************************************************
+ * Name: ledc_slow_clk_calibrate
+ *
+ * Description:
+ *   Calibrate RC_FAST clock.
+ *
+ * Input Parameters:
+ *   None.
+ *
+ * Returned Value:
+ *   True if calibration was successful, false otherwise.
+ *
+ ****************************************************************************/
+
+static bool ledc_slow_clk_calibrate(void)
+{
+  if (periph_rtc_dig_clk8m_enable())
+    {
+      s_ledc_slow_clk_rc_fast_freq = periph_rtc_dig_clk8m_get_freq();
+#if !SOC_CLK_RC_FAST_SUPPORT_CALIBRATION
+      pwminfo("Calibration cannot be performed."
+              "Approximate RC_FAST_CLK : %"PRIu32" Hz\n",
+              s_ledc_slow_clk_rc_fast_freq);
+#else
+      pwminfo("Calibrate RC_FAST_CLK : %"PRIu32" Hz",
+              s_ledc_slow_clk_rc_fast_freq);
+#endif
+      return true;
+    }
+
+  pwmerr("Calibrate RC_FAST_CLK failed\n");
+  return false;
+}
+
+/****************************************************************************
+ * Name: ledc_calculate_divisor
+ *
+ * Description:
+ *   Calculate the divisor to achieve the desired frequency.
+ *
+ * Input Parameters:
+ *   src_clk_freq - The source clock frequency.
+ *   freq_hz      - The desired frequency.
+ *   precision    - The granularity of the clock.
+ *
+ * Returned Value:
+ *   The divisor parameter to use to achieve the frequency requested.
+ *
+ ****************************************************************************/
+
+static inline uint32_t ledc_calculate_divisor(uint32_t src_clk_freq,
+                                              int freq_hz,
+                                              uint32_t precision)
+{
+  /* In order to find the right divisor, we need to divide the source clock
+   * frequency by the desired frequency. However, two things to note here:
+   * - The lowest LEDC_LL_FRACTIONAL_BITS bits of the result are the
+   *   FRACTIONAL part. The higher bits represent the integer part, this is
+   *   why we need to right shift the source frequency.
+   * - The `precision` parameter represents the granularity of the clock. It
+   *   **must** be a power of 2. It means that the resulted divisor is
+   *   a multiplier of `precision`.
+   *
+   * Let's take a concrete example, we need to generate a 5KHz clock out of
+   * a 80MHz clock (APB).
+   * If the precision is 1024 (10 bits), the resulted multiplier is:
+   * (80000000 << 8) / (5000 * 1024) = 4000 (0xfa0)
+   * Let's ignore the fractional part to simplify the explanation, so we get
+   * a result of 15 (0xf).
+   * This can be interpreted as: every 15 "precision" ticks, the resulted
+   * clock will go high, where one precision tick is made out of 1024 source
+   * clock ticks.
+   * Thus, every `15 * 1024` source clock ticks, the resulted clock will go
+   * high.
+   *
+   * NOTE: We are also going to round up the value when necessary, thanks to:
+   * (freq_hz * precision) / 2
+   */
+
+  return (((uint64_t)src_clk_freq << LEDC_LL_FRACTIONAL_BITS) + \
+          ((freq_hz * precision) / 2)) / (freq_hz * precision);
+}
+
+/****************************************************************************
+ * Name: ledc_auto_global_clk_div
+ *
+ * Description:
+ *   Try to find the clock with its divisor giving the frequency requested
+ *   by the caller.
+ *
+ * Input Parameters:
+ *   freq_hz    - Frequency to achieve;
+ *   precision  - Precision of the frequency to achieve;
+ *   clk_target - Clock target to use.
+ *
+ * Returned Value:
+ *   The divisor parameter to use to achieve the frequency requested.
+ *
+ ****************************************************************************/
+
+static uint32_t ledc_auto_global_clk_div(int freq_hz,
+                                         uint32_t precision,
+                                         ledc_slow_clk_sel_t *clk_target)
+{
+  uint32_t ret = LEDC_CLK_NOT_FOUND;
+  uint32_t clk_freq = 0;
+
+  /* This function will go through all the following clock sources to look
+   * for a valid divisor which generates the requested frequency.
+   */
+
+  for (int i = 0; i < nitems(s_glb_clks); i++)
+    {
+      /* Before calculating the divisor, we need to have the RC_FAST
+       * frequency. If it hasn't been measured yet, try calibrating
+       * it now.
+       */
+
+      if (s_glb_clks[i] == LEDC_SLOW_CLK_RC_FAST &&
+          s_ledc_slow_clk_rc_fast_freq == 0 &&
+          !ledc_slow_clk_calibrate())
+        {
+          pwminfo("Unable to retrieve RC_FAST clock frequency, skipping it");
+          continue;
+        }
+
+      esp_clk_tree_src_get_freq_hz((soc_module_clk_t)s_glb_clks[i],
+                                   LEDC_CLK_SRC_FREQ_PRECISION,
+                                   &clk_freq);
+
+      uint32_t div_param = ledc_calculate_divisor(clk_freq,
+                                                  freq_hz,
+                                                  precision);
+
+      /* If the divisor is valid, we can return this value. */
+
+      if (!LEDC_IS_DIV_INVALID(div_param))
+        {
+          *clk_target = s_glb_clks[i];
+          ret = div_param;
+          break;
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: ledc_auto_clk_divisor
+ *
+ * Description:
+ *   Try to find the clock with its divisor giving the frequency requested
+ *   by the caller.
+ *
+ * Input Parameters:
+ *   freq_hz    - Frequency to achieve;
+ *   precision  - Precision of the frequency to achieve;
+ *   clk_source - Clock source to use;
+ *   clk_target - Clock target to use.
+ *
+ * Returned Value:
+ *   The divisor parameter to use to achieve the frequency requested.
+ *
+ ****************************************************************************/
+
+static uint32_t ledc_auto_clk_divisor(int freq_hz,
+                                      uint32_t precision,
+                                      ledc_clk_src_t *clk_source,
+                                      ledc_slow_clk_sel_t *clk_target)
+{
+  uint32_t ret = LEDC_CLK_NOT_FOUND;
+
+  uint32_t div_param_global = ledc_auto_global_clk_div(freq_hz,
+                                                       precision,
+                                                       clk_target);
+
+  if (div_param_global != LEDC_CLK_NOT_FOUND)
+    {
+      pwminfo("Found a global clock source for frequency %d Hz "
+              "and precision 0x%"PRIx32"\n", freq_hz, precision);
+      *clk_source = LEDC_SCLK;
+      ret = div_param_global;
+    }
+  else
+    {
+      pwminfo("Could not find a global clock source for frequency %d Hz "
+              "and precision 0x%"PRIx32"\n", freq_hz, precision);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: ledc_timer_set
+ *
+ * Description:
+ *   Set LEDC timer.
+ *
+ * Input Parameters:
+ *   timer_sel      - Select the timer to be set;
+ *   clock_divider  - The divider of the clock source;
+ *   duty_resolution- The duty resolution of the timer;
+ *   clk_src        - The clock source of the timer;
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned on
+ *   failure.
+ *
+ ****************************************************************************/
+
+static int ledc_timer_set(ledc_timer_t timer_sel,
+                          uint32_t clock_divider,
+                          uint32_t duty_resolution,
+                          ledc_clk_src_t clk_src)
+{
+  DEBUGASSERT(timer_sel < LEDC_TIMER_MAX);
+
+  if (p_ledc_obj == NULL)
+    {
+      pwmerr("ERROR: LEDC not initialized\n");
+      return -ENODEV;
+    }
+
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  ledc_hal_set_clock_divider(&(p_ledc_obj->ledc_hal),
+                             timer_sel,
+                             clock_divider);
+
+  ledc_hal_set_duty_resolution(&(p_ledc_obj->ledc_hal),
+                               timer_sel,
+                               duty_resolution);
+
+  ledc_hal_ls_timer_update(&(p_ledc_obj->ledc_hal), timer_sel);
+
+  leave_critical_section(flags);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: ledc_set_timer_div
+ *
+ * Description:
+ *   Set LEDC timer divider.
+ *
+ * Input Parameters:
+ *   timer_num - LEDC timer number;
+ *   clk_cfg - LEDC timer clock source;
+ *   freq_hz - LEDC timer frequency;
+ *   duty_resolution - LEDC timer duty resolution.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned on
+ *   failure.
+ *
+ ****************************************************************************/
+
+static int ledc_set_timer_div(ledc_timer_t timer_num,
+                              ledc_clk_cfg_t clk_cfg,
+                              int freq_hz,
+                              int duty_resolution)
+{
+  irqstate_t flags;
+  uint32_t div_param = 0;
+  int i;
+  const uint32_t precision = (0x1 << duty_resolution);
+
+  /* The clock sources are not initialized on purpose. To produce compiler
+   * warning if used but the selector functions don't set them properly.
+   */
+
+  /* Timer-specific mux. Set to timer-specific clock or LEDC_SCLK if a global
+   * clock is used.
+   */
+
+  ledc_clk_src_t timer_clk_src;
+
+  /* Global clock mux. Should be set when LEDC_SCLK is used in
+   * LOW_SPEED_MODE. Otherwise left uninitialized.
+   */
+
+  ledc_slow_clk_sel_t glb_clk = LEDC_SLOW_CLK_UNINIT;
+
+  if (clk_cfg == LEDC_AUTO_CLK)
+    {
+      /* User hasn't specified the speed, we should try to guess it. */
+
+      pwminfo("Using auto clock source selection\n");
+
+      div_param = ledc_auto_clk_divisor(freq_hz,
+                                        precision,
+                                        &timer_clk_src,
+                                        &glb_clk);
+    }
+  else if (clk_cfg == LEDC_USE_RC_FAST_CLK)
+    {
+      pwminfo("Using RC_FAST clock source\n");
+
+      /* Before calculating the divisor, we need to have the RC_FAST
+       * frequency. If it hasn't been measured yet, try calibrating
+       * it now.
+       */
+
+      if (s_ledc_slow_clk_rc_fast_freq == 0 &&
+          ledc_slow_clk_calibrate() == false)
+        {
+          goto error;
+        }
+
+      /* Set the global clock source */
+
+      timer_clk_src = LEDC_SCLK;
+      glb_clk =  LEDC_SLOW_CLK_RC_FAST;
+
+      /* We have the RC_FAST clock frequency now. */
+
+      div_param = ledc_calculate_divisor(s_ledc_slow_clk_rc_fast_freq,
+                                         freq_hz,
+                                         precision);
+
+      if (LEDC_IS_DIV_INVALID(div_param))
+        {
+          div_param = LEDC_CLK_NOT_FOUND;
+        }
+    }
+  else
+    {
+      timer_clk_src = LEDC_SCLK;
+      glb_clk = (ledc_slow_clk_sel_t)clk_cfg;
+
+      uint32_t src_clk_freq = 0;
+      esp_clk_tree_src_get_freq_hz((soc_module_clk_t)clk_cfg,
+                                    LEDC_CLK_SRC_FREQ_PRECISION,
+                                    &src_clk_freq);
+
+      div_param = ledc_calculate_divisor(src_clk_freq, freq_hz, precision);
+
+      if (LEDC_IS_DIV_INVALID(div_param))
+        {
+          div_param = LEDC_CLK_NOT_FOUND;
+        }
+    }
+
+  if (div_param == LEDC_CLK_NOT_FOUND)
+    {
+      goto error;
+    }
+
+  pwminfo("Using clock source %d (in slow mode). Divisor: 0x%"PRIx32,
+          timer_clk_src,
+          div_param);
+
+  /* The following block configures the global clock.
+   * Arriving here, variable glb_clk must have been assigned to one of the
+   * ledc_slow_clk_sel_t enum values
+   */
+
+  ASSERT(timer_clk_src == LEDC_SCLK);
+  ASSERT(glb_clk != LEDC_SLOW_CLK_UNINIT);
+
+  flags = enter_critical_section();
+
+  if (p_ledc_obj->glb_clk != LEDC_SLOW_CLK_UNINIT &&
+      p_ledc_obj->glb_clk != glb_clk)
+    {
+      for (i = 0; i < LEDC_TIMER_MAX; i++)
+        {
+          if (i != timer_num && p_ledc_obj->glb_clk_is_acquired[i])
+            {
+              leave_critical_section(flags);
+              pwmerr("Timer clock conflict. Already is %d but attempt to %d",
+                     p_ledc_obj->glb_clk,
+                     glb_clk);
+            }
+        }
+    }
+
+  if (timer_num == LEDC_TIMER_MAX - 1 &&
+      p_ledc_obj->glb_clk_is_acquired[timer_num - 1])
+    {
+      return -EINVAL;
+    }
+
+  p_ledc_obj->glb_clk_is_acquired[timer_num] = true;
+  if (p_ledc_obj->glb_clk != glb_clk)
+    {
+      p_ledc_obj->glb_clk = glb_clk;
+      ledc_hal_set_slow_clk_sel(&(p_ledc_obj->ledc_hal), glb_clk);
+    }
+
+  leave_critical_section(flags);
+
+  pwminfo("In slow speed mode. Global clock: %d", glb_clk);
+
+  /* Keep ESP_PD_DOMAIN_RC_FAST on during light sleep */
+
+#if 0 /* Should be added when sleep is supported */
+  esp_sleep_periph_use_8m(glb_clk == LEDC_SLOW_CLK_RC_FAST);
+#endif
+
+  /* The divisor is correct, we can write in the hardware. */
+
+  ledc_timer_set(timer_num, div_param, duty_resolution, timer_clk_src);
+  return OK;
+
+error:
+  pwmerr("Requested frequency and duty resolution can not be achieved. "
+         "Try reducing the frequency or timer resolution.\n");
+
+  return -EINVAL;
+}
+
+/****************************************************************************
+ * Name: ledc_timer_resume
+ *
+ * Description:
+ *   Resume a LEDC timer.
+ *
+ * Input Parameters:
+ *   timer_sel - LEDC timer id.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned on
+ *   failure.
+ *
+ ****************************************************************************/
+
+static int ledc_timer_resume(ledc_timer_t timer_sel)
+{
+  DEBUGASSERT(timer_sel < LEDC_TIMER_MAX);
+
+  if (p_ledc_obj == NULL)
+    {
+      pwmerr("ERROR: LEDC not initialized\n");
+      return -ENODEV;
+    }
+
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  p_ledc_obj->timer_is_stopped[timer_sel] = false;
+  ledc_hal_timer_resume(&(p_ledc_obj->ledc_hal), timer_sel);
+
+  leave_critical_section(flags);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: ledc_timer_rst
+ *
+ * Description:
+ *   Reset a LEDC timer.
+ *
+ * Input Parameters:
+ *   timer_sel - LEDC timer id.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned on
+ *   failure.
+ *
+ ****************************************************************************/
+
+static int ledc_timer_rst(ledc_timer_t timer_sel)
+{
+  DEBUGASSERT(timer_sel < LEDC_TIMER_MAX);
+
+  if (p_ledc_obj == NULL)
+    {
+      pwmerr("ERROR: LEDC not initialized\n");
+      return -ENODEV;
+    }
+
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  ledc_hal_timer_rst(&(p_ledc_obj->ledc_hal), timer_sel);
+
+  leave_critical_section(flags);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: ledc_timer_pause
+ *
+ * Description:
+ *   Pause a LEDC timer.
+ *
+ * Input Parameters:
+ *   timer_sel - LEDC timer id.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned on
+ *   failure.
+ *
+ ****************************************************************************/
+
+static int ledc_timer_pause(ledc_timer_t timer_sel)
+{
+  DEBUGASSERT(timer_sel < LEDC_TIMER_MAX);
+
+  if (p_ledc_obj == NULL)
+    {
+      pwmerr("ERROR: LEDC not initialized\n");
+      return -ENODEV;
+    }
+
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  p_ledc_obj->timer_is_stopped[timer_sel] = true;
+  ledc_hal_timer_pause(&(p_ledc_obj->ledc_hal), timer_sel);
+
+  leave_critical_section(flags);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: setup_timer
+ *
+ * Description:
+ *   Setup LEDC timer frequency and reload.
+ *
+ * Input Parameters:
+ *   priv - A reference to the LEDC timer state structure
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success; a negated errno value is returned on
+ *   failure.
+ *
+ ****************************************************************************/
+
+static int setup_timer(struct esp_ledc_s *priv)
+{
+  DEBUGASSERT(priv != NULL);
+  DEBUGASSERT(priv->timer < LEDC_TIMER_MAX);
+  DEBUGASSERT(priv->frequency > 0);
+  DEBUGASSERT(priv->duty_resolution < LEDC_TIMER_BIT_MAX &&
+              priv->duty_resolution > 0);
+
+  int ret;
+
+  if (!ledc_ctx_create() && !p_ledc_obj)
+    {
+      pwmerr("ERROR: No memory for LEDC context\n");
+      PANIC();
+    }
+
+  ret = ledc_set_timer_div(priv->timer,
+                           priv->clk_cfg,
+                           priv->frequency,
+                           priv->duty_resolution);
+
+  if (ret == OK)
+    {
+      ledc_timer_pause(priv->timer);
+      ledc_timer_rst(priv->timer);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: ledc_duty_config
+ *
+ * Description:
+ *   Set the duty cycle of a PWM channel.
+ *
+ * Input Parameters:
+ *   channel - LEDC channel index.
+ *   hpoint_val - LEDC channel hpoint value. This value sets
+ *                the pulse start point in timer ticks allowing phase control
+ *                of the signal.
+ *   duty_val - LEDC channel duty value.
+ *   duty_direction - LEDC channel duty direction.
+ *   duty_num - LEDC channel duty number.
+ *   duty_cycle - LEDC channel duty cycle.
+ *
+ * Returned Value:
+ *   OK.
+ *
+ ****************************************************************************/
+
+static IRAM_ATTR int ledc_duty_config(ledc_channel_t channel,
+                                      int hpoint_val,
+                                      int duty_val,
+                                      ledc_duty_direction_t duty_direction,
+                                      uint32_t duty_num,
+                                      uint32_t duty_cycle,
+                                      uint32_t duty_scale)
+{
+  if (hpoint_val >= 0)
+    {
+      ledc_hal_set_hpoint(&(p_ledc_obj->ledc_hal), channel, hpoint_val);
+    }
+
+  if (duty_val >= 0)
+    {
+      ledc_hal_set_duty_int_part(&(p_ledc_obj->ledc_hal), channel, duty_val);
+    }
+
+  pwminfo("ledc_duty_config: channel: %d, hpoint_val: %d, duty_val: %d, "
+          "duty_direction: %d, duty_num: %" PRIu32 ", "
+          "duty_cycle: %" PRIu32 ", duty_scale: %" PRIu32 "\n",
+          channel, hpoint_val, duty_val, duty_direction, duty_num,
+          duty_cycle, duty_scale);
+  ledc_hal_set_fade_param(&(p_ledc_obj->ledc_hal), channel, 0,
+                         duty_direction, duty_cycle, duty_scale, duty_num);
+
+#if SOC_LEDC_GAMMA_CURVE_FADE_SUPPORTED
+  ledc_hal_set_range_number(&(p_ledc_obj->ledc_hal), channel, 1);
+  ledc_hal_clear_left_off_fade_param(&(p_ledc_obj->ledc_hal), channel, 1);
+#endif
+  return OK;
+}
+
+/****************************************************************************
+ * Name: ledc_set_duty_with_hpoint
+ *
+ * Description:
+ *   Set the duty cycle of a PWM channel with a given hpoint value to set
+ *   pulse start point in timer ticks for phase control of the signal.
+ *
+ * Input Parameters:
+ *   channel - LEDC channel index.
+ *   duty - Duty cycle value.
+ *   hpoint - Hpoint value.
+ *
+ * Returned Value:
+ *   Ok on success; A negated errno value is returned on failure.
+ *
+ ****************************************************************************/
+
+static int ledc_set_duty_with_hpoint(ledc_channel_t channel,
+                                     uint32_t duty,
+                                     uint32_t hpoint)
+{
+  DEBUGASSERT(channel < LEDC_CHANNEL_MAX);
+  DEBUGASSERT(hpoint <= LEDC_LL_HPOINT_VAL_MAX);
+
+  if (p_ledc_obj == NULL)
+    {
+      pwmerr("ERROR: LEDC not initialized\n");
+      return -ENODEV;
+    }
+
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  ledc_duty_config(channel, hpoint, duty, LEDC_DUTY_DIR_INCREASE, 1, 1, 0);
+
+  leave_critical_section(flags);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: ledc_channel_output_enable
+ *
+ * Description:
+ *   Enable LEDC channel output.
+ *
+ * Input Parameters:
+ *   channel - LEDC channel index.
+ *
+ * Returned Value:
+ *   Ok on success; A negated errno value is returned on failure.
+ *
+ ****************************************************************************/
+
+static int ledc_channel_output_enable(ledc_channel_t channel)
+{
+  DEBUGASSERT(channel < LEDC_CHANNEL_MAX);
+
+  if (p_ledc_obj == NULL)
+    {
+      pwmerr("ERROR: LEDC not initialized\n");
+      return -ENODEV;
+    }
+
+  ledc_hal_set_sig_out_en(&(p_ledc_obj->ledc_hal), channel, true);
+  ledc_hal_set_duty_start(&(p_ledc_obj->ledc_hal), channel, true);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: ledc_channel_output_disable
+ *
+ * Description:
+ *   Disable LEDC channel output.
+ *
+ * Input Parameters:
+ *   channel - LEDC channel index.
+ *
+ * Returned Value:
+ *   Ok on success; A negated errno value is returned on failure.
+ *
+ ****************************************************************************/
+
+static int ledc_channel_output_disable(ledc_channel_t channel)
+{
+  DEBUGASSERT(channel < LEDC_CHANNEL_MAX);
+
+  if (p_ledc_obj == NULL)
+    {
+      pwmerr("ERROR: LEDC not initialized\n");
+      return -ENODEV;
+    }
+
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  ledc_hal_set_idle_level(&(p_ledc_obj->ledc_hal), channel, 0);
+  ledc_hal_set_sig_out_en(&(p_ledc_obj->ledc_hal), channel, false);
+  ledc_hal_set_duty_start(&(p_ledc_obj->ledc_hal), channel, false);
+
+  leave_critical_section(flags);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: ledc_update_duty
+ *
+ * Description:
+ *   Update the duty cycle of a PWM channel.
+ *
+ * Input Parameters:
+ *   channel - LEDC channel index.
+ *
+ * Returned Value:
+ *   Ok on success; A negated errno value is returned on failure.
+ *
+ ****************************************************************************/
+
+static int ledc_update_duty(ledc_channel_t channel)
+{
+  DEBUGASSERT(channel < LEDC_CHANNEL_MAX);
+
+  if (p_ledc_obj == NULL)
+    {
+      pwmerr("ERROR: LEDC not initialized\n");
+      return -ENODEV;
+    }
+
+  irqstate_t flags;
+
+  ledc_channel_output_enable(channel);
+
+  flags = enter_critical_section();
+  ledc_hal_ls_channel_update(&(p_ledc_obj->ledc_hal), channel);
+  leave_critical_section(flags);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: ledc_duty_bin_conversion
+ *
+ * Description:
+ *   Truncate or expand the duty cycle value to fit the duty resolution.
+ *
+ * Input Parameters:
+ *   nuttx_duty - Duty cycle value from nuttx.
+ *   duty_resolution - Duty resolution of the channel.
+ *
+ * Returned Value:
+ *   Truncated or expanded duty cycle value.
+ *
+ ****************************************************************************/
+
+static uint32_t ledc_duty_bin_conversion(uint16_t nuttx_duty,
+                                         uint32_t duty_resolution)
+{
+  /* Calculate the maximum value based on the duty resolution */
+
+  uint32_t max_value = (1 << duty_resolution) - 1;
+
+  /* Map the value to the specified range */
+
+  uint32_t mapped_value = (nuttx_duty * max_value) / UINT16_MAX;
+
+  return mapped_value;
+}
+
+/****************************************************************************
+ * Name: ledc_bind_channel_timer
+ *
+ * Description:
+ *   Bind a LEDC channel to a LEDC timer.
+ *
+ * Input Parameters:
+ *   channel - LEDC channel index.
+ *   timer_sel - LEDC timer index.
+ *
+ * Returned Value:
+ *   Ok on success; A negated errno value is returned on failure.
+ *
+ ****************************************************************************/
+
+static int ledc_bind_channel_timer(ledc_channel_t channel,
+                                   ledc_timer_t timer_sel)
+{
+  DEBUGASSERT(timer_sel < LEDC_TIMER_MAX);
+
+  if (p_ledc_obj == NULL)
+    {
+      pwmerr("ERROR: LEDC not initialized\n");
+      return -ENODEV;
+    }
+
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  ledc_hal_bind_channel_timer(&(p_ledc_obj->ledc_hal), channel, timer_sel);
+  ledc_hal_ls_channel_update(&(p_ledc_obj->ledc_hal), channel);
+
+  leave_critical_section(flags);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: setup_channel
+ *
+ * Description:
+ *   Setup LEDC timer channel duty.
+ *
+ * Input Parameters:
+ *   priv - A reference to the LEDC timer state structure
+ *   cn   - Timer channel number
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void setup_channel(struct esp_ledc_s *priv, int cn)
+{
+  irqstate_t flags;
+  bool new_ctx_created;
+  struct esp_ledc_chan_s *chan = &priv->chans[cn];
+
+  new_ctx_created = ledc_ctx_create();
+  if (!new_ctx_created && !p_ledc_obj)
+    {
+      pwmerr("ERROR: No memory for LEDC context\n");
+      PANIC();
+    }
+
+  /* On such targets (ESP32, ESP32-H2, ESP32-P4),
+   * the default ledc core(global) clock does not connect to
+   * any clock source. Setting channel configurations and updating bits
+   * before core clock is enabled could lead to an error.
+   * Therefore, we should connect the core clock to a real clock source to
+   * enable it before any ledc register operation happens.
+   * It can be switched to the other desired clock sources to meet the output
+   * PWM frequency requirements later at timer configuration.
+   * So we consider the glb_clk still as LEDC_SLOW_CLK_UNINIT.
+   */
+
+  else if (new_ctx_created)
+    {
+      flags = enter_critical_section();
+
+      if (p_ledc_obj->glb_clk == LEDC_SLOW_CLK_UNINIT)
+        {
+          ledc_hal_set_slow_clk_sel(&(p_ledc_obj->ledc_hal),
+                                    LEDC_LL_GLOBAL_CLK_DEFAULT);
+        }
+
+      leave_critical_section(flags);
+    }
+
+  ledc_set_duty_with_hpoint(chan->num,
+                            chan->duty,
+                            CONFIG_ESPRESSIF_LEDC_HPOINT);
+
+  ledc_bind_channel_timer(chan->num, priv->timer);
+
+  flags = enter_critical_section();
+  ledc_hal_set_fade_end_intr(&(p_ledc_obj->ledc_hal), chan->num, false);
+  leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: pwm_setup
+ *
+ * Description:
+ *   This method is called when the driver is opened. The lower half driver
+ *   should configure and initialize the device so that it is ready for use.
+ *   It should not, however, output pulses until the start method is called.
+ *
+ * Input Parameters:
+ *   dev - A reference to the lower half PWM driver state structure
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int pwm_setup(struct pwm_lowerhalf_s *dev)
+{
+  struct esp_ledc_s *priv = (struct esp_ledc_s *)dev;
+  int ret;
+
+  pwminfo("Initializing PWM Timer %d with default frequency of %d Hz\n",
+          priv->timer,
+          LEDC_DEFAULT_FREQ);
+
+  ret = setup_timer(priv);
+
+  if (ret != OK)
+    {
+      pwmerr("ERROR: Failed to setup timer\n");
+      return ret;
+    }
+
+  /* Setup channel GPIO pins */
+
+  for (int i = 0; i < priv->channels; i++)
+    {
+      setup_channel(priv, i);
+
+      pwminfo("Channel %d mapped to pin %d\n", priv->chans[i].num,
+              priv->chans[i].pin);
+
+      esp_configgpio(priv->chans[i].pin, OUTPUT | PULLUP);
+      esp_gpio_matrix_out(priv->chans[i].pin,
+                          LEDC_LS_SIG_OUT0_IDX + priv->chans[i].num,
+                          0, 0);
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: pwm_shutdown
+ *
+ * Description:
+ *   This method is called when the driver is closed. The lower half driver
+ *   stop pulsed output, free any resources, disable the timer hardware, and
+ *   put the system into the lowest possible power usage state
+ *
+ * Input Parameters:
+ *   dev - A reference to the lower half PWM driver state structure
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int pwm_shutdown(struct pwm_lowerhalf_s *dev)
+{
+  struct esp_ledc_s *priv = (struct esp_ledc_s *)dev;
+#ifdef CONFIG_PWM_NCHANNELS
+  int channels = MIN(priv->channels, CONFIG_PWM_NCHANNELS);
+#else
+  int channels = 1;
+#endif
+
+  pwminfo("Shutting down PWM Timer %d\n", priv->timer);
+
+  /* Stop timer */
+
+  pwm_stop(dev);
+
+  /* Clear timer and channel configuration */
+
+  priv->frequency = LEDC_DEFAULT_FREQ;
+
+  for (int i = 0; i < channels; i++)
+    {
+      priv->chans[i].duty = 0;
+    }
+
+  if (p_ledc_obj != NULL)
+    {
+      periph_module_disable(PERIPH_LEDC_MODULE);
+      kmm_free(p_ledc_obj);
+      p_ledc_obj = NULL;
+      s_ledc_slow_clk_rc_fast_freq = 0;
+    }
+  else
+    {
+      pwmerr("ERROR: LEDC not initialized\n");
+      return -ENODEV;
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: pwm_start
+ *
+ * Description:
+ *   (Re-)initialize the timer resources and start the pulsed output
+ *
+ * Input Parameters:
+ *   dev  - A reference to the lower half PWM driver state structure
+ *   info - A reference to the characteristics of the pulsed output
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int pwm_start(struct pwm_lowerhalf_s *dev,
+                     const struct pwm_info_s *info)
+{
+  uint32_t duty;
+  int ret = OK;
+  irqstate_t flags;
+  struct esp_ledc_s *priv = (struct esp_ledc_s *)dev;
+#ifdef CONFIG_PWM_NCHANNELS
+  int channels = MIN(priv->channels, CONFIG_PWM_NCHANNELS);
+#else
+  int channels = 1;
+#endif
+
+  /* Update timer with given PWM timer frequency */
+
+  if (priv->frequency != info->frequency)
+    {
+      pwminfo("Setting Timer %" PRIu8
+              " to frequency %" PRIu32
+              " Hz using %" PRIu8 " bits of resolution\n",
+              priv->timer,
+              info->frequency,
+              priv->duty_resolution);
+
+      ret |= ledc_set_timer_div(priv->timer,
+                                priv->clk_cfg,
+                                info->frequency,
+                                priv->duty_resolution);
+
+      ret |= ledc_timer_rst(priv->timer);
+
+      if (ret != OK)
+        {
+          pwmerr("ERROR: Failed to set timer configuration\n");
+          return ret;
+        }
+
+      pwminfo("Timer %d successfully configured\n", priv->timer);
+      priv->frequency = info->frequency;
+    }
+
+  /* Update timer with given PWM channel duty */
+
+  for (int i = 0; i < channels; i++)
+    {
+#ifdef CONFIG_PWM_NCHANNELS
+      duty = ledc_duty_bin_conversion(info->channels[i].duty,
+                                      priv->duty_resolution);
+#else
+      duty = ledc_duty_bin_conversion(info[i].duty,
+                                      priv->duty_resolution);
+#endif
+      if (priv->chans[i].duty != duty)
+        {
+          uint32_t max_value = (1 << priv->duty_resolution) - 1;
+          pwminfo("Setting PWM channel %" PRIu8
+                  " to duty cycle %" PRIu32 "(%0.4f)\n",
+                  priv->chans[i].num,
+                  duty,
+                  (float)duty / max_value);
+
+          flags = enter_critical_section();
+
+          ret |= ledc_duty_config(priv->chans[i].num,
+                                  LEDC_VAL_NO_CHANGE,
+                                  duty,
+                                  LEDC_DUTY_DIR_INCREASE,
+                                  1,
+                                  1,
+                                  0);
+
+          leave_critical_section(flags);
+          ret |= ledc_update_duty(priv->chans[i].num);
+
+          if (ret != OK)
+            {
+              pwmerr("ERROR: Failed to set channel configuration\n");
+              return ret;
+            }
+
+          pwminfo("Channel %d successfully configured\n",
+                  priv->chans[i].num);
+
+          priv->chans[i].duty = duty;
+        }
+
+      ledc_channel_output_enable(priv->chans[i].num);
+    }
+
+  ledc_timer_resume(priv->timer);
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: pwm_stop
+ *
+ * Description:
+ *   Stop the pulsed output and reset the timer resources.
+ *
+ * Input Parameters:
+ *   dev - A reference to the lower half PWM driver state structure
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int pwm_stop(struct pwm_lowerhalf_s *dev)
+{
+  int i;
+  int channel;
+  struct esp_ledc_s *priv = (struct esp_ledc_s *)dev;
+
+  pwminfo("Stopping PWM Timer %d\n", priv->timer);
+
+  for (i = 0; i < priv->channels; i++)
+    {
+      ledc_channel_output_disable(priv->chans[i].num);
+    }
+
+  ledc_timer_pause(priv->timer);
+  ledc_timer_rst(priv->timer);
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: pwm_ioctl
+ *
+ * Description:
+ *   Lower-half logic may support platform-specific ioctl commands
+ *
+ * Input Parameters:
+ *   dev - A reference to the lower half PWM driver state structure
+ *   cmd - The ioctl command
+ *   arg - The argument accompanying the ioctl command
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure
+ *
+ ****************************************************************************/
+
+static int pwm_ioctl(struct pwm_lowerhalf_s *dev, int cmd,
+                     unsigned long arg)
+{
+#ifdef CONFIG_DEBUG_PWM_INFO
+  struct esp_ledc_s *priv = (struct esp_ledc_s *)dev;
+
+  pwminfo("PWM Timer %d\n", priv->timer);
+#endif
+
+  return -ENOTTY;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_ledc_init
+ *
+ * Description:
+ *   Initialize one LEDC timer for use with the upper_level PWM driver.
+ *
+ * Input Parameters:
+ *   timer - A number identifying the timer use.
+ *
+ * Returned Value:
+ *   On success, a pointer to the ESP LEDC lower half PWM driver is
+ *   returned. NULL is returned on any failure.
+ *
+ ****************************************************************************/
+
+struct pwm_lowerhalf_s *esp_ledc_init(int timer)
+{
+  struct esp_ledc_s *lower = NULL;
+
+  pwminfo("PWM Timer %u initialized\n", timer);
+
+  switch (timer)
+    {
+#ifdef CONFIG_ESPRESSIF_LEDC_TIMER0
+      case 0:
+        {
+          lower = &g_pwm0dev;
+          break;
+        }
+#endif
+
+#ifdef CONFIG_ESPRESSIF_LEDC_TIMER1
+      case 1:
+        {
+          lower = &g_pwm1dev;
+          break;
+        }
+#endif
+
+#ifdef CONFIG_ESPRESSIF_LEDC_TIMER2
+      case 2:
+        {
+          lower = &g_pwm2dev;
+          break;
+        }
+#endif
+
+#ifdef CONFIG_ESPRESSIF_LEDC_TIMER3
+      case 3:
+        {
+          lower = &g_pwm3dev;
+          break;
+        }
+#endif
+
+      default:
+        {
+          pwmerr("ERROR: No such timer configured %d\n", timer);
+          lower = NULL;
+          break;
+        }
+    }
+
+  return (struct pwm_lowerhalf_s *)lower;
+}
diff --git a/arch/xtensa/src/esp32s2/esp32s2_ledc.h 
b/arch/xtensa/src/common/espressif/esp_ledc.h
similarity index 81%
rename from arch/xtensa/src/esp32s2/esp32s2_ledc.h
rename to arch/xtensa/src/common/espressif/esp_ledc.h
index 542f160c2c..b6e1e29845 100644
--- a/arch/xtensa/src/esp32s2/esp32s2_ledc.h
+++ b/arch/xtensa/src/common/espressif/esp_ledc.h
@@ -1,5 +1,7 @@
 /****************************************************************************
- * arch/xtensa/src/esp32s2/esp32s2_ledc.h
+ * arch/xtensa/src/common/espressif/esp_ledc.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -18,8 +20,8 @@
  *
  ****************************************************************************/
 
-#ifndef __ARCH_XTENSA_SRC_ESP32S2_ESP32S2_LEDC_H
-#define __ARCH_XTENSA_SRC_ESP32S2_ESP32S2_LEDC_H
+#ifndef __ARCH_XTENSA_SRC_COMMON_ESPRESSIF_ESP_LEDC_H
+#define __ARCH_XTENSA_SRC_COMMON_ESPRESSIF_ESP_LEDC_H
 
 /****************************************************************************
  * Included Files
@@ -33,7 +35,7 @@
  ****************************************************************************/
 
 /****************************************************************************
- * Name: esp32s2_ledc_init
+ * Name: esp_ledc_init
  *
  * Description:
  *   Initialize one LEDC timer for use with the upper_level PWM driver.
@@ -42,11 +44,11 @@
  *   timer - A number identifying the timer use.
  *
  * Returned Value:
- *   On success, a pointer to the ESP32S2-C3 LEDC lower half PWM driver is
+ *   On success, a pointer to the ESP LEDC lower half PWM driver is
  *   returned. NULL is returned on any failure.
  *
  ****************************************************************************/
 
-struct pwm_lowerhalf_s *esp32s2_ledc_init(int timer);
+struct pwm_lowerhalf_s *esp_ledc_init(int timer);
 
-#endif /* __ARCH_RISCV_SRC_ESP32S2_ESP32S2_LEDC_H */
+#endif /* __ARCH_XTENSA_SRC_COMMON_ESPRESSIF_ESP_LEDC_H */
diff --git a/arch/xtensa/src/esp32s2/Kconfig b/arch/xtensa/src/esp32s2/Kconfig
index 59249b43df..8f88fd6b33 100644
--- a/arch/xtensa/src/esp32s2/Kconfig
+++ b/arch/xtensa/src/esp32s2/Kconfig
@@ -540,6 +540,7 @@ config ESP32S2_LEDC
        default n
        select PWM
        select ARCH_HAVE_PWM_MULTICHAN
+       select ESPRESSIF_LEDC
        ---help---
                Enable support to PWM on ESP32S2 using LEDC peripheral.
 
diff --git a/arch/xtensa/src/esp32s2/Make.defs 
b/arch/xtensa/src/esp32s2/Make.defs
index 72bfe6cd15..94350ff2d9 100644
--- a/arch/xtensa/src/esp32s2/Make.defs
+++ b/arch/xtensa/src/esp32s2/Make.defs
@@ -63,10 +63,6 @@ ifeq ($(CONFIG_ESP32S2_TWAI),y)
 CHIP_CSRCS += esp32s2_twai.c
 endif
 
-ifeq ($(CONFIG_ESP32S2_LEDC),y)
-CHIP_CSRCS += esp32s2_ledc.c
-endif
-
 ifeq ($(CONFIG_ESP32S2_SPI),y)
 CHIP_CSRCS += esp32s2_spi.c
 ifeq ($(CONFIG_SPI_SLAVE),y)
diff --git a/arch/xtensa/src/esp32s2/esp32s2_ledc.c 
b/arch/xtensa/src/esp32s2/esp32s2_ledc.c
deleted file mode 100644
index 8a66bc6caa..0000000000
--- a/arch/xtensa/src/esp32s2/esp32s2_ledc.c
+++ /dev/null
@@ -1,810 +0,0 @@
-/****************************************************************************
- * arch/xtensa/src/esp32s2/esp32s2_ledc.c
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.  The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- ****************************************************************************/
-
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-#include <sys/param.h>
-#include <inttypes.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <string.h>
-#include <debug.h>
-#include <errno.h>
-
-#include "esp32s2_clockconfig.h"
-#include "esp32s2_gpio.h"
-#include "esp32s2_ledc.h"
-
-#include "xtensa.h"
-#include "hardware/esp32s2_ledc.h"
-#include "hardware/esp32s2_system.h"
-#include "hardware/esp32s2_gpio_sigmap.h"
-
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
-
-/* LEDC total timers */
-
-#define LEDC_TIMERS               (4)
-
-/* LEDC total channels */
-
-#if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS > 1
-#  define LEDC_CHANNELS           (8)
-#else
-#  define LEDC_CHANNELS           (4)
-#endif
-
-/* LEDC timer0 channels and offset */
-
-#ifdef CONFIG_ESP32S2_LEDC_TIM0
-#  if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS > 1
-#    define LEDC_TIM0_CHANS       CONFIG_ESP32S2_LEDC_TIM0_CHANNELS
-#  else
-#    define LEDC_TIM0_CHANS       (1)
-#  endif
-#    define LEDC_TIM0_CHANS_OFF   (0)
-#endif
-
-/* LEDC timer1 channels and offset */
-
-#ifdef CONFIG_ESP32S2_LEDC_TIM1
-#  if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS > 1
-#    define LEDC_TIM1_CHANS       CONFIG_ESP32S2_LEDC_TIM1_CHANNELS
-#  else
-#    define LEDC_TIM1_CHANS       (1)
-#  endif
-#  define LEDC_TIM1_CHANS_OFF     (LEDC_TIM0_CHANS_OFF + LEDC_TIM0_CHANS)
-#endif
-
-/* LEDC timer2 channels and offset */
-
-#ifdef CONFIG_ESP32S2_LEDC_TIM2
-#  if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS > 1
-#    define LEDC_TIM2_CHANS       CONFIG_ESP32S2_LEDC_TIM2_CHANNELS
-#  else
-#    define LEDC_TIM2_CHANS       (1)
-#  endif
-
-#  define LEDC_TIM2_CHANS_OFF     (LEDC_TIM1_CHANS_OFF + LEDC_TIM1_CHANS)
-#endif
-
-/* LEDC timer3 channels and offset */
-
-#ifdef CONFIG_ESP32S2_LEDC_TIM3
-#  if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS > 1
-#    define LEDC_TIM3_CHANS       CONFIG_ESP32S2_LEDC_TIM3_CHANNELS
-#  else
-#    define LEDC_TIM3_CHANS       (1)
-#  endif
-
-#  define LEDC_TIM3_CHANS_OFF     (LEDC_TIM2_CHANS_OFF + LEDC_TIM2_CHANS)
-#endif
-
-/* LEDC clock resource */
-
-#define LEDC_CLK_RES              (1)         /* APB clock */
-
-/* LEDC timer max reload */
-
-#define LEDC_RELOAD_MAX           (16384)    /* 2^14 */
-
-/* LEDC timer max clock divider parameter */
-
-#define LEDC_CLKDIV_MAX           (262144)    /* 2^18 */
-
-/* LEDC timer registers mapping */
-
-#define LEDC_TIMER_REG(r, n)      ((r) + (n) * (LEDC_TIMER1_CONF_REG - \
-                                                LEDC_TIMER0_CONF_REG))
-
-/* LEDC timer channel registers mapping */
-
-#define setbits(bs, a)            modifyreg32(a, 0, bs)
-#define resetbits(bs, a)          modifyreg32(a, bs, 0)
-
-#define LEDC_CHAN_REG(r, n)       ((r) + (n) * (LEDC_CH1_CONF0_REG - \
-                                                LEDC_CH0_CONF0_REG))
-
-#define SET_TIMER_BITS(t, r, b)   setbits(b, LEDC_TIMER_REG(r, (t)->num));
-#define SET_TIMER_REG(t, r, v)    putreg32(v, LEDC_TIMER_REG(r, (t)->num));
-
-#define SET_CHAN_BITS(c, r, b)    setbits(b, LEDC_CHAN_REG(r, (c)->num));
-#define SET_CHAN_REG(c, r, v)     putreg32(v, LEDC_CHAN_REG(r, (c)->num));
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-/* LEDC timer channel configuration */
-
-struct esp32s2_ledc_chan_s
-{
-  const uint8_t num;                    /* Timer channel ID */
-  const uint8_t pin;                    /* Timer channel GPIO pin number */
-  uint16_t duty;                        /* Timer channel current duty */
-};
-
-/* This structure represents the state of one LEDC timer */
-
-struct esp32s2_ledc_s
-{
-  const struct pwm_ops_s *ops;          /* PWM operations */
-
-  const uint8_t num;                    /* Timer ID */
-
-  const uint8_t channels;               /* Timer channels number */
-  struct esp32s2_ledc_chan_s *chans;    /* Timer channels pointer */
-
-  uint32_t frequency;                   /* Timer current frequency */
-  uint32_t reload;                      /* Timer current reload */
-};
-
-/****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
-
-static int pwm_setup(struct pwm_lowerhalf_s *dev);
-static int pwm_shutdown(struct pwm_lowerhalf_s *dev);
-static int pwm_start(struct pwm_lowerhalf_s *dev,
-                     const struct pwm_info_s *info);
-static int pwm_stop(struct pwm_lowerhalf_s *dev);
-static int pwm_ioctl(struct pwm_lowerhalf_s *dev, int cmd,
-                     unsigned long arg);
-
-/****************************************************************************
- * Private Data
- ****************************************************************************/
-
-/* LEDC PWM operations */
-
-static const struct pwm_ops_s g_pwmops =
-{
-  .setup       = pwm_setup,
-  .shutdown    = pwm_shutdown,
-  .start       = pwm_start,
-  .stop        = pwm_stop,
-  .ioctl       = pwm_ioctl
-};
-
-/* LEDC channels table */
-
-static struct esp32s2_ledc_chan_s g_ledc_chans[LEDC_CHANNELS] =
-{
-  {
-    .num       = 0,
-    .pin       = CONFIG_ESP32S2_LEDC_CHANNEL0_PIN
-  },
-
-  {
-    .num       = 1,
-    .pin       = CONFIG_ESP32S2_LEDC_CHANNEL1_PIN
-  },
-
-  {
-    .num       = 2,
-    .pin       = CONFIG_ESP32S2_LEDC_CHANNEL2_PIN
-  },
-
-  {
-    .num       = 3,
-    .pin       = CONFIG_ESP32S2_LEDC_CHANNEL3_PIN
-  },
-
-#if LEDC_CHANNELS > 4
-  {
-    .num       = 4,
-    .pin       = CONFIG_ESP32S2_LEDC_CHANNEL4_PIN
-  },
-
-  {
-    .num       = 5,
-    .pin       = CONFIG_ESP32S2_LEDC_CHANNEL5_PIN
-  },
-
-  {
-    .num       = 6,
-    .pin       = CONFIG_ESP32S2_LEDC_CHANNEL6_PIN
-  },
-
-  {
-    .num       = 7,
-    .pin       = CONFIG_ESP32S2_LEDC_CHANNEL7_PIN
-  }
-#endif
-};
-
-/* LEDC timer0 private data */
-
-#ifdef CONFIG_ESP32S2_LEDC_TIM0
-static struct esp32s2_ledc_s g_pwm0dev =
-{
-  .ops         = &g_pwmops,
-  .num         = 0,
-  .channels    = LEDC_TIM0_CHANS,
-  .chans       = &g_ledc_chans[LEDC_TIM0_CHANS_OFF]
-};
-#endif /* CONFIG_ESP32S2_LEDC_TIM0 */
-
-/* LEDC timer1 private data */
-
-#ifdef CONFIG_ESP32S2_LEDC_TIM1
-static struct esp32s2_ledc_s g_pwm1dev =
-{
-  .ops         = &g_pwmops,
-  .num         = 1,
-  .channels    = LEDC_TIM1_CHANS,
-  .chans       = &g_ledc_chans[LEDC_TIM1_CHANS_OFF]
-};
-#endif /* CONFIG_ESP32S2_LEDC_TIM1 */
-
-/* LEDC timer2 private data */
-
-#ifdef CONFIG_ESP32S2_LEDC_TIM2
-static struct esp32s2_ledc_s g_pwm2dev =
-{
-  .ops         = &g_pwmops,
-  .num         = 2,
-  .channels    = LEDC_TIM2_CHANS,
-  .chans       = &g_ledc_chans[LEDC_TIM2_CHANS_OFF]
-};
-#endif /* CONFIG_ESP32S2_LEDC_TIM2 */
-
-/* LEDC timer3 private data */
-
-#ifdef CONFIG_ESP32S2_LEDC_TIM3
-static struct esp32s2_ledc_s g_pwm3dev =
-{
-  .ops         = &g_pwmops,
-  .num         = 3,
-  .channels    = LEDC_TIM3_CHANS,
-  .chans       = &g_ledc_chans[LEDC_TIM3_CHANS_OFF]
-};
-#endif /* CONFIG_ESP32S2_LEDC_TIM3 */
-
-/* Clock reference count */
-
-static uint32_t g_clk_ref;
-
-/****************************************************************************
- * Private functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: ledc_enable_clk
- *
- * Description:
- *   Enable LEDC clock.
- *
- * Input Parameters:
- *   None
- *
- * Returned Value:
- *   None.
- *
- ****************************************************************************/
-
-static void ledc_enable_clk(void)
-{
-  irqstate_t flags;
-
-  flags = enter_critical_section();
-
-  if (g_clk_ref == 0)
-    {
-      setbits(SYSTEM_LEDC_CLK_EN, SYSTEM_PERIP_CLK_EN0_REG);
-      resetbits(SYSTEM_LEDC_RST, SYSTEM_PERIP_RST_EN0_REG);
-
-      putreg32(LEDC_CLK_RES, LEDC_CONF_REG);
-      putreg32(LEDC_CLK_EN, LEDC_CONF_REG);
-
-      pwminfo("Enable ledc clock\n");
-    }
-
-  g_clk_ref++;
-
-  leave_critical_section(flags);
-}
-
-/****************************************************************************
- * Name: ledc_disable_clk
- *
- * Description:
- *   Disable LEDC clock.
- *
- * Input Parameters:
- *   None
- *
- * Returned Value:
- *   None.
- *
- ****************************************************************************/
-
-static void ledc_disable_clk(void)
-{
-  irqstate_t flags;
-
-  flags = enter_critical_section();
-
-  g_clk_ref--;
-
-  if (g_clk_ref == 0)
-    {
-      pwminfo("Disable ledc clock\n");
-
-      setbits(SYSTEM_LEDC_RST, SYSTEM_PERIP_RST_EN0_REG);
-      resetbits(SYSTEM_LEDC_CLK_EN, SYSTEM_PERIP_CLK_EN0_REG);
-    }
-
-  leave_critical_section(flags);
-}
-
-/****************************************************************************
- * Name: setup_timer
- *
- * Description:
- *   Setup LEDC timer frequency and reload.
- *
- * Input Parameters:
- *   priv - A reference to the LEDC timer state structure
- *
- * Returned Value:
- *   None
- *
- ****************************************************************************/
-
-static void setup_timer(struct esp32s2_ledc_s *priv)
-{
-  irqstate_t flags;
-  uint32_t regval;
-  uint32_t reload;
-  uint32_t prescaler;
-  uint32_t shift = 1;
-  uint64_t pwmclk = esp_clk_apb_freq();
-
-  /* Reset timer */
-
-  SET_TIMER_BITS(priv, LEDC_TIMER0_CONF_REG, LEDC_TIMER0_RST);
-
-  /* Calculate optimal values for the timer prescaler and for the timer
-   * modulo register.  If 'frequency' is the desired frequency, then
-   *
-   *   tpmclk = pwmclk / presc
-   *   frequency = tpmclk / reload
-   *
-   * ==>
-   *
-   *   reload = pwmclk / presc / frequency
-   *
-   * In ESP32S2, there are 3 clock resources for PWM:
-   *
-   *   1. APB clock (80 MHz)
-   *   2. RTC clock (8 MHz)
-   *   3. XTAL_CLK
-   *
-   * We mostly use APB clock generally.
-   *
-   * There are many solutions to this, but the best solution will be the one
-   * that has the largest reload value and the smallest prescaler value.
-   * That is the solution that should give us the most accuracy in the timer
-   * control.  Subject to:
-   *
-   *   2 <= presc  <= 2^18(262144)
-   *   1 <= clkdiv <= 2^10
-   *
-   * clkdiv has 8-bit decimal precision, so
-   * clkdiv = pwmclk * 256 / 16384 / frequency would be optimal.
-   *
-   * Example:
-   *
-   *  pwmclk    = 80 MHz
-   *  frequency = 100 Hz
-   *
-   *  presc     = 80,000,000 * 256 / 16,384 / 100
-   *            = 12,500
-   *  timclk    = 80,000,000 / (12,500 / 256)
-   *            = 1,638,400
-   *  counter   = 1,638,400 / 100
-   *            = 16,384
-   *            = 2^14
-   *  shift     = 14
-   */
-
-  reload = (pwmclk * 256 / priv->frequency + LEDC_CLKDIV_MAX) /
-           LEDC_CLKDIV_MAX;
-  if (reload == 0)
-    {
-      reload = 1;
-    }
-  else if (reload > LEDC_RELOAD_MAX)
-    {
-      reload = LEDC_RELOAD_MAX;
-    }
-
-  for (int c = 2; c <= LEDC_RELOAD_MAX; c *= 2)
-    {
-      if (c * 2 > reload)
-        {
-          reload = c;
-          break;
-        }
-
-      shift++;
-    }
-
-  prescaler = pwmclk * 256 / reload / priv->frequency;
-
-  pwminfo("PWM timer%" PRIu8 " frequency=%0.4f reload=%" PRIu32 " shift=%"
-          PRIu32 " prescaler=%0.4f\n",
-          priv->num, (float)pwmclk / reload / ((float)prescaler / 256),
-          reload, shift, (float)prescaler / 256);
-
-  /* Store reload for channel duty */
-
-  priv->reload = reload;
-
-  flags = enter_critical_section();
-
-  /* Set timer clock divide and reload */
-
-  regval = (shift << LEDC_TIMER0_DUTY_RES_S) |
-           (prescaler << LEDC_CLK_DIV_TIMER0_S);
-  SET_TIMER_REG(priv, LEDC_TIMER0_CONF_REG, regval);
-
-  /* Setup to timer to use APB clock (80MHz) */
-
-  SET_TIMER_BITS(priv, LEDC_TIMER0_CONF_REG, LEDC_TICK_SEL_TIMER0);
-
-  /* Update clock divide and reload to hardware */
-
-  SET_TIMER_BITS(priv, LEDC_TIMER0_CONF_REG, LEDC_TIMER0_PARA_UP);
-
-  leave_critical_section(flags);
-}
-
-/****************************************************************************
- * Name: setup_channel
- *
- * Description:
- *   Setup LEDC timer channel duty.
- *
- * Input Parameters:
- *   priv - A reference to the LEDC timer state structure
- *   cn   - Timer channel number
- *
- * Returned Value:
- *   None
- *
- ****************************************************************************/
-
-static void setup_channel(struct esp32s2_ledc_s *priv, int cn)
-{
-  irqstate_t flags;
-  uint32_t regval;
-  struct esp32s2_ledc_chan_s *chan = &priv->chans[cn];
-
-  /* Duty cycle:
-   *
-   * duty cycle = duty / 65536 * reload (fractional value)
-   */
-
-  regval = b16toi(chan->duty * priv->reload + b16HALF);
-
-  pwminfo("channel=%" PRIu8 " duty=%" PRIu16 "(%0.4f) regval=%" PRIu32
-          " reload=%" PRIu32 "\n",
-          chan->num, chan->duty, (float)chan->duty / UINT16_MAX,
-          regval, priv->reload);
-
-  flags = enter_critical_section();
-
-  /* Reset config 0 & 1 registers */
-
-  SET_CHAN_REG(chan, LEDC_CH0_CONF0_REG, 0);
-  SET_CHAN_REG(chan, LEDC_CH0_CONF1_REG, 0);
-
-  /* Set pulse phase 0 */
-
-  SET_CHAN_REG(chan, LEDC_CH0_HPOINT_REG, 0);
-
-  /* Duty register uses bits [18:4]  */
-
-  SET_CHAN_REG(chan, LEDC_CH0_DUTY_REG, regval << 4);
-
-  /* Start GPIO output  */
-
-  SET_CHAN_BITS(chan, LEDC_CH0_CONF0_REG, LEDC_SIG_OUT_EN_CH0);
-
-  /* Start Duty counter  */
-
-  SET_CHAN_BITS(chan, LEDC_CH0_CONF1_REG, LEDC_DUTY_START_CH0);
-
-  /* Update duty and phase to hardware */
-
-  SET_CHAN_BITS(chan, LEDC_CH0_CONF0_REG, LEDC_PARA_UP_CH0);
-
-  leave_critical_section(flags);
-}
-
-/****************************************************************************
- * Name: pwm_setup
- *
- * Description:
- *   This method is called when the driver is opened.  The lower half driver
- *   should configure and initialize the device so that it is ready for use.
- *   It should not, however, output pulses until the start method is called.
- *
- * Input Parameters:
- *   dev - A reference to the lower half PWM driver state structure
- *
- * Returned Value:
- *   Zero on success; a negated errno value on failure
- *
- ****************************************************************************/
-
-static int pwm_setup(struct pwm_lowerhalf_s *dev)
-{
-  struct esp32s2_ledc_s *priv = (struct esp32s2_ledc_s *)dev;
-
-  pwminfo("PWM timer%u\n", priv->num);
-
-  ledc_enable_clk();
-
-  /* Setup channel GPIO pins */
-
-  for (int i = 0; i < priv->channels; i++)
-    {
-      pwminfo("channel%d --> pin%d\n", priv->chans[i].num,
-              priv->chans[i].pin);
-
-      esp32s2_configgpio(priv->chans[i].pin, OUTPUT | PULLUP);
-      esp32s2_gpio_matrix_out(priv->chans[i].pin,
-                              LEDC_LS_SIG_OUT0_IDX + priv->chans[i].num,
-                              0, 0);
-    }
-
-  return 0;
-}
-
-/****************************************************************************
- * Name: pwm_shutdown
- *
- * Description:
- *   This method is called when the driver is closed.  The lower half driver
- *   stop pulsed output, free any resources, disable the timer hardware, and
- *   put the system into the lowest possible power usage state
- *
- * Input Parameters:
- *   dev - A reference to the lower half PWM driver state structure
- *
- * Returned Value:
- *   Zero on success; a negated errno value on failure
- *
- ****************************************************************************/
-
-static int pwm_shutdown(struct pwm_lowerhalf_s *dev)
-{
-  struct esp32s2_ledc_s *priv = (struct esp32s2_ledc_s *)dev;
-#ifdef CONFIG_PWM_NCHANNELS
-  int channels = MIN(priv->channels, CONFIG_PWM_NCHANNELS);
-#else
-  int channels = 1;
-#endif
-
-  /* Stop timer */
-
-  pwm_stop(dev);
-
-  /* Clear timer and channel configuration */
-
-  priv->frequency = 0;
-  priv->reload    = 0;
-  for (int i = 0; i < channels; i++)
-    {
-      priv->chans[i].duty = 0;
-    }
-
-  ledc_disable_clk();
-
-  return 0;
-}
-
-/****************************************************************************
- * Name: pwm_start
- *
- * Description:
- *   (Re-)initialize the timer resources and start the pulsed output
- *
- * Input Parameters:
- *   dev  - A reference to the lower half PWM driver state structure
- *   info - A reference to the characteristics of the pulsed output
- *
- * Returned Value:
- *   Zero on success; a negated errno value on failure
- *
- ****************************************************************************/
-
-static int pwm_start(struct pwm_lowerhalf_s *dev,
-                     const struct pwm_info_s *info)
-{
-  struct esp32s2_ledc_s *priv = (struct esp32s2_ledc_s *)dev;
-#ifdef CONFIG_PWM_NCHANNELS
-  int channels = MIN(priv->channels, CONFIG_PWM_NCHANNELS);
-#else
-  int channels = 1;
-#endif
-
-  pwminfo("PWM timer%d\n", priv->num);
-
-  /* Update timer with given PWM timer frequency */
-
-  if (priv->frequency != info->frequency)
-    {
-      priv->frequency = info->frequency;
-      setup_timer(priv);
-    }
-
-  /* Update timer with given PWM channel duty */
-
-  for (int i = 0; i < channels; i++)
-    {
-#ifdef CONFIG_PWM_NCHANNELS
-      if (priv->chans[i].duty != info->channels[i].duty)
-#else
-      if (priv->chans[i].duty != info[i].duty)
-#endif
-        {
-#ifdef CONFIG_PWM_NCHANNELS
-          priv->chans[i].duty = info->channels[i].duty;
-#else
-          priv->chans[i].duty = info[i].duty;
-#endif
-          setup_channel(priv, i);
-        }
-    }
-
-  return 0;
-}
-
-/****************************************************************************
- * Name: pwm_stop
- *
- * Description:
- *   Stop the pulsed output and reset the timer resources.
- *
- * Input Parameters:
- *   dev - A reference to the lower half PWM driver state structure
- *
- * Returned Value:
- *   Zero on success; a negated errno value on failure
- *
- ****************************************************************************/
-
-static int pwm_stop(struct pwm_lowerhalf_s *dev)
-{
-  irqstate_t flags;
-  struct esp32s2_ledc_s *priv = (struct esp32s2_ledc_s *)dev;
-
-  pwminfo("PWM timer%d\n", priv->num);
-
-  flags = enter_critical_section();
-
-  /* Stop timer */
-
-  SET_TIMER_BITS(priv, LEDC_TIMER0_CONF_REG, LEDC_TIMER0_PAUSE);
-
-  /* Reset timer */
-
-  SET_TIMER_BITS(priv, LEDC_TIMER0_CONF_REG, LEDC_TIMER0_RST);
-
-  leave_critical_section(flags);
-  return 0;
-}
-
-/****************************************************************************
- * Name: pwm_ioctl
- *
- * Description:
- *   Lower-half logic may support platform-specific ioctl commands
- *
- * Input Parameters:
- *   dev - A reference to the lower half PWM driver state structure
- *   cmd - The ioctl command
- *   arg - The argument accompanying the ioctl command
- *
- * Returned Value:
- *   Zero on success; a negated errno value on failure
- *
- ****************************************************************************/
-
-static int pwm_ioctl(struct pwm_lowerhalf_s *dev, int cmd,
-                     unsigned long arg)
-{
-#ifdef CONFIG_DEBUG_PWM_INFO
-  struct esp32s2_ledc_s *priv = (struct esp32s2_ledc_s *)dev;
-
-  pwminfo("PWM timer%d\n", priv->num);
-#endif
-
-  return -ENOTTY;
-}
-
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: esp32s2_ledc_init
- *
- * Description:
- *   Initialize one LEDC timer for use with the upper_level PWM driver.
- *
- * Input Parameters:
- *   timer - A number identifying the timer use.
- *
- * Returned Value:
- *   On success, a pointer to the ESP32S2 LEDC lower half PWM driver is
- *   returned. NULL is returned on any failure.
- *
- ****************************************************************************/
-
-struct pwm_lowerhalf_s *esp32s2_ledc_init(int timer)
-{
-  struct esp32s2_ledc_s *lower = NULL;
-
-  pwminfo("TIM%u\n", timer);
-
-  switch (timer)
-    {
-#ifdef CONFIG_ESP32S2_LEDC_TIM0
-      case 0:
-        lower = &g_pwm0dev;
-        break;
-#endif
-
-#ifdef CONFIG_ESP32S2_LEDC_TIM1
-      case 1:
-        lower = &g_pwm1dev;
-        break;
-#endif
-
-#ifdef CONFIG_ESP32S2_LEDC_TIM2
-      case 2:
-        lower = &g_pwm2dev;
-        break;
-#endif
-
-#ifdef CONFIG_ESP32S2_LEDC_TIM3
-      case 3:
-        lower = &g_pwm3dev;
-        break;
-#endif
-
-      default:
-        pwmerr("ERROR: No such timer configured %d\n", timer);
-        lower = NULL;
-        break;
-    }
-
-  return (struct pwm_lowerhalf_s *)lower;
-}
diff --git a/arch/xtensa/src/esp32s3/Kconfig b/arch/xtensa/src/esp32s3/Kconfig
index ae8436c07b..f1e577e33c 100644
--- a/arch/xtensa/src/esp32s3/Kconfig
+++ b/arch/xtensa/src/esp32s3/Kconfig
@@ -813,6 +813,7 @@ config ESP32S3_LEDC
        default n
        select PWM
        select ARCH_HAVE_PWM_MULTICHAN
+       select ESPRESSIF_LEDC
        ---help---
                Enable support to PWM on ESP32S3 using LEDC peripheral.
 
diff --git a/arch/xtensa/src/esp32s3/Make.defs 
b/arch/xtensa/src/esp32s3/Make.defs
index 1abe16fc01..a145f48bb0 100644
--- a/arch/xtensa/src/esp32s3/Make.defs
+++ b/arch/xtensa/src/esp32s3/Make.defs
@@ -61,10 +61,6 @@ ifeq ($(CONFIG_ESP32S3_TWAI),y)
 CHIP_CSRCS += esp32s3_twai.c
 endif
 
-ifeq ($(CONFIG_ESP32S3_LEDC),y)
-CHIP_CSRCS += esp32s3_ledc.c
-endif
-
 ifeq ($(CONFIG_ESP32S3_USBSERIAL),y)
 CHIP_CSRCS += esp32s3_usbserial.c
 endif
diff --git a/arch/xtensa/src/esp32s3/esp32s3_ledc.c 
b/arch/xtensa/src/esp32s3/esp32s3_ledc.c
deleted file mode 100644
index f01926eb65..0000000000
--- a/arch/xtensa/src/esp32s3/esp32s3_ledc.c
+++ /dev/null
@@ -1,865 +0,0 @@
-/****************************************************************************
- * arch/xtensa/src/esp32s3/esp32s3_ledc.c
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.  The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- ****************************************************************************/
-
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-#include <sys/param.h>
-#include <inttypes.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <string.h>
-#include <debug.h>
-#include <errno.h>
-#include <nuttx/config.h>
-
-#include "esp32s3_clockconfig.h"
-#include "esp32s3_gpio.h"
-#include "esp32s3_ledc.h"
-
-#include "xtensa.h"
-#include "hardware/esp32s3_ledc.h"
-#include "hardware/esp32s3_system.h"
-#include "hardware/esp32s3_gpio_sigmap.h"
-
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
-
-/* LEDC total timers */
-
-#define LEDC_TIMERS               (4)
-
-/* LEDC total channels */
-
-#if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS > 1
-#  define LEDC_CHANNELS           (8)
-#else
-#  define LEDC_CHANNELS           (4)
-#endif
-
-/* LEDC timer0 channels and offset */
-
-#ifdef CONFIG_ESP32S3_LEDC_TIM0
-#  if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS > 1
-#    define LEDC_TIM0_CHANS       CONFIG_ESP32S3_LEDC_TIM0_CHANNELS
-#  else
-#    define LEDC_TIM0_CHANS       (1)
-#  endif
-#    define LEDC_TIM0_CHANS_OFF   (0)
-#endif
-
-/* LEDC timer1 channels and offset */
-
-#ifdef CONFIG_ESP32S3_LEDC_TIM1
-#  if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS > 1
-#    define LEDC_TIM1_CHANS       CONFIG_ESP32S3_LEDC_TIM1_CHANNELS
-#  else
-#    define LEDC_TIM1_CHANS       (1)
-#  endif
-#  define LEDC_TIM1_CHANS_OFF     (LEDC_TIM0_CHANS_OFF + LEDC_TIM0_CHANS)
-#endif
-
-/* LEDC timer2 channels and offset */
-
-#ifdef CONFIG_ESP32S3_LEDC_TIM2
-#  if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS > 1
-#    define LEDC_TIM2_CHANS       CONFIG_ESP32S3_LEDC_TIM2_CHANNELS
-#  else
-#    define LEDC_TIM2_CHANS       (1)
-#  endif
-
-#  define LEDC_TIM2_CHANS_OFF     (LEDC_TIM1_CHANS_OFF + LEDC_TIM1_CHANS)
-#endif
-
-/* LEDC timer3 channels and offset */
-
-#ifdef CONFIG_ESP32S3_LEDC_TIM3
-#  if defined(CONFIG_PWM_NCHANNELS) && CONFIG_PWM_NCHANNELS > 1
-#    define LEDC_TIM3_CHANS       CONFIG_ESP32S3_LEDC_TIM3_CHANNELS
-#  else
-#    define LEDC_TIM3_CHANS       (1)
-#  endif
-
-#  define LEDC_TIM3_CHANS_OFF     (LEDC_TIM2_CHANS_OFF + LEDC_TIM2_CHANS)
-#endif
-
-/* LEDC clock resource */
-
-#define LEDC_CLK_RES_APB          (1)         /* APB clock */
-#define LEDC_CLK_RES_RC_FAST      (2)         /* RC_FAST clock */
-#define LEDC_CLK_RES_XTAL         (3)         /* XTAL clock */
-
-/* LEDC clock source frequency */
-
-#define LEDC_CLK_APB_FREQ         (80 * MHZ)      /* APB clock frequency */
-#define LEDC_CLK_RC_FAST_FREQ     (17.5 * MHZ)    /* RC_FAST clock frequency */
-#define LEDC_CLK_XTAL_FREQ        (40 * MHZ)      /* XTAL clock frequency */
-
-/* LEDC timer max reload */
-
-#define LEDC_RELOAD_MAX           (16384)    /* 2^14 */
-
-/* LEDC timer max reload bit length */
-
-#define LEDC_RELOAD_MAX_BIT_LEN   (14)
-
-/* LEDC timer max clock divider parameter */
-
-#define LEDC_CLKDIV_MAX           (1024)    /* 2^10 */
-
-/* LEDC timer registers mapping */
-
-#define LEDC_TIMER_REG(r, n)      ((r) + (n) * (LEDC_TIMER1_CONF_REG - \
-                                                LEDC_TIMER0_CONF_REG))
-
-/* LEDC timer channel registers mapping */
-
-#define setbits(bs, a)            modifyreg32(a, 0, bs)
-#define resetbits(bs, a)          modifyreg32(a, bs, 0)
-
-#define LEDC_CHAN_REG(r, n)       ((r) + (n) * (LEDC_CH1_CONF0_REG - \
-                                                LEDC_CH0_CONF0_REG))
-
-#define SET_TIMER_BITS(t, r, b)   setbits(b, LEDC_TIMER_REG(r, (t)->num));
-#define SET_TIMER_REG(t, r, v)    putreg32(v, LEDC_TIMER_REG(r, (t)->num));
-
-#define SET_CHAN_BITS(c, r, b)    setbits(b, LEDC_CHAN_REG(r, (c)->num));
-#define SET_CHAN_REG(c, r, v)     putreg32(v, LEDC_CHAN_REG(r, (c)->num));
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-/* LEDC timer channel configuration */
-
-struct esp32s3_ledc_chan_s
-{
-  const uint8_t num;                    /* Timer channel ID */
-  const uint8_t pin;                    /* Timer channel GPIO pin number */
-  uint16_t duty;                        /* Timer channel current duty */
-};
-
-/* This structure represents the state of one LEDC timer */
-
-struct esp32s3_ledc_s
-{
-  const struct pwm_ops_s *ops;          /* PWM operations */
-
-  const uint8_t num;                    /* Timer ID */
-
-  const uint8_t channels;               /* Timer channels number */
-  struct esp32s3_ledc_chan_s *chans;    /* Timer channels pointer */
-
-  uint32_t frequency;                   /* Timer current frequency */
-  uint32_t reload;                      /* Timer current reload */
-};
-
-/****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
-
-static int pwm_setup(struct pwm_lowerhalf_s *dev);
-static int pwm_shutdown(struct pwm_lowerhalf_s *dev);
-static int pwm_start(struct pwm_lowerhalf_s *dev,
-                     const struct pwm_info_s *info);
-static int pwm_stop(struct pwm_lowerhalf_s *dev);
-static int pwm_ioctl(struct pwm_lowerhalf_s *dev, int cmd,
-                     unsigned long arg);
-
-/****************************************************************************
- * Private Data
- ****************************************************************************/
-
-/* LEDC PWM operations */
-
-static const struct pwm_ops_s g_pwmops =
-{
-  .setup       = pwm_setup,
-  .shutdown    = pwm_shutdown,
-  .start       = pwm_start,
-  .stop        = pwm_stop,
-  .ioctl       = pwm_ioctl
-};
-
-/* LEDC channels table */
-
-static struct esp32s3_ledc_chan_s g_ledc_chans[LEDC_CHANNELS] =
-{
-  {
-    .num       = 0,
-    .pin       = CONFIG_ESP32S3_LEDC_CHANNEL0_PIN
-  },
-
-  {
-    .num       = 1,
-    .pin       = CONFIG_ESP32S3_LEDC_CHANNEL1_PIN
-  },
-
-  {
-    .num       = 2,
-    .pin       = CONFIG_ESP32S3_LEDC_CHANNEL2_PIN
-  },
-
-  {
-    .num       = 3,
-    .pin       = CONFIG_ESP32S3_LEDC_CHANNEL3_PIN
-  },
-
-#if LEDC_CHANNELS > 4
-  {
-    .num       = 4,
-    .pin       = CONFIG_ESP32S3_LEDC_CHANNEL4_PIN
-  },
-
-  {
-    .num       = 5,
-    .pin       = CONFIG_ESP32S3_LEDC_CHANNEL5_PIN
-  },
-
-  {
-    .num       = 6,
-    .pin       = CONFIG_ESP32S3_LEDC_CHANNEL6_PIN
-  },
-
-  {
-    .num       = 7,
-    .pin       = CONFIG_ESP32S3_LEDC_CHANNEL7_PIN
-  }
-#endif
-};
-
-/* LEDC timer0 private data */
-
-#ifdef CONFIG_ESP32S3_LEDC_TIM0
-static struct esp32s3_ledc_s g_pwm0dev =
-{
-  .ops         = &g_pwmops,
-  .num         = 0,
-  .channels    = LEDC_TIM0_CHANS,
-  .chans       = &g_ledc_chans[LEDC_TIM0_CHANS_OFF]
-};
-#endif /* CONFIG_ESP32S3_LEDC_TIM0 */
-
-/* LEDC timer1 private data */
-
-#ifdef CONFIG_ESP32S3_LEDC_TIM1
-static struct esp32s3_ledc_s g_pwm1dev =
-{
-  .ops         = &g_pwmops,
-  .num         = 1,
-  .channels    = LEDC_TIM1_CHANS,
-  .chans       = &g_ledc_chans[LEDC_TIM1_CHANS_OFF]
-};
-#endif /* CONFIG_ESP32S3_LEDC_TIM1 */
-
-/* LEDC timer2 private data */
-
-#ifdef CONFIG_ESP32S3_LEDC_TIM2
-static struct esp32s3_ledc_s g_pwm2dev =
-{
-  .ops         = &g_pwmops,
-  .num         = 2,
-  .channels    = LEDC_TIM2_CHANS,
-  .chans       = &g_ledc_chans[LEDC_TIM2_CHANS_OFF]
-};
-#endif /* CONFIG_ESP32S3_LEDC_TIM2 */
-
-/* LEDC timer3 private data */
-
-#ifdef CONFIG_ESP32S3_LEDC_TIM3
-static struct esp32s3_ledc_s g_pwm3dev =
-{
-  .ops         = &g_pwmops,
-  .num         = 3,
-  .channels    = LEDC_TIM3_CHANS,
-  .chans       = &g_ledc_chans[LEDC_TIM3_CHANS_OFF]
-};
-#endif /* CONFIG_ESP32S3_LEDC_TIM3 */
-
-/* Clock source */
-
-static uint32_t clk_src = 0;
-
-/****************************************************************************
- * Private functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: ledc_enable_clk
- *
- * Description:
- *   Enable LEDC clock.
- *
- * Input Parameters:
- *   None
- *
- * Returned Value:
- *   None.
- *
- ****************************************************************************/
-
-static void ledc_enable_clk(void)
-{
-  irqstate_t flags;
-
-  flags = enter_critical_section();
-
-  if (clk_src == 0)
-    {
-      setbits(SYSTEM_LEDC_CLK_EN, SYSTEM_PERIP_CLK_EN0_REG);
-      resetbits(SYSTEM_LEDC_RST, SYSTEM_PERIP_RST_EN0_REG);
-
-      putreg32(LEDC_CLK_RES_APB, LEDC_CONF_REG);
-      setbits(LEDC_CLK_EN, LEDC_CONF_REG);
-
-      /* We set default clock is APB. */
-
-      clk_src = LEDC_CLK_RES_APB;
-
-      pwminfo("Enable ledc clock\n");
-    }
-
-  leave_critical_section(flags);
-}
-
-/****************************************************************************
- * Name: ledc_disable_clk
- *
- * Description:
- *   Disable LEDC clock.
- *
- * Input Parameters:
- *   None
- *
- * Returned Value:
- *   None.
- *
- ****************************************************************************/
-
-static void ledc_disable_clk(void)
-{
-  irqstate_t flags;
-
-  flags = enter_critical_section();
-
-  if (clk_src != 0)
-    {
-      pwminfo("Disable ledc clock\n");
-
-      setbits(SYSTEM_LEDC_RST, SYSTEM_PERIP_RST_EN0_REG);
-      resetbits(SYSTEM_LEDC_CLK_EN, SYSTEM_PERIP_CLK_EN0_REG);
-      clk_src = 0;
-    }
-
-  leave_critical_section(flags);
-}
-
-/****************************************************************************
- * Name: setup_timer
- *
- * Description:
- *   Setup LEDC timer frequency and reload.
- *
- * Input Parameters:
- *   priv - A reference to the LEDC timer state structure
- *
- * Returned Value:
- *   None
- *
- ****************************************************************************/
-
-static void setup_timer(struct esp32s3_ledc_s *priv)
-{
-  irqstate_t flags;
-  uint32_t regval;
-  uint32_t reload;
-  float prescaler;
-  uint32_t integral_prescaler;
-  uint32_t fractional_prescaler;
-  uint8_t shift;
-  uint64_t pwmclk = LEDC_CLK_APB_FREQ;
-
-  /* Determine the using clock source and set pwmclk */
-
-  switch (clk_src)
-  {
-  case LEDC_CLK_RES_APB:
-
-    /* use APB clock */
-
-    pwmclk = LEDC_CLK_APB_FREQ;
-    break;
-
-  case LEDC_CLK_RES_RC_FAST:
-
-    /* use RC_FAST clock */
-
-    pwmclk = LEDC_CLK_RC_FAST_FREQ;
-    break;
-
-  case LEDC_CLK_RES_XTAL:
-
-    /* use XTAL clock */
-
-    pwmclk = LEDC_CLK_XTAL_FREQ;
-    break;
-
-  default:
-    pwmerr("Invalid clock source or no clock has been inited !");
-    break;
-  }
-
-  /* Reset timer */
-
-  SET_TIMER_BITS(priv, LEDC_TIMER0_CONF_REG, LEDC_TIMER0_RST);
-
-  /* Calculate optimal values for the timer prescaler and for the timer
-   * modulo register.  If 'frequency' is the desired frequency, then
-   *
-   *   tpmclk = pwmclk / presc
-   *   frequency = tpmclk / reload
-   *
-   * ==>
-   *
-   *   reload = pwmclk / presc / frequency
-   *
-   * In ESP32S3, there are 3 clock resources for PWM:
-   *
-   *   1. APB clock (80 MHz)
-   *   2. RC_FAST_CLK (17.5 MHz)
-   *   3. XTAL_CLK (40 MHZ)
-   *
-   * We mostly use APB clock generally.
-   *
-   * There are many solutions to this, but the best solution will be the one
-   * that has the largest reload value and the smallest prescaler value.
-   * That is the solution that should give us the most accuracy in the timer
-   * control.  Subject to:
-   *
-   *   2 <= presc  <= 2^14(16384)
-   *   1 <= clkdiv <= 2^10
-   *
-   * clkdiv has 10-bit integral precision and 8-bit fractional precision, so
-   * clkdiv = pwmclk / 16384 / frequency would be optimal.
-   *
-   * Example:
-   *
-   *  pwmclk    = 80 MHz
-   *  frequency = 100 Hz
-   *
-   *  presc     = 80,000,000 * 256 / 16,384 / 100
-   *            = 12,500
-   *  timclk    = 80,000,000 / (12,500 / 256)
-   *            = 1,638,400
-   *  counter   = 1,638,400 / 100
-   *            = 16,384
-   *            = 2^14
-   *  shift     = 14
-   */
-
-  /* Search the maximum value of timer reload value */
-
-  for (reload = LEDC_RELOAD_MAX , shift = LEDC_RELOAD_MAX_BIT_LEN;
-       reload > 1;
-       reload = (reload >> 1), shift -= 1)
-      {
-        if (reload * priv->frequency <= pwmclk)
-        {
-          break;
-        }
-  }
-
-  /* Calculate the prescaler */
-
-  prescaler = (float)pwmclk / priv->frequency / reload;
-
-  /* Get the integral part */
-
-  integral_prescaler = (uint32_t) prescaler;
-
-  /* Get the fractional part. To write to the registers, value need to be
-  * multiply by 256
-  */
-
-  fractional_prescaler = (uint32_t)((prescaler - integral_prescaler) * 256);
-
-  /* Prevent prescaler goto 0. In esp32 series, prescaler == 1 means
-  * clock signal goes pass-through
-  */
-
-  if (integral_prescaler == 0) integral_prescaler = 1;
-
-  pwminfo("PWM timer%" PRIu8 " frequency=%0.4f reload=%" PRIu32 " shift=%"
-          PRIu8 " prescaler=%0.4f\n",
-          priv->num, (float)pwmclk / reload / ((float)prescaler),
-          reload, shift, (float)prescaler);
-
-  /* Store reload for channel duty */
-
-  priv->reload = reload;
-
-  flags = enter_critical_section();
-
-  /* Set timer clock divide and reload */
-
-  regval = (shift << LEDC_TIMER0_DUTY_RES_S) |
-           (fractional_prescaler << LEDC_CLK_DIV_TIMER0_S) |
-           (integral_prescaler << LEDC_CLK_DIV_TIMER0_S << 8);
-  SET_TIMER_REG(priv, LEDC_TIMER0_CONF_REG, regval);
-
-  /* Update clock divide and reload to hardware */
-
-  SET_TIMER_BITS(priv, LEDC_TIMER0_CONF_REG, LEDC_TIMER0_PARA_UP);
-
-  leave_critical_section(flags);
-}
-
-/****************************************************************************
- * Name: setup_channel
- *
- * Description:
- *   Setup LEDC timer channel duty.
- *
- * Input Parameters:
- *   priv - A reference to the LEDC timer state structure
- *   cn   - Timer channel number
- *
- * Returned Value:
- *   None
- *
- ****************************************************************************/
-
-static void setup_channel(struct esp32s3_ledc_s *priv, int cn)
-{
-  irqstate_t flags;
-  uint32_t regval;
-  struct esp32s3_ledc_chan_s *chan = &priv->chans[cn];
-
-  /* Duty cycle:
-   *
-   * duty cycle = duty / 65536 * reload (fractional value)
-   */
-
-  regval = b16toi(chan->duty * priv->reload + b16HALF);
-
-  pwminfo("channel=%" PRIu8 " duty=%" PRIu16 "(%0.4f) regval=%" PRIu32
-          " reload=%" PRIu32 "\n",
-          chan->num, chan->duty, (float)chan->duty / UINT16_MAX,
-          regval, priv->reload);
-
-  flags = enter_critical_section();
-
-  /* Reset config 0 & 1 registers */
-
-  SET_CHAN_REG(chan, LEDC_CH0_CONF0_REG, 0);
-  SET_CHAN_REG(chan, LEDC_CH0_CONF1_REG, 0);
-
-  /* Select the clock source */
-
-  SET_CHAN_REG(chan, LEDC_CH0_CONF0_REG, priv->num);
-
-  /* Set pulse phase 0 */
-
-  SET_CHAN_REG(chan, LEDC_CH0_HPOINT_REG, 0);
-
-  /* Duty register uses bits [18:4]  */
-
-  SET_CHAN_REG(chan, LEDC_CH0_DUTY_REG, regval << 4);
-
-  /* Start GPIO output  */
-
-  SET_CHAN_BITS(chan, LEDC_CH0_CONF0_REG, LEDC_SIG_OUT_EN_CH0);
-
-  /* Start Duty counter  */
-
-  SET_CHAN_BITS(chan, LEDC_CH0_CONF1_REG, LEDC_DUTY_START_CH0);
-
-  /* Update duty and phase to hardware */
-
-  SET_CHAN_BITS(chan, LEDC_CH0_CONF0_REG, LEDC_PARA_UP_CH0);
-
-  leave_critical_section(flags);
-}
-
-/****************************************************************************
- * Name: pwm_setup
- *
- * Description:
- *   This method is called when the driver is opened.  The lower half driver
- *   should configure and initialize the device so that it is ready for use.
- *   It should not, however, output pulses until the start method is called.
- *
- * Input Parameters:
- *   dev - A reference to the lower half PWM driver state structure
- *
- * Returned Value:
- *   Zero on success; a negated errno value on failure
- *
- ****************************************************************************/
-
-static int pwm_setup(struct pwm_lowerhalf_s *dev)
-{
-  struct esp32s3_ledc_s *priv = (struct esp32s3_ledc_s *)dev;
-
-  pwminfo("PWM timer%u\n", priv->num);
-
-  ledc_enable_clk();
-
-  /* Setup channel GPIO pins */
-
-  for (int i = 0; i < priv->channels; i++)
-    {
-      pwminfo("channel%d --> pin%d\n", priv->chans[i].num,
-              priv->chans[i].pin);
-
-      esp32s3_configgpio(priv->chans[i].pin, OUTPUT | PULLUP);
-      esp32s3_gpio_matrix_out(priv->chans[i].pin,
-                              LEDC_LS_SIG_OUT0_IDX + priv->chans[i].num,
-                              0, 0);
-    }
-
-  return 0;
-}
-
-/****************************************************************************
- * Name: pwm_shutdown
- *
- * Description:
- *   This method is called when the driver is closed.  The lower half driver
- *   stop pulsed output, free any resources, disable the timer hardware, and
- *   put the system into the lowest possible power usage state
- *
- * Input Parameters:
- *   dev - A reference to the lower half PWM driver state structure
- *
- * Returned Value:
- *   Zero on success; a negated errno value on failure
- *
- ****************************************************************************/
-
-static int pwm_shutdown(struct pwm_lowerhalf_s *dev)
-{
-  struct esp32s3_ledc_s *priv = (struct esp32s3_ledc_s *)dev;
-#ifdef CONFIG_PWM_NCHANNELS
-  int channels = MIN(priv->channels, CONFIG_PWM_NCHANNELS);
-#else
-  int channels = 1;
-#endif
-
-  /* Stop timer */
-
-  pwm_stop(dev);
-
-  /* Clear timer and channel configuration */
-
-  priv->frequency = 0;
-  priv->reload    = 0;
-  for (int i = 0; i < channels; i++)
-    {
-      priv->chans[i].duty = 0;
-    }
-
-  ledc_disable_clk();
-
-  return 0;
-}
-
-/****************************************************************************
- * Name: pwm_start
- *
- * Description:
- *   (Re-)initialize the timer resources and start the pulsed output
- *
- * Input Parameters:
- *   dev  - A reference to the lower half PWM driver state structure
- *   info - A reference to the characteristics of the pulsed output
- *
- * Returned Value:
- *   Zero on success; a negated errno value on failure
- *
- ****************************************************************************/
-
-static int pwm_start(struct pwm_lowerhalf_s *dev,
-                     const struct pwm_info_s *info)
-{
-  struct esp32s3_ledc_s *priv = (struct esp32s3_ledc_s *)dev;
-#ifdef CONFIG_PWM_NCHANNELS
-  int channels = MIN(priv->channels, CONFIG_PWM_NCHANNELS);
-#else
-  int channels = 1;
-#endif
-
-  pwminfo("PWM timer%d\n", priv->num);
-
-  /* Update timer with given PWM timer frequency */
-
-  if (priv->frequency != info->frequency)
-    {
-      priv->frequency = info->frequency;
-      setup_timer(priv);
-    }
-
-  /* Update timer with given PWM channel duty */
-
-  for (int i = 0; i < channels; i++)
-    {
-#ifdef CONFIG_PWM_NCHANNELS
-      if (priv->chans[i].duty != info->channels[i].duty)
-#else
-      if (priv->chans[i].duty != info[i].duty)
-#endif
-        {
-#ifdef CONFIG_PWM_NCHANNELS
-          priv->chans[i].duty = info->channels[i].duty;
-#else
-          priv->chans[i].duty = info[i].duty;
-#endif
-          setup_channel(priv, i);
-        }
-    }
-
-  return 0;
-}
-
-/****************************************************************************
- * Name: pwm_stop
- *
- * Description:
- *   Stop the pulsed output and reset the timer resources.
- *
- * Input Parameters:
- *   dev - A reference to the lower half PWM driver state structure
- *
- * Returned Value:
- *   Zero on success; a negated errno value on failure
- *
- ****************************************************************************/
-
-static int pwm_stop(struct pwm_lowerhalf_s *dev)
-{
-  irqstate_t flags;
-  struct esp32s3_ledc_s *priv = (struct esp32s3_ledc_s *)dev;
-
-  pwminfo("PWM timer%d\n", priv->num);
-
-  flags = enter_critical_section();
-
-  /* Stop timer */
-
-  SET_TIMER_BITS(priv, LEDC_TIMER0_CONF_REG, LEDC_TIMER0_PAUSE);
-
-  /* Reset timer */
-
-  SET_TIMER_BITS(priv, LEDC_TIMER0_CONF_REG, LEDC_TIMER0_RST);
-
-  leave_critical_section(flags);
-  return 0;
-}
-
-/****************************************************************************
- * Name: pwm_ioctl
- *
- * Description:
- *   Lower-half logic may support platform-specific ioctl commands
- *
- * Input Parameters:
- *   dev - A reference to the lower half PWM driver state structure
- *   cmd - The ioctl command
- *   arg - The argument accompanying the ioctl command
- *
- * Returned Value:
- *   Zero on success; a negated errno value on failure
- *
- ****************************************************************************/
-
-static int pwm_ioctl(struct pwm_lowerhalf_s *dev, int cmd,
-                     unsigned long arg)
-{
-#ifdef CONFIG_DEBUG_PWM_INFO
-  struct esp32s3_ledc_s *priv = (struct esp32s3_ledc_s *)dev;
-
-  pwminfo("PWM timer%d\n", priv->num);
-#endif
-
-  return -ENOTTY;
-}
-
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: esp32s3_ledc_init
- *
- * Description:
- *   Initialize one LEDC timer for use with the upper_level PWM driver.
- *
- * Input Parameters:
- *   timer - A number identifying the timer use.
- *
- * Returned Value:
- *   On success, a pointer to the ESP32S3 LEDC lower half PWM driver is
- *   returned. NULL is returned on any failure.
- *
- ****************************************************************************/
-
-struct pwm_lowerhalf_s *esp32s3_ledc_init(int timer)
-{
-  struct esp32s3_ledc_s *lower = NULL;
-
-  pwminfo("TIM%u\n", timer);
-
-  switch (timer)
-    {
-#ifdef CONFIG_ESP32S3_LEDC_TIM0
-      case 0:
-        lower = &g_pwm0dev;
-        break;
-#endif
-
-#ifdef CONFIG_ESP32S3_LEDC_TIM1
-      case 1:
-        lower = &g_pwm1dev;
-        break;
-#endif
-
-#ifdef CONFIG_ESP32S3_LEDC_TIM2
-      case 2:
-        lower = &g_pwm2dev;
-        break;
-#endif
-
-#ifdef CONFIG_ESP32S3_LEDC_TIM3
-      case 3:
-        lower = &g_pwm3dev;
-        break;
-#endif
-
-      default:
-        pwmerr("ERROR: No such timer configured %d\n", timer);
-        lower = NULL;
-        break;
-    }
-
-  return (struct pwm_lowerhalf_s *)lower;
-}
diff --git a/arch/xtensa/src/esp32s3/esp32s3_ledc.h 
b/arch/xtensa/src/esp32s3/esp32s3_ledc.h
deleted file mode 100644
index f39d102603..0000000000
--- a/arch/xtensa/src/esp32s3/esp32s3_ledc.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/****************************************************************************
- * arch/xtensa/src/esp32s3/esp32s3_ledc.h
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.  The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- ****************************************************************************/
-
-#ifndef __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_LEDC_H
-#define __ARCH_XTENSA_SRC_ESP32S3_ESP32S3_LEDC_H
-
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-#include <nuttx/config.h>
-#include <nuttx/timers/pwm.h>
-
-/****************************************************************************
- * Public functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: esp32s3_ledc_init
- *
- * Description:
- *   Initialize one LEDC timer for use with the upper_level PWM driver.
- *
- * Input Parameters:
- *   timer - A number identifying the timer use.
- *
- * Returned Value:
- *   On success, a pointer to the ESP32S3-C3 LEDC lower half PWM driver is
- *   returned. NULL is returned on any failure.
- *
- ****************************************************************************/
-
-struct pwm_lowerhalf_s *esp32s3_ledc_init(int timer);
-
-#endif /* __ARCH_RISCV_SRC_ESP32S3_ESP32S3_LEDC_H */
diff --git a/boards/xtensa/esp32s2/esp32s2-saola-1/configs/pwm/defconfig 
b/boards/xtensa/esp32s2/esp32s2-saola-1/configs/pwm/defconfig
index bdb2e1e405..18028f92e7 100644
--- a/boards/xtensa/esp32s2/esp32s2-saola-1/configs/pwm/defconfig
+++ b/boards/xtensa/esp32s2/esp32s2-saola-1/configs/pwm/defconfig
@@ -19,12 +19,12 @@ CONFIG_ARCH_STACKDUMP=y
 CONFIG_ARCH_XTENSA=y
 CONFIG_BOARD_LOOPSPERMSEC=16717
 CONFIG_BUILTIN=y
-CONFIG_ESP32S2_LEDC=y
-CONFIG_ESP32S2_LEDC_TIM0=y
-CONFIG_ESP32S2_LEDC_TIM1=y
-CONFIG_ESP32S2_LEDC_TIM2=y
-CONFIG_ESP32S2_LEDC_TIM3=y
 CONFIG_ESP32S2_UART0=y
+CONFIG_ESPRESSIF_LEDC=y
+CONFIG_ESPRESSIF_LEDC_TIMER0=y
+CONFIG_ESPRESSIF_LEDC_TIMER1=y
+CONFIG_ESPRESSIF_LEDC_TIMER2=y
+CONFIG_ESPRESSIF_LEDC_TIMER3=y
 CONFIG_EXAMPLES_PWM=y
 CONFIG_FS_PROCFS=y
 CONFIG_HAVE_CXX=y
diff --git a/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2-saola-1.h 
b/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2-saola-1.h
index fac2a2ca18..e242ba00af 100644
--- a/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2-saola-1.h
+++ b/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2-saola-1.h
@@ -232,7 +232,7 @@ int esp32s2_cs4344_initialize(void);
  *
  ****************************************************************************/
 
-#ifdef CONFIG_ESP32S2_LEDC
+#ifdef CONFIG_ESPRESSIF_LEDC
 int esp32s2_pwm_setup(void);
 #endif
 
diff --git a/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_bringup.c 
b/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_bringup.c
index 03ec565d7c..f6cd43178a 100644
--- a/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_bringup.c
+++ b/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_bringup.c
@@ -66,8 +66,8 @@
 #  include "esp32s2_efuse.h"
 #endif
 
-#ifdef CONFIG_ESP32S2_LEDC
-#  include "esp32s2_ledc.h"
+#ifdef CONFIG_ESPRESSIF_LEDC
+#  include "espressif/esp_ledc.h"
 #endif
 
 #ifdef CONFIG_WATCHDOG
@@ -184,13 +184,13 @@ int esp32s2_bringup(void)
     }
 #endif
 
-#ifdef CONFIG_ESP32S2_LEDC
+#ifdef CONFIG_ESPRESSIF_LEDC
   ret = esp32s2_pwm_setup();
   if (ret < 0)
     {
       syslog(LOG_ERR, "ERROR: esp32s2_pwm_setup() failed: %d\n", ret);
     }
-#endif /* CONFIG_ESP32S2_LEDC */
+#endif /* CONFIG_ESPRESSIF_LEDC */
 
 #ifdef CONFIG_ESPRESSIF_SPIFLASH
   ret = board_spiflash_init();
diff --git a/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_ledc.c 
b/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_ledc.c
index 442eccc627..e74c06f82f 100644
--- a/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_ledc.c
+++ b/boards/xtensa/esp32s2/esp32s2-saola-1/src/esp32s2_ledc.c
@@ -35,7 +35,7 @@
 
 #include <arch/board/board.h>
 
-#include "esp32s2_ledc.h"
+#include "espressif/esp_ledc.h"
 
 /****************************************************************************
  * Pre-processor Definitions
@@ -58,8 +58,8 @@ int esp32s2_pwm_setup(void)
   int ret;
   struct pwm_lowerhalf_s *pwm;
 
-#ifdef CONFIG_ESP32S2_LEDC_TIM0
-  pwm = esp32s2_ledc_init(0);
+#if defined(CONFIG_ESP32S2_LEDC_TIM0) || defined(CONFIG_ESPRESSIF_LEDC_TIMER0)
+  pwm = esp_ledc_init(0);
   if (!pwm)
     {
       syslog(LOG_ERR, "ERROR: Failed to get the LEDC PWM 0 lower half\n");
@@ -76,8 +76,8 @@ int esp32s2_pwm_setup(void)
     }
 #endif
 
-#ifdef CONFIG_ESP32S2_LEDC_TIM1
-  pwm = esp32s2_ledc_init(1);
+#if defined(CONFIG_ESP32S2_LEDC_TIM1) || defined(CONFIG_ESPRESSIF_LEDC_TIMER1)
+  pwm = esp_ledc_init(1);
   if (!pwm)
     {
       syslog(LOG_ERR, "ERROR: Failed to get the LEDC PWM 1 lower half\n");
@@ -94,8 +94,8 @@ int esp32s2_pwm_setup(void)
     }
 #endif
 
-#ifdef CONFIG_ESP32S2_LEDC_TIM2
-  pwm = esp32s2_ledc_init(2);
+#if defined(CONFIG_ESP32S2_LEDC_TIM2) || defined(CONFIG_ESPRESSIF_LEDC_TIMER2)
+  pwm = esp_ledc_init(2);
   if (!pwm)
     {
       syslog(LOG_ERR, "ERROR: Failed to get the LEDC PWM 2 lower half\n");
@@ -112,8 +112,8 @@ int esp32s2_pwm_setup(void)
     }
 #endif
 
-#ifdef CONFIG_ESP32S2_LEDC_TIM3
-  pwm = esp32s2_ledc_init(3);
+#if defined(CONFIG_ESP32S2_LEDC_TIM3) || defined(CONFIG_ESPRESSIF_LEDC_TIMER3)
+  pwm = esp_ledc_init(3);
   if (!pwm)
     {
       syslog(LOG_ERR, "ERROR: Failed to get the LEDC PWM 3 lower half\n");
diff --git a/boards/xtensa/esp32s3/common/include/esp32s3_board_ledc.h 
b/boards/xtensa/esp32s3/common/include/esp32s3_board_ledc.h
index f5b514073e..8b3a3c36de 100644
--- a/boards/xtensa/esp32s3/common/include/esp32s3_board_ledc.h
+++ b/boards/xtensa/esp32s3/common/include/esp32s3_board_ledc.h
@@ -56,7 +56,7 @@ extern "C"
  *
  ****************************************************************************/
 
-#ifdef CONFIG_ESP32S3_LEDC
+#ifdef CONFIG_ESPRESSIF_LEDC
 int esp32s3_pwm_setup(void);
 #endif
 
diff --git a/boards/xtensa/esp32s3/common/src/Make.defs 
b/boards/xtensa/esp32s3/common/src/Make.defs
index 100c9a84a7..14eab861b3 100644
--- a/boards/xtensa/esp32s3/common/src/Make.defs
+++ b/boards/xtensa/esp32s3/common/src/Make.defs
@@ -98,7 +98,7 @@ ifeq ($(CONFIG_USBMSC),y)
   CSRCS += esp32s3_usbmsc.c
 endif
 
-ifeq ($(CONFIG_ESP32S3_LEDC),y)
+ifeq ($(CONFIG_ESPRESSIF_LEDC),y)
 CSRCS += esp32s3_board_ledc.c
 endif
 
diff --git a/boards/xtensa/esp32s3/common/src/esp32s3_board_ledc.c 
b/boards/xtensa/esp32s3/common/src/esp32s3_board_ledc.c
index bf3f469cfa..6c9dd6eebe 100644
--- a/boards/xtensa/esp32s3/common/src/esp32s3_board_ledc.c
+++ b/boards/xtensa/esp32s3/common/src/esp32s3_board_ledc.c
@@ -35,7 +35,7 @@
 
 #include <arch/board/board.h>
 
-#include "esp32s3_ledc.h"
+#include "espressif/esp_ledc.h"
 
 /****************************************************************************
  * Pre-processor Definitions
@@ -58,8 +58,8 @@ int esp32s3_pwm_setup(void)
   int ret;
   struct pwm_lowerhalf_s *pwm;
 
-#ifdef CONFIG_ESP32S3_LEDC_TIM0
-  pwm = esp32s3_ledc_init(0);
+#if defined(CONFIG_ESP32S3_LEDC_TIM0) || defined(CONFIG_ESPRESSIF_LEDC_TIMER0)
+  pwm = esp_ledc_init(0);
   if (!pwm)
     {
       syslog(LOG_ERR, "ERROR: Failed to get the LEDC PWM 0 lower half\n");
@@ -76,8 +76,8 @@ int esp32s3_pwm_setup(void)
     }
 #endif
 
-#ifdef CONFIG_ESP32S3_LEDC_TIM1
-  pwm = esp32s3_ledc_init(1);
+#if defined(CONFIG_ESP32S3_LEDC_TIM1) || defined(CONFIG_ESPRESSIF_LEDC_TIMER1)
+  pwm = esp_ledc_init(1);
   if (!pwm)
     {
       syslog(LOG_ERR, "ERROR: Failed to get the LEDC PWM 1 lower half\n");
@@ -94,8 +94,8 @@ int esp32s3_pwm_setup(void)
     }
 #endif
 
-#ifdef CONFIG_ESP32S3_LEDC_TIM2
-  pwm = esp32s3_ledc_init(2);
+#if defined(CONFIG_ESP32S3_LEDC_TIM2) || defined(CONFIG_ESPRESSIF_LEDC_TIMER2)
+  pwm = esp_ledc_init(2);
   if (!pwm)
     {
       syslog(LOG_ERR, "ERROR: Failed to get the LEDC PWM 2 lower half\n");
@@ -112,8 +112,8 @@ int esp32s3_pwm_setup(void)
     }
 #endif
 
-#ifdef CONFIG_ESP32S3_LEDC_TIM3
-  pwm = esp32s3_ledc_init(3);
+#if defined(CONFIG_ESP32S3_LEDC_TIM3) || defined(CONFIG_ESPRESSIF_LEDC_TIMER3)
+  pwm = esp_ledc_init(3);
   if (!pwm)
     {
       syslog(LOG_ERR, "ERROR: Failed to get the LEDC PWM 3 lower half\n");
diff --git a/boards/xtensa/esp32s3/esp32s3-devkit/configs/pwm/defconfig 
b/boards/xtensa/esp32s3/esp32s3-devkit/configs/pwm/defconfig
index 579224e214..d87be5396a 100644
--- a/boards/xtensa/esp32s3/esp32s3-devkit/configs/pwm/defconfig
+++ b/boards/xtensa/esp32s3/esp32s3-devkit/configs/pwm/defconfig
@@ -20,12 +20,12 @@ CONFIG_ARCH_STACKDUMP=y
 CONFIG_ARCH_XTENSA=y
 CONFIG_BOARD_LOOPSPERMSEC=16717
 CONFIG_BUILTIN=y
-CONFIG_ESP32S3_LEDC=y
-CONFIG_ESP32S3_LEDC_TIM0=y
-CONFIG_ESP32S3_LEDC_TIM1=y
-CONFIG_ESP32S3_LEDC_TIM2=y
-CONFIG_ESP32S3_LEDC_TIM3=y
 CONFIG_ESP32S3_UART0=y
+CONFIG_ESPRESSIF_LEDC=y
+CONFIG_ESPRESSIF_LEDC_TIMER0=y
+CONFIG_ESPRESSIF_LEDC_TIMER1=y
+CONFIG_ESPRESSIF_LEDC_TIMER2=y
+CONFIG_ESPRESSIF_LEDC_TIMER3=y
 CONFIG_EXAMPLES_PWM=y
 CONFIG_EXAMPLES_PWM_CHANNEL1=0
 CONFIG_EXAMPLES_PWM_CHANNEL2=1
diff --git a/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_bringup.c 
b/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_bringup.c
index d254bde29f..2e5021f39c 100644
--- a/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_bringup.c
+++ b/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_bringup.c
@@ -92,7 +92,7 @@
 #  include "esp32s3_efuse.h"
 #endif
 
-#ifdef CONFIG_ESP32S3_LEDC
+#ifdef CONFIG_ESPRESSIF_LEDC
 #  include "esp32s3_board_ledc.h"
 #endif
 
@@ -238,13 +238,13 @@ int esp32s3_bringup(void)
     }
 #endif
 
-#ifdef CONFIG_ESP32S3_LEDC
+#ifdef CONFIG_ESPRESSIF_LEDC
   ret = esp32s3_pwm_setup();
   if (ret < 0)
     {
       syslog(LOG_ERR, "ERROR: esp32s3_pwm_setup() failed: %d\n", ret);
     }
-#endif /* CONFIG_ESP32S3_LEDC */
+#endif /* CONFIG_ESPRESSIF_LEDC */
 
 #ifdef CONFIG_ESP32S3_TIMER
   /* Configure general purpose timers */
diff --git a/boards/xtensa/esp32s3/esp32s3-korvo-2/src/esp32s3_bringup.c 
b/boards/xtensa/esp32s3/esp32s3-korvo-2/src/esp32s3_bringup.c
index d56ae1f468..d1fb021736 100644
--- a/boards/xtensa/esp32s3/esp32s3-korvo-2/src/esp32s3_bringup.c
+++ b/boards/xtensa/esp32s3/esp32s3-korvo-2/src/esp32s3_bringup.c
@@ -85,7 +85,7 @@
 #  include "esp32s3_efuse.h"
 #endif
 
-#ifdef CONFIG_ESP32S3_LEDC
+#ifdef CONFIG_ESPRESSIF_LEDC
 #  include "esp32s3_board_ledc.h"
 #endif
 
@@ -203,13 +203,13 @@ int esp32s3_bringup(void)
     }
 #endif
 
-#ifdef CONFIG_ESP32S3_LEDC
+#ifdef CONFIG_ESPRESSIF_LEDC
   ret = esp32s3_pwm_setup();
   if (ret < 0)
     {
       syslog(LOG_ERR, "ERROR: esp32s3_pwm_setup() failed: %d\n", ret);
     }
-#endif /* CONFIG_ESP32S3_LEDC */
+#endif /* CONFIG_ESPRESSIF_LEDC */
 
 #ifdef CONFIG_ESP32S3_TIMER
   /* Configure general purpose timers */
diff --git a/boards/xtensa/esp32s3/lckfb-szpi-esp32s3/configs/lcd/defconfig 
b/boards/xtensa/esp32s3/lckfb-szpi-esp32s3/configs/lcd/defconfig
index 3bb5b45851..dbf50c4259 100644
--- a/boards/xtensa/esp32s3/lckfb-szpi-esp32s3/configs/lcd/defconfig
+++ b/boards/xtensa/esp32s3/lckfb-szpi-esp32s3/configs/lcd/defconfig
@@ -31,10 +31,6 @@ CONFIG_DEV_GPIO=y
 CONFIG_DRIVERS_VIDEO=y
 CONFIG_ESP32S3_GPIO_IRQ=y
 CONFIG_ESP32S3_I2C0=y
-CONFIG_ESP32S3_LEDC=y
-CONFIG_ESP32S3_LEDC_CHANNEL0_PIN=42
-CONFIG_ESP32S3_LEDC_TIM0=y
-CONFIG_ESP32S3_LEDC_TIM0_CHANNELS=1
 CONFIG_ESP32S3_SPI2=y
 CONFIG_ESP32S3_SPI2_CLKPIN=41
 CONFIG_ESP32S3_SPI2_CSPIN=-1
@@ -43,6 +39,9 @@ CONFIG_ESP32S3_SPI2_MOSIPIN=40
 CONFIG_ESP32S3_SPI_SWCS=y
 CONFIG_ESP32S3_SPI_UDCS=y
 CONFIG_ESP32S3_UART0=y
+CONFIG_ESPRESSIF_LEDC=y
+CONFIG_ESPRESSIF_LEDC_CHANNEL0_PIN=42
+CONFIG_ESPRESSIF_LEDC_TIMER0=y
 CONFIG_EXAMPLES_FB=y
 CONFIG_EXAMPLES_PWM=y
 CONFIG_FS_PROCFS=y
diff --git a/boards/xtensa/esp32s3/lckfb-szpi-esp32s3/configs/lvgl/defconfig 
b/boards/xtensa/esp32s3/lckfb-szpi-esp32s3/configs/lvgl/defconfig
index a823218382..277806a3b6 100644
--- a/boards/xtensa/esp32s3/lckfb-szpi-esp32s3/configs/lvgl/defconfig
+++ b/boards/xtensa/esp32s3/lckfb-szpi-esp32s3/configs/lvgl/defconfig
@@ -35,10 +35,6 @@ CONFIG_DEV_GPIO=y
 CONFIG_DRIVERS_VIDEO=y
 CONFIG_ESP32S3_GPIO_IRQ=y
 CONFIG_ESP32S3_I2C0=y
-CONFIG_ESP32S3_LEDC=y
-CONFIG_ESP32S3_LEDC_CHANNEL0_PIN=42
-CONFIG_ESP32S3_LEDC_TIM0=y
-CONFIG_ESP32S3_LEDC_TIM0_CHANNELS=1
 CONFIG_ESP32S3_SPI2=y
 CONFIG_ESP32S3_SPI2_CLKPIN=41
 CONFIG_ESP32S3_SPI2_CSPIN=-1
@@ -50,6 +46,9 @@ CONFIG_ESP32S3_SPIRAM_MODE_OCT=y
 CONFIG_ESP32S3_SPI_SWCS=y
 CONFIG_ESP32S3_SPI_UDCS=y
 CONFIG_ESP32S3_UART0=y
+CONFIG_ESPRESSIF_LEDC=y
+CONFIG_ESPRESSIF_LEDC_CHANNEL0_PIN=42
+CONFIG_ESPRESSIF_LEDC_TIMER0=y
 CONFIG_EXAMPLES_FB=y
 CONFIG_EXAMPLES_LVGLDEMO=y
 CONFIG_EXAMPLES_PWM=y
diff --git a/boards/xtensa/esp32s3/lckfb-szpi-esp32s3/configs/pwm/defconfig 
b/boards/xtensa/esp32s3/lckfb-szpi-esp32s3/configs/pwm/defconfig
index ed5d8b60c7..7f35a8fa26 100644
--- a/boards/xtensa/esp32s3/lckfb-szpi-esp32s3/configs/pwm/defconfig
+++ b/boards/xtensa/esp32s3/lckfb-szpi-esp32s3/configs/pwm/defconfig
@@ -22,11 +22,10 @@ CONFIG_BOARD_LOOPSPERMSEC=16717
 CONFIG_BUILTIN=y
 CONFIG_DEBUG_FULLOPT=y
 CONFIG_DEBUG_SYMBOLS=y
-CONFIG_ESP32S3_LEDC=y
-CONFIG_ESP32S3_LEDC_CHANNEL0_PIN=42
-CONFIG_ESP32S3_LEDC_TIM0=y
-CONFIG_ESP32S3_LEDC_TIM0_CHANNELS=1
 CONFIG_ESP32S3_UART0=y
+CONFIG_ESPRESSIF_LEDC=y
+CONFIG_ESPRESSIF_LEDC_CHANNEL0_PIN=42
+CONFIG_ESPRESSIF_LEDC_TIMER0=y
 CONFIG_EXAMPLES_PWM=y
 CONFIG_FS_PROCFS=y
 CONFIG_HAVE_CXX=y
diff --git a/boards/xtensa/esp32s3/lckfb-szpi-esp32s3/src/esp32s3_bringup.c 
b/boards/xtensa/esp32s3/lckfb-szpi-esp32s3/src/esp32s3_bringup.c
index 9be06f7f71..52eb07d853 100644
--- a/boards/xtensa/esp32s3/lckfb-szpi-esp32s3/src/esp32s3_bringup.c
+++ b/boards/xtensa/esp32s3/lckfb-szpi-esp32s3/src/esp32s3_bringup.c
@@ -85,7 +85,7 @@
 #  include "esp32s3_efuse.h"
 #endif
 
-#ifdef CONFIG_ESP32S3_LEDC
+#ifdef CONFIG_ESPRESSIF_LEDC
 #  include "esp32s3_board_ledc.h"
 #endif
 
@@ -223,7 +223,7 @@ int esp32s3_bringup(void)
     }
 #endif
 
-#ifdef CONFIG_ESP32S3_LEDC
+#ifdef CONFIG_ESPRESSIF_LEDC
   ret = esp32s3_pwm_setup();
   if (ret < 0)
     {

Reply via email to