From 061e5dc695a01b24f8351f0f68d74ff01a6088d4 Mon Sep 17 00:00:00 2001 From: morris Date: Sat, 16 Mar 2024 23:58:01 +0800 Subject: [PATCH 1/6] feat(ldo): add ldo regulator driver for public use --- components/esp_hw_support/CMakeLists.txt | 6 +- .../esp_hw_support/ldo/esp_ldo_regulator.c | 169 ++++++++++++++++++ .../ldo/include/esp_ldo_regulator.h | 90 ++++++++++ components/esp_hw_support/ldo/linker.lf | 4 - .../main/CMakeLists.txt | 2 +- .../main/test_ldo.c | 113 +++++++----- .../mipi_dsi_lcd/main/test_mipi_dsi_board.c | 18 +- .../mipi_dsi_lcd/main/test_mipi_dsi_board.h | 2 +- components/hal/esp32p4/include/hal/ldo_ll.h | 6 +- .../esp32p4/include/soc/Kconfig.soc_caps.in | 2 +- components/soc/esp32p4/include/soc/soc_caps.h | 2 +- 11 files changed, 342 insertions(+), 72 deletions(-) create mode 100644 components/esp_hw_support/ldo/esp_ldo_regulator.c create mode 100644 components/esp_hw_support/ldo/include/esp_ldo_regulator.h delete mode 100644 components/esp_hw_support/ldo/linker.lf diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index 73b72cc997..d96236b270 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/components/esp_hw_support/CMakeLists.txt @@ -73,8 +73,8 @@ if(NOT BOOTLOADER_BUILD) endif() endif() - if(CONFIG_SOC_MULTI_USAGE_LDO_SUPPORTED) - list(APPEND srcs "ldo/esp_ldo.c") + if(CONFIG_SOC_GP_LDO_SUPPORTED) + list(APPEND srcs "ldo/esp_ldo.c" "ldo/esp_ldo_regulator.c") if(CONFIG_SPIRAM OR CONFIG_SOC_CLK_MPLL_SUPPORTED) list(APPEND srcs "ldo/esp_ldo_psram.c") endif() @@ -168,7 +168,7 @@ else() endif() idf_component_register(SRCS ${srcs} - INCLUDE_DIRS include include/soc include/soc/${target} dma/include + INCLUDE_DIRS include include/soc include/soc/${target} dma/include ldo/include PRIV_INCLUDE_DIRS port/include include/esp_private REQUIRES ${requires} PRIV_REQUIRES "${priv_requires}" diff --git a/components/esp_hw_support/ldo/esp_ldo_regulator.c b/components/esp_hw_support/ldo/esp_ldo_regulator.c new file mode 100644 index 0000000000..97dcc6f4bb --- /dev/null +++ b/components/esp_hw_support/ldo/esp_ldo_regulator.c @@ -0,0 +1,169 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "esp_log.h" +#include "esp_check.h" +#include "esp_heap_caps.h" +#include "soc/soc_caps.h" +#include "hal/ldo_ll.h" +#include "esp_ldo_regulator.h" + +static const char *TAG = "ldo"; + +typedef struct ldo_regulator_channel_t { + int chan_id; + int voltage_mv; + int ref_cnt; + struct { + uint32_t adjustable : 1; + } flags; +} ldo_regulator_channel_t; + +static portMUX_TYPE s_spinlock = portMUX_INITIALIZER_UNLOCKED; + +static const uint32_t s_ldo_channel_adjustable_mask = LDO_LL_ADJUSTABLE_CHAN_MASK; // each bit represents if the LDO channel is adjustable in hardware + +static ldo_regulator_channel_t s_ldo_channels[LDO_LL_UNIT_NUM] = { + [0 ... LDO_LL_UNIT_NUM - 1] = { + .chan_id = -1, + .voltage_mv = 0, + .ref_cnt = 0, + .flags.adjustable = 1, + }, +}; + +esp_err_t esp_ldo_acquire_channel(const esp_ldo_channel_config_t *config, esp_ldo_channel_handle_t *out_handle) +{ + ESP_RETURN_ON_FALSE(config, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + ESP_RETURN_ON_FALSE(ldo_ll_is_valid_ldo_id(config->chan_id), ESP_ERR_INVALID_ARG, TAG, "invalid ldo channel ID"); + ESP_RETURN_ON_FALSE(config->voltage_mv <= LDO_LL_MAX_VOLTAGE_MV, + ESP_ERR_INVALID_ARG, TAG, "invalid voltage value: %d", config->voltage_mv); + int unit_id = LDO_ID2UNIT(config->chan_id); + ldo_regulator_channel_t *channel = &s_ldo_channels[unit_id]; + + bool check_adjustable_constraint_valid = true; + bool check_voltage_constraint_valid = true; + portENTER_CRITICAL(&s_spinlock); + if (config->flags.adjustable) { + // the user wants to adjust it + // but the channel is marked as not adjustable + if (channel->flags.adjustable == 0) { + check_adjustable_constraint_valid = false; + } else if (channel->ref_cnt != 0) { + // or the channel is already in use by others + // but we don't allow different users to adjust the same LDO, in case they set to different voltages + // that's to say, if the LDO channel is adjustable, it can only have one reference + check_adjustable_constraint_valid = false; + } + } else { + // the user doesn't want to adjust the voltage + // but the channel is already in use by others + if (channel->ref_cnt != 0) { + if (channel->flags.adjustable) { + // we don't allow to have another non-adjustable user + check_adjustable_constraint_valid = false; + } else if (channel->voltage_mv != config->voltage_mv) { + // the voltage is different from us + check_voltage_constraint_valid = false; + } + } + } + if (check_voltage_constraint_valid && check_adjustable_constraint_valid) { + if (channel->ref_cnt == 0) { + // if the channel is not in use, we need to set the voltage and enable it + ldo_ll_set_output_voltage_mv(unit_id, config->voltage_mv); + ldo_ll_enable(unit_id, true); + } + // update the channel attributes + channel->ref_cnt++; + channel->voltage_mv = config->voltage_mv; + channel->flags.adjustable = config->flags.adjustable; + channel->chan_id = config->chan_id; + } + portEXIT_CRITICAL(&s_spinlock); + + ESP_RETURN_ON_FALSE(check_voltage_constraint_valid, ESP_ERR_INVALID_ARG, TAG, + "can't change the voltage for a non-adjustable channel, expect:%dmV, current:%dmV", + config->voltage_mv, channel->voltage_mv); + ESP_RETURN_ON_FALSE(check_adjustable_constraint_valid, ESP_ERR_INVALID_ARG, TAG, + "can't acquire the channel, already in use by others or not adjustable"); + + if (out_handle) { + *out_handle = channel; + } + return ESP_OK; +} + +esp_err_t esp_ldo_release_channel(esp_ldo_channel_handle_t chan) +{ + ESP_RETURN_ON_FALSE(chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + int unit_id = LDO_ID2UNIT(chan->chan_id); + + bool is_valid_state = true; + portENTER_CRITICAL(&s_spinlock); + if (chan->ref_cnt <= 0) { + is_valid_state = false; + } else { + chan->ref_cnt--; + if (chan->ref_cnt == 0) { + // if the channel is not in use, we need to disable it + ldo_ll_enable(unit_id, false); + // and reset the ldo voltage + chan->voltage_mv = 0; + chan->flags.adjustable = (s_ldo_channel_adjustable_mask & (1 << unit_id)) != 0; + chan->chan_id = -1; + } + } + portEXIT_CRITICAL(&s_spinlock); + + ESP_RETURN_ON_FALSE(is_valid_state, ESP_ERR_INVALID_STATE, TAG, "LDO channel released too many times"); + + return ESP_OK; +} + +esp_err_t esp_ldo_channel_adjust_voltage(esp_ldo_channel_handle_t chan, int voltage_mv) +{ + ESP_RETURN_ON_FALSE(chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + ESP_RETURN_ON_FALSE(chan->flags.adjustable, ESP_ERR_NOT_SUPPORTED, TAG, "LDO is not adjustable"); + // check if the voltage is within the valid range + ESP_RETURN_ON_FALSE(voltage_mv >= LDO_LL_MIN_VOLTAGE_MV && voltage_mv <= LDO_LL_MAX_VOLTAGE_MV, + ESP_ERR_INVALID_ARG, TAG, "invalid voltage value: %d", voltage_mv); + + // About Thread Safety: + // because there won't be more than 1 consumer for the same adjustable LDO channel (guaranteed by esp_ldo_acquire_channel) + // this function should be thread safe as long as the LDO channel handle is thread safe, + // i.e., the handle is not shared between threads without mutex protection + chan->voltage_mv = voltage_mv; + int unit_id = LDO_ID2UNIT(chan->chan_id); + ldo_ll_set_output_voltage_mv(unit_id, voltage_mv); + + return ESP_OK; +} + +esp_err_t esp_ldo_dump(FILE *stream) +{ + char line[100]; + fprintf(stream, "ESP LDO Channel State:\n"); + fprintf(stream, "%-5s %-5s %-10s %-12s %-5s\n", "Index", "ID", "ref_cnt", "voltage_mv", "adjustable"); + for (int i = 0; i < LDO_LL_UNIT_NUM; i++) { + char *buf = line; + size_t len = sizeof(line); + memset(line, 0x0, len); + snprintf(buf, len, "%-5d %-5d %-10d %-12d %-5s\n", + i, + s_ldo_channels[i].chan_id, + s_ldo_channels[i].ref_cnt, + s_ldo_channels[i].voltage_mv, + s_ldo_channels[i].flags.adjustable ? "yes" : "no"); + fputs(line, stream); + } + return ESP_OK; +} diff --git a/components/esp_hw_support/ldo/include/esp_ldo_regulator.h b/components/esp_hw_support/ldo/include/esp_ldo_regulator.h new file mode 100644 index 0000000000..0540541003 --- /dev/null +++ b/components/esp_hw_support/ldo/include/esp_ldo_regulator.h @@ -0,0 +1,90 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "esp_err.h" +#include "hal/ldo_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Type of LDO regulator channel handle + */ +typedef struct ldo_regulator_channel_t *esp_ldo_channel_handle_t; + +/** + * @brief LDO channel configurations + */ +typedef struct { + int chan_id; /*!< You must set the LDO channel ID according to the datasheet, e.g., set it to 1 for LDO_VO1 */ + int voltage_mv; /*!< The voltage value to be set to the LDO channel */ + + /// Extra flags of a LDO channel + struct ldo_extra_flags { + uint32_t adjustable : 1; /*!< Whether the LDO channel is adjustable, and the voltage can be updated by `esp_ldo_channel_adjust_voltage` */ + } flags; /*!< Flags for the LDO channel */ +} esp_ldo_channel_config_t; + +/** + * @brief Acquire an LDO channel with the specified configuration + * + * @note This function can't automatically search a LDO channel for you, you must specify a LDO channel ID manually, based on your schematic. + * @note The same channel can be acquired multiple times in different places of the application code, however, + * if the LDO channel is adjustable, you can't acquire it multiple times, in case user A changes the voltage and breaks the voltage setting of user B. + * @note You should release the channel by `esp_ldo_release_channel` when it's no longer needed. + * + * @param[in] config The configuration of the LDO channel + * @param[out] out_handle The returned LDO channel handle + * @return + * - ESP_OK: Acquire the LDO channel successfully + * - ESP_ERR_INVALID_ARG: Acquire the LDO channel failed due to invalid arguments + * - ESP_FAIL: Acquire the LDO channel failed due to other reasons + */ +esp_err_t esp_ldo_acquire_channel(const esp_ldo_channel_config_t *config, esp_ldo_channel_handle_t *out_handle); + +/** + * @brief Release the LDO channel + * + * @param[in] chan The LDO channel handle returned from `esp_ldo_acquire_channel` + * @return + * - ESP_OK: Release the LDO channel successfully + * - ESP_ERR_INVALID_ARG: Release the LDO channel failed due to invalid arguments + * - ESP_ERR_INVALID_STATE: Release the LDO channel failed due to invalid state, e.g., the channel handle is double released + * - ESP_FAIL: Release the LDO channel failed due to other reasons + */ +esp_err_t esp_ldo_release_channel(esp_ldo_channel_handle_t chan); + +/** + * @brief Adjust the voltage of the LDO channel + * + * @param[in] chan The LDO channel handle returned from `esp_ldo_acquire_channel` + * @param[in] voltage_mv The voltage value to be set to the LDO channel, in millivolts + * @return + * - ESP_OK: Adjust the voltage of the LDO channel successfully + * - ESP_ERR_INVALID_ARG: Adjust the voltage of the LDO channel failed due to invalid arguments + * - ESP_ERR_NOT_SUPPORTED: Adjust the voltage of the LDO channel failed due to the channel is not adjustable + * - ESP_FAIL: Adjust the voltage of the LDO channel failed due to other reasons + */ +esp_err_t esp_ldo_channel_adjust_voltage(esp_ldo_channel_handle_t chan, int voltage_mv); + +/** + * @brief Dump LDO channel status to the specified stream + * + * @param[in] stream IO stream. Can be stdout, stderr, or a file/string stream. + * @return + * - ESP_OK: Dump the LDO channel status successfully + * - ESP_FAIL: Dump the LDO channel status failed + */ +esp_err_t esp_ldo_dump(FILE *stream); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hw_support/ldo/linker.lf b/components/esp_hw_support/ldo/linker.lf deleted file mode 100644 index 2d1732faca..0000000000 --- a/components/esp_hw_support/ldo/linker.lf +++ /dev/null @@ -1,4 +0,0 @@ -[mapping:ldo_driver] -archive: libesp_hw_support.a -entries: - esp_ldo: esp_ldo_init_unit_early (noflash) diff --git a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/CMakeLists.txt b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/CMakeLists.txt index 3ff1c7fabf..daa7c071a1 100644 --- a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/CMakeLists.txt +++ b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/CMakeLists.txt @@ -9,7 +9,7 @@ set(srcs "test_app_main.c" "test_key_mgr.c" ) -if(CONFIG_SOC_MULTI_USAGE_LDO_SUPPORTED) +if(CONFIG_SOC_GP_LDO_SUPPORTED) list(APPEND srcs "test_ldo.c") endif() diff --git a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_ldo.c b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_ldo.c index 546f9baed4..39f57f1b5c 100644 --- a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_ldo.c +++ b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_ldo.c @@ -1,74 +1,89 @@ /* - * SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include "sdkconfig.h" -#include "unity.h" -#include "esp_private/esp_ldo.h" - #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "unity.h" +#include "esp_ldo_regulator.h" -TEST_CASE("LDO unit early / normal allocation", "[LDO]") +TEST_CASE("LDO channel acquire and release (no adjustable)", "[LDO]") { - esp_ldo_unit_init_cfg_t init_early_unit_cfg = { - .unit_id = LDO_UNIT_3, - .cfg = { - .voltage_mv = 1800, - }, - .flags.enable_unit = true, + esp_ldo_channel_handle_t success_ldo_chans[3] = {}; + esp_ldo_channel_handle_t fail_ldo_chan = NULL; + esp_ldo_channel_config_t ldo_chan_config = { + .chan_id = 4, + .voltage_mv = 1800, }; - esp_ldo_unit_handle_t early_unit = esp_ldo_init_unit_early(&init_early_unit_cfg); - TEST_ASSERT(esp_ldo_enable_unit(early_unit) == ESP_ERR_INVALID_STATE); - TEST_ESP_OK(esp_ldo_disable_unit(early_unit)); - - esp_ldo_unit_handle_t unit = NULL; - esp_ldo_unit_init_cfg_t init_unit_cfg = { - .unit_id = LDO_UNIT_4, - .cfg = { - .voltage_mv = 2500, - }, + for (int i = 0; i < 3; i++) { + TEST_ESP_OK(esp_ldo_acquire_channel(&ldo_chan_config, &success_ldo_chans[i])); + } + TEST_ASSERT_EQUAL(success_ldo_chans[0], success_ldo_chans[1]); + TEST_ASSERT_EQUAL(success_ldo_chans[0], success_ldo_chans[2]); + // can't acquire with a different voltage + ldo_chan_config.voltage_mv = 3300; + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_ldo_acquire_channel(&ldo_chan_config, &fail_ldo_chan)); + // the channel has been acquired as "not adjustable" before, so we can't acquire it as "adjustable" again + ldo_chan_config = (esp_ldo_channel_config_t) { + .chan_id = 4, + .voltage_mv = 1800, + .flags.adjustable = true, }; - TEST_ESP_OK(esp_ldo_init_unit(&init_unit_cfg, &unit)); - TEST_ESP_OK(esp_ldo_enable_unit(unit)); - TEST_ESP_OK(esp_ldo_disable_unit(unit)); + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_ldo_acquire_channel(&ldo_chan_config, &fail_ldo_chan)); - init_unit_cfg.flags.shared_ldo = true; - esp_ldo_unit_handle_t shared_unit = NULL; - TEST_ESP_OK(esp_ldo_init_unit(&init_unit_cfg, &shared_unit)); + // can't change the voltage for a non-adjustable channel + TEST_ESP_ERR(ESP_ERR_NOT_SUPPORTED, esp_ldo_channel_adjust_voltage(success_ldo_chans[0], 3300)); - TEST_ESP_OK(esp_ldo_deinit_unit(early_unit)); - TEST_ESP_OK(esp_ldo_deinit_unit(shared_unit)); - TEST_ESP_OK(esp_ldo_deinit_unit(unit)); + for (int i = 0; i < 3; i++) { + TEST_ESP_OK(esp_ldo_release_channel(success_ldo_chans[i])); + } + TEST_ESP_ERR(ESP_ERR_INVALID_STATE, esp_ldo_release_channel(success_ldo_chans[0])); } -TEST_CASE("LDO unit output", "[LDO][mannual][ignore]") +TEST_CASE("LDO channel acquire and release (adjustable)", "[LDO]") { - esp_ldo_unit_init_cfg_t early_unit_cfg = { - .unit_id = LDO_UNIT_2, - .cfg = { - .voltage_mv = 1800, - }, - .flags.shared_ldo = true, - .flags.enable_unit = true, + esp_ldo_channel_handle_t success_ldo_chan = NULL; + esp_ldo_channel_handle_t fail_ldo_chan = NULL; + esp_ldo_channel_config_t ldo_chan_config = { + .chan_id = 4, + .voltage_mv = 1800, + .flags.adjustable = true, }; - esp_ldo_unit_handle_t early_unit2 = esp_ldo_init_unit_early(&early_unit_cfg); - assert(early_unit2); + TEST_ESP_OK(esp_ldo_acquire_channel(&ldo_chan_config, &success_ldo_chan)); - early_unit_cfg.unit_id = LDO_UNIT_3; - early_unit_cfg.cfg.voltage_mv = 3300; - esp_ldo_unit_handle_t early_unit3 = esp_ldo_init_unit_early(&early_unit_cfg); - assert(early_unit3); + // can't acquire multiple handles for the same adjustable channel + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_ldo_acquire_channel(&ldo_chan_config, &fail_ldo_chan)); + // even we acquire another copy as non-adjustable, it's still not allowed + ldo_chan_config.flags.adjustable = false; + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_ldo_acquire_channel(&ldo_chan_config, &fail_ldo_chan)); - early_unit_cfg.unit_id = LDO_UNIT_4; - early_unit_cfg.cfg.voltage_mv = 1100; - esp_ldo_unit_handle_t early_unit4 = esp_ldo_init_unit_early(&early_unit_cfg); - assert(early_unit4); + // can change voltage for an adjustable channel + TEST_ESP_OK(esp_ldo_channel_adjust_voltage(success_ldo_chan, 3300)); + TEST_ESP_OK(esp_ldo_release_channel(success_ldo_chan)); +} - esp_ldo_usage_dump(stdout); +TEST_CASE("LDO channel state dump", "[LDO][manual][ignore]") +{ + esp_ldo_channel_handle_t success_ldo_chans[3] = {}; + esp_ldo_channel_config_t ldo_chan_config = { + .chan_id = 2, + .voltage_mv = 1800, + }; + TEST_ESP_OK(esp_ldo_acquire_channel(&ldo_chan_config, &success_ldo_chans[0])); + + ldo_chan_config.chan_id = 3; + ldo_chan_config.voltage_mv = 2500; + TEST_ESP_OK(esp_ldo_acquire_channel(&ldo_chan_config, &success_ldo_chans[1])); + + ldo_chan_config.chan_id = 4; + ldo_chan_config.voltage_mv = 1100; + TEST_ESP_OK(esp_ldo_acquire_channel(&ldo_chan_config, &success_ldo_chans[2])); + + esp_ldo_dump(stdout); while (1) { vTaskDelay(1); diff --git a/components/esp_lcd/test_apps/mipi_dsi_lcd/main/test_mipi_dsi_board.c b/components/esp_lcd/test_apps/mipi_dsi_lcd/main/test_mipi_dsi_board.c index 56867df2f8..b9168daa38 100644 --- a/components/esp_lcd/test_apps/mipi_dsi_lcd/main/test_mipi_dsi_board.c +++ b/components/esp_lcd/test_apps/mipi_dsi_lcd/main/test_mipi_dsi_board.c @@ -6,25 +6,21 @@ #include "unity.h" #include "test_mipi_dsi_board.h" -#include "esp_private/esp_ldo.h" +#include "esp_ldo_regulator.h" -static esp_ldo_unit_handle_t phy_pwr_unit = NULL; +static esp_ldo_channel_handle_t ldo_phy_chan = NULL; void test_bsp_enable_dsi_phy_power(void) { // Turn on the power for MIPI DSI PHY, so it can go from "No Power" state to "Shutdown" state - esp_ldo_unit_init_cfg_t ldo_cfg = { - .unit_id = TEST_MIPI_DSI_PHY_PWR_LDO_UNIT, - .cfg = { - .voltage_mv = TEST_MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV, - }, + esp_ldo_channel_config_t ldo_cfg = { + .chan_id = TEST_MIPI_DSI_PHY_PWR_LDO_CHAN, + .voltage_mv = TEST_MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV, }; - TEST_ESP_OK(esp_ldo_init_unit(&ldo_cfg, &phy_pwr_unit)); - TEST_ESP_OK(esp_ldo_enable_unit(phy_pwr_unit)); + TEST_ESP_OK(esp_ldo_acquire_channel(&ldo_cfg, &ldo_phy_chan)); } void test_bsp_disable_dsi_phy_power(void) { - TEST_ESP_OK(esp_ldo_disable_unit(phy_pwr_unit)); - TEST_ESP_OK(esp_ldo_deinit_unit(phy_pwr_unit)); + TEST_ESP_OK(esp_ldo_release_channel(ldo_phy_chan)); } diff --git a/components/esp_lcd/test_apps/mipi_dsi_lcd/main/test_mipi_dsi_board.h b/components/esp_lcd/test_apps/mipi_dsi_lcd/main/test_mipi_dsi_board.h index b7543de915..d1e57d9a47 100644 --- a/components/esp_lcd/test_apps/mipi_dsi_lcd/main/test_mipi_dsi_board.h +++ b/components/esp_lcd/test_apps/mipi_dsi_lcd/main/test_mipi_dsi_board.h @@ -20,7 +20,7 @@ extern "C" { #define MIPI_DSI_LCD_VBP 16 #define MIPI_DSI_LCD_VFP 16 -#define TEST_MIPI_DSI_PHY_PWR_LDO_UNIT 3 +#define TEST_MIPI_DSI_PHY_PWR_LDO_CHAN 3 #define TEST_MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV 2500 void test_bsp_enable_dsi_phy_power(void); diff --git a/components/hal/esp32p4/include/hal/ldo_ll.h b/components/hal/esp32p4/include/hal/ldo_ll.h index 5e58532039..d470107d5c 100644 --- a/components/hal/esp32p4/include/hal/ldo_ll.h +++ b/components/hal/esp32p4/include/hal/ldo_ll.h @@ -18,7 +18,6 @@ #include "hal/assert.h" #include "soc/pmu_struct.h" - #ifdef __cplusplus extern "C" { #endif @@ -28,6 +27,11 @@ extern "C" { */ #define LDO_LL_UNIT_NUM 4 +#define LDO_LL_ADJUSTABLE_CHAN_MASK 0x0F // all the 4 channels can be adjustable + +#define LDO_LL_MAX_VOLTAGE_MV 3300 +#define LDO_LL_MIN_VOLTAGE_MV 500 + /** * LDO LL macros, these macros are in the unit of mV */ diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 63fc75006d..df74111cc2 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -227,7 +227,7 @@ config SOC_SPI_FLASH_SUPPORTED bool default y -config SOC_MULTI_USAGE_LDO_SUPPORTED +config SOC_GP_LDO_SUPPORTED bool default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 51998f17ca..2ccdeb3908 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -85,7 +85,7 @@ #define SOC_SPI_FLASH_SUPPORTED 1 // #define SOC_TOUCH_SENSOR_SUPPORTED 1 //TODO: IDF-7477 // #define SOC_RNG_SUPPORTED 1 //TODO: IDF-6522 -#define SOC_MULTI_USAGE_LDO_SUPPORTED 1 +#define SOC_GP_LDO_SUPPORTED 1 // General purpose LDO // #define SOC_PPA_SUPPORTED 1 //TODO: IDF-6878 #define SOC_LIGHT_SLEEP_SUPPORTED 1 // #define SOC_DEEP_SLEEP_SUPPORTED 1 //TODO: IDF-7529 From 7de228d0a3f6e4b163838cea767a6f3e80bdb6d2 Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 18 Mar 2024 14:30:59 +0800 Subject: [PATCH 2/6] docs(ldo): add api reference for ldo regulator driver --- docs/conf_common.py | 3 + docs/doxygen/Doxyfile | 1 + .../api-reference/peripherals/dedic_gpio.rst | 2 +- docs/en/api-reference/peripherals/index.rst | 1 + .../peripherals/ldo_regulator.rst | 59 +++++++++++++++++++ .../api-reference/peripherals/dedic_gpio.rst | 2 +- .../zh_CN/api-reference/peripherals/index.rst | 1 + .../peripherals/ldo_regulator.rst | 59 +++++++++++++++++++ 8 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 docs/en/api-reference/peripherals/ldo_regulator.rst create mode 100644 docs/zh_CN/api-reference/peripherals/ldo_regulator.rst diff --git a/docs/conf_common.py b/docs/conf_common.py index 51c4702530..cf7a7f7cb7 100644 --- a/docs/conf_common.py +++ b/docs/conf_common.py @@ -102,6 +102,8 @@ DAC_DOCS = ['api-reference/peripherals/dac.rst'] ETM_DOCS = ['api-reference/peripherals/etm.rst'] +LDO_DOCS = ['api-reference/peripherals/ldo_regulator.rst'] + TEMP_SENSOR_DOCS = ['api-reference/peripherals/temp_sensor.rst'] TOUCH_SENSOR_DOCS = ['api-reference/peripherals/touch_pad.rst'] @@ -251,6 +253,7 @@ conditional_include_dict = {'SOC_BT_SUPPORTED':BT_DOCS, 'SOC_SPI_SUPPORT_SLAVE_HD_VER2':SPI_SLAVE_HD_DOCS, 'SOC_WIFI_NAN_SUPPORT':NAN_DOCS, 'SOC_JPEG_CODEC_SUPPORTED':JPEG_DOCS, + 'SOC_GP_LDO_SUPPORTED':LDO_DOCS, 'esp32':ESP32_DOCS, 'esp32s2':ESP32S2_DOCS, 'esp32s3':ESP32S3_DOCS, diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index 278eb61808..98e9c5237f 100644 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -173,6 +173,7 @@ INPUT = \ $(PROJECT_PATH)/components/esp_hw_support/include/esp_mac.h \ $(PROJECT_PATH)/components/esp_hw_support/include/esp_random.h \ $(PROJECT_PATH)/components/esp_hw_support/include/esp_sleep.h \ + $(PROJECT_PATH)/components/esp_hw_support/ldo/include/esp_ldo_regulator.h \ $(PROJECT_PATH)/components/esp_lcd/include/esp_lcd_panel_io.h \ $(PROJECT_PATH)/components/esp_lcd/include/esp_lcd_panel_ops.h \ $(PROJECT_PATH)/components/esp_lcd/include/esp_lcd_panel_vendor.h \ diff --git a/docs/en/api-reference/peripherals/dedic_gpio.rst b/docs/en/api-reference/peripherals/dedic_gpio.rst index a568c98289..bdb7f4a3f3 100644 --- a/docs/en/api-reference/peripherals/dedic_gpio.rst +++ b/docs/en/api-reference/peripherals/dedic_gpio.rst @@ -156,7 +156,7 @@ Application Example .. list:: - * Emulate UART/I2C/SPI peripherals in assembly with dedicate CPU instructions designed for manipulating the GPIOs: :example:`peripherals/dedicated_gpio`. + * Software emulation (bit banging) of the UART/I2C/SPI protocols in assembly using the dedicated GPIOs and their associated CPU instructions: :example:`peripherals/dedicated_gpio`. :SOC_DEDIC_GPIO_HAS_INTERRUPT: * Matrix keyboard example based on dedicated GPIO: :example:`peripherals/gpio/matrix_keyboard`. diff --git a/docs/en/api-reference/peripherals/index.rst b/docs/en/api-reference/peripherals/index.rst index 5004f52370..e03d03f471 100644 --- a/docs/en/api-reference/peripherals/index.rst +++ b/docs/en/api-reference/peripherals/index.rst @@ -22,6 +22,7 @@ Peripherals API i2c :SOC_I2S_SUPPORTED: i2s lcd/index + :SOC_GP_LDO_SUPPORTED: ldo_regulator ledc :SOC_MCPWM_SUPPORTED: mcpwm :SOC_PARLIO_SUPPORTED: parlio diff --git a/docs/en/api-reference/peripherals/ldo_regulator.rst b/docs/en/api-reference/peripherals/ldo_regulator.rst new file mode 100644 index 0000000000..3734c91894 --- /dev/null +++ b/docs/en/api-reference/peripherals/ldo_regulator.rst @@ -0,0 +1,59 @@ +Low Dropout Voltage Regulator (LDO) +=================================== + +:link_to_translation:`zh_CN:[中文]` + +{IDF_TARGET_LDO_CHANNELS:default="unknown", esp32p4="4"} + +Introduction +------------ + +The {IDF_TARGET_NAME} chip internally integrates {IDF_TARGET_LDO_CHANNELS} channels of low-dropout voltage regulators (LDOs). Each channel's voltage is programmable. In our hardware reference designs, some of these LDO outputs are typically used to power the internal Flash and PSRAM, while the remaining LDOs can be used to supply external devices. + +.. note:: + + It's essential to read the manual first and ensure that the required current does not exceed the chip's specifications. + +Functional Overview +------------------- + +The description of the LDO driver is divided into the following sections: + +- :ref:`ldo-channel-acquisition` - Introduces the types of LDO channels and how to apply for LDO channel resources. +- :ref:`ldo-adjust-voltage` - Describes how to adjust the voltage of the LDO channel. + +.. _ldo-channel-acquisition: + +LDO Channel Acquisition +^^^^^^^^^^^^^^^^^^^^^^^ + +LDO channels can be classified into two types: fixed voltage and adjustable voltage. For a fixed voltage channel, it allows multiple users to simultaneously use it (in software, we allow a variable to have multiple immutable references ). However, for an adjustable voltage channel, only one user is allowed to use it at a time (in software, we don't allow a variable to have multiple mutable references or coexistence of mutable and immutable references). + +In the driver, the LDO channel is represented by the :cpp:type:`esp_ldo_channel_handle_t`. You can use the :cpp:func:`esp_ldo_acquire_channel` function to request LDO channel resources. Upon successful acquisition, a handle for the LDO channel will be returned, which can be used for subsequent voltage adjustment operations. When applying for a channel, the :cpp:type:`esp_ldo_channel_config_t` structure is used to specify the basic information of the LDO channel, including the channel ID, the desired output voltage, and whether the voltage can be dynamically adjusted. + +- :cpp:member:`esp_ldo_channel_config_t::chan_id` - LDO channels are uniquely identified by a label, which is used to distinguish different LDO channels. Please note that this information needs to be determined based on the circuit schematic and chip datasheet. For example, an LDO channel labeled as ``LDO_VO3`` corresponds to an ID of ``3``. +- :cpp:member:`esp_ldo_channel_config_t::voltage_mv` - The desired output voltage of the LDO channel, in millivolts. +- :cpp:member:`esp_ldo_channel_config_t::ldo_extra_flags::adjustable` - Whether the LDO channel's output voltage can be dynamically adjusted. Only when it is set to `true`, can the :cpp:func:`esp_ldo_channel_adjust_voltage` function be used to dynamically adjust the output voltage. + +Since multiple users are allowed to use a fixed voltage LDO channel simultaneously, the driver internally maintains a reference counter. The LDO channel will be automatically closed when the last user releases the LDO channel resources. The function to release LDO channel resources is :cpp:func:`esp_ldo_release_channel`. Additionally, it is important to note that the acquisition and release of LDO channels should appear in pairs during usage. + +.. _ldo-adjust-voltage: + +LDO Voltage Adjustment +^^^^^^^^^^^^^^^^^^^^^^ + +:cpp:func:`esp_ldo_channel_adjust_voltage` function is used to adjust the output voltage of an LDO channel at runtime. However, please note that this function can only be used for LDO channels with adjustable voltage. Attempting to use this function on a fixed voltage LDO channel will result in an error. + +Also, it is important to keep in mind that due to hardware limitations, the LDO channel voltage may have a deviation of approximately 50-100mV. Therefore, it is not advisable to rely on the LDO channel's output voltage for precise analog control. + +Application Examples +-------------------- + +.. list:: + + :SOC_MIPI_DSI_SUPPORTED: * Use the internal LDO channel to power up the MIPI DPHY: :example:`peripherals/lcd/mipi_dsi` + +API Reference +------------- + +.. include-build-file:: inc/esp_ldo_regulator.inc diff --git a/docs/zh_CN/api-reference/peripherals/dedic_gpio.rst b/docs/zh_CN/api-reference/peripherals/dedic_gpio.rst index f55d2de56b..e3ce374f43 100644 --- a/docs/zh_CN/api-reference/peripherals/dedic_gpio.rst +++ b/docs/zh_CN/api-reference/peripherals/dedic_gpio.rst @@ -156,7 +156,7 @@ GPIO 捆绑包操作 .. list:: - * 通过汇编代码使用专用的 CPU 指令来操作 GPIO 以模拟 UART/I2C/SPI 外设 :example:`peripherals/dedicated_gpio`. + * 通过汇编代码使用专用的 CPU 指令来操作 GPIO 以模拟 UART/I2C/SPI 协议(Bit Banging) :example:`peripherals/dedicated_gpio`. :SOC_DEDIC_GPIO_HAS_INTERRUPT: * 基于专用 GPIO 驱动的矩阵键盘::example:`peripherals/gpio/matrix_keyboard`. diff --git a/docs/zh_CN/api-reference/peripherals/index.rst b/docs/zh_CN/api-reference/peripherals/index.rst index 55e29abe38..d5e237ec42 100644 --- a/docs/zh_CN/api-reference/peripherals/index.rst +++ b/docs/zh_CN/api-reference/peripherals/index.rst @@ -22,6 +22,7 @@ i2c :SOC_I2S_SUPPORTED: i2s lcd/index + :SOC_GP_LDO_SUPPORTED: ldo_regulator ledc :SOC_MCPWM_SUPPORTED: mcpwm :SOC_PARLIO_SUPPORTED: parlio diff --git a/docs/zh_CN/api-reference/peripherals/ldo_regulator.rst b/docs/zh_CN/api-reference/peripherals/ldo_regulator.rst new file mode 100644 index 0000000000..ab8634e5c2 --- /dev/null +++ b/docs/zh_CN/api-reference/peripherals/ldo_regulator.rst @@ -0,0 +1,59 @@ +低压差线性稳压器 (LDO) +====================== + +:link_to_translation:`en:[English]` + +{IDF_TARGET_LDO_CHANNELS:default="unknown", esp32p4="4"} + +简介 +---- + +{IDF_TARGET_NAME} 芯片内部集成了 {IDF_TARGET_LDO_CHANNELS} 路低压差线性稳压器 (LDO),每路的电压都是可编程调节的。在硬件的参考设计中,我们通常会将其中一些的 LDO 输出作为内部 Flash 和 PSRAM 的电源,剩余的一些 LDO 可以用于给外部设备供电。 + +.. note:: + + 使用前请阅读手册,确保你需要的电流不会超过芯片的规格。 + +功能概述 +-------- + +下文将分节介绍 LDO 驱动的功能: + +- :ref:`ldo-channel-acquisition` - 介绍LDO通道的种类以及如何申请 LDO 通道资源 +- :ref:`ldo-adjust-voltage` - 介绍如何调节 LDO 通道的输出电压 + +.. _ldo-channel-acquisition: + +LDO 通道申请 +^^^^^^^^^^^^ + +LDO 通道可以分为两种,一种是电压固定的,另一种是电压可调的。对于同一个输出通道,如果电压固定,那么可以允许有多个用户同时使用(软件允许一个变量拥有多个不可变引用)。如果电压可调,那么只能允许一个用户使用(软件上不允许一个变量有多个可变引用或者可变和不可变引用同时存在)。 + +LDO 通道在驱动软件中由 :cpp:type:`esp_ldo_channel_handle_t` 句柄表示。申请 LDO 通道资源的函数是 :cpp:func:`esp_ldo_acquire_channel`。申请成功后,会返回一个 LDO 通道的句柄,这个句柄可以用于后续的电压调节操作。在申请通道的时候,我们需要通过 :cpp:type:`esp_ldo_channel_config_t` 结构体来指定 LDO 通道的基本信息,包括通道 ID,期望的输出电压,以及电压是否可以动态调节。 + +- :cpp:member:`esp_ldo_channel_config_t::chan_id` - LDO 通道的唯一标记,用于区分不同的 LDO 通道。注意,这需要你根据电路原理图和芯片数据手册来确定。比如,一个标记着 "LDO_VO3" 的 LDO 通道,对应的 ID 是 3。 +- :cpp:member:`esp_ldo_channel_config_t::voltage_mv` - 期望的输出电压,单位是毫伏。 +- :cpp:member:`esp_ldo_channel_config_t::ldo_extra_flags::adjustable` - 是否允许调节输出电压。只有设置为 `true`,才允许使用 :cpp:func:`esp_ldo_channel_adjust_voltage` 函数来动态地调节输出电压。 + +由于允许多个用户同时使用固定电压的 LDO 通道,所以驱动内部会维持一个引用计数器。当最后一个用户释放 LDO 通道资源时,LDO 通道会被自动关闭。释放 LDO 通道资源的函数是 :cpp:func:`esp_ldo_release_channel`。另外还需要注意,申请和释放 LDO 通道在使用的时候需要成对出现。 + +.. _ldo-adjust-voltage: + +LDO 通道电压调节 +^^^^^^^^^^^^^^^^ + +:cpp:func:`esp_ldo_channel_adjust_voltage` 函数用来在运行时调整 LDO 通道的输出电压。但是,这个函数只能用于可调节电压的 LDO 通道,否则会返回错误。 + +注意,由于硬件限制,LDO 通道电压的精度可能会 50~100mV 左右的偏差,请勿依赖于 LDO 通道的输出电压来进行精确的模拟量控制。 + +应用示例 +-------- + +.. list:: + + :SOC_MIPI_DSI_SUPPORTED: * Use the internal LDO channel to power up the MIPI DPHY: :example:`peripherals/lcd/mipi_dsi` + +API 参考 +-------- + +.. include-build-file:: inc/esp_ldo_regulator.inc From 56b40a028d35ad7ee0bbd303aafe96f32da6db96 Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 25 Mar 2024 18:27:17 +0800 Subject: [PATCH 3/6] change(mipi): use public ldo driver for powering dphy --- .../lcd/mipi_dsi/main/idf_component.yml | 2 +- .../mipi_dsi/main/mipi_dsi_lcd_example_main.c | 22 ++++++++----------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/examples/peripherals/lcd/mipi_dsi/main/idf_component.yml b/examples/peripherals/lcd/mipi_dsi/main/idf_component.yml index 8e0bcd79b5..4cf2c942b0 100644 --- a/examples/peripherals/lcd/mipi_dsi/main/idf_component.yml +++ b/examples/peripherals/lcd/mipi_dsi/main/idf_component.yml @@ -1,3 +1,3 @@ dependencies: - lvgl/lvgl: "~9.0.0" + lvgl/lvgl: "^9.0.0" esp_lcd_ili9881c: "*" diff --git a/examples/peripherals/lcd/mipi_dsi/main/mipi_dsi_lcd_example_main.c b/examples/peripherals/lcd/mipi_dsi/main/mipi_dsi_lcd_example_main.c index 48910abb2a..292266adb7 100644 --- a/examples/peripherals/lcd/mipi_dsi/main/mipi_dsi_lcd_example_main.c +++ b/examples/peripherals/lcd/mipi_dsi/main/mipi_dsi_lcd_example_main.c @@ -9,11 +9,11 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" -#include "esp_private/esp_ldo.h" #include "esp_timer.h" #include "esp_lcd_panel_ops.h" #include "esp_lcd_mipi_dsi.h" #include "esp_lcd_ili9881c.h" +#include "esp_ldo_regulator.h" #include "driver/gpio.h" #include "esp_err.h" #include "esp_log.h" @@ -43,8 +43,8 @@ static const char *TAG = "example"; //////////////////// Please update the following configuration according to your Board Design ////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// The "VDD_MIPI_DPHY" should be supplied with 2.5V, it can source from the integrated LDO unit or from external LDO chip -#define EXAMPLE_MIPI_DSI_PHY_PWR_LDO_UNIT 3 // LDO_VO3 is connected to VDD_MIPI_DPHY +// The "VDD_MIPI_DPHY" should be supplied with 2.5V, it can source from the internal LDO regulator or from external LDO chip +#define EXAMPLE_MIPI_DSI_PHY_PWR_LDO_CHAN 3 // LDO_VO3 is connected to VDD_MIPI_DPHY #define EXAMPLE_MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV 2500 #define EXAMPLE_LCD_BK_LIGHT_ON_LEVEL 1 #define EXAMPLE_LCD_BK_LIGHT_OFF_LEVEL !EXAMPLE_LCD_BK_LIGHT_ON_LEVEL @@ -126,17 +126,13 @@ static bool example_notify_lvgl_flush_ready(esp_lcd_panel_handle_t panel, esp_lc static void example_bsp_enable_dsi_phy_power(void) { // Turn on the power for MIPI DSI PHY, so it can go from "No Power" state to "Shutdown" state - esp_ldo_unit_handle_t phy_pwr_unit = NULL; -#if EXAMPLE_MIPI_DSI_PHY_PWR_LDO_UNIT > 0 - esp_ldo_unit_init_cfg_t ldo_cfg = { - .unit_id = EXAMPLE_MIPI_DSI_PHY_PWR_LDO_UNIT, - .cfg = { - .voltage_mv = EXAMPLE_MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV, - }, + esp_ldo_channel_handle_t ldo_mipi_phy = NULL; +#ifdef EXAMPLE_MIPI_DSI_PHY_PWR_LDO_CHAN + esp_ldo_channel_config_t ldo_mipi_phy_config = { + .chan_id = EXAMPLE_MIPI_DSI_PHY_PWR_LDO_CHAN, + .voltage_mv = EXAMPLE_MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV, }; - ESP_ERROR_CHECK(esp_ldo_init_unit(&ldo_cfg, &phy_pwr_unit)); - ESP_ERROR_CHECK(esp_ldo_enable_unit(phy_pwr_unit)); - + ESP_ERROR_CHECK(esp_ldo_acquire_channel(&ldo_mipi_phy_config, &ldo_mipi_phy)); ESP_LOGI(TAG, "MIPI DSI PHY Powered on"); #endif } From 4c2569e2fc1570bb5bbf6520759d96946be7532e Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 25 Mar 2024 15:41:20 +0800 Subject: [PATCH 4/6] change(sdmmc): update ldo acquire driver to new API --- components/esp_driver_sdmmc/src/sdmmc_host.c | 2 -- .../sdmmc_test_boards/sdmmc_test_board.c | 2 +- components/sdmmc/CMakeLists.txt | 2 +- .../include/sd_pwr_ctrl_by_on_chip_ldo.h | 2 +- .../sd_pwr_ctrl/sd_pwr_ctrl_by_on_chip_ldo.c | 24 ++++++++----------- .../sd_card/sdmmc/main/sd_card_example_main.c | 2 +- 6 files changed, 14 insertions(+), 20 deletions(-) diff --git a/components/esp_driver_sdmmc/src/sdmmc_host.c b/components/esp_driver_sdmmc/src/sdmmc_host.c index 05b94f5839..c6a552eb37 100644 --- a/components/esp_driver_sdmmc/src/sdmmc_host.c +++ b/components/esp_driver_sdmmc/src/sdmmc_host.c @@ -19,7 +19,6 @@ #include "driver/gpio.h" #include "driver/sdmmc_host.h" #include "esp_private/periph_ctrl.h" -#include "esp_private/esp_ldo.h" #include "sdmmc_private.h" #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" @@ -55,7 +54,6 @@ typedef struct slot_ctx_t { size_t slot_width; sdmmc_slot_io_info_t slot_gpio_num; bool use_gpio_matrix; - esp_ldo_unit_handle_t ldo_unit; } slot_ctx_t; /** diff --git a/components/esp_driver_sdmmc/test_apps/sd_test_utils/components/sdmmc_test_boards/sdmmc_test_board.c b/components/esp_driver_sdmmc/test_apps/sd_test_utils/components/sdmmc_test_boards/sdmmc_test_board.c index 5b41982941..ab8adcbfd9 100644 --- a/components/esp_driver_sdmmc/test_apps/sd_test_utils/components/sdmmc_test_boards/sdmmc_test_board.c +++ b/components/esp_driver_sdmmc/test_apps/sd_test_utils/components/sdmmc_test_boards/sdmmc_test_board.c @@ -39,7 +39,7 @@ void sdmmc_test_board_get_config_sdmmc(int slot_index, sdmmc_host_t *out_host_co #define SDMMC_PWR_LDO_CHANNEL 4 sd_pwr_ctrl_ldo_config_t ldo_config = { - .ldo_unit_id = SDMMC_PWR_LDO_CHANNEL, + .ldo_chan_id = SDMMC_PWR_LDO_CHANNEL, }; sd_pwr_ctrl_handle_t pwr_ctrl_handle = NULL; diff --git a/components/sdmmc/CMakeLists.txt b/components/sdmmc/CMakeLists.txt index a1a6d80c68..df25a79ecc 100644 --- a/components/sdmmc/CMakeLists.txt +++ b/components/sdmmc/CMakeLists.txt @@ -12,7 +12,7 @@ set(srcs "sdmmc_cmd.c" "sdmmc_sd.c" "sd_pwr_ctrl/sd_pwr_ctrl.c") -if(CONFIG_SOC_MULTI_USAGE_LDO_SUPPORTED) +if(CONFIG_SOC_GP_LDO_SUPPORTED) list(APPEND srcs "sd_pwr_ctrl/sd_pwr_ctrl_by_on_chip_ldo.c") endif() diff --git a/components/sdmmc/include/sd_pwr_ctrl_by_on_chip_ldo.h b/components/sdmmc/include/sd_pwr_ctrl_by_on_chip_ldo.h index 121097d3a8..39075482d3 100644 --- a/components/sdmmc/include/sd_pwr_ctrl_by_on_chip_ldo.h +++ b/components/sdmmc/include/sd_pwr_ctrl_by_on_chip_ldo.h @@ -19,7 +19,7 @@ extern "C" { * @brief LDO configurations */ typedef struct { - int ldo_unit_id; ///< On-chip LDO ID + int ldo_chan_id; ///< On-chip LDO channel ID, e.g. set to `4` is the `LDO_VO4` is connected to power the SDMMC IO } sd_pwr_ctrl_ldo_config_t; /** diff --git a/components/sdmmc/sd_pwr_ctrl/sd_pwr_ctrl_by_on_chip_ldo.c b/components/sdmmc/sd_pwr_ctrl/sd_pwr_ctrl_by_on_chip_ldo.c index 1d8585100d..b8232d4a42 100644 --- a/components/sdmmc/sd_pwr_ctrl/sd_pwr_ctrl_by_on_chip_ldo.c +++ b/components/sdmmc/sd_pwr_ctrl/sd_pwr_ctrl_by_on_chip_ldo.c @@ -12,14 +12,14 @@ #include "esp_log.h" #include "esp_check.h" #include "esp_heap_caps.h" -#include "esp_private/esp_ldo.h" +#include "esp_ldo_regulator.h" #include "soc/soc_caps.h" #include "sd_pwr_ctrl.h" #include "sd_pwr_ctrl_by_on_chip_ldo.h" #include "sd_pwr_ctrl_interface.h" typedef struct { - esp_ldo_unit_handle_t ldo_unit; + esp_ldo_channel_handle_t ldo_chan; int voltage_mv; } sd_pwr_ctrl_ldo_ctx_t; @@ -37,19 +37,16 @@ esp_err_t sd_pwr_ctrl_new_on_chip_ldo(const sd_pwr_ctrl_ldo_config_t *configs, s sd_pwr_ctrl_ldo_ctx_t *ctx = (sd_pwr_ctrl_ldo_ctx_t *)heap_caps_calloc(1, sizeof(sd_pwr_ctrl_ldo_ctx_t), MALLOC_CAP_DEFAULT | MALLOC_CAP_8BIT); ESP_GOTO_ON_FALSE(ctx, ESP_ERR_NO_MEM, err, TAG, "no mem for on-chip ldo control driver context"); - esp_ldo_unit_init_cfg_t unit_cfg = { - .unit_id = configs->ldo_unit_id, - .cfg = { - .voltage_mv = 0, //will be adjusted dynamically by sdmmc driver later - }, + esp_ldo_channel_config_t chan_cfg = { + .chan_id = configs->ldo_chan_id, + .flags.adjustable = true, // the SDMMC power control driver will adjust the voltage later according to different speed mode }; - esp_ldo_unit_handle_t ldo_unit = NULL; - ESP_GOTO_ON_ERROR(esp_ldo_init_unit(&unit_cfg, &ldo_unit), err, TAG, "failed to create an on-chip LDO unit handle"); - ESP_GOTO_ON_ERROR(esp_ldo_enable_unit(ldo_unit), err, TAG, "failed to enable the on-chip LDO unit"); + esp_ldo_channel_handle_t ldo_chan = NULL; + ESP_GOTO_ON_ERROR(esp_ldo_acquire_channel(&chan_cfg, &ldo_chan), err, TAG, "failed to enable the on-chip LDO unit"); driver->set_io_voltage = s_ldo_set_voltage; driver->ctx = ctx; - ctx->ldo_unit = ldo_unit; + ctx->ldo_chan = ldo_chan; ctx->voltage_mv = 0; *ret_drv = driver; @@ -66,8 +63,7 @@ esp_err_t sd_pwr_ctrl_del_on_chip_ldo(sd_pwr_ctrl_handle_t handle) ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid arg: null pointer"); sd_pwr_ctrl_ldo_ctx_t *ctx = handle->ctx; - ESP_RETURN_ON_ERROR(esp_ldo_disable_unit(ctx->ldo_unit), TAG, "failed to disable the on-chip LDO unit"); - ESP_RETURN_ON_ERROR(esp_ldo_deinit_unit(ctx->ldo_unit), TAG, "failed to deinit the LDO unit handle"); + ESP_RETURN_ON_ERROR(esp_ldo_release_channel(ctx->ldo_chan), TAG, "failed to release the on-chip LDO channel"); free(handle->ctx); handle->ctx = NULL; free(handle); @@ -80,7 +76,7 @@ static esp_err_t s_ldo_set_voltage(void *arg, int voltage_mv) { //API checks done by caller sd_pwr_ctrl_ldo_ctx_t *ctx = arg; - ESP_RETURN_ON_ERROR(esp_ldo_set_voltage(ctx->ldo_unit, voltage_mv), TAG, "failed to set LDO unit output voltage"); + ESP_RETURN_ON_ERROR(esp_ldo_channel_adjust_voltage(ctx->ldo_chan, voltage_mv), TAG, "failed to set LDO unit output voltage"); ctx->voltage_mv = voltage_mv; return ESP_OK; } diff --git a/examples/storage/sd_card/sdmmc/main/sd_card_example_main.c b/examples/storage/sd_card/sdmmc/main/sd_card_example_main.c index 16f86194a2..e752d3a3cb 100644 --- a/examples/storage/sd_card/sdmmc/main/sd_card_example_main.c +++ b/examples/storage/sd_card/sdmmc/main/sd_card_example_main.c @@ -132,7 +132,7 @@ void app_main(void) */ #if CONFIG_EXAMPLE_SDMMC_IO_POWER_INTERNAL_LDO sd_pwr_ctrl_ldo_config_t ldo_config = { - .ldo_unit_id = 4, + .ldo_chan_id = 4, // `LDO_VO4` is used as the SDMMC IO power }; sd_pwr_ctrl_handle_t pwr_ctrl_handle = NULL; From cf59c0056416a55ea5c705cc22918a7cf6a7d27a Mon Sep 17 00:00:00 2001 From: morris Date: Sun, 17 Mar 2024 21:40:57 +0800 Subject: [PATCH 5/6] change(mpll): clean up mpll clock acquire with ldo driver --- components/esp_hw_support/CMakeLists.txt | 3 - components/esp_hw_support/Kconfig | 5 +- components/esp_hw_support/clk_ctrl_os.c | 58 ++++++----------- .../esp_hw_support/include/clk_ctrl_os.h | 5 -- .../include/esp_private/esp_ldo_psram.h | 49 --------------- components/esp_hw_support/ldo/esp_ldo_psram.c | 62 ------------------- .../esp_hw_support/port/esp32p4/Kconfig.ldo | 46 +++++++------- .../esp_psram/device/esp_psram_impl_ap_hex.c | 3 +- components/esp_system/port/cpu_start.c | 1 - docs/en/api-guides/external-ram.rst | 2 +- docs/zh_CN/api-guides/external-ram.rst | 2 +- 11 files changed, 47 insertions(+), 189 deletions(-) delete mode 100644 components/esp_hw_support/include/esp_private/esp_ldo_psram.h delete mode 100644 components/esp_hw_support/ldo/esp_ldo_psram.c diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index d96236b270..ef9af022fb 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/components/esp_hw_support/CMakeLists.txt @@ -75,9 +75,6 @@ if(NOT BOOTLOADER_BUILD) if(CONFIG_SOC_GP_LDO_SUPPORTED) list(APPEND srcs "ldo/esp_ldo.c" "ldo/esp_ldo_regulator.c") - if(CONFIG_SPIRAM OR CONFIG_SOC_CLK_MPLL_SUPPORTED) - list(APPEND srcs "ldo/esp_ldo_psram.c") - endif() endif() if(CONFIG_SOC_ASYNC_MEMCPY_SUPPORTED) diff --git a/components/esp_hw_support/Kconfig b/components/esp_hw_support/Kconfig index 66b01515db..74c89f00cd 100644 --- a/components/esp_hw_support/Kconfig +++ b/components/esp_hw_support/Kconfig @@ -331,10 +331,7 @@ menu "Hardware Settings" endmenu - menu "LDO Config" - depends on SOC_MULTI_USAGE_LDO_SUPPORTED - orsource "./port/$IDF_TARGET/Kconfig.ldo" - endmenu + orsource "./port/$IDF_TARGET/Kconfig.ldo" # Invisible bringup bypass options for esp_hw_support component config ESP_BRINGUP_BYPASS_CPU_CLK_SETTING diff --git a/components/esp_hw_support/clk_ctrl_os.c b/components/esp_hw_support/clk_ctrl_os.c index 7b766a7545..4866b65a8e 100644 --- a/components/esp_hw_support/clk_ctrl_os.c +++ b/components/esp_hw_support/clk_ctrl_os.c @@ -7,11 +7,11 @@ #include #include "clk_ctrl_os.h" #include "soc/rtc.h" +#include "esp_ldo_regulator.h" #include "esp_private/esp_clk_tree_common.h" #include "esp_check.h" #if SOC_CLK_MPLL_SUPPORTED #include "rtc_clk.h" -#include "esp_private/esp_ldo_psram.h" #endif #if SOC_CLK_APLL_SUPPORTED || SOC_CLK_MPLL_SUPPORTED @@ -30,7 +30,7 @@ static int s_apll_ref_cnt = 0; #if SOC_CLK_MPLL_SUPPORTED static uint32_t s_cur_mpll_freq = 0; static int s_mpll_ref_cnt = 0; -static esp_ldo_unit_handle_t s_ldo_unit_hndl = NULL; +static esp_ldo_channel_handle_t s_ldo_chan = NULL; #endif bool periph_rtc_dig_clk8m_enable(void) @@ -125,7 +125,7 @@ esp_err_t periph_rtc_apll_freq_set(uint32_t expt_freq, uint32_t *real_freq) if (need_config) { ESP_LOGD(TAG, "APLL will working at %"PRIu32" Hz with coefficients [sdm0] %"PRIu32" [sdm1] %"PRIu32" [sdm2] %"PRIu32" [o_div] %"PRIu32"", - apll_freq, sdm0, sdm1, sdm2, o_div); + apll_freq, sdm0, sdm1, sdm2, o_div); /* Set coefficients for APLL, notice that it doesn't mean APLL will start */ rtc_clk_apll_coeff_set(o_div, sdm0, sdm1, sdm2); } else { @@ -137,51 +137,34 @@ esp_err_t periph_rtc_apll_freq_set(uint32_t expt_freq, uint32_t *real_freq) #endif // SOC_CLK_APLL_SUPPORTED #if SOC_CLK_MPLL_SUPPORTED -void periph_rtc_mpll_early_acquire(void) -{ - portENTER_CRITICAL(&periph_spinlock); - s_mpll_ref_cnt++; - if (s_mpll_ref_cnt == 1) { -#if SOC_PSRAM_VDD_POWER_MPLL - // configure MPPL power (MPLL power pin is the same as for the PSRAM) - s_ldo_unit_hndl = esp_ldo_vdd_psram_early_init(); -#endif - // For the first time enable MPLL, need to set power up - rtc_clk_mpll_enable(); - } - portEXIT_CRITICAL(&periph_spinlock); -} - esp_err_t periph_rtc_mpll_acquire(void) { - esp_err_t ret = ESP_OK; + // power up LDO for the MPLL +#if defined(CONFIG_ESP_LDO_CHAN_PSRAM_DOMAIN) && CONFIG_ESP_LDO_CHAN_PSRAM_DOMAIN != -1 + esp_ldo_channel_config_t ldo_mpll_config = { + .chan_id = CONFIG_ESP_LDO_CHAN_PSRAM_DOMAIN, + .voltage_mv = CONFIG_ESP_LDO_VOLTAGE_PSRAM_DOMAIN, + }; + ESP_RETURN_ON_ERROR(esp_ldo_acquire_channel(&ldo_mpll_config, &s_ldo_chan), TAG, "acquire internal LDO for MPLL failed"); +#endif + portENTER_CRITICAL(&periph_spinlock); s_mpll_ref_cnt++; if (s_mpll_ref_cnt == 1) { -#if SOC_PSRAM_VDD_POWER_MPLL - // configure MPPL power (MPLL power pin is the same as for the PSRAM) - ret = esp_ldo_vdd_psram_init(&s_ldo_unit_hndl); - // external power supply in use is a valid condition - if (ret == ESP_ERR_INVALID_STATE) { - ret = ESP_OK; - } else if (ret != ESP_OK ) { - portEXIT_CRITICAL(&periph_spinlock); - ESP_LOGE(TAG, "failed to initialize PSRAM internal LDO"); - goto err; - } -#endif // For the first time enable MPLL, need to set power up rtc_clk_mpll_enable(); } portEXIT_CRITICAL(&periph_spinlock); -#if SOC_PSRAM_VDD_POWER_MPLL -err: -#endif - return ret; + return ESP_OK; } void periph_rtc_mpll_release(void) { +#if defined(CONFIG_ESP_LDO_CHAN_PSRAM_DOMAIN) && CONFIG_ESP_LDO_CHAN_PSRAM_DOMAIN != -1 + if (s_ldo_chan) { + esp_ldo_release_channel(s_ldo_chan); + } +#endif portENTER_CRITICAL(&periph_spinlock); assert(s_mpll_ref_cnt > 0); s_mpll_ref_cnt--; @@ -189,11 +172,6 @@ void periph_rtc_mpll_release(void) // If there is no peripheral using MPLL, shut down the power s_cur_mpll_freq = 0; rtc_clk_mpll_disable(); -#if SOC_PSRAM_VDD_POWER_MPLL - if (s_ldo_unit_hndl) { - esp_ldo_vdd_psram_deinit(s_ldo_unit_hndl); - } -#endif } portEXIT_CRITICAL(&periph_spinlock); } diff --git a/components/esp_hw_support/include/clk_ctrl_os.h b/components/esp_hw_support/include/clk_ctrl_os.h index 7212994edf..fa2a7a679f 100644 --- a/components/esp_hw_support/include/clk_ctrl_os.h +++ b/components/esp_hw_support/include/clk_ctrl_os.h @@ -73,11 +73,6 @@ esp_err_t periph_rtc_apll_freq_set(uint32_t expt_freq, uint32_t *real_freq); #endif // SOC_CLK_APLL_SUPPORTED #if SOC_CLK_MPLL_SUPPORTED -/** - * @brief Enable MPLL power if it has not enabled (early version) - */ -void periph_rtc_mpll_early_acquire(void); - /** * @brief Enable MPLL power if it has not enabled */ diff --git a/components/esp_hw_support/include/esp_private/esp_ldo_psram.h b/components/esp_hw_support/include/esp_private/esp_ldo_psram.h deleted file mode 100644 index 5cda6e19f2..0000000000 --- a/components/esp_hw_support/include/esp_private/esp_ldo_psram.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include -#include "esp_err.h" -#include "esp_private/esp_ldo.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Init PSRAM VDD LDO during early stage - * - * @return - * - LDO unit handle on success - * - NULL when external power supply is configured to be used - */ -esp_ldo_unit_handle_t esp_ldo_vdd_psram_early_init(void); - -/** - * @brief Init PSRAM VDD LDO - * - * @param[out] ldo_unit LDO unit handle - * - * @return - * - ESP_OK Successful. - * - ESP_ERR_INVALID_STATE External power supply is configured to be used - * - ESP_ERR_INVALID_ARG Arguments is NULL or invalid LDO configuration. - * - other error codes from lower-level driver. - * - */ -esp_err_t esp_ldo_vdd_psram_init(esp_ldo_unit_handle_t *ldo_unit); - -/** - * @brief De-init PSRAM VDD LDO - * - * @param[in] ldo_unit LDO unit handle - */ -esp_err_t esp_ldo_vdd_psram_deinit(esp_ldo_unit_handle_t ldo_unit); - -#ifdef __cplusplus -} -#endif diff --git a/components/esp_hw_support/ldo/esp_ldo_psram.c b/components/esp_hw_support/ldo/esp_ldo_psram.c deleted file mode 100644 index c0f97be217..0000000000 --- a/components/esp_hw_support/ldo/esp_ldo_psram.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include "sdkconfig.h" -#include "esp_attr.h" -#include "esp_log.h" -#include "esp_check.h" -#include "soc/soc_caps.h" -#include "hal/ldo_ll.h" -#include "esp_private/esp_ldo_psram.h" - -static const char *TAG = "ldo_psram"; - -esp_ldo_unit_handle_t esp_ldo_vdd_psram_early_init(void) -{ - if (CONFIG_ESP_VDD_PSRAM_LDO_ID != -1) { - esp_ldo_unit_init_cfg_t unit_cfg = { - .unit_id = CONFIG_ESP_VDD_PSRAM_LDO_ID, - .cfg = { - .voltage_mv = CONFIG_ESP_VDD_PSRAM_LDO_VOLTAGE_MV, - }, - .flags.enable_unit = true, - .flags.shared_ldo = true, - }; - esp_ldo_unit_handle_t early_unit = esp_ldo_init_unit_early(&unit_cfg); - assert(early_unit); - return early_unit; - } - return NULL; -} - -esp_err_t esp_ldo_vdd_psram_init(esp_ldo_unit_handle_t *ldo_unit) -{ - esp_err_t ret = ESP_OK; - ESP_RETURN_ON_FALSE(ldo_unit, ESP_ERR_INVALID_ARG, TAG, "null pointer"); - if (CONFIG_ESP_VDD_PSRAM_LDO_ID != -1) { - esp_ldo_unit_init_cfg_t unit_cfg = { - .unit_id = LDO_ID2UNIT(CONFIG_ESP_VDD_PSRAM_LDO_ID), - .cfg = { - .voltage_mv = CONFIG_ESP_VDD_PSRAM_LDO_VOLTAGE_MV, - }, - .flags.enable_unit = true, - .flags.shared_ldo = true, - }; - ESP_RETURN_ON_ERROR(esp_ldo_init_unit(&unit_cfg, ldo_unit), TAG, "internal LDO init failed"); - } else { - ESP_LOGD(TAG, "internal LDO not initialized, external power supply is configured to be used"); - *ldo_unit = NULL; - return ESP_ERR_INVALID_STATE; - } - return ret; -} - -esp_err_t esp_ldo_vdd_psram_deinit(esp_ldo_unit_handle_t ldo_unit) -{ - return esp_ldo_deinit_unit(ldo_unit); -} diff --git a/components/esp_hw_support/port/esp32p4/Kconfig.ldo b/components/esp_hw_support/port/esp32p4/Kconfig.ldo index 8e076587e3..da3c8de84a 100644 --- a/components/esp_hw_support/port/esp32p4/Kconfig.ldo +++ b/components/esp_hw_support/port/esp32p4/Kconfig.ldo @@ -1,24 +1,28 @@ -config ESP_VDD_PSRAM_LDO_ID - int "PSRAM VDD connected LDO ID, set -1 for using external power supply and disable internal LDO" - default 2 - range -1 4 - help - PSRAM VDD pin connected LDO ID. - PSRAM VDD needs to be connected to an voltage output. This option selects the on-chip - LDO which is connected to the PSRAM VDD. - Set to -1 for connecting to external voltage output. +menu "LDO Regulator Configurations" + depends on SOC_GP_LDO_SUPPORTED -choice ESP_VDD_PSRAM_LDO_VOLTAGE_MV - prompt "PSRAM VDD connected LDO voltage" - depends on ESP_VDD_PSRAM_LDO_ID != -1 - default ESP_VDD_PSRAM_LDO_VOLTAGE_MV_1900 - help - Select the LDO (ESP_VDD_PSRAM_LDO_ID) voltage output + config ESP_LDO_CHAN_PSRAM_DOMAIN + int "LDO regulator channel that used to power PSRAM and MPLL (READ HELP)" + default 2 + range -1 4 + help + The internal LDO regulator can be used to power the PSRAM specific power domain. + This option is to select which LDO channel to connect to that domain. + Please set this option correctly according to your schematic. + Set to -1 if the PSRAM is using any external power supply. - config ESP_VDD_PSRAM_LDO_VOLTAGE_MV_1900 - bool "1.9V" -endchoice + choice ESP_LDO_VOLTAGE_PSRAM_DOMAIN + prompt "PSRAM power domain voltage" + depends on ESP_LDO_CHAN_PSRAM_DOMAIN != -1 + default ESP_LDO_VOLTAGE_PSRAM_1900_MV + help + Select the voltage used by the PSRAM power domain. -config ESP_VDD_PSRAM_LDO_VOLTAGE_MV - int - default 1900 if ESP_VDD_PSRAM_LDO_VOLTAGE_MV_1900 + config ESP_LDO_VOLTAGE_PSRAM_1900_MV + bool "1.9V" + endchoice + + config ESP_LDO_VOLTAGE_PSRAM_DOMAIN + int + default 1900 if ESP_LDO_VOLTAGE_PSRAM_1900_MV +endmenu diff --git a/components/esp_psram/device/esp_psram_impl_ap_hex.c b/components/esp_psram/device/esp_psram_impl_ap_hex.c index 116657cf63..82a1b4e0b8 100644 --- a/components/esp_psram/device/esp_psram_impl_ap_hex.c +++ b/components/esp_psram/device/esp_psram_impl_ap_hex.c @@ -9,7 +9,6 @@ #include "esp_err.h" #include "esp_log.h" #include "esp_private/periph_ctrl.h" -#include "esp_private/esp_ldo_psram.h" #include "esp_private/mspi_timing_tuning.h" #include "../esp_psram_impl.h" #include "hal/psram_ctrlr_ll.h" @@ -366,7 +365,7 @@ static void s_configure_psram_ecc(void) esp_err_t esp_psram_impl_enable(void) { #if SOC_CLK_MPLL_SUPPORTED - periph_rtc_mpll_early_acquire(); + periph_rtc_mpll_acquire(); periph_rtc_mpll_freq_set(AP_HEX_PSRAM_MPLL_DEFAULT_FREQ_MHZ * 1000000, NULL); #endif diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index 5bcc3a05e3..2c2d80fe7a 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -76,7 +76,6 @@ #endif #include "esp_private/rtc_clk.h" -#include "esp_private/esp_ldo_psram.h" #if SOC_INT_CLIC_SUPPORTED #include "hal/interrupt_clic_ll.h" diff --git a/docs/en/api-guides/external-ram.rst b/docs/en/api-guides/external-ram.rst index 8807e1376b..b7a84f954e 100644 --- a/docs/en/api-guides/external-ram.rst +++ b/docs/en/api-guides/external-ram.rst @@ -32,7 +32,7 @@ Hardware Some PSRAM chips are 1.8 V devices and some are 3.3 V. Consult the datasheet for your PSRAM chip and {IDF_TARGET_NAME} device to find out the working voltages. - By default, the PSRAM is powered up by the on-chip LDO2. You can use :ref:`CONFIG_ESP_VDD_PSRAM_LDO_ID` to switch the LDO ID accordingly. Set this value to -1 to use an external power supply, which means the on-chip LDO will not be used. By default, the PSRAM connected to LDO is set to the correct voltage based on the Espressif module used. You can still use :ref:`CONFIG_ESP_VDD_PSRAM_LDO_VOLTAGE_MV` to select the LDO output voltage if you are not using an Espressif module. When using an external power supply, this option does not exist. + By default, the PSRAM is powered up by the on-chip LDO2. You can use :ref:`CONFIG_ESP_LDO_CHAN_PSRAM_DOMAIN` to switch the LDO channel accordingly. Set this value to -1 to use an external power supply, which means the on-chip LDO will not be used. By default, the PSRAM connected to LDO is set to the correct voltage based on the Espressif module used. You can still use :ref:`CONFIG_ESP_LDO_VOLTAGE_PSRAM_DOMAIN` to select the LDO output voltage if you are not using an Espressif module. When using an external power supply, this option does not exist. .. note:: diff --git a/docs/zh_CN/api-guides/external-ram.rst b/docs/zh_CN/api-guides/external-ram.rst index 7e196e3c06..cfd851fdd4 100644 --- a/docs/zh_CN/api-guides/external-ram.rst +++ b/docs/zh_CN/api-guides/external-ram.rst @@ -32,7 +32,7 @@ 请查询相应 PSRAM 芯片以及 {IDF_TARGET_NAME} 的技术规格书获取准确的工作电压。 - PSRAM 默认由片上 LDO2 供电。可设置 :ref:`CONFIG_ESP_VDD_PSRAM_LDO_ID` 来切换相应的 LDO ID,将该值设为 -1 表示使用外部电源,即不使用片上 LDO。默认情况下,连接到 LDO 的 PSRAM 会基于所使用的乐鑫模组设置正确电压。如果未使用乐鑫模组,仍可设置 :ref:`CONFIG_ESP_VDD_PSRAM_LDO_VOLTAGE_MV` 来选择 LDO 输出电压。使用外部电源时,该选项不存在。 + PSRAM 默认由片上 LDO2 供电。可设置 :ref:`CONFIG_ESP_LDO_CHAN_PSRAM_DOMAIN` 来切换相应的 LDO 输出通道,将该值设为 -1 表示使用外部电源,即不使用片上 LDO。默认情况下,连接到 LDO 的 PSRAM 会基于所使用的乐鑫模组设置正确电压。如果未使用乐鑫模组,仍可设置 :ref:`CONFIG_ESP_LDO_VOLTAGE_PSRAM_DOMAIN` 来选择 LDO 输出电压。使用外部电源时,该选项不存在。 .. note:: From 5369b68bc8bfb437c0c0a776c4aef9609ef4197e Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 25 Mar 2024 18:23:59 +0800 Subject: [PATCH 6/6] change(flash): acquire the LDO channel used by flash so that even if the same channel has other consumers, the voltage won't be changed --- .../esp_hw_support/port/esp32p4/Kconfig.ldo | 25 +++++++++++++++++++ components/spi_flash/esp_flash_spi_init.c | 16 +++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/components/esp_hw_support/port/esp32p4/Kconfig.ldo b/components/esp_hw_support/port/esp32p4/Kconfig.ldo index da3c8de84a..6c0bea47ed 100644 --- a/components/esp_hw_support/port/esp32p4/Kconfig.ldo +++ b/components/esp_hw_support/port/esp32p4/Kconfig.ldo @@ -1,6 +1,31 @@ menu "LDO Regulator Configurations" depends on SOC_GP_LDO_SUPPORTED + config ESP_LDO_CHAN_SPI_NOR_FLASH_DOMAIN + int "LDO regulator channel that used to power SPI NOR Flash (READ HELP)" + default 1 + range -1 4 + help + The internal LDO regulator can be used to power the SPI Flash specific power domain. + This option is to select which LDO channel to connect to that domain. + Please set this option correctly according to your schematic. + Set to -1 if the Flash is using any external power supply. + + choice ESP_LDO_VOLTAGE_SPI_NOR_FLASH_DOMAIN + prompt "SPI NOR Flash power domain voltage" + depends on ESP_LDO_CHAN_SPI_NOR_FLASH_DOMAIN != -1 + default ESP_LDO_VOLTAGE_SPI_NOR_FLASH_3300_MV + help + Select the voltage used by the Flash power domain. + + config ESP_LDO_VOLTAGE_SPI_NOR_FLASH_3300_MV + bool "3.3V" + endchoice + + config ESP_LDO_VOLTAGE_SPI_NOR_FLASH_DOMAIN + int + default 3300 if ESP_LDO_VOLTAGE_SPI_NOR_FLASH_3300_MV + config ESP_LDO_CHAN_PSRAM_DOMAIN int "LDO regulator channel that used to power PSRAM and MPLL (READ HELP)" default 2 diff --git a/components/spi_flash/esp_flash_spi_init.c b/components/spi_flash/esp_flash_spi_init.c index 575da4e808..aee5da0c8a 100644 --- a/components/spi_flash/esp_flash_spi_init.c +++ b/components/spi_flash/esp_flash_spi_init.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,6 +15,7 @@ #include "esp_heap_caps.h" #include "hal/spi_types.h" #include "esp_private/spi_share_hw_ctrl.h" +#include "esp_ldo_regulator.h" #include "hal/spi_flash_hal.h" #include "hal/gpio_hal.h" #include "esp_flash_internal.h" @@ -420,6 +421,19 @@ esp_err_t esp_flash_init_default_chip(void) esp_err_t esp_flash_app_init(void) { esp_err_t err = ESP_OK; + + // Acquire the LDO channel used by the SPI NOR flash + // in case the LDO voltage is changed by other users +#if defined(CONFIG_ESP_LDO_CHAN_SPI_NOR_FLASH_DOMAIN) && CONFIG_ESP_LDO_CHAN_SPI_NOR_FLASH_DOMAIN != -1 + static esp_ldo_channel_handle_t s_ldo_chan = NULL; + esp_ldo_channel_config_t ldo_config = { + .chan_id = CONFIG_ESP_LDO_CHAN_SPI_NOR_FLASH_DOMAIN, + .voltage_mv = CONFIG_ESP_LDO_VOLTAGE_SPI_NOR_FLASH_DOMAIN, + }; + err = esp_ldo_acquire_channel(&ldo_config, &s_ldo_chan); + if (err != ESP_OK) return err; +#endif + spi_flash_init_lock(); spi_flash_guard_set(&g_flash_guard_default_ops); #if CONFIG_SPI_FLASH_ENABLE_COUNTERS