mirror of
https://github.com/espressif/esp-idf.git
synced 2026-05-28 16:46:31 +03:00
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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
|
||||
#define GLITCH_FILTER_PM_LOCK_NAME_LEN_MAX 16
|
||||
|
||||
///!< Logging settings
|
||||
#define TAG "gpio-filter"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#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;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdatomic.h>
|
||||
#include <sys/lock.h>
|
||||
#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 = {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 {
|
||||
|
||||
90
components/esp_hw_support/io_mux.c
Normal file
90
components/esp_hw_support/io_mux.c
Normal file
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user