mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-11 04:57:38 +00:00
feat(ldo): add config to let hardware control the ldo output
If LDO1 is used by spi flash, then we recommend to give the ownership to the hardware. Software just read the parameters from the efuse and set to PMU.
This commit is contained in:
@@ -4,29 +4,19 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
* NOTICE
|
||||
* The ll is not public api, don't use in application code.
|
||||
* See readme.md in hal/include/hal/readme.md
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_bit_defs.h"
|
||||
#include "hal/assert.h"
|
||||
#include "hal/misc.h"
|
||||
#include "soc/pmu_struct.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* LDO capabilities
|
||||
*/
|
||||
#define LDO_LL_UNIT_NUM 4
|
||||
|
||||
#define LDO_LL_NUM_UNITS 4 // NUmber of LDO units
|
||||
#define LDO_LL_ADJUSTABLE_CHAN_MASK 0x0F // all the 4 channels can be adjustable
|
||||
|
||||
#define LDO_LL_MAX_VOLTAGE_MV 3300
|
||||
@@ -48,91 +38,186 @@ extern "C" {
|
||||
#define LDO_ID2UNIT(ldo_id) ((ldo_id) - 1)
|
||||
|
||||
/**
|
||||
* @brief Check if a LDO ID is valid
|
||||
* @brief LDO unit owner
|
||||
*/
|
||||
typedef enum {
|
||||
LDO_LL_UNIT_OWNER_HW, // LDO unit is controlled by hardware
|
||||
LDO_LL_UNIT_OWNER_SW, // LDO unit is controlled by software
|
||||
} ldo_ll_unit_owner_t;
|
||||
|
||||
/**
|
||||
* @brief Check if a LDO channel is valid
|
||||
*
|
||||
* @return True for valid
|
||||
* @return True for valid, false for invalid
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline bool ldo_ll_is_valid_ldo_id(int ldo_id)
|
||||
static inline bool ldo_ll_is_valid_ldo_channel(int ldo_chan)
|
||||
{
|
||||
return ((ldo_id > 0) && (ldo_id <= LDO_LL_UNIT_NUM));
|
||||
return (ldo_chan > 0) && (ldo_chan <= LDO_LL_NUM_UNITS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable a LDO
|
||||
* @brief Convert voltage to dref and mul value
|
||||
*
|
||||
* @param ldo_id LDO ID
|
||||
* @note Vref = (dref < 9)?(0.5+dref*0.05):(1+(dref-9)*0.1)
|
||||
* @note Vout = (Vref*K+Vos)*(1+0.25*mul*C), K, Vos, C are constants saved in the eFuse, for calibration
|
||||
*
|
||||
* @param ldo_unit LDO unit
|
||||
* @param voltage_mv Voltage in mV
|
||||
* @param dref Returned dref value
|
||||
* @param mul Returned mul value
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void ldo_ll_voltage_to_dref_mul(int ldo_unit, int voltage_mv, uint8_t *dref, uint8_t *mul)
|
||||
{
|
||||
// TODO [IDF-10754]: also take the calibration parameters into account
|
||||
if (voltage_mv <= 500) {
|
||||
*dref = 0;
|
||||
*mul = 0;
|
||||
} else if (voltage_mv <= 900) {
|
||||
*mul = 0;
|
||||
*dref = (voltage_mv - LDO_LL_EXT_LDO_DREF_VOL_L_BASE) / LDO_LL_EXT_LDO_DREF_VOL_L_STEP;
|
||||
} else if (voltage_mv <= 1600) {
|
||||
*mul = 1;
|
||||
*dref = 6 + (voltage_mv - LDO_LL_EXT_LDO_DREF_VOL_H_BASE) / LDO_LL_EXT_LDO_DREF_VOL_H_STEP;
|
||||
} else if (voltage_mv <= 2000) {
|
||||
*mul = 4;
|
||||
*dref = (voltage_mv / 2 - LDO_LL_EXT_LDO_DREF_VOL_L_BASE) / LDO_LL_EXT_LDO_DREF_VOL_L_STEP;
|
||||
} else if (voltage_mv <= 3200) {
|
||||
*mul = 4;
|
||||
*dref = 9 + (voltage_mv / 2 - LDO_LL_EXT_LDO_DREF_VOL_H_BASE) / LDO_LL_EXT_LDO_DREF_VOL_H_STEP;
|
||||
} else {
|
||||
*mul = 7;
|
||||
*dref = 15;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set owner of a LDO unit
|
||||
*
|
||||
* @note Even if the LDO unit is controlled by hardware, its voltage can still be changed by software by `ldo_ll_adjust_voltage`
|
||||
*
|
||||
* @param ldo_unit LDO unit
|
||||
* @param owner Owner of the LDO unit
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void ldo_ll_set_owner(int ldo_unit, ldo_ll_unit_owner_t owner)
|
||||
{
|
||||
uint8_t index_array[LDO_LL_NUM_UNITS] = {0, 3, 1, 4};
|
||||
/*
|
||||
* force_tieh_sel:
|
||||
* - 0: efuse, i.e. by hardware
|
||||
* - 1: tieh_sel, i.e. by software
|
||||
*/
|
||||
PMU.ext_ldo[index_array[ldo_unit]].pmu_ext_ldo.force_tieh_sel = owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable a LDO unit
|
||||
*
|
||||
* @param ldo_unit LDO unit
|
||||
* @param enable True: enable; False: disable
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void ldo_ll_enable(int ldo_id, bool enable)
|
||||
static inline void ldo_ll_enable(int ldo_unit, bool enable)
|
||||
{
|
||||
HAL_ASSERT(ldo_id < LDO_LL_UNIT_NUM);
|
||||
uint8_t index_array[LDO_LL_UNIT_NUM] = {0,3,1,4};
|
||||
PMU.ext_ldo[index_array[ldo_id]].pmu_ext_ldo.xpd = enable;
|
||||
uint8_t index_array[LDO_LL_NUM_UNITS] = {0, 3, 1, 4};
|
||||
PMU.ext_ldo[index_array[ldo_unit]].pmu_ext_ldo.xpd = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable a LDO
|
||||
* @brief Adjust voltage of a LDO unit
|
||||
*
|
||||
* @param ldo_id LDO ID
|
||||
* @param voltage_mv Voltage in mV
|
||||
* @param ldo_unit LDO unit
|
||||
* @param dref A parameter which controls the internal reference voltage
|
||||
* @param mul Multiply factor
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void ldo_ll_set_output_voltage_mv(int ldo_id, int voltage_mv)
|
||||
static inline void ldo_ll_adjust_voltage(int ldo_unit, uint8_t dref, uint8_t mul)
|
||||
{
|
||||
int dref = 0, mul = 0;
|
||||
|
||||
uint8_t index_array[LDO_LL_NUM_UNITS] = {0, 3, 1, 4};
|
||||
PMU.ext_ldo[index_array[ldo_unit]].pmu_ext_ldo_ana.dref = dref;
|
||||
PMU.ext_ldo[index_array[ldo_unit]].pmu_ext_ldo_ana.mul = mul;
|
||||
/**
|
||||
* Vout = dref * mul
|
||||
* tieh:
|
||||
* - 0: Vref * Mul
|
||||
* - 1: 3.3V
|
||||
*
|
||||
* mul reg[2:0]:
|
||||
* mul = 1~2.75, step = 0.25
|
||||
|
||||
* dref reg[3:0]:
|
||||
* 0~8 : dref = 0.5V ~ 0.9V, step 50mV
|
||||
* 9~15 : dref = 1.0V ~ 1.6V, step 100mV
|
||||
*/
|
||||
if (voltage_mv <= 500) {
|
||||
dref = 0;
|
||||
mul = 0;
|
||||
} else if (voltage_mv <= 900) {
|
||||
mul = 0;
|
||||
dref = (voltage_mv - LDO_LL_EXT_LDO_DREF_VOL_L_BASE) / LDO_LL_EXT_LDO_DREF_VOL_L_STEP;
|
||||
} else if (voltage_mv <= 1600) {
|
||||
mul = 1;
|
||||
dref = 6 + (voltage_mv - LDO_LL_EXT_LDO_DREF_VOL_H_BASE) / LDO_LL_EXT_LDO_DREF_VOL_H_STEP;
|
||||
} else if (voltage_mv <= 2000) {
|
||||
mul = 4;
|
||||
dref = (voltage_mv / 2 - LDO_LL_EXT_LDO_DREF_VOL_L_BASE) / LDO_LL_EXT_LDO_DREF_VOL_L_STEP;
|
||||
} else if (voltage_mv <= 3200) {
|
||||
mul = 4;
|
||||
dref = 9 + (voltage_mv / 2 - LDO_LL_EXT_LDO_DREF_VOL_H_BASE) / LDO_LL_EXT_LDO_DREF_VOL_H_STEP;
|
||||
} else {
|
||||
mul = 7;
|
||||
dref = 15;
|
||||
}
|
||||
/**
|
||||
* tieh_sel:
|
||||
* - 0: tieh;
|
||||
* - 1: sdmmc0_tieh;
|
||||
* - 2: 3.3V;
|
||||
* - 3: sdmmc1_tieh;
|
||||
*
|
||||
* tieh:
|
||||
* - 0: dref * mul
|
||||
* - 1: 3.3V
|
||||
*
|
||||
* force_tieh_sel:
|
||||
* - 0: efuse
|
||||
* - 1: tieh_sel
|
||||
*/
|
||||
uint8_t index_array[LDO_LL_UNIT_NUM] = {0,3,1,4};
|
||||
PMU.ext_ldo[index_array[ldo_id]].pmu_ext_ldo.tieh_sel = 0;
|
||||
PMU.ext_ldo[index_array[ldo_id]].pmu_ext_ldo.tieh = 0;
|
||||
PMU.ext_ldo[index_array[ldo_id]].pmu_ext_ldo.force_tieh_sel = 1;
|
||||
PMU.ext_ldo[index_array[ldo_id]].pmu_ext_ldo_ana.dref = dref;
|
||||
PMU.ext_ldo[index_array[ldo_id]].pmu_ext_ldo_ana.mul = mul;
|
||||
PMU.ext_ldo[index_array[ldo_unit]].pmu_ext_ldo.tieh_sel = 0;
|
||||
PMU.ext_ldo[index_array[ldo_unit]].pmu_ext_ldo.tieh = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable power on delay of a LDO unit
|
||||
*
|
||||
* @param ldo_unit LDO unit
|
||||
* @param enable True: enable; False: disable
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void ldo_ll_enable_power_on_delay(int ldo_unit, bool enable)
|
||||
{
|
||||
uint8_t index_array[LDO_LL_NUM_UNITS] = {0, 3, 1, 4};
|
||||
PMU.ext_ldo[index_array[ldo_unit]].pmu_ext_ldo.tieh_pos_en = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable power off delay of a LDO unit
|
||||
*
|
||||
* @param ldo_unit LDO unit
|
||||
* @param enable True: enable; False: disable
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void ldo_ll_enable_power_off_delay(int ldo_unit, bool enable)
|
||||
{
|
||||
uint8_t index_array[LDO_LL_NUM_UNITS] = {0, 3, 1, 4};
|
||||
PMU.ext_ldo[index_array[ldo_unit]].pmu_ext_ldo.tieh_neg_en = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set power on delay target of a LDO unit
|
||||
*
|
||||
* @param ldo_unit LDO unit
|
||||
* @param target0 Target 0
|
||||
* @param target1 Target 1
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void ldo_ll_set_delay_target(int ldo_unit, uint8_t target0, uint8_t target1)
|
||||
{
|
||||
uint8_t index_array[LDO_LL_NUM_UNITS] = {0, 3, 1, 4};
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(PMU.ext_ldo[index_array[ldo_unit]].pmu_ext_ldo, target0, target0);
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(PMU.ext_ldo[index_array[ldo_unit]].pmu_ext_ldo, target1, target1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable current limit of a LDO unit to avoid inrush current
|
||||
*
|
||||
* @param ldo_unit LDO unit
|
||||
* @param enable True: enable; False: disable
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void ldo_ll_enable_current_limit(int ldo_unit, bool enable)
|
||||
{
|
||||
uint8_t index_array[LDO_LL_NUM_UNITS] = {0, 3, 1, 4};
|
||||
PMU.ext_ldo[index_array[ldo_unit]].pmu_ext_ldo_ana.en_cur_lim = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable ripple suppression of a LDO unit
|
||||
*
|
||||
* @param ldo_unit LDO unit
|
||||
* @param enable True: enable; False: disable
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void ldo_ll_enable_ripple_suppression(int ldo_unit, bool enable)
|
||||
{
|
||||
uint8_t index_array[LDO_LL_NUM_UNITS] = {0, 3, 1, 4};
|
||||
PMU.ext_ldo[index_array[ldo_unit]].pmu_ext_ldo_ana.en_vdet = enable;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
Reference in New Issue
Block a user