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.
This commit is contained in:
morris
2026-05-22 19:10:08 +08:00
parent 6b711f91f5
commit 38c4f27102
31 changed files with 362 additions and 355 deletions
@@ -0,0 +1,45 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "esp_err.h"
#include "driver/gpio_filter.h"
#include "esp_heap_caps.h"
#define FILTER_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
#define GLITCH_FILTER_PM_LOCK_NAME_LEN_MAX 16
///!< Logging settings
#define TAG "gpio-filter"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct gpio_glitch_filter_t gpio_glitch_filter_t;
typedef enum {
GLITCH_FILTER_FSM_INIT,
GLITCH_FILTER_FSM_ENABLE,
} glitch_filter_fsm_t;
/**
* @brief Glitch Filter base class
*/
struct gpio_glitch_filter_t {
glitch_filter_fsm_t fsm;
gpio_num_t gpio_num;
esp_err_t (*enable)(gpio_glitch_filter_t *filter);
esp_err_t (*disable)(gpio_glitch_filter_t *filter);
esp_err_t (*del)(gpio_glitch_filter_t *filter);
};
#ifdef __cplusplus
}
#endif
@@ -5,16 +5,16 @@
*/
#include <sys/cdefs.h>
#include <stdbool.h>
#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
@@ -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 ///////////
@@ -5,22 +5,24 @@
*/
#include <sys/cdefs.h>
#include <stdbool.h>
#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;