From 38c4f27102c240a66978cc4230ece8c799803ce2 Mon Sep 17 00:00:00 2001 From: morris Date: Thu, 14 May 2026 15:48:48 +0800 Subject: [PATCH] fix(iomux): move clock source gating to IOMUX consumers Remove io_mux_set_clock_source internal source enabling and make SDM, ana_cmpr, and gpio glitch filter drivers explicitly manage clock source enable/disable with safe cleanup paths. --- components/esp_driver_ana_cmpr/ana_cmpr.c | 32 ++- .../esp_driver_ana_cmpr/ana_cmpr_private.h | 2 + .../esp_private => src}/glitch_filter_priv.h | 3 + .../src/gpio_flex_glitch_filter.c | 46 ++-- .../src/gpio_glitch_filter_ops.c | 6 +- .../src/gpio_pin_glitch_filter.c | 28 +- components/esp_driver_sdm/src/sdm.c | 248 +++++++++++------- .../esp32c5/include/hal/gpio_ll.h | 2 + .../esp32c6/include/hal/gpio_ll.h | 2 + .../esp32c61/include/hal/gpio_ll.h | 2 + .../esp32h2/include/hal/gpio_ll.h | 2 + .../esp32h21/include/hal/gpio_ll.h | 2 + .../esp32h4/include/hal/gpio_ll.h | 2 + .../esp32p4/include/hal/gpio_ll.h | 2 + .../esp32s31/include/hal/gpio_ll.h | 2 + components/esp_hw_support/CMakeLists.txt | 1 + .../include/esp_private/io_mux.h | 21 +- components/esp_hw_support/io_mux.c | 90 +++++++ components/esp_hw_support/port/esp32/io_mux.c | 6 - .../esp_hw_support/port/esp32c2/io_mux.c | 6 - .../esp_hw_support/port/esp32c3/io_mux.c | 6 - .../esp_hw_support/port/esp32c5/io_mux.c | 25 -- .../esp_hw_support/port/esp32c6/io_mux.c | 23 -- .../esp_hw_support/port/esp32c61/io_mux.c | 23 -- .../esp_hw_support/port/esp32h2/io_mux.c | 23 -- .../esp_hw_support/port/esp32h21/io_mux.c | 23 -- .../esp_hw_support/port/esp32h4/io_mux.c | 23 -- .../esp_hw_support/port/esp32p4/io_mux.c | 27 -- .../esp_hw_support/port/esp32s2/io_mux.c | 6 - .../esp_hw_support/port/esp32s3/io_mux.c | 6 - .../esp_hw_support/port/esp32s31/io_mux.c | 27 -- 31 files changed, 362 insertions(+), 355 deletions(-) rename components/esp_driver_gpio/{include/esp_private => src}/glitch_filter_priv.h (94%) create mode 100644 components/esp_hw_support/io_mux.c diff --git a/components/esp_driver_ana_cmpr/ana_cmpr.c b/components/esp_driver_ana_cmpr/ana_cmpr.c index 6e55ace968b..ad46ac62d95 100644 --- a/components/esp_driver_ana_cmpr/ana_cmpr.c +++ b/components/esp_driver_ana_cmpr/ana_cmpr.c @@ -13,6 +13,7 @@ #include "esp_private/gpio.h" #include "esp_private/io_mux.h" #include "esp_private/esp_clk.h" +#include "esp_private/esp_clk_tree_common.h" #include "ana_cmpr_private.h" /* Global static object of the Analog Comparator unit */ @@ -133,12 +134,22 @@ static void ana_cmpr_destroy_unit(ana_cmpr_handle_t cmpr) if (cmpr->intr_handle) { esp_intr_free(cmpr->intr_handle); } - free(cmpr); - // Disable function clock first analog_cmpr_ll_enable_function_clock(unit_id, false); // Disable bus clock last analog_cmpr_ll_enable_bus_clock(unit_id, false); + // Disable the clock source if it is enabled by this driver +#if ANALOG_CMPR_LL_GET(IP_VERSION) <= 1 + if (cmpr->io_mux_acquired) { + io_mux_release_clock_source(cmpr->clk_src); + cmpr->io_mux_acquired = false; + } +#endif + if (cmpr->clk_src != SOC_MOD_CLK_INVALID) { + esp_clk_tree_enable_src(cmpr->clk_src, false); + } + + free(cmpr); } #if ANALOG_CMPR_LL_GET(IP_VERSION) > 1 @@ -301,6 +312,8 @@ esp_err_t ana_cmpr_new_unit(const ana_cmpr_config_t *config, ana_cmpr_handle_t * // analog comparator unit must be allocated from internal memory because it contains atomic variable ana_cmpr_hdl = heap_caps_calloc(1, sizeof(struct ana_cmpr_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); ESP_GOTO_ON_FALSE(ana_cmpr_hdl, ESP_ERR_NO_MEM, err, TAG, "no memory for analog comparator object"); + ana_cmpr_hdl->clk_src = SOC_MOD_CLK_INVALID; + ana_cmpr_hdl->io_mux_acquired = false; /* Assign analog comparator unit */ ana_cmpr_hdl->dev = ANALOG_CMPR_LL_GET_HW(unit_id); @@ -316,18 +329,27 @@ esp_err_t ana_cmpr_new_unit(const ana_cmpr_config_t *config, ana_cmpr_handle_t * analog_cmpr_ll_reset_core(unit_id); // Set clock source (use default if not specified in config) - ana_cmpr_clk_src_t clk_src = config->clk_src ? config->clk_src : ANA_CMPR_CLK_SRC_DEFAULT; + soc_module_clk_t clk_src = config->clk_src ? config->clk_src : ANA_CMPR_CLK_SRC_DEFAULT; + ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src(clk_src, true), err, TAG, "enable clock source failed"); #if ANALOG_CMPR_LL_GET(IP_VERSION) > 1 analog_cmpr_ll_set_clk_src(unit_id, clk_src); // Set clock divider to 1 analog_cmpr_ll_set_clk_div(unit_id, 1); // Enable function clock analog_cmpr_ll_enable_function_clock(unit_id, true); + ana_cmpr_hdl->clk_src = clk_src; #else // Analog comparator located in the IO MUX module in older chips, so the clock source is shared with IO MUX. - ESP_GOTO_ON_ERROR(io_mux_set_clock_source((soc_module_clk_t)clk_src), err, TAG, "clock source conflicts with other IOMUX consumers"); + ret = io_mux_acquire_clock_source(clk_src); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "clock source conflicts with other IOMUX consumers"); + esp_clk_tree_enable_src(clk_src, false); + goto err; + } + ana_cmpr_hdl->io_mux_acquired = true; + ana_cmpr_hdl->clk_src = clk_src; #endif - ESP_GOTO_ON_ERROR(esp_clk_tree_src_get_freq_hz((soc_module_clk_t)clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &ana_cmpr_hdl->src_clk_freq_hz), + ESP_GOTO_ON_ERROR(esp_clk_tree_src_get_freq_hz(clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &ana_cmpr_hdl->src_clk_freq_hz), err, TAG, "get source clock frequency failed"); // init the default source and reference channels according to the config diff --git a/components/esp_driver_ana_cmpr/ana_cmpr_private.h b/components/esp_driver_ana_cmpr/ana_cmpr_private.h index 103eed46209..3bb6df7d7d7 100644 --- a/components/esp_driver_ana_cmpr/ana_cmpr_private.h +++ b/components/esp_driver_ana_cmpr/ana_cmpr_private.h @@ -103,6 +103,8 @@ struct ana_cmpr_t { intr_handle_t intr_handle; // Interrupt handle uint32_t intr_mask; // Interrupt mask int intr_priority; // Interrupt priority + soc_module_clk_t clk_src; // Clock source of the Analog Comparator unit + bool io_mux_acquired; // Whether IO MUX clock source was acquired (IP v1 only) uint32_t src_clk_freq_hz; // Source clock frequency of the Analog Comparator unit ana_cmpr_src_chan_t src_chans[ANALOG_CMPR_LL_GET(SRC_CHANNEL_NUM)]; // The source channel objects in the unit ana_cmpr_ref_chan_t ref_chan; // The reference channel object in the unit diff --git a/components/esp_driver_gpio/include/esp_private/glitch_filter_priv.h b/components/esp_driver_gpio/src/glitch_filter_priv.h similarity index 94% rename from components/esp_driver_gpio/include/esp_private/glitch_filter_priv.h rename to components/esp_driver_gpio/src/glitch_filter_priv.h index e9d14bb871c..caa7fac7ab8 100644 --- a/components/esp_driver_gpio/include/esp_private/glitch_filter_priv.h +++ b/components/esp_driver_gpio/src/glitch_filter_priv.h @@ -15,6 +15,9 @@ #define GLITCH_FILTER_PM_LOCK_NAME_LEN_MAX 16 +///!< Logging settings +#define TAG "gpio-filter" + #ifdef __cplusplus extern "C" { #endif diff --git a/components/esp_driver_gpio/src/gpio_flex_glitch_filter.c b/components/esp_driver_gpio/src/gpio_flex_glitch_filter.c index a97134172a1..e8739b2d984 100644 --- a/components/esp_driver_gpio/src/gpio_flex_glitch_filter.c +++ b/components/esp_driver_gpio/src/gpio_flex_glitch_filter.c @@ -5,16 +5,16 @@ */ #include +#include #include "freertos/FreeRTOS.h" #include "esp_check.h" -#include "esp_private/glitch_filter_priv.h" +#include "glitch_filter_priv.h" #include "esp_private/io_mux.h" #include "soc/soc_caps.h" #include "hal/gpio_glitch_filter_ll.h" #include "esp_pm.h" #include "esp_clk_tree.h" - -static const char *TAG = "gpio-filter"; +#include "esp_private/esp_clk_tree_common.h" typedef struct gpio_flex_glitch_filter_t gpio_flex_glitch_filter_t; @@ -28,6 +28,8 @@ struct gpio_flex_glitch_filter_t { gpio_glitch_filter_t base; gpio_flex_glitch_filter_group_t *group; uint32_t filter_id; + soc_module_clk_t clk_src; + bool io_mux_clk_acquired; #if CONFIG_PM_ENABLE esp_pm_lock_handle_t pm_lock; char pm_lock_name[GLITCH_FILTER_PM_LOCK_NAME_LEN_MAX]; // pm lock name @@ -62,11 +64,10 @@ static esp_err_t gpio_filter_register_to_group(gpio_flex_glitch_filter_t *filter static esp_err_t gpio_filter_destroy(gpio_flex_glitch_filter_t *filter) { - gpio_flex_glitch_filter_group_t *group = &s_gpio_glitch_filter_group; + gpio_flex_glitch_filter_group_t *group = filter->group; int filter_id = filter->filter_id; - // unregister the filter from the group - if (filter->group) { + if (group) { portENTER_CRITICAL(&group->spinlock); group->filters[filter_id] = NULL; portEXIT_CRITICAL(&group->spinlock); @@ -78,6 +79,13 @@ static esp_err_t gpio_filter_destroy(gpio_flex_glitch_filter_t *filter) } #endif + if (filter->io_mux_clk_acquired) { + io_mux_release_clock_source(filter->clk_src); + } + if (filter->clk_src != SOC_MOD_CLK_INVALID) { + esp_clk_tree_enable_src(filter->clk_src, false); + } + free(filter); return ESP_OK; } @@ -101,8 +109,7 @@ static esp_err_t gpio_flex_glitch_filter_enable(gpio_glitch_filter_t *filter) } #endif - int filter_id = flex_filter->filter_id; - gpio_ll_glitch_filter_enable(s_gpio_glitch_filter_group.hw, filter_id, true); + gpio_ll_glitch_filter_enable(s_gpio_glitch_filter_group.hw, flex_filter->filter_id, true); filter->fsm = GLITCH_FILTER_FSM_ENABLE; return ESP_OK; } @@ -112,8 +119,7 @@ static esp_err_t gpio_flex_glitch_filter_disable(gpio_glitch_filter_t *filter) ESP_RETURN_ON_FALSE(filter->fsm == GLITCH_FILTER_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "filter not in enable state"); gpio_flex_glitch_filter_t *flex_filter = __containerof(filter, gpio_flex_glitch_filter_t, base); - int filter_id = flex_filter->filter_id; - gpio_ll_glitch_filter_enable(s_gpio_glitch_filter_group.hw, filter_id, false); + gpio_ll_glitch_filter_enable(s_gpio_glitch_filter_group.hw, flex_filter->filter_id, false); #if CONFIG_PM_ENABLE // release pm lock @@ -130,20 +136,27 @@ esp_err_t gpio_new_flex_glitch_filter(const gpio_flex_glitch_filter_config_t *co { esp_err_t ret = ESP_OK; gpio_flex_glitch_filter_t *filter = NULL; - ESP_GOTO_ON_FALSE(config && ret_filter, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); - ESP_GOTO_ON_FALSE(GPIO_IS_VALID_GPIO(config->gpio_num), ESP_ERR_INVALID_ARG, err, TAG, "invalid gpio number"); + ESP_RETURN_ON_FALSE(config && ret_filter, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + ESP_RETURN_ON_FALSE(GPIO_IS_VALID_GPIO(config->gpio_num), ESP_ERR_INVALID_ARG, TAG, "invalid gpio number"); // allocate driver object filter = heap_caps_calloc(1, sizeof(gpio_flex_glitch_filter_t), FILTER_MEM_ALLOC_CAPS); - ESP_GOTO_ON_FALSE(filter, ESP_ERR_NO_MEM, err, TAG, "no memory for flex glitch filter"); + ESP_RETURN_ON_FALSE(filter, ESP_ERR_NO_MEM, TAG, "no memory for flex glitch filter"); + filter->clk_src = SOC_MOD_CLK_INVALID; // default to invalid, will be set later + filter->io_mux_clk_acquired = false; // register the filter to the group ESP_GOTO_ON_ERROR(gpio_filter_register_to_group(filter), err, TAG, "register filter to group failed"); int filter_id = filter->filter_id; - // set clock source + soc_module_clk_t clk_src = config->clk_src ? config->clk_src : GLITCH_FILTER_CLK_SRC_DEFAULT; + ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src(clk_src, true), err, TAG, "enable IOMUX clock source failed"); + filter->clk_src = clk_src; + ESP_GOTO_ON_ERROR(io_mux_acquire_clock_source(clk_src), err, TAG, "acquire IOMUX clock source failed"); + filter->io_mux_clk_acquired = true; + uint32_t clk_freq_hz = 0; - ESP_GOTO_ON_ERROR(esp_clk_tree_src_get_freq_hz((soc_module_clk_t)config->clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_freq_hz), + ESP_GOTO_ON_ERROR(esp_clk_tree_src_get_freq_hz(clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_freq_hz), err, TAG, "get clock source frequency failed"); // create pm_lock according to different clock source @@ -159,9 +172,6 @@ esp_err_t gpio_new_flex_glitch_filter(const gpio_flex_glitch_filter_config_t *co ESP_GOTO_ON_FALSE(window_thres_ticks && window_thres_ticks <= window_width_ticks && window_width_ticks <= GPIO_LL_GLITCH_FILTER_MAX_WINDOW, ESP_ERR_INVALID_ARG, err, TAG, "invalid or out of range window width/threshold"); - // Glitch filter's clock source is same to the IOMUX clock - ESP_GOTO_ON_ERROR(io_mux_set_clock_source((soc_module_clk_t)(config->clk_src)), err, TAG, "set IO MUX clock source failed"); - // make sure the filter is disabled gpio_ll_glitch_filter_enable(s_gpio_glitch_filter_group.hw, filter_id, false); // apply the filter to the GPIO diff --git a/components/esp_driver_gpio/src/gpio_glitch_filter_ops.c b/components/esp_driver_gpio/src/gpio_glitch_filter_ops.c index 001968575d4..21c0d2ca012 100644 --- a/components/esp_driver_gpio/src/gpio_glitch_filter_ops.c +++ b/components/esp_driver_gpio/src/gpio_glitch_filter_ops.c @@ -1,13 +1,11 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include "esp_check.h" -#include "esp_private/glitch_filter_priv.h" - -static const char *TAG = "gpio-filter"; +#include "glitch_filter_priv.h" /////////// Public abstract functions /////////// diff --git a/components/esp_driver_gpio/src/gpio_pin_glitch_filter.c b/components/esp_driver_gpio/src/gpio_pin_glitch_filter.c index 39e3c912956..16686bb7f8b 100644 --- a/components/esp_driver_gpio/src/gpio_pin_glitch_filter.c +++ b/components/esp_driver_gpio/src/gpio_pin_glitch_filter.c @@ -5,22 +5,24 @@ */ #include +#include #include "freertos/FreeRTOS.h" #include "esp_check.h" #include "esp_pm.h" -#include "esp_private/glitch_filter_priv.h" +#include "glitch_filter_priv.h" #include "hal/gpio_ll.h" #include "esp_clk_tree.h" +#include "esp_private/esp_clk_tree_common.h" #include "esp_private/io_mux.h" #include "hal/gpio_caps.h" -static const char *TAG = "gpio-filter"; - /** * @brief Type of GPIO pin glitch filter */ typedef struct gpio_pin_glitch_filter_t { gpio_glitch_filter_t base; + soc_module_clk_t clk_src; + bool io_mux_clk_acquired; #if CONFIG_PM_ENABLE esp_pm_lock_handle_t pm_lock; char pm_lock_name[GLITCH_FILTER_PM_LOCK_NAME_LEN_MAX]; // pm lock name @@ -29,6 +31,13 @@ typedef struct gpio_pin_glitch_filter_t { static esp_err_t gpio_filter_destroy(gpio_pin_glitch_filter_t *filter) { + if (filter->io_mux_clk_acquired) { + io_mux_release_clock_source(filter->clk_src); + } + if (filter->clk_src != SOC_MOD_CLK_INVALID) { + esp_clk_tree_enable_src(filter->clk_src, false); + } + #if CONFIG_PM_ENABLE if (filter->pm_lock) { esp_pm_lock_delete(filter->pm_lock); @@ -90,12 +99,20 @@ esp_err_t gpio_new_pin_glitch_filter(const gpio_pin_glitch_filter_config_t *conf filter = heap_caps_calloc(1, sizeof(gpio_pin_glitch_filter_t), FILTER_MEM_ALLOC_CAPS); ESP_GOTO_ON_FALSE(filter, ESP_ERR_NO_MEM, err, TAG, "no memory for pin glitch filter"); + filter->clk_src = SOC_MOD_CLK_INVALID; + filter->io_mux_clk_acquired = false; + + soc_module_clk_t clk_src = config->clk_src ? config->clk_src : GLITCH_FILTER_CLK_SRC_DEFAULT; + ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src(clk_src, true), err, TAG, "enable IOMUX clock source failed"); + filter->clk_src = clk_src; + ESP_GOTO_ON_ERROR(io_mux_acquire_clock_source(clk_src), err, TAG, "acquire IOMUX clock source failed"); + filter->io_mux_clk_acquired = true; // create pm lock according to different clock source #if CONFIG_PM_ENABLE esp_pm_lock_type_t lock_type = ESP_PM_NO_LIGHT_SLEEP; #if GPIO_CAPS_GET(FILTER_CLK_SUPPORT_APB) - if (config->clk_src == GLITCH_FILTER_CLK_SRC_APB) { + if (clk_src == (soc_module_clk_t)GLITCH_FILTER_CLK_SRC_APB) { lock_type = ESP_PM_APB_FREQ_MAX; } #endif // GPIO_CAPS_GET(FILTER_CLK_SUPPORT_APB) @@ -104,9 +121,6 @@ esp_err_t gpio_new_pin_glitch_filter(const gpio_pin_glitch_filter_config_t *conf err, TAG, "create pm_lock failed"); #endif // CONFIG_PM_ENABLE - // Glitch filter's clock source is same to the IOMUX clock - ESP_GOTO_ON_ERROR(io_mux_set_clock_source((soc_module_clk_t)(config->clk_src)), err, TAG, "set IO MUX clock source failed"); - filter->base.gpio_num = config->gpio_num; filter->base.fsm = GLITCH_FILTER_FSM_INIT; filter->base.del = gpio_pin_glitch_filter_del; diff --git a/components/esp_driver_sdm/src/sdm.c b/components/esp_driver_sdm/src/sdm.c index b01bc3fda84..6eee4030a5b 100644 --- a/components/esp_driver_sdm/src/sdm.c +++ b/components/esp_driver_sdm/src/sdm.c @@ -5,6 +5,7 @@ */ #include +#include #include #include #include "sdkconfig.h" @@ -29,6 +30,7 @@ #include "hal/sdm_ll.h" #include "hal/hal_utils.h" #include "esp_private/esp_clk.h" +#include "esp_private/esp_clk_tree_common.h" #include "esp_private/io_mux.h" #include "esp_private/gpio.h" #include "esp_private/sleep_retention.h" @@ -60,7 +62,9 @@ struct sdm_group_t { portMUX_TYPE spinlock; // to protect per-group register level concurrent access sdm_hal_context_t hal; // hal context sdm_channel_t *channels[SDM_CAPS_GET(CHANS_PER_INST)]; // array of sdm channels - sdm_clock_source_t clk_src; // Clock source + soc_module_clk_t clk_src; // Clock source + bool io_mux_clk_acquired; + uint32_t src_clk_hz; // Source clock frequency in Hz #if CONFIG_PM_ENABLE esp_pm_lock_handle_t pm_lock; // PM lock, to prevent the system going into light sleep when SDM is running #endif @@ -113,107 +117,158 @@ static void sdm_create_retention_module(sdm_group_t *group) } #endif // SDM_USE_RETENTION_LINK -static sdm_group_t *sdm_acquire_group_handle(int group_id, sdm_clock_source_t clk_src) +static sdm_group_t *sdm_group_acquire(int group_id) { - bool new_group = false; sdm_group_t *group = NULL; - // prevent install sdm group concurrently _lock_acquire(&s_platform.mutex); if (!s_platform.groups[group_id]) { group = heap_caps_calloc(1, sizeof(sdm_group_t), SDM_MEM_ALLOC_CAPS); - if (group) { - new_group = true; - s_platform.groups[group_id] = group; // register to platform - // initialize sdm group members - group->group_id = group_id; - group->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; - group->clk_src = clk_src; - -#if SDM_USE_RETENTION_LINK - sleep_retention_module_t module = soc_sdm_retention_infos[group_id].module; - sleep_retention_module_init_param_t init_param = { - .cbs = { - .create = { - .handle = sdm_create_sleep_retention_link_cb, - .arg = group, - }, - }, - .attribute = SLEEP_RETENTION_MODULE_ATTR_ATTACH, - .depends = RETENTION_MODULE_BITMAP_INIT(CLOCK_SYSTEM) - }; - // retention module init must be called BEFORE the hal init - if (sleep_retention_module_init(module, &init_param) != ESP_OK) { - ESP_LOGW(TAG, "init sleep retention failed on SDM Group%d, power domain may be turned off during sleep", group_id); - } -#endif // SDM_USE_RETENTION_LINK - - // [IDF-12975]: enable APB register clock explicitly - // initialize HAL context - sdm_hal_init_config_t hal_config = { - .group_id = group_id, - }; - sdm_hal_init(&group->hal, &hal_config); + if (!group) { + _lock_release(&s_platform.mutex); + return NULL; } + s_platform.groups[group_id] = group; + group->group_id = group_id; + group->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; + group->clk_src = SOC_MOD_CLK_INVALID; } else { group = s_platform.groups[group_id]; } - if (group) { - // someone acquired the group handle means we have a new object that refer to this group - s_platform.group_ref_counts[group_id]++; - } + s_platform.group_ref_counts[group_id]++; _lock_release(&s_platform.mutex); - if (new_group) { - ESP_LOGD(TAG, "new group (%d) at %p", group_id, group); -#if CONFIG_PM_ENABLE - esp_pm_lock_type_t pm_type = ESP_PM_NO_LIGHT_SLEEP; -#if SDM_CAPS_GET(FUNC_CLOCK_SUPPORT_APB) - if (clk_src == SDM_CLK_SRC_APB) { - pm_type = ESP_PM_APB_FREQ_MAX; - } -#endif // SDM_CAPS_GET(FUNC_CLOCK_SUPPORT_APB) - if (esp_pm_lock_create(pm_type, 0, soc_sdm_signals[group_id].module_name, &group->pm_lock) != ESP_OK) { - ESP_LOGE(TAG, "fail to create PM lock for group %d", group_id); - } -#endif // CONFIG_PM_ENABLE - } - return group; } -static void sdm_release_group_handle(sdm_group_t *group) +static esp_err_t sdm_group_install(sdm_group_t *group, soc_module_clk_t clk_src) +{ + esp_err_t ret = ESP_OK; + int group_id = group->group_id; + + _lock_acquire(&s_platform.mutex); + if (group->clk_src != SOC_MOD_CLK_INVALID) { + ret = (group->clk_src == clk_src) ? ESP_OK : ESP_ERR_INVALID_STATE; + _lock_release(&s_platform.mutex); + return ret; + } + +#if SDM_USE_RETENTION_LINK + sleep_retention_module_t module = soc_sdm_retention_infos[group_id].module; + sleep_retention_module_init_param_t init_param = { + .cbs = { + .create = { + .handle = sdm_create_sleep_retention_link_cb, + .arg = group, + }, + }, + .attribute = SLEEP_RETENTION_MODULE_ATTR_ATTACH, + .depends = RETENTION_MODULE_BITMAP_INIT(CLOCK_SYSTEM) + }; + // retention module init must be called BEFORE the hal init + if (sleep_retention_module_init(module, &init_param) != ESP_OK) { + ESP_LOGW(TAG, "init sleep retention failed on SDM Group%d, power domain may be turned off during sleep", group_id); + } +#endif // SDM_USE_RETENTION_LINK + + ESP_GOTO_ON_ERROR(esp_clk_tree_enable_src(clk_src, true), err, TAG, "enable clock source failed for group %d", group_id); + group->clk_src = clk_src; + // SDM clock comes from IO MUX, but IO MUX clock might be shared with other submodules as well + ESP_GOTO_ON_ERROR(io_mux_acquire_clock_source(clk_src), err, TAG, "acquire IO MUX clock source failed for group %d", group_id); + group->io_mux_clk_acquired = true; + esp_clk_tree_src_get_freq_hz(clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &group->src_clk_hz); + + sdm_hal_init_config_t hal_config = { + .group_id = group_id, + }; + sdm_hal_init(&group->hal, &hal_config); + +#if CONFIG_PM_ENABLE + esp_pm_lock_type_t pm_type = ESP_PM_NO_LIGHT_SLEEP; +#if SDM_CAPS_GET(FUNC_CLOCK_SUPPORT_APB) + if (clk_src == (soc_module_clk_t)SDM_CLK_SRC_APB) { + pm_type = ESP_PM_APB_FREQ_MAX; + } +#endif // SDM_CAPS_GET(FUNC_CLOCK_SUPPORT_APB) + ESP_GOTO_ON_ERROR(esp_pm_lock_create(pm_type, 0, soc_sdm_signals[group_id].module_name, &group->pm_lock), + err, TAG, "fail to create PM lock for group %d", group_id); +#endif // CONFIG_PM_ENABLE + + _lock_release(&s_platform.mutex); + ESP_LOGD(TAG, "new group (%d) at %p", group_id, group); + return ESP_OK; + +err: +#if CONFIG_PM_ENABLE + if (group->pm_lock) { + esp_pm_lock_delete(group->pm_lock); + group->pm_lock = NULL; + } +#endif + if (group->io_mux_clk_acquired) { + sdm_hal_deinit(&group->hal); + io_mux_release_clock_source(group->clk_src); + group->io_mux_clk_acquired = false; + } + if (group->clk_src != SOC_MOD_CLK_INVALID) { + esp_clk_tree_enable_src(group->clk_src, false); + group->clk_src = SOC_MOD_CLK_INVALID; + } + _lock_release(&s_platform.mutex); + return ret; +} + +static void sdm_group_uninstall(sdm_group_t *group) +{ + if (group->clk_src == SOC_MOD_CLK_INVALID) { + return; + } + + sdm_hal_deinit(&group->hal); + if (group->io_mux_clk_acquired) { + io_mux_release_clock_source(group->clk_src); + group->io_mux_clk_acquired = false; + } + if (group->clk_src != SOC_MOD_CLK_INVALID) { + esp_clk_tree_enable_src(group->clk_src, false); + group->clk_src = SOC_MOD_CLK_INVALID; + } + +#if SDM_USE_RETENTION_LINK + sleep_retention_module_t module = soc_sdm_retention_infos[group->group_id].module; + sleep_retention_module_detach(module); + if (sleep_retention_is_module_created(module)) { + sleep_retention_module_free(module); + } + if (sleep_retention_is_module_inited(module)) { + sleep_retention_module_deinit(module); + } +#endif // SDM_USE_RETENTION_LINK + +#if CONFIG_PM_ENABLE + if (group->pm_lock) { + esp_pm_lock_delete(group->pm_lock); + group->pm_lock = NULL; + } +#endif // CONFIG_PM_ENABLE +} + +static void sdm_group_release(sdm_group_t *group) { int group_id = group->group_id; - bool do_deinitialize = false; + bool do_teardown = false; _lock_acquire(&s_platform.mutex); s_platform.group_ref_counts[group_id]--; if (s_platform.group_ref_counts[group_id] == 0) { assert(s_platform.groups[group_id]); - do_deinitialize = true; - s_platform.groups[group_id] = NULL; // deregister from platform - sdm_hal_deinit(&group->hal); - -#if SDM_USE_RETENTION_LINK - sleep_retention_module_t module = soc_sdm_retention_infos[group_id].module; - sleep_retention_module_detach(module); - if (sleep_retention_is_module_created(module)) { - sleep_retention_module_free(module); - } - if (sleep_retention_is_module_inited(module)) { - sleep_retention_module_deinit(module); - } -#endif // SDM_USE_RETENTION_LINK + s_platform.groups[group_id] = NULL; + do_teardown = true; } _lock_release(&s_platform.mutex); - if (do_deinitialize) { -#if CONFIG_PM_ENABLE - if (group->pm_lock) { - esp_pm_lock_delete(group->pm_lock); - } -#endif + if (do_teardown) { + sdm_group_uninstall(group); free(group); ESP_LOGD(TAG, "del group (%d)", group_id); } @@ -221,11 +276,20 @@ static void sdm_release_group_handle(sdm_group_t *group) static esp_err_t sdm_register_to_group(sdm_channel_t *chan, sdm_clock_source_t clk_src) { + esp_err_t ret = ESP_OK; sdm_group_t *group = NULL; int chan_id = -1; for (int i = 0; i < SDM_CAPS_GET(INST_NUM); i++) { - group = sdm_acquire_group_handle(i, clk_src); + group = sdm_group_acquire(i); ESP_RETURN_ON_FALSE(group, ESP_ERR_NO_MEM, TAG, "no mem for group (%d)", i); + + ret = sdm_group_install(group, clk_src); + if (ret == ESP_ERR_INVALID_STATE) { + sdm_group_release(group); + continue; + } + ESP_GOTO_ON_ERROR(ret, err, TAG, "install group (%d) failed", i); + // loop to search free unit in the group portENTER_CRITICAL(&group->spinlock); for (int j = 0; j < SDM_CAPS_GET(CHANS_PER_INST); j++) { @@ -239,13 +303,19 @@ static esp_err_t sdm_register_to_group(sdm_channel_t *chan, sdm_clock_source_t c } portEXIT_CRITICAL(&group->spinlock); if (chan_id < 0) { - sdm_release_group_handle(group); + sdm_group_release(group); } else { break; } } ESP_RETURN_ON_FALSE(chan_id != -1, ESP_ERR_NOT_FOUND, TAG, "no free channels"); return ESP_OK; + +err: + if (group) { + sdm_group_release(group); + } + return ret; } static void sdm_unregister_from_group(sdm_channel_t *chan) @@ -256,18 +326,18 @@ static void sdm_unregister_from_group(sdm_channel_t *chan) group->channels[chan_id] = NULL; portEXIT_CRITICAL(&group->spinlock); // channel has a reference on group, release it now - sdm_release_group_handle(group); + sdm_group_release(group); } static esp_err_t sdm_destroy(sdm_channel_t *chan) { - if (chan->group) { - sdm_unregister_from_group(chan); - } if (chan->gpio_num >= 0) { gpio_output_disable(chan->gpio_num); esp_gpio_revoke(BIT64(chan->gpio_num)); } + if (chan->group) { + sdm_unregister_from_group(chan); + } free(chan); return ESP_OK; } @@ -289,22 +359,13 @@ esp_err_t sdm_new_channel(const sdm_config_t *config, sdm_channel_handle_t *ret_ ESP_RETURN_ON_FALSE(chan, ESP_ERR_NO_MEM, TAG, "no mem for channel"); chan->gpio_num = GPIO_NUM_NC; // default to NC, will be set later - sdm_clock_source_t clk_src = config->clk_src ? config->clk_src : SDM_CLK_SRC_DEFAULT; + soc_module_clk_t clk_src = config->clk_src ? config->clk_src : SDM_CLK_SRC_DEFAULT; // register channel to the group ESP_GOTO_ON_ERROR(sdm_register_to_group(chan, clk_src), err, TAG, "register to group failed"); sdm_group_t *group = chan->group; int group_id = group->group_id; int chan_id = chan->chan_id; - ESP_GOTO_ON_FALSE(group->clk_src == clk_src, ESP_ERR_INVALID_ARG, err, TAG, "clock source conflict"); - - // SDM clock comes from IO MUX, but IO MUX clock might be shared with other submodules as well - ESP_GOTO_ON_ERROR(io_mux_set_clock_source((soc_module_clk_t)clk_src), err, TAG, "set IO MUX clock source failed"); - - uint32_t src_clk_hz = 0; - ESP_GOTO_ON_ERROR(esp_clk_tree_src_get_freq_hz((soc_module_clk_t)clk_src, - ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &src_clk_hz), err, TAG, "get source clock frequency failed"); - // Reserve the new GPIO uint64_t old_gpio_rsv_mask = esp_gpio_reserve(BIT64(config->gpio_num)); if (old_gpio_rsv_mask & BIT64(config->gpio_num)) { @@ -314,6 +375,7 @@ esp_err_t sdm_new_channel(const sdm_config_t *config, sdm_channel_handle_t *ret_ gpio_matrix_output(config->gpio_num, soc_sdm_signals[group_id].channels[chan_id].sig_id_matrix, config->flags.invert_out, false); chan->gpio_num = config->gpio_num; + uint32_t src_clk_hz = group->src_clk_hz; // set prescale based on sample rate uint32_t prescale = 0; hal_utils_clk_info_t clk_info = { diff --git a/components/esp_hal_gpio/esp32c5/include/hal/gpio_ll.h b/components/esp_hal_gpio/esp32c5/include/hal/gpio_ll.h index a271fb14df6..c6e8a896408 100644 --- a/components/esp_hal_gpio/esp32c5/include/hal/gpio_ll.h +++ b/components/esp_hal_gpio/esp32c5/include/hal/gpio_ll.h @@ -39,6 +39,8 @@ #define GPIO_LL_INTR_SOURCE0 ETS_GPIO_INTR_SOURCE +#define GPIO_LL_CLK_SRC_SELECTABLE 1 + #ifdef __cplusplus extern "C" { #endif diff --git a/components/esp_hal_gpio/esp32c6/include/hal/gpio_ll.h b/components/esp_hal_gpio/esp32c6/include/hal/gpio_ll.h index d22a4f47a93..458ce292192 100644 --- a/components/esp_hal_gpio/esp32c6/include/hal/gpio_ll.h +++ b/components/esp_hal_gpio/esp32c6/include/hal/gpio_ll.h @@ -38,6 +38,8 @@ #define GPIO_LL_INTR_SOURCE0 ETS_GPIO_INTR_SOURCE +#define GPIO_LL_CLK_SRC_SELECTABLE 1 + #ifdef __cplusplus extern "C" { #endif diff --git a/components/esp_hal_gpio/esp32c61/include/hal/gpio_ll.h b/components/esp_hal_gpio/esp32c61/include/hal/gpio_ll.h index 62eac10d626..af3d35a6beb 100644 --- a/components/esp_hal_gpio/esp32c61/include/hal/gpio_ll.h +++ b/components/esp_hal_gpio/esp32c61/include/hal/gpio_ll.h @@ -40,6 +40,8 @@ #define GPIO_LL_INTR_SOURCE0 ETS_GPIO_INTERRUPT_PRO_SOURCE +#define GPIO_LL_CLK_SRC_SELECTABLE 1 + #ifdef __cplusplus extern "C" { #endif diff --git a/components/esp_hal_gpio/esp32h2/include/hal/gpio_ll.h b/components/esp_hal_gpio/esp32h2/include/hal/gpio_ll.h index 99646d16508..4e3a78afb05 100644 --- a/components/esp_hal_gpio/esp32h2/include/hal/gpio_ll.h +++ b/components/esp_hal_gpio/esp32h2/include/hal/gpio_ll.h @@ -38,6 +38,8 @@ #define GPIO_LL_INTR_SOURCE0 ETS_GPIO_INTR_SOURCE +#define GPIO_LL_CLK_SRC_SELECTABLE 1 + #ifdef __cplusplus extern "C" { #endif diff --git a/components/esp_hal_gpio/esp32h21/include/hal/gpio_ll.h b/components/esp_hal_gpio/esp32h21/include/hal/gpio_ll.h index fb05f818a42..b7e159f8832 100644 --- a/components/esp_hal_gpio/esp32h21/include/hal/gpio_ll.h +++ b/components/esp_hal_gpio/esp32h21/include/hal/gpio_ll.h @@ -38,6 +38,8 @@ #define GPIO_LL_INTR_SOURCE0 ETS_GPIO_INTERRUPT_PRO_SOURCE +#define GPIO_LL_CLK_SRC_SELECTABLE 1 + #ifdef __cplusplus extern "C" { #endif diff --git a/components/esp_hal_gpio/esp32h4/include/hal/gpio_ll.h b/components/esp_hal_gpio/esp32h4/include/hal/gpio_ll.h index 32ca031cb58..71ee5f9ce4c 100644 --- a/components/esp_hal_gpio/esp32h4/include/hal/gpio_ll.h +++ b/components/esp_hal_gpio/esp32h4/include/hal/gpio_ll.h @@ -39,6 +39,8 @@ #define GPIO_LL_PRO_CPU_2_INTR_ENA (BIT(1)) #define GPIO_LL_INTR_SOURCE0 ETS_GPIO_INTERRUPT_PRO_SOURCE +#define GPIO_LL_CLK_SRC_SELECTABLE 1 + #ifdef __cplusplus extern "C" { #endif diff --git a/components/esp_hal_gpio/esp32p4/include/hal/gpio_ll.h b/components/esp_hal_gpio/esp32p4/include/hal/gpio_ll.h index d344761cb07..c48c8331c34 100644 --- a/components/esp_hal_gpio/esp32p4/include/hal/gpio_ll.h +++ b/components/esp_hal_gpio/esp32p4/include/hal/gpio_ll.h @@ -45,6 +45,8 @@ #define GPIO_LL_INTR_SOURCE0 ETS_GPIO_INTR0_SOURCE +#define GPIO_LL_CLK_SRC_SELECTABLE 1 + #ifdef __cplusplus extern "C" { #endif diff --git a/components/esp_hal_gpio/esp32s31/include/hal/gpio_ll.h b/components/esp_hal_gpio/esp32s31/include/hal/gpio_ll.h index 983678f57fd..cad4bdeffe5 100644 --- a/components/esp_hal_gpio/esp32s31/include/hal/gpio_ll.h +++ b/components/esp_hal_gpio/esp32s31/include/hal/gpio_ll.h @@ -46,6 +46,8 @@ #define GPIO_LL_INTR_SOURCE0 ETS_GPIO_INTR0_SOURCE +#define GPIO_LL_CLK_SRC_SELECTABLE 1 + #ifdef __cplusplus extern "C" { #endif diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index 422e215c425..9ff7582e140 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/components/esp_hw_support/CMakeLists.txt @@ -38,6 +38,7 @@ if(NOT non_os_build) "esp_gpio_reserve.c" "sar_tsens_ctrl.c" "sar_periph_ctrl_common.c" + "io_mux.c" "port/${target}/io_mux.c" "port/${target}/esp_clk_tree.c" "spi_bus_lock.c" diff --git a/components/esp_hw_support/include/esp_private/io_mux.h b/components/esp_hw_support/include/esp_private/io_mux.h index 1636e4459ec..275115225fd 100644 --- a/components/esp_hw_support/include/esp_private/io_mux.h +++ b/components/esp_hw_support/include/esp_private/io_mux.h @@ -17,17 +17,30 @@ extern "C" { #endif /** - * @brief Set the clock source for IO MUX + * @brief Acquire the clock source for IO MUX * * @note IO MUX clock is shared by submodules like SDM, Glitch Filter. - * The submodule drivers should call this function to detect if the user set the clock differently. + * Each consumer should call this function when starting to use a specific clock source, + * and call @ref io_mux_release_clock_source when done. * * @param clk_src The clock source for IO MUX * @return * - ESP_OK: Success - * - ESP_ERR_INVALID_STATE: The IO MUX has been set to another clock source + * - ESP_ERR_INVALID_STATE: The IO MUX has been acquired with another clock source */ -esp_err_t io_mux_set_clock_source(soc_module_clk_t clk_src); +esp_err_t io_mux_acquire_clock_source(soc_module_clk_t clk_src); + +/** + * @brief Release the clock source for IO MUX + * + * When the last consumer releases, the clock source will be switched back to SOC_MOD_CLK_XTAL. + * + * @param clk_src The clock source to release (must match the one used in acquire) + * @return + * - ESP_OK: Success + * - ESP_ERR_INVALID_STATE: Reference count is zero or clock source mismatch + */ +esp_err_t io_mux_release_clock_source(soc_module_clk_t clk_src); #if SOC_LP_IO_CLOCK_IS_INDEPENDENT typedef struct { diff --git a/components/esp_hw_support/io_mux.c b/components/esp_hw_support/io_mux.c new file mode 100644 index 00000000000..d334c2c1996 --- /dev/null +++ b/components/esp_hw_support/io_mux.c @@ -0,0 +1,90 @@ +/* + * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "esp_private/io_mux.h" +#include "esp_private/critical_section.h" +#include "esp_private/periph_ctrl.h" +#include "soc/clk_tree_defs.h" +#include "hal/gpio_ll.h" + +#if GPIO_LL_CLK_SRC_SELECTABLE + +DEFINE_CRIT_SECTION_LOCK_STATIC(s_io_mux_clk_spinlock); + +static soc_module_clk_t s_io_mux_clk_src = 0; +static uint32_t s_io_mux_clk_ref_count = 0; + +#endif // GPIO_LL_CLK_SRC_SELECTABLE + +esp_err_t io_mux_acquire_clock_source(soc_module_clk_t clk_src) +{ +#if GPIO_LL_CLK_SRC_SELECTABLE + bool clk_conflict = false; + bool need_update_hw = false; + + esp_os_enter_critical(&s_io_mux_clk_spinlock); + if (s_io_mux_clk_ref_count > 0 && s_io_mux_clk_src != clk_src) { + clk_conflict = true; + } else { + if (s_io_mux_clk_ref_count == 0) { + s_io_mux_clk_src = clk_src; + need_update_hw = true; + } + s_io_mux_clk_ref_count++; + } + esp_os_exit_critical(&s_io_mux_clk_spinlock); + + if (clk_conflict) { + return ESP_ERR_INVALID_STATE; + } + + if (need_update_hw) { + PERIPH_RCC_ATOMIC() { + gpio_ll_iomux_set_clk_src(clk_src); + } + } + + return ESP_OK; +#else + (void)clk_src; + return ESP_OK; +#endif +} + +esp_err_t io_mux_release_clock_source(soc_module_clk_t clk_src) +{ +#if GPIO_LL_CLK_SRC_SELECTABLE + bool invalid = false; + bool need_revert_hw = false; + + esp_os_enter_critical(&s_io_mux_clk_spinlock); + if (s_io_mux_clk_ref_count == 0 || s_io_mux_clk_src != clk_src) { + invalid = true; + } else { + s_io_mux_clk_ref_count--; + if (s_io_mux_clk_ref_count == 0) { + s_io_mux_clk_src = 0; + need_revert_hw = true; + } + } + esp_os_exit_critical(&s_io_mux_clk_spinlock); + + if (invalid) { + return ESP_ERR_INVALID_STATE; + } + + if (need_revert_hw) { + PERIPH_RCC_ATOMIC() { + gpio_ll_iomux_set_clk_src(SOC_MOD_CLK_XTAL); + } + } + + return ESP_OK; +#else + (void)clk_src; + return ESP_OK; +#endif +} diff --git a/components/esp_hw_support/port/esp32/io_mux.c b/components/esp_hw_support/port/esp32/io_mux.c index bfc960f549c..db8ff0b8d94 100644 --- a/components/esp_hw_support/port/esp32/io_mux.c +++ b/components/esp_hw_support/port/esp32/io_mux.c @@ -6,12 +6,6 @@ #include "esp_private/io_mux.h" -esp_err_t io_mux_set_clock_source(soc_module_clk_t clk_src) -{ - // IO MUX clock source is not selectable - return ESP_OK; -} - bool io_mux_is_lp_io_in_use(gpio_num_t gpio_num) { // ESP32 does not have SOC_LP_IO_CLOCK_IS_INDEPENDENT diff --git a/components/esp_hw_support/port/esp32c2/io_mux.c b/components/esp_hw_support/port/esp32c2/io_mux.c index d17a300030c..0730041568c 100644 --- a/components/esp_hw_support/port/esp32c2/io_mux.c +++ b/components/esp_hw_support/port/esp32c2/io_mux.c @@ -5,9 +5,3 @@ */ #include "esp_private/io_mux.h" - -esp_err_t io_mux_set_clock_source(soc_module_clk_t clk_src) -{ - // IO MUX clock source is not selectable - return ESP_OK; -} diff --git a/components/esp_hw_support/port/esp32c3/io_mux.c b/components/esp_hw_support/port/esp32c3/io_mux.c index d17a300030c..0730041568c 100644 --- a/components/esp_hw_support/port/esp32c3/io_mux.c +++ b/components/esp_hw_support/port/esp32c3/io_mux.c @@ -5,9 +5,3 @@ */ #include "esp_private/io_mux.h" - -esp_err_t io_mux_set_clock_source(soc_module_clk_t clk_src) -{ - // IO MUX clock source is not selectable - return ESP_OK; -} diff --git a/components/esp_hw_support/port/esp32c5/io_mux.c b/components/esp_hw_support/port/esp32c5/io_mux.c index 4b50b8b96e6..2b5bf357024 100644 --- a/components/esp_hw_support/port/esp32c5/io_mux.c +++ b/components/esp_hw_support/port/esp32c5/io_mux.c @@ -5,17 +5,14 @@ */ #include "sdkconfig.h" -#include "esp_private/esp_clk_tree_common.h" #include "esp_private/io_mux.h" #include "esp_private/periph_ctrl.h" #include "esp_private/critical_section.h" -#include "hal/gpio_ll.h" #include "hal/rtc_io_ll.h" #define RTCIO_RCC_ATOMIC() PERIPH_RCC_ATOMIC() DEFINE_CRIT_SECTION_LOCK_STATIC(s_io_mux_spinlock); -static soc_module_clk_t s_io_mux_clk_src = 0; // by default, the clock source is not set explicitly by any consumer (e.g. SDM, Filter) #if CONFIG_ULP_COPROC_ENABLED RTC_DATA_ATTR @@ -25,28 +22,6 @@ static rtc_io_status_t s_rtc_io_status = { .rtc_io_using_mask = 0 }; -esp_err_t io_mux_set_clock_source(soc_module_clk_t clk_src) -{ - bool clk_conflict = false; - // check if the IO MUX has been set to another clock source - esp_os_enter_critical(&s_io_mux_spinlock); - if (s_io_mux_clk_src != 0 && s_io_mux_clk_src != clk_src) { - clk_conflict = true; - } else { - s_io_mux_clk_src = clk_src; - } - esp_os_exit_critical(&s_io_mux_spinlock); - - if (clk_conflict) { - return ESP_ERR_INVALID_STATE; - } - - ESP_ERROR_CHECK(esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true)); - gpio_ll_iomux_set_clk_src(clk_src); - - return ESP_OK; -} - void io_mux_enable_lp_io_clock(gpio_num_t gpio_num, bool enable) { uint32_t rtc_io_num = gpio_num - RTCIO_LL_GPIO_NUM_OFFSET; diff --git a/components/esp_hw_support/port/esp32c6/io_mux.c b/components/esp_hw_support/port/esp32c6/io_mux.c index b0682682a07..28a2f52ed1f 100644 --- a/components/esp_hw_support/port/esp32c6/io_mux.c +++ b/components/esp_hw_support/port/esp32c6/io_mux.c @@ -9,13 +9,11 @@ #include "esp_private/io_mux.h" #include "esp_private/periph_ctrl.h" #include "esp_private/critical_section.h" -#include "hal/gpio_ll.h" #include "hal/rtc_io_ll.h" #define RTCIO_RCC_ATOMIC() PERIPH_RCC_ATOMIC() DEFINE_CRIT_SECTION_LOCK_STATIC(s_io_mux_spinlock); -static soc_module_clk_t s_io_mux_clk_src = 0; // by default, the clock source is not set explicitly by any consumer (e.g. SDM, Filter) #if CONFIG_ULP_COPROC_ENABLED RTC_DATA_ATTR @@ -25,27 +23,6 @@ static rtc_io_status_t s_rtc_io_status = { .rtc_io_using_mask = 0 }; -esp_err_t io_mux_set_clock_source(soc_module_clk_t clk_src) -{ - bool clk_conflict = false; - // check if the IO MUX has been set to another clock source - esp_os_enter_critical(&s_io_mux_spinlock); - if (s_io_mux_clk_src != 0 && s_io_mux_clk_src != clk_src) { - clk_conflict = true; - } else { - s_io_mux_clk_src = clk_src; - } - esp_os_exit_critical(&s_io_mux_spinlock); - - if (clk_conflict) { - return ESP_ERR_INVALID_STATE; - } - - gpio_ll_iomux_set_clk_src(clk_src); - - return ESP_OK; -} - void io_mux_enable_lp_io_clock(gpio_num_t gpio_num, bool enable) { uint32_t rtc_io_num = gpio_num - RTCIO_LL_GPIO_NUM_OFFSET; diff --git a/components/esp_hw_support/port/esp32c61/io_mux.c b/components/esp_hw_support/port/esp32c61/io_mux.c index c67ed6eec64..b1c8e0e84a7 100644 --- a/components/esp_hw_support/port/esp32c61/io_mux.c +++ b/components/esp_hw_support/port/esp32c61/io_mux.c @@ -7,40 +7,17 @@ #include "esp_private/io_mux.h" #include "esp_private/periph_ctrl.h" #include "esp_private/critical_section.h" -#include "hal/gpio_ll.h" #include "hal/rtc_io_ll.h" #define RTCIO_RCC_ATOMIC() PERIPH_RCC_ATOMIC() DEFINE_CRIT_SECTION_LOCK_STATIC(s_io_mux_spinlock); -static soc_module_clk_t s_io_mux_clk_src = 0; // by default, the clock source is not set explicitly by any consumer (e.g. SDM, Filter) static rtc_io_status_t s_rtc_io_status = { .rtc_io_enabled_cnt = { 0 }, .rtc_io_using_mask = 0 }; -esp_err_t io_mux_set_clock_source(soc_module_clk_t clk_src) -{ - bool clk_conflict = false; - // check if the IO MUX has been set to another clock source - esp_os_enter_critical(&s_io_mux_spinlock); - if (s_io_mux_clk_src != 0 && s_io_mux_clk_src != clk_src) { - clk_conflict = true; - } else { - s_io_mux_clk_src = clk_src; - } - esp_os_exit_critical(&s_io_mux_spinlock); - - if (clk_conflict) { - return ESP_ERR_INVALID_STATE; - } - - gpio_ll_iomux_set_clk_src(clk_src); - - return ESP_OK; -} - void io_mux_enable_lp_io_clock(gpio_num_t gpio_num, bool enable) { uint32_t rtc_io_num = gpio_num - RTCIO_LL_GPIO_NUM_OFFSET; diff --git a/components/esp_hw_support/port/esp32h2/io_mux.c b/components/esp_hw_support/port/esp32h2/io_mux.c index 3f9b01c80f6..876314d1940 100644 --- a/components/esp_hw_support/port/esp32h2/io_mux.c +++ b/components/esp_hw_support/port/esp32h2/io_mux.c @@ -7,40 +7,17 @@ #include "esp_private/io_mux.h" #include "esp_private/periph_ctrl.h" #include "esp_private/critical_section.h" -#include "hal/gpio_ll.h" #include "hal/rtc_io_ll.h" #define RTCIO_RCC_ATOMIC() PERIPH_RCC_ATOMIC() DEFINE_CRIT_SECTION_LOCK_STATIC(s_io_mux_spinlock); -static soc_module_clk_t s_io_mux_clk_src = 0; // by default, the clock source is not set explicitly by any consumer (e.g. SDM, Filter) static rtc_io_status_t s_rtc_io_status = { .rtc_io_enabled_cnt = { 0 }, .rtc_io_using_mask = 0 }; -esp_err_t io_mux_set_clock_source(soc_module_clk_t clk_src) -{ - bool clk_conflict = false; - // check if the IO MUX has been set to another clock source - esp_os_enter_critical(&s_io_mux_spinlock); - if (s_io_mux_clk_src != 0 && s_io_mux_clk_src != clk_src) { - clk_conflict = true; - } else { - s_io_mux_clk_src = clk_src; - } - esp_os_exit_critical(&s_io_mux_spinlock); - - if (clk_conflict) { - return ESP_ERR_INVALID_STATE; - } - - gpio_ll_iomux_set_clk_src(clk_src); - - return ESP_OK; -} - void io_mux_enable_lp_io_clock(gpio_num_t gpio_num, bool enable) { uint32_t rtc_io_num = gpio_num - RTCIO_LL_GPIO_NUM_OFFSET; diff --git a/components/esp_hw_support/port/esp32h21/io_mux.c b/components/esp_hw_support/port/esp32h21/io_mux.c index d0ffa2462f5..58098d30753 100644 --- a/components/esp_hw_support/port/esp32h21/io_mux.c +++ b/components/esp_hw_support/port/esp32h21/io_mux.c @@ -8,40 +8,17 @@ #include "esp_private/io_mux.h" #include "esp_private/periph_ctrl.h" #include "esp_private/critical_section.h" -#include "hal/gpio_ll.h" #include "hal/rtc_io_ll.h" #define RTCIO_RCC_ATOMIC() PERIPH_RCC_ATOMIC() DEFINE_CRIT_SECTION_LOCK_STATIC(s_io_mux_spinlock); -static soc_module_clk_t s_io_mux_clk_src = 0; // by default, the clock source is not set explicitly by any consumer (e.g. SDM, Filter) static rtc_io_status_t s_rtc_io_status = { .rtc_io_enabled_cnt = { 0 }, .rtc_io_using_mask = 0 }; -esp_err_t io_mux_set_clock_source(soc_module_clk_t clk_src) -{ - bool clk_conflict = false; - // check if the IO MUX has been set to another clock source - esp_os_enter_critical(&s_io_mux_spinlock); - if (s_io_mux_clk_src != 0 && s_io_mux_clk_src != clk_src) { - clk_conflict = true; - } else { - s_io_mux_clk_src = clk_src; - } - esp_os_exit_critical(&s_io_mux_spinlock); - - if (clk_conflict) { - return ESP_ERR_INVALID_STATE; - } - - gpio_ll_iomux_set_clk_src(clk_src); - - return ESP_OK; -} - void io_mux_enable_lp_io_clock(gpio_num_t gpio_num, bool enable) { uint32_t rtc_io_num = gpio_num - RTCIO_LL_GPIO_NUM_OFFSET; diff --git a/components/esp_hw_support/port/esp32h4/io_mux.c b/components/esp_hw_support/port/esp32h4/io_mux.c index d714f9f4a11..d16bb18fa50 100644 --- a/components/esp_hw_support/port/esp32h4/io_mux.c +++ b/components/esp_hw_support/port/esp32h4/io_mux.c @@ -8,40 +8,17 @@ #include "esp_private/io_mux.h" #include "esp_private/periph_ctrl.h" #include "esp_private/critical_section.h" -#include "hal/gpio_ll.h" #include "hal/rtc_io_ll.h" #define RTCIO_RCC_ATOMIC() PERIPH_RCC_ATOMIC() DEFINE_CRIT_SECTION_LOCK_STATIC(s_io_mux_spinlock); -static soc_module_clk_t s_io_mux_clk_src = 0; // by default, the clock source is not set explicitly by any consumer (e.g. SDM, Filter) static rtc_io_status_t s_rtc_io_status = { .rtc_io_enabled_cnt = { 0 }, .rtc_io_using_mask = 0 }; -esp_err_t io_mux_set_clock_source(soc_module_clk_t clk_src) -{ - bool clk_conflict = false; - // check if the IO MUX has been set to another clock source - esp_os_enter_critical(&s_io_mux_spinlock); - if (s_io_mux_clk_src != 0 && s_io_mux_clk_src != clk_src) { - clk_conflict = true; - } else { - s_io_mux_clk_src = clk_src; - } - esp_os_exit_critical(&s_io_mux_spinlock); - - if (clk_conflict) { - return ESP_ERR_INVALID_STATE; - } - - gpio_ll_iomux_set_clk_src(clk_src); - - return ESP_OK; -} - void io_mux_enable_lp_io_clock(gpio_num_t gpio_num, bool enable) { uint32_t rtc_io_num = gpio_num - RTCIO_LL_GPIO_NUM_OFFSET; diff --git a/components/esp_hw_support/port/esp32p4/io_mux.c b/components/esp_hw_support/port/esp32p4/io_mux.c index bf59c7dcba9..86bc74f1605 100644 --- a/components/esp_hw_support/port/esp32p4/io_mux.c +++ b/components/esp_hw_support/port/esp32p4/io_mux.c @@ -6,19 +6,15 @@ #include "sdkconfig.h" #include "esp_attr.h" -#include "esp_check.h" -#include "esp_private/esp_clk_tree_common.h" #include "esp_private/io_mux.h" #include "esp_private/periph_ctrl.h" #include "esp_private/critical_section.h" -#include "hal/gpio_ll.h" #include "hal/rtc_io_ll.h" #include "soc/soc_caps.h" #define RTCIO_RCC_ATOMIC() PERIPH_RCC_ATOMIC() DEFINE_CRIT_SECTION_LOCK_STATIC(s_io_mux_spinlock); -static soc_module_clk_t s_io_mux_clk_src = 0; // by default, the clock source is not set explicitly by any consumer (e.g. SDM, Filter) #if CONFIG_ULP_COPROC_ENABLED RTC_DATA_ATTR @@ -28,29 +24,6 @@ static rtc_io_status_t s_rtc_io_status = { .rtc_io_using_mask = 0 }; -esp_err_t io_mux_set_clock_source(soc_module_clk_t clk_src) -{ - bool clk_conflict = false; - // check if the IO MUX has been set to another clock source - esp_os_enter_critical(&s_io_mux_spinlock); - if (s_io_mux_clk_src != 0 && s_io_mux_clk_src != clk_src) { - clk_conflict = true; - } else { - s_io_mux_clk_src = clk_src; - } - esp_os_exit_critical(&s_io_mux_spinlock); - - if (clk_conflict) { - return ESP_ERR_INVALID_STATE; - } - - ESP_ERROR_CHECK(esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true)); - PERIPH_RCC_ATOMIC() { - gpio_ll_iomux_set_clk_src(clk_src); - } - return ESP_OK; -} - void io_mux_enable_lp_io_clock(gpio_num_t gpio_num, bool enable) { uint32_t rtc_io_num = gpio_num - RTCIO_LL_GPIO_NUM_OFFSET; diff --git a/components/esp_hw_support/port/esp32s2/io_mux.c b/components/esp_hw_support/port/esp32s2/io_mux.c index 0340d271e90..5ca675b8b72 100644 --- a/components/esp_hw_support/port/esp32s2/io_mux.c +++ b/components/esp_hw_support/port/esp32s2/io_mux.c @@ -15,12 +15,6 @@ _rc_cnt ? (esp_os_enter_critical(&rtc_spinlock), 1) : 0; \ esp_os_exit_critical(&rtc_spinlock), _rc_cnt--) -esp_err_t io_mux_set_clock_source(soc_module_clk_t clk_src) -{ - // IO MUX clock source is not selectable - return ESP_OK; -} - extern portMUX_TYPE rtc_spinlock; DEFINE_CRIT_SECTION_LOCK_STATIC(s_io_mux_spinlock); diff --git a/components/esp_hw_support/port/esp32s3/io_mux.c b/components/esp_hw_support/port/esp32s3/io_mux.c index 0340d271e90..5ca675b8b72 100644 --- a/components/esp_hw_support/port/esp32s3/io_mux.c +++ b/components/esp_hw_support/port/esp32s3/io_mux.c @@ -15,12 +15,6 @@ _rc_cnt ? (esp_os_enter_critical(&rtc_spinlock), 1) : 0; \ esp_os_exit_critical(&rtc_spinlock), _rc_cnt--) -esp_err_t io_mux_set_clock_source(soc_module_clk_t clk_src) -{ - // IO MUX clock source is not selectable - return ESP_OK; -} - extern portMUX_TYPE rtc_spinlock; DEFINE_CRIT_SECTION_LOCK_STATIC(s_io_mux_spinlock); diff --git a/components/esp_hw_support/port/esp32s31/io_mux.c b/components/esp_hw_support/port/esp32s31/io_mux.c index e0ad4879464..066044f4000 100644 --- a/components/esp_hw_support/port/esp32s31/io_mux.c +++ b/components/esp_hw_support/port/esp32s31/io_mux.c @@ -6,19 +6,15 @@ #include "sdkconfig.h" #include "esp_attr.h" -#include "esp_check.h" -#include "esp_private/esp_clk_tree_common.h" #include "esp_private/io_mux.h" #include "esp_private/periph_ctrl.h" #include "esp_private/critical_section.h" -#include "hal/gpio_ll.h" #include "hal/rtc_io_ll.h" #include "soc/soc_caps.h" #define RTCIO_RCC_ATOMIC() PERIPH_RCC_ATOMIC() DEFINE_CRIT_SECTION_LOCK_STATIC(s_io_mux_spinlock); -static soc_module_clk_t s_io_mux_clk_src = 0; // by default, the clock source is not set explicitly by any consumer (e.g. SDM, Filter) #if CONFIG_ULP_COPROC_ENABLED RTC_DATA_ATTR @@ -28,29 +24,6 @@ static rtc_io_status_t s_rtc_io_status = { .rtc_io_using_mask = 0 }; -esp_err_t io_mux_set_clock_source(soc_module_clk_t clk_src) -{ - bool clk_conflict = false; - // check if the IO MUX has been set to another clock source - esp_os_enter_critical(&s_io_mux_spinlock); - if (s_io_mux_clk_src != 0 && s_io_mux_clk_src != clk_src) { - clk_conflict = true; - } else { - s_io_mux_clk_src = clk_src; - } - esp_os_exit_critical(&s_io_mux_spinlock); - - if (clk_conflict) { - return ESP_ERR_INVALID_STATE; - } - - ESP_ERROR_CHECK(esp_clk_tree_enable_src((soc_module_clk_t)clk_src, true)); - PERIPH_RCC_ATOMIC() { - gpio_ll_iomux_set_clk_src(clk_src); - } - return ESP_OK; -} - void io_mux_enable_lp_io_clock(gpio_num_t gpio_num, bool enable) { uint32_t rtc_io_num = gpio_num - RTCIO_LL_GPIO_NUM_OFFSET;