mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-18 02:24:18 +00:00
Merge changes from topic "st_regulator" into integration
* changes: feat(st-sdmmc2): manage cards power cycle feat(stm32mp1): register fixed regulator feat(st-drivers): introduce fixed regulator driver refactor(st): update CPU and VDD voltage get refactor(stm32mp1-fdts): update regulator description refactor(st-pmic): use regulator framework for DDR init feat(st-pmic): register the PMIC to regulator framework refactor(st-pmic): split initialize_pmic() feat(stm32mp1): add regulator framework compilation feat(regulator): add a regulator framework feat(stpmic1): add new services feat(stpmic1): add USB OTG regulators refactor(st-pmic): improve driver usage refactor(stpmic1): set stpmic1_is_regulator_enabled() as boolean refactor(stm32mp1): re-order drivers init
This commit is contained in:
commit
93b153b5bf
17 changed files with 1317 additions and 244 deletions
|
@ -8,10 +8,6 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libfdt.h>
|
||||
|
||||
#include <platform_def.h>
|
||||
|
||||
#include <arch.h>
|
||||
#include <arch_helpers.h>
|
||||
#include <common/debug.h>
|
||||
|
@ -23,8 +19,11 @@
|
|||
#include <drivers/st/stm32mp_reset.h>
|
||||
#include <lib/mmio.h>
|
||||
#include <lib/utils.h>
|
||||
#include <libfdt.h>
|
||||
#include <plat/common/platform.h>
|
||||
|
||||
#include <platform_def.h>
|
||||
|
||||
/* Registers offsets */
|
||||
#define SDMMC_POWER 0x00U
|
||||
#define SDMMC_CLKCR 0x04U
|
||||
|
@ -51,6 +50,7 @@
|
|||
|
||||
/* SDMMC power control register */
|
||||
#define SDMMC_POWER_PWRCTRL GENMASK(1, 0)
|
||||
#define SDMMC_POWER_PWRCTRL_PWR_CYCLE BIT(1)
|
||||
#define SDMMC_POWER_DIRPOL BIT(4)
|
||||
|
||||
/* SDMMC clock control register */
|
||||
|
@ -118,6 +118,13 @@
|
|||
#define TIMEOUT_US_10_MS 10000U
|
||||
#define TIMEOUT_US_1_S 1000000U
|
||||
|
||||
/* Power cycle delays in ms */
|
||||
#define VCC_POWER_OFF_DELAY 2
|
||||
#define VCC_POWER_ON_DELAY 2
|
||||
#define POWER_CYCLE_DELAY 2
|
||||
#define POWER_OFF_DELAY 2
|
||||
#define POWER_ON_DELAY 1
|
||||
|
||||
#define DT_SDMMC2_COMPAT "st,stm32-sdmmc2"
|
||||
|
||||
static void stm32_sdmmc2_init(void);
|
||||
|
@ -155,6 +162,25 @@ static void stm32_sdmmc2_init(void)
|
|||
freq = MIN(sdmmc2_params.max_freq, freq);
|
||||
}
|
||||
|
||||
if (sdmmc2_params.vmmc_regu != NULL) {
|
||||
regulator_disable(sdmmc2_params.vmmc_regu);
|
||||
}
|
||||
|
||||
mdelay(VCC_POWER_OFF_DELAY);
|
||||
|
||||
mmio_write_32(base + SDMMC_POWER,
|
||||
SDMMC_POWER_PWRCTRL_PWR_CYCLE | sdmmc2_params.dirpol);
|
||||
mdelay(POWER_CYCLE_DELAY);
|
||||
|
||||
if (sdmmc2_params.vmmc_regu != NULL) {
|
||||
regulator_enable(sdmmc2_params.vmmc_regu);
|
||||
}
|
||||
|
||||
mdelay(VCC_POWER_ON_DELAY);
|
||||
|
||||
mmio_write_32(base + SDMMC_POWER, sdmmc2_params.dirpol);
|
||||
mdelay(POWER_OFF_DELAY);
|
||||
|
||||
clock_div = div_round_up(sdmmc2_params.clk_rate, freq * 2U);
|
||||
|
||||
mmio_write_32(base + SDMMC_CLKCR, SDMMC_CLKCR_HWFC_EN | clock_div |
|
||||
|
@ -164,7 +190,7 @@ static void stm32_sdmmc2_init(void)
|
|||
mmio_write_32(base + SDMMC_POWER,
|
||||
SDMMC_POWER_PWRCTRL | sdmmc2_params.dirpol);
|
||||
|
||||
mdelay(1);
|
||||
mdelay(POWER_ON_DELAY);
|
||||
}
|
||||
|
||||
static int stm32_sdmmc2_stop_transfer(void)
|
||||
|
@ -690,6 +716,8 @@ static int stm32_sdmmc2_dt_get_config(void)
|
|||
sdmmc2_params.max_freq = fdt32_to_cpu(*cuint);
|
||||
}
|
||||
|
||||
sdmmc2_params.vmmc_regu = regulator_get_by_supply_name(fdt, sdmmc_node, "vmmc");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -710,6 +738,8 @@ int stm32_sdmmc2_mmc_init(struct stm32_sdmmc2_params *params)
|
|||
|
||||
memcpy(&sdmmc2_params, params, sizeof(struct stm32_sdmmc2_params));
|
||||
|
||||
sdmmc2_params.vmmc_regu = NULL;
|
||||
|
||||
if (stm32_sdmmc2_dt_get_config() != 0) {
|
||||
ERROR("%s: DT error\n", __func__);
|
||||
return -ENOMEM;
|
||||
|
|
|
@ -4,54 +4,63 @@
|
|||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <libfdt.h>
|
||||
|
||||
#include <platform_def.h>
|
||||
|
||||
#include <common/debug.h>
|
||||
#include <drivers/delay_timer.h>
|
||||
#include <drivers/st/regulator.h>
|
||||
#include <drivers/st/stm32_i2c.h>
|
||||
#include <drivers/st/stm32mp_pmic.h>
|
||||
#include <drivers/st/stpmic1.h>
|
||||
#include <lib/mmio.h>
|
||||
#include <lib/utils_def.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#define STPMIC1_LDO12356_OUTPUT_MASK (uint8_t)(GENMASK(6, 2))
|
||||
#define STPMIC1_LDO12356_OUTPUT_SHIFT 2
|
||||
#define STPMIC1_LDO3_MODE (uint8_t)(BIT(7))
|
||||
#define STPMIC1_LDO3_DDR_SEL 31U
|
||||
#define STPMIC1_LDO3_1800000 (9U << STPMIC1_LDO12356_OUTPUT_SHIFT)
|
||||
#include <platform_def.h>
|
||||
|
||||
#define STPMIC1_BUCK_OUTPUT_SHIFT 2
|
||||
#define STPMIC1_BUCK3_1V8 (39U << STPMIC1_BUCK_OUTPUT_SHIFT)
|
||||
|
||||
#define STPMIC1_DEFAULT_START_UP_DELAY_MS 1
|
||||
#define PMIC_NODE_NOT_FOUND 1
|
||||
|
||||
static struct i2c_handle_s i2c_handle;
|
||||
static uint32_t pmic_i2c_addr;
|
||||
|
||||
static int register_pmic(void);
|
||||
|
||||
static int dt_get_pmic_node(void *fdt)
|
||||
{
|
||||
return fdt_node_offset_by_compatible(fdt, -1, "st,stpmic1");
|
||||
static int node = -FDT_ERR_BADOFFSET;
|
||||
|
||||
if (node == -FDT_ERR_BADOFFSET) {
|
||||
node = fdt_node_offset_by_compatible(fdt, -1, "st,stpmic1");
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
int dt_pmic_status(void)
|
||||
{
|
||||
static int status = -FDT_ERR_BADVALUE;
|
||||
int node;
|
||||
void *fdt;
|
||||
|
||||
if (status != -FDT_ERR_BADVALUE) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (fdt_get_address(&fdt) == 0) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
node = dt_get_pmic_node(fdt);
|
||||
if (node <= 0) {
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
status = -FDT_ERR_NOTFOUND;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
return fdt_get_status(node);
|
||||
status = (int)fdt_get_status(node);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static bool dt_pmic_is_secure(void)
|
||||
|
@ -65,37 +74,41 @@ static bool dt_pmic_is_secure(void)
|
|||
|
||||
/*
|
||||
* Get PMIC and its I2C bus configuration from the device tree.
|
||||
* Return 0 on success, negative on error, 1 if no PMIC node is found.
|
||||
* Return 0 on success, negative on error, 1 if no PMIC node is defined.
|
||||
*/
|
||||
static int dt_pmic_i2c_config(struct dt_node_info *i2c_info,
|
||||
struct stm32_i2c_init_s *init)
|
||||
{
|
||||
int pmic_node, i2c_node;
|
||||
static int i2c_node = -FDT_ERR_NOTFOUND;
|
||||
void *fdt;
|
||||
const fdt32_t *cuint;
|
||||
|
||||
if (fdt_get_address(&fdt) == 0) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
pmic_node = dt_get_pmic_node(fdt);
|
||||
if (pmic_node < 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
cuint = fdt_getprop(fdt, pmic_node, "reg", NULL);
|
||||
if (cuint == NULL) {
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
}
|
||||
|
||||
pmic_i2c_addr = fdt32_to_cpu(*cuint) << 1;
|
||||
if (pmic_i2c_addr > UINT16_MAX) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (i2c_node == -FDT_ERR_NOTFOUND) {
|
||||
int pmic_node;
|
||||
const fdt32_t *cuint;
|
||||
|
||||
i2c_node = fdt_parent_offset(fdt, pmic_node);
|
||||
if (i2c_node < 0) {
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
pmic_node = dt_get_pmic_node(fdt);
|
||||
if (pmic_node < 0) {
|
||||
return PMIC_NODE_NOT_FOUND;
|
||||
}
|
||||
|
||||
cuint = fdt_getprop(fdt, pmic_node, "reg", NULL);
|
||||
if (cuint == NULL) {
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
}
|
||||
|
||||
pmic_i2c_addr = fdt32_to_cpu(*cuint) << 1;
|
||||
if (pmic_i2c_addr > UINT16_MAX) {
|
||||
return -FDT_ERR_BADVALUE;
|
||||
}
|
||||
|
||||
i2c_node = fdt_parent_offset(fdt, pmic_node);
|
||||
if (i2c_node < 0) {
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
}
|
||||
}
|
||||
|
||||
dt_fill_device_info(i2c_info, i2c_node);
|
||||
|
@ -106,86 +119,6 @@ static int dt_pmic_i2c_config(struct dt_node_info *i2c_info,
|
|||
return stm32_i2c_get_setup_from_fdt(fdt, i2c_node, init);
|
||||
}
|
||||
|
||||
int dt_pmic_configure_boot_on_regulators(void)
|
||||
{
|
||||
int pmic_node, regulators_node, regulator_node;
|
||||
void *fdt;
|
||||
|
||||
if (fdt_get_address(&fdt) == 0) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
pmic_node = dt_get_pmic_node(fdt);
|
||||
if (pmic_node < 0) {
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
}
|
||||
|
||||
regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators");
|
||||
if (regulators_node < 0) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
fdt_for_each_subnode(regulator_node, fdt, regulators_node) {
|
||||
const fdt32_t *cuint;
|
||||
const char *node_name = fdt_get_name(fdt, regulator_node, NULL);
|
||||
uint16_t voltage;
|
||||
int status;
|
||||
|
||||
#if defined(IMAGE_BL2)
|
||||
if ((fdt_getprop(fdt, regulator_node, "regulator-boot-on",
|
||||
NULL) == NULL) &&
|
||||
(fdt_getprop(fdt, regulator_node, "regulator-always-on",
|
||||
NULL) == NULL)) {
|
||||
#else
|
||||
if (fdt_getprop(fdt, regulator_node, "regulator-boot-on",
|
||||
NULL) == NULL) {
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fdt_getprop(fdt, regulator_node, "regulator-pull-down",
|
||||
NULL) != NULL) {
|
||||
|
||||
status = stpmic1_regulator_pull_down_set(node_name);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (fdt_getprop(fdt, regulator_node, "st,mask-reset",
|
||||
NULL) != NULL) {
|
||||
|
||||
status = stpmic1_regulator_mask_reset_set(node_name);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
cuint = fdt_getprop(fdt, regulator_node,
|
||||
"regulator-min-microvolt", NULL);
|
||||
if (cuint == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* DT uses microvolts, whereas driver awaits millivolts */
|
||||
voltage = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U);
|
||||
|
||||
status = stpmic1_regulator_voltage_set(node_name, voltage);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (stpmic1_is_regulator_enabled(node_name) == 0U) {
|
||||
status = stpmic1_regulator_enable(node_name);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool initialize_pmic_i2c(void)
|
||||
{
|
||||
int ret;
|
||||
|
@ -251,8 +184,6 @@ static void register_pmic_shared_peripherals(void)
|
|||
|
||||
void initialize_pmic(void)
|
||||
{
|
||||
unsigned long pmic_version;
|
||||
|
||||
if (!initialize_pmic_i2c()) {
|
||||
VERBOSE("No PMIC\n");
|
||||
return;
|
||||
|
@ -260,70 +191,77 @@ void initialize_pmic(void)
|
|||
|
||||
register_pmic_shared_peripherals();
|
||||
|
||||
if (register_pmic() < 0) {
|
||||
panic();
|
||||
}
|
||||
|
||||
if (stpmic1_powerctrl_on() < 0) {
|
||||
panic();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
void print_pmic_info_and_debug(void)
|
||||
{
|
||||
unsigned long pmic_version;
|
||||
|
||||
if (stpmic1_get_version(&pmic_version) != 0) {
|
||||
ERROR("Failed to access PMIC\n");
|
||||
panic();
|
||||
}
|
||||
|
||||
INFO("PMIC version = 0x%02lx\n", pmic_version);
|
||||
stpmic1_dump_regulators();
|
||||
|
||||
#if defined(IMAGE_BL2)
|
||||
if (dt_pmic_configure_boot_on_regulators() != 0) {
|
||||
panic();
|
||||
};
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
int pmic_ddr_power_init(enum ddr_type ddr_type)
|
||||
{
|
||||
bool buck3_at_1v8 = false;
|
||||
uint8_t read_val;
|
||||
int status;
|
||||
uint16_t buck3_min_mv;
|
||||
struct rdev *buck2, *buck3, *ldo3, *vref;
|
||||
|
||||
buck2 = regulator_get_by_name("buck2");
|
||||
if (buck2 == NULL) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ldo3 = regulator_get_by_name("ldo3");
|
||||
if (ldo3 == NULL) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
vref = regulator_get_by_name("vref_ddr");
|
||||
if (vref == NULL) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
switch (ddr_type) {
|
||||
case STM32MP_DDR3:
|
||||
/* Set LDO3 to sync mode */
|
||||
status = stpmic1_register_read(LDO3_CONTROL_REG, &read_val);
|
||||
status = regulator_set_flag(ldo3, REGUL_SINK_SOURCE);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
read_val &= ~STPMIC1_LDO3_MODE;
|
||||
read_val &= ~STPMIC1_LDO12356_OUTPUT_MASK;
|
||||
read_val |= STPMIC1_LDO3_DDR_SEL <<
|
||||
STPMIC1_LDO12356_OUTPUT_SHIFT;
|
||||
|
||||
status = stpmic1_register_write(LDO3_CONTROL_REG, read_val);
|
||||
status = regulator_set_min_voltage(buck2);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = stpmic1_regulator_voltage_set("buck2", 1350);
|
||||
status = regulator_enable(buck2);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = stpmic1_regulator_enable("buck2");
|
||||
status = regulator_enable(vref);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
|
||||
|
||||
status = stpmic1_regulator_enable("vref_ddr");
|
||||
status = regulator_enable(ldo3);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
|
||||
|
||||
status = stpmic1_regulator_enable("ldo3");
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
|
||||
break;
|
||||
|
||||
case STM32MP_LPDDR2:
|
||||
|
@ -333,57 +271,44 @@ int pmic_ddr_power_init(enum ddr_type ddr_type)
|
|||
* Set LDO3 to bypass mode if BUCK3 = 1.8V
|
||||
* Set LDO3 to normal mode if BUCK3 != 1.8V
|
||||
*/
|
||||
status = stpmic1_register_read(BUCK3_CONTROL_REG, &read_val);
|
||||
buck3 = regulator_get_by_name("buck3");
|
||||
if (buck3 == NULL) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
regulator_get_range(buck3, &buck3_min_mv, NULL);
|
||||
|
||||
if (buck3_min_mv != 1800) {
|
||||
status = regulator_set_min_voltage(ldo3);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
} else {
|
||||
status = regulator_set_flag(ldo3, REGUL_ENABLE_BYPASS);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
status = regulator_set_min_voltage(buck2);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if ((read_val & STPMIC1_BUCK3_1V8) == STPMIC1_BUCK3_1V8) {
|
||||
buck3_at_1v8 = true;
|
||||
}
|
||||
|
||||
status = stpmic1_register_read(LDO3_CONTROL_REG, &read_val);
|
||||
status = regulator_enable(ldo3);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
read_val &= ~STPMIC1_LDO3_MODE;
|
||||
read_val &= ~STPMIC1_LDO12356_OUTPUT_MASK;
|
||||
read_val |= STPMIC1_LDO3_1800000;
|
||||
if (buck3_at_1v8) {
|
||||
read_val |= STPMIC1_LDO3_MODE;
|
||||
}
|
||||
|
||||
status = stpmic1_register_write(LDO3_CONTROL_REG, read_val);
|
||||
status = regulator_enable(buck2);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = stpmic1_regulator_voltage_set("buck2", 1200);
|
||||
status = regulator_enable(vref);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = stpmic1_regulator_enable("ldo3");
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
|
||||
|
||||
status = stpmic1_regulator_enable("buck2");
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
|
||||
|
||||
status = stpmic1_regulator_enable("vref_ddr");
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -392,3 +317,169 @@ int pmic_ddr_power_init(enum ddr_type ddr_type)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum {
|
||||
STPMIC1_BUCK1 = 0,
|
||||
STPMIC1_BUCK2,
|
||||
STPMIC1_BUCK3,
|
||||
STPMIC1_BUCK4,
|
||||
STPMIC1_LDO1,
|
||||
STPMIC1_LDO2,
|
||||
STPMIC1_LDO3,
|
||||
STPMIC1_LDO4,
|
||||
STPMIC1_LDO5,
|
||||
STPMIC1_LDO6,
|
||||
STPMIC1_VREF_DDR,
|
||||
STPMIC1_BOOST,
|
||||
STPMIC1_VBUS_OTG,
|
||||
STPMIC1_SW_OUT,
|
||||
};
|
||||
|
||||
static int pmic_set_state(const struct regul_description *desc, bool enable)
|
||||
{
|
||||
VERBOSE("%s: set state to %u\n", desc->node_name, enable);
|
||||
|
||||
if (enable == STATE_ENABLE) {
|
||||
return stpmic1_regulator_enable(desc->node_name);
|
||||
} else {
|
||||
return stpmic1_regulator_disable(desc->node_name);
|
||||
}
|
||||
}
|
||||
|
||||
static int pmic_get_state(const struct regul_description *desc)
|
||||
{
|
||||
VERBOSE("%s: get state\n", desc->node_name);
|
||||
|
||||
return stpmic1_is_regulator_enabled(desc->node_name);
|
||||
}
|
||||
|
||||
static int pmic_get_voltage(const struct regul_description *desc)
|
||||
{
|
||||
VERBOSE("%s: get volt\n", desc->node_name);
|
||||
|
||||
return stpmic1_regulator_voltage_get(desc->node_name);
|
||||
}
|
||||
|
||||
static int pmic_set_voltage(const struct regul_description *desc, uint16_t mv)
|
||||
{
|
||||
VERBOSE("%s: get volt\n", desc->node_name);
|
||||
|
||||
return stpmic1_regulator_voltage_set(desc->node_name, mv);
|
||||
}
|
||||
|
||||
static int pmic_list_voltages(const struct regul_description *desc,
|
||||
const uint16_t **levels, size_t *count)
|
||||
{
|
||||
VERBOSE("%s: list volt\n", desc->node_name);
|
||||
|
||||
return stpmic1_regulator_levels_mv(desc->node_name, levels, count);
|
||||
}
|
||||
|
||||
static int pmic_set_flag(const struct regul_description *desc, uint16_t flag)
|
||||
{
|
||||
VERBOSE("%s: set_flag 0x%x\n", desc->node_name, flag);
|
||||
|
||||
switch (flag) {
|
||||
case REGUL_OCP:
|
||||
return stpmic1_regulator_icc_set(desc->node_name);
|
||||
|
||||
case REGUL_ACTIVE_DISCHARGE:
|
||||
return stpmic1_active_discharge_mode_set(desc->node_name);
|
||||
|
||||
case REGUL_PULL_DOWN:
|
||||
return stpmic1_regulator_pull_down_set(desc->node_name);
|
||||
|
||||
case REGUL_MASK_RESET:
|
||||
return stpmic1_regulator_mask_reset_set(desc->node_name);
|
||||
|
||||
case REGUL_SINK_SOURCE:
|
||||
return stpmic1_regulator_sink_mode_set(desc->node_name);
|
||||
|
||||
case REGUL_ENABLE_BYPASS:
|
||||
return stpmic1_regulator_bypass_mode_set(desc->node_name);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
struct regul_ops pmic_ops = {
|
||||
.set_state = pmic_set_state,
|
||||
.get_state = pmic_get_state,
|
||||
.set_voltage = pmic_set_voltage,
|
||||
.get_voltage = pmic_get_voltage,
|
||||
.list_voltages = pmic_list_voltages,
|
||||
.set_flag = pmic_set_flag,
|
||||
};
|
||||
|
||||
#define DEFINE_REGU(name) { \
|
||||
.node_name = name, \
|
||||
.ops = &pmic_ops, \
|
||||
.driver_data = NULL, \
|
||||
.enable_ramp_delay = 1000, \
|
||||
}
|
||||
|
||||
static const struct regul_description pmic_regs[] = {
|
||||
[STPMIC1_BUCK1] = DEFINE_REGU("buck1"),
|
||||
[STPMIC1_BUCK2] = DEFINE_REGU("buck2"),
|
||||
[STPMIC1_BUCK3] = DEFINE_REGU("buck3"),
|
||||
[STPMIC1_BUCK4] = DEFINE_REGU("buck4"),
|
||||
[STPMIC1_LDO1] = DEFINE_REGU("ldo1"),
|
||||
[STPMIC1_LDO2] = DEFINE_REGU("ldo2"),
|
||||
[STPMIC1_LDO3] = DEFINE_REGU("ldo3"),
|
||||
[STPMIC1_LDO4] = DEFINE_REGU("ldo4"),
|
||||
[STPMIC1_LDO5] = DEFINE_REGU("ldo5"),
|
||||
[STPMIC1_LDO6] = DEFINE_REGU("ldo6"),
|
||||
[STPMIC1_VREF_DDR] = DEFINE_REGU("vref_ddr"),
|
||||
[STPMIC1_BOOST] = DEFINE_REGU("boost"),
|
||||
[STPMIC1_VBUS_OTG] = DEFINE_REGU("pwr_sw1"),
|
||||
[STPMIC1_SW_OUT] = DEFINE_REGU("pwr_sw2"),
|
||||
};
|
||||
|
||||
#define NB_REG ARRAY_SIZE(pmic_regs)
|
||||
|
||||
static int register_pmic(void)
|
||||
{
|
||||
void *fdt;
|
||||
int pmic_node, regulators_node, subnode;
|
||||
|
||||
VERBOSE("Register pmic\n");
|
||||
|
||||
if (fdt_get_address(&fdt) == 0) {
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
}
|
||||
|
||||
pmic_node = dt_get_pmic_node(fdt);
|
||||
if (pmic_node < 0) {
|
||||
return pmic_node;
|
||||
}
|
||||
|
||||
regulators_node = fdt_subnode_offset(fdt, pmic_node, "regulators");
|
||||
if (regulators_node < 0) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
fdt_for_each_subnode(subnode, fdt, regulators_node) {
|
||||
const char *reg_name = fdt_get_name(fdt, subnode, NULL);
|
||||
const struct regul_description *desc;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < NB_REG; i++) {
|
||||
desc = &pmic_regs[i];
|
||||
if (strcmp(desc->node_name, reg_name) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(i < NB_REG);
|
||||
|
||||
ret = regulator_register(desc, subnode);
|
||||
if (ret != 0) {
|
||||
WARN("%s:%d failed to register %s\n", __func__,
|
||||
__LINE__, reg_name);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -23,10 +23,17 @@ struct regul_struct {
|
|||
uint8_t pull_down;
|
||||
uint8_t mask_reset_reg;
|
||||
uint8_t mask_reset;
|
||||
uint8_t icc_reg;
|
||||
uint8_t icc_mask;
|
||||
};
|
||||
|
||||
static struct i2c_handle_s *pmic_i2c_handle;
|
||||
static uint16_t pmic_i2c_addr;
|
||||
/*
|
||||
* Special mode corresponds to LDO3 in sink source mode or in bypass mode.
|
||||
* LDO3 doesn't switch back from special to normal mode.
|
||||
*/
|
||||
static bool ldo3_special_mode;
|
||||
|
||||
/* Voltage tables in mV */
|
||||
static const uint16_t buck1_voltage_table[] = {
|
||||
|
@ -347,8 +354,11 @@ static const uint16_t ldo3_voltage_table[] = {
|
|||
3300,
|
||||
3300,
|
||||
3300,
|
||||
500,
|
||||
0xFFFF, /* VREFDDR */
|
||||
};
|
||||
|
||||
/* Special mode table is used for sink source OR bypass mode */
|
||||
static const uint16_t ldo3_special_mode_table[] = {
|
||||
0,
|
||||
};
|
||||
|
||||
static const uint16_t ldo5_voltage_table[] = {
|
||||
|
@ -421,6 +431,10 @@ static const uint16_t vref_ddr_voltage_table[] = {
|
|||
3300,
|
||||
};
|
||||
|
||||
static const uint16_t fixed_5v_voltage_table[] = {
|
||||
5000,
|
||||
};
|
||||
|
||||
/* Table of Regulators in PMIC SoC */
|
||||
static const struct regul_struct regulators_table[] = {
|
||||
{
|
||||
|
@ -434,6 +448,8 @@ static const struct regul_struct regulators_table[] = {
|
|||
.pull_down = BUCK1_PULL_DOWN_SHIFT,
|
||||
.mask_reset_reg = MASK_RESET_BUCK_REG,
|
||||
.mask_reset = BUCK1_MASK_RESET,
|
||||
.icc_reg = BUCK_ICC_TURNOFF_REG,
|
||||
.icc_mask = BUCK1_ICC_SHIFT,
|
||||
},
|
||||
{
|
||||
.dt_node_name = "buck2",
|
||||
|
@ -446,6 +462,8 @@ static const struct regul_struct regulators_table[] = {
|
|||
.pull_down = BUCK2_PULL_DOWN_SHIFT,
|
||||
.mask_reset_reg = MASK_RESET_BUCK_REG,
|
||||
.mask_reset = BUCK2_MASK_RESET,
|
||||
.icc_reg = BUCK_ICC_TURNOFF_REG,
|
||||
.icc_mask = BUCK2_ICC_SHIFT,
|
||||
},
|
||||
{
|
||||
.dt_node_name = "buck3",
|
||||
|
@ -458,6 +476,8 @@ static const struct regul_struct regulators_table[] = {
|
|||
.pull_down = BUCK3_PULL_DOWN_SHIFT,
|
||||
.mask_reset_reg = MASK_RESET_BUCK_REG,
|
||||
.mask_reset = BUCK3_MASK_RESET,
|
||||
.icc_reg = BUCK_ICC_TURNOFF_REG,
|
||||
.icc_mask = BUCK3_ICC_SHIFT,
|
||||
},
|
||||
{
|
||||
.dt_node_name = "buck4",
|
||||
|
@ -470,6 +490,8 @@ static const struct regul_struct regulators_table[] = {
|
|||
.pull_down = BUCK4_PULL_DOWN_SHIFT,
|
||||
.mask_reset_reg = MASK_RESET_BUCK_REG,
|
||||
.mask_reset = BUCK4_MASK_RESET,
|
||||
.icc_reg = BUCK_ICC_TURNOFF_REG,
|
||||
.icc_mask = BUCK4_ICC_SHIFT,
|
||||
},
|
||||
{
|
||||
.dt_node_name = "ldo1",
|
||||
|
@ -480,6 +502,8 @@ static const struct regul_struct regulators_table[] = {
|
|||
.low_power_reg = LDO1_PWRCTRL_REG,
|
||||
.mask_reset_reg = MASK_RESET_LDO_REG,
|
||||
.mask_reset = LDO1_MASK_RESET,
|
||||
.icc_reg = LDO_ICC_TURNOFF_REG,
|
||||
.icc_mask = LDO1_ICC_SHIFT,
|
||||
},
|
||||
{
|
||||
.dt_node_name = "ldo2",
|
||||
|
@ -490,6 +514,8 @@ static const struct regul_struct regulators_table[] = {
|
|||
.low_power_reg = LDO2_PWRCTRL_REG,
|
||||
.mask_reset_reg = MASK_RESET_LDO_REG,
|
||||
.mask_reset = LDO2_MASK_RESET,
|
||||
.icc_reg = LDO_ICC_TURNOFF_REG,
|
||||
.icc_mask = LDO2_ICC_SHIFT,
|
||||
},
|
||||
{
|
||||
.dt_node_name = "ldo3",
|
||||
|
@ -500,6 +526,8 @@ static const struct regul_struct regulators_table[] = {
|
|||
.low_power_reg = LDO3_PWRCTRL_REG,
|
||||
.mask_reset_reg = MASK_RESET_LDO_REG,
|
||||
.mask_reset = LDO3_MASK_RESET,
|
||||
.icc_reg = LDO_ICC_TURNOFF_REG,
|
||||
.icc_mask = LDO3_ICC_SHIFT,
|
||||
},
|
||||
{
|
||||
.dt_node_name = "ldo4",
|
||||
|
@ -510,6 +538,8 @@ static const struct regul_struct regulators_table[] = {
|
|||
.low_power_reg = LDO4_PWRCTRL_REG,
|
||||
.mask_reset_reg = MASK_RESET_LDO_REG,
|
||||
.mask_reset = LDO4_MASK_RESET,
|
||||
.icc_reg = LDO_ICC_TURNOFF_REG,
|
||||
.icc_mask = LDO4_ICC_SHIFT,
|
||||
},
|
||||
{
|
||||
.dt_node_name = "ldo5",
|
||||
|
@ -520,6 +550,8 @@ static const struct regul_struct regulators_table[] = {
|
|||
.low_power_reg = LDO5_PWRCTRL_REG,
|
||||
.mask_reset_reg = MASK_RESET_LDO_REG,
|
||||
.mask_reset = LDO5_MASK_RESET,
|
||||
.icc_reg = LDO_ICC_TURNOFF_REG,
|
||||
.icc_mask = LDO5_ICC_SHIFT,
|
||||
},
|
||||
{
|
||||
.dt_node_name = "ldo6",
|
||||
|
@ -530,6 +562,8 @@ static const struct regul_struct regulators_table[] = {
|
|||
.low_power_reg = LDO6_PWRCTRL_REG,
|
||||
.mask_reset_reg = MASK_RESET_LDO_REG,
|
||||
.mask_reset = LDO6_MASK_RESET,
|
||||
.icc_reg = LDO_ICC_TURNOFF_REG,
|
||||
.icc_mask = LDO6_ICC_SHIFT,
|
||||
},
|
||||
{
|
||||
.dt_node_name = "vref_ddr",
|
||||
|
@ -541,6 +575,33 @@ static const struct regul_struct regulators_table[] = {
|
|||
.mask_reset_reg = MASK_RESET_LDO_REG,
|
||||
.mask_reset = VREF_DDR_MASK_RESET,
|
||||
},
|
||||
{
|
||||
.dt_node_name = "boost",
|
||||
.voltage_table = fixed_5v_voltage_table,
|
||||
.voltage_table_size = ARRAY_SIZE(fixed_5v_voltage_table),
|
||||
.control_reg = USB_CONTROL_REG,
|
||||
.enable_mask = BOOST_ENABLED,
|
||||
.icc_reg = BUCK_ICC_TURNOFF_REG,
|
||||
.icc_mask = BOOST_ICC_SHIFT,
|
||||
},
|
||||
{
|
||||
.dt_node_name = "pwr_sw1",
|
||||
.voltage_table = fixed_5v_voltage_table,
|
||||
.voltage_table_size = ARRAY_SIZE(fixed_5v_voltage_table),
|
||||
.control_reg = USB_CONTROL_REG,
|
||||
.enable_mask = USBSW_OTG_SWITCH_ENABLED,
|
||||
.icc_reg = BUCK_ICC_TURNOFF_REG,
|
||||
.icc_mask = PWR_SW1_ICC_SHIFT,
|
||||
},
|
||||
{
|
||||
.dt_node_name = "pwr_sw2",
|
||||
.voltage_table = fixed_5v_voltage_table,
|
||||
.voltage_table_size = ARRAY_SIZE(fixed_5v_voltage_table),
|
||||
.control_reg = USB_CONTROL_REG,
|
||||
.enable_mask = SWIN_SWOUT_ENABLED,
|
||||
.icc_reg = BUCK_ICC_TURNOFF_REG,
|
||||
.icc_mask = PWR_SW2_ICC_SHIFT,
|
||||
},
|
||||
};
|
||||
|
||||
#define MAX_REGUL ARRAY_SIZE(regulators_table)
|
||||
|
@ -606,7 +667,7 @@ int stpmic1_regulator_disable(const char *name)
|
|||
regul->enable_mask);
|
||||
}
|
||||
|
||||
uint8_t stpmic1_is_regulator_enabled(const char *name)
|
||||
bool stpmic1_is_regulator_enabled(const char *name)
|
||||
{
|
||||
uint8_t val;
|
||||
const struct regul_struct *regul = get_regulator_data(name);
|
||||
|
@ -615,7 +676,7 @@ uint8_t stpmic1_is_regulator_enabled(const char *name)
|
|||
panic();
|
||||
}
|
||||
|
||||
return (val & regul->enable_mask);
|
||||
return (val & regul->enable_mask) == regul->enable_mask;
|
||||
}
|
||||
|
||||
int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts)
|
||||
|
@ -624,11 +685,21 @@ int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts)
|
|||
const struct regul_struct *regul = get_regulator_data(name);
|
||||
uint8_t mask;
|
||||
|
||||
if ((strncmp(name, "ldo3", 5) == 0) && ldo3_special_mode) {
|
||||
/*
|
||||
* when the LDO3 is in special mode, we do not change voltage,
|
||||
* because by setting voltage, the LDO would leaves sink-source
|
||||
* mode. There is obviously no reason to leave sink-source mode
|
||||
* at runtime.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Voltage can be set for buck<N> or ldo<N> (except ldo4) regulators */
|
||||
if (strncmp(name, "buck", 4) == 0) {
|
||||
mask = BUCK_VOLTAGE_MASK;
|
||||
} else if ((strncmp(name, "ldo", 3) == 0) &&
|
||||
(strncmp(name, "ldo4", 4) != 0)) {
|
||||
(strncmp(name, "ldo4", 5) != 0)) {
|
||||
mask = LDO_VOLTAGE_MASK;
|
||||
} else {
|
||||
return 0;
|
||||
|
@ -657,12 +728,90 @@ int stpmic1_regulator_mask_reset_set(const char *name)
|
|||
{
|
||||
const struct regul_struct *regul = get_regulator_data(name);
|
||||
|
||||
if (regul->mask_reset_reg == 0U) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
return stpmic1_register_update(regul->mask_reset_reg,
|
||||
BIT(regul->mask_reset),
|
||||
LDO_BUCK_RESET_MASK <<
|
||||
regul->mask_reset);
|
||||
}
|
||||
|
||||
int stpmic1_regulator_icc_set(const char *name)
|
||||
{
|
||||
const struct regul_struct *regul = get_regulator_data(name);
|
||||
|
||||
if (regul->mask_reset_reg == 0U) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
return stpmic1_register_update(regul->icc_reg,
|
||||
BIT(regul->icc_mask),
|
||||
BIT(regul->icc_mask));
|
||||
}
|
||||
|
||||
int stpmic1_regulator_sink_mode_set(const char *name)
|
||||
{
|
||||
if (strncmp(name, "ldo3", 5) != 0) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
ldo3_special_mode = true;
|
||||
|
||||
/* disable bypass mode, enable sink mode */
|
||||
return stpmic1_register_update(LDO3_CONTROL_REG,
|
||||
LDO3_DDR_SEL << LDO_BUCK_VOLTAGE_SHIFT,
|
||||
LDO3_BYPASS | LDO_VOLTAGE_MASK);
|
||||
}
|
||||
|
||||
int stpmic1_regulator_bypass_mode_set(const char *name)
|
||||
{
|
||||
if (strncmp(name, "ldo3", 5) != 0) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
ldo3_special_mode = true;
|
||||
|
||||
/* enable bypass mode, disable sink mode */
|
||||
return stpmic1_register_update(LDO3_CONTROL_REG,
|
||||
LDO3_BYPASS,
|
||||
LDO3_BYPASS | LDO_VOLTAGE_MASK);
|
||||
}
|
||||
|
||||
int stpmic1_active_discharge_mode_set(const char *name)
|
||||
{
|
||||
if (strncmp(name, "pwr_sw1", 8) == 0) {
|
||||
return stpmic1_register_update(USB_CONTROL_REG,
|
||||
VBUS_OTG_DISCHARGE,
|
||||
VBUS_OTG_DISCHARGE);
|
||||
}
|
||||
|
||||
if (strncmp(name, "pwr_sw2", 8) == 0) {
|
||||
return stpmic1_register_update(USB_CONTROL_REG,
|
||||
SW_OUT_DISCHARGE,
|
||||
SW_OUT_DISCHARGE);
|
||||
}
|
||||
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
int stpmic1_regulator_levels_mv(const char *name, const uint16_t **levels,
|
||||
size_t *levels_count)
|
||||
{
|
||||
const struct regul_struct *regul = get_regulator_data(name);
|
||||
|
||||
if ((strncmp(name, "ldo3", 5) == 0) && ldo3_special_mode) {
|
||||
*levels_count = ARRAY_SIZE(ldo3_special_mode_table);
|
||||
*levels = ldo3_special_mode_table;
|
||||
} else {
|
||||
*levels_count = regul->voltage_table_size;
|
||||
*levels = regul->voltage_table;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stpmic1_regulator_voltage_get(const char *name)
|
||||
{
|
||||
const struct regul_struct *regul = get_regulator_data(name);
|
||||
|
@ -670,11 +819,15 @@ int stpmic1_regulator_voltage_get(const char *name)
|
|||
uint8_t mask;
|
||||
int status;
|
||||
|
||||
if ((strncmp(name, "ldo3", 5) == 0) && ldo3_special_mode) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Voltage can be set for buck<N> or ldo<N> (except ldo4) regulators */
|
||||
if (strncmp(name, "buck", 4) == 0) {
|
||||
mask = BUCK_VOLTAGE_MASK;
|
||||
} else if ((strncmp(name, "ldo", 3) == 0) &&
|
||||
(strncmp(name, "ldo4", 4) != 0)) {
|
||||
(strncmp(name, "ldo4", 5) != 0)) {
|
||||
mask = LDO_VOLTAGE_MASK;
|
||||
} else {
|
||||
return 0;
|
||||
|
|
536
drivers/st/regulator/regulator_core.c
Normal file
536
drivers/st/regulator/regulator_core.c
Normal file
|
@ -0,0 +1,536 @@
|
|||
/*
|
||||
* Copyright (c) 2021, STMicroelectronics - All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <common/debug.h>
|
||||
#include <drivers/delay_timer.h>
|
||||
#include <drivers/st/regulator.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#define MAX_PROPERTY_LEN 64
|
||||
|
||||
static struct rdev rdev_array[PLAT_NB_RDEVS];
|
||||
|
||||
#define for_each_rdev(rdev) \
|
||||
for (rdev = rdev_array; rdev < (rdev_array + PLAT_NB_RDEVS); rdev++)
|
||||
|
||||
#define for_each_registered_rdev(rdev) \
|
||||
for (rdev = rdev_array; \
|
||||
(rdev < (rdev_array + PLAT_NB_RDEVS)) && (rdev->desc != NULL); rdev++)
|
||||
|
||||
static void lock_driver(const struct rdev *rdev)
|
||||
{
|
||||
if (rdev->desc->ops->lock != NULL) {
|
||||
rdev->desc->ops->lock(rdev->desc);
|
||||
}
|
||||
}
|
||||
|
||||
static void unlock_driver(const struct rdev *rdev)
|
||||
{
|
||||
if (rdev->desc->ops->unlock != NULL) {
|
||||
rdev->desc->ops->unlock(rdev->desc);
|
||||
}
|
||||
}
|
||||
|
||||
static struct rdev *regulator_get_by_phandle(int32_t phandle)
|
||||
{
|
||||
struct rdev *rdev;
|
||||
|
||||
for_each_registered_rdev(rdev) {
|
||||
if (rdev->phandle == phandle) {
|
||||
return rdev;
|
||||
}
|
||||
}
|
||||
|
||||
WARN("%s: phandle %d not found\n", __func__, phandle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a regulator from its node name
|
||||
*
|
||||
* @fdt - pointer to device tree memory
|
||||
* @node_name - name of the node "ldo1"
|
||||
* Return pointer to rdev if succeed, NULL else.
|
||||
*/
|
||||
struct rdev *regulator_get_by_name(const char *node_name)
|
||||
{
|
||||
struct rdev *rdev;
|
||||
|
||||
assert(node_name != NULL);
|
||||
VERBOSE("get %s\n", node_name);
|
||||
|
||||
for_each_registered_rdev(rdev) {
|
||||
if (strcmp(rdev->desc->node_name, node_name) == 0) {
|
||||
return rdev;
|
||||
}
|
||||
}
|
||||
|
||||
WARN("%s: %s not found\n", __func__, node_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int32_t get_supply_phandle(const void *fdt, int node, const char *name)
|
||||
{
|
||||
const fdt32_t *cuint;
|
||||
int len __unused;
|
||||
int supply_phandle = -FDT_ERR_NOTFOUND;
|
||||
char prop_name[MAX_PROPERTY_LEN];
|
||||
|
||||
len = snprintf(prop_name, MAX_PROPERTY_LEN - 1, "%s-supply", name);
|
||||
assert((len >= 0) && (len < MAX_PROPERTY_LEN - 1));
|
||||
|
||||
cuint = fdt_getprop(fdt, node, prop_name, NULL);
|
||||
if (cuint != NULL) {
|
||||
supply_phandle = fdt32_to_cpu(*cuint);
|
||||
VERBOSE("%s: supplied by %d\n", name, supply_phandle);
|
||||
}
|
||||
|
||||
return supply_phandle;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a regulator from a supply name
|
||||
*
|
||||
* @fdt - pointer to device tree memory
|
||||
* @node - offset of the node that contains the supply description
|
||||
* @name - name of the supply "vdd" for "vdd-supply'
|
||||
* Return pointer to rdev if succeed, NULL else.
|
||||
*/
|
||||
struct rdev *regulator_get_by_supply_name(const void *fdt, int node, const char *name)
|
||||
{
|
||||
const int p = get_supply_phandle(fdt, node, name);
|
||||
|
||||
if (p < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return regulator_get_by_phandle(p);
|
||||
}
|
||||
|
||||
static int __regulator_set_state(struct rdev *rdev, bool state)
|
||||
{
|
||||
if (rdev->desc->ops->set_state == NULL) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return rdev->desc->ops->set_state(rdev->desc, state);
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable regulator
|
||||
*
|
||||
* @rdev - pointer to rdev struct
|
||||
* Return 0 if succeed, non 0 else.
|
||||
*/
|
||||
int regulator_enable(struct rdev *rdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
assert(rdev != NULL);
|
||||
|
||||
ret = __regulator_set_state(rdev, STATE_ENABLE);
|
||||
|
||||
udelay(rdev->enable_ramp_delay);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable regulator
|
||||
*
|
||||
* @rdev - pointer to rdev struct
|
||||
* Return 0 if succeed, non 0 else.
|
||||
*/
|
||||
int regulator_disable(struct rdev *rdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
assert(rdev != NULL);
|
||||
|
||||
ret = __regulator_set_state(rdev, STATE_DISABLE);
|
||||
|
||||
udelay(rdev->enable_ramp_delay);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Regulator enabled query
|
||||
*
|
||||
* @rdev - pointer to rdev struct
|
||||
* Return 0 if disabled, 1 if enabled, <0 else.
|
||||
*/
|
||||
int regulator_is_enabled(const struct rdev *rdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
assert(rdev != NULL);
|
||||
|
||||
VERBOSE("%s: is en\n", rdev->desc->node_name);
|
||||
|
||||
if (rdev->desc->ops->get_state == NULL) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
lock_driver(rdev);
|
||||
|
||||
ret = rdev->desc->ops->get_state(rdev->desc);
|
||||
if (ret < 0) {
|
||||
ERROR("regul %s get state failed: err:%d\n",
|
||||
rdev->desc->node_name, ret);
|
||||
}
|
||||
|
||||
unlock_driver(rdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set regulator voltage
|
||||
*
|
||||
* @rdev - pointer to rdev struct
|
||||
* @mvolt - Target voltage level in millivolt
|
||||
* Return 0 if succeed, non 0 else.
|
||||
*/
|
||||
int regulator_set_voltage(struct rdev *rdev, uint16_t mvolt)
|
||||
{
|
||||
int ret;
|
||||
|
||||
assert(rdev != NULL);
|
||||
|
||||
VERBOSE("%s: set mvolt\n", rdev->desc->node_name);
|
||||
|
||||
if (rdev->desc->ops->set_voltage == NULL) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if ((mvolt < rdev->min_mv) || (mvolt > rdev->max_mv)) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
lock_driver(rdev);
|
||||
|
||||
ret = rdev->desc->ops->set_voltage(rdev->desc, mvolt);
|
||||
if (ret < 0) {
|
||||
ERROR("regul %s set volt failed: err:%d\n",
|
||||
rdev->desc->node_name, ret);
|
||||
}
|
||||
|
||||
unlock_driver(rdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set regulator min voltage
|
||||
*
|
||||
* @rdev - pointer to rdev struct
|
||||
* Return 0 if succeed, non 0 else.
|
||||
*/
|
||||
int regulator_set_min_voltage(struct rdev *rdev)
|
||||
{
|
||||
return regulator_set_voltage(rdev, rdev->min_mv);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get regulator voltage
|
||||
*
|
||||
* @rdev - pointer to rdev struct
|
||||
* Return milli volts if succeed, <0 else.
|
||||
*/
|
||||
int regulator_get_voltage(const struct rdev *rdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
assert(rdev != NULL);
|
||||
|
||||
VERBOSE("%s: get volt\n", rdev->desc->node_name);
|
||||
|
||||
if (rdev->desc->ops->get_voltage == NULL) {
|
||||
return rdev->min_mv;
|
||||
}
|
||||
|
||||
lock_driver(rdev);
|
||||
|
||||
ret = rdev->desc->ops->get_voltage(rdev->desc);
|
||||
if (ret < 0) {
|
||||
ERROR("regul %s get voltage failed: err:%d\n",
|
||||
rdev->desc->node_name, ret);
|
||||
}
|
||||
|
||||
unlock_driver(rdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* List regulator voltages
|
||||
*
|
||||
* @rdev - pointer to rdev struct
|
||||
* @levels - out: array of supported millitvolt levels from min to max value
|
||||
* @count - out: number of possible millivolt values
|
||||
* Return 0 if succeed, non 0 else.
|
||||
*/
|
||||
int regulator_list_voltages(const struct rdev *rdev, const uint16_t **levels, size_t *count)
|
||||
{
|
||||
int ret;
|
||||
size_t n;
|
||||
|
||||
assert(rdev != NULL);
|
||||
assert(levels != NULL);
|
||||
assert(count != NULL);
|
||||
|
||||
VERBOSE("%s: list volt\n", rdev->desc->node_name);
|
||||
|
||||
if (rdev->desc->ops->list_voltages == NULL) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
lock_driver(rdev);
|
||||
|
||||
ret = rdev->desc->ops->list_voltages(rdev->desc, levels, count);
|
||||
|
||||
unlock_driver(rdev);
|
||||
|
||||
if (ret < 0) {
|
||||
ERROR("regul %s list_voltages failed: err: %d\n",
|
||||
rdev->desc->node_name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reduce the possible values depending on min and max from device-tree
|
||||
*/
|
||||
n = *count;
|
||||
while ((n > 1U) && ((*levels)[n - 1U] > rdev->max_mv)) {
|
||||
n--;
|
||||
}
|
||||
|
||||
/* Verify that max val is a valid value */
|
||||
if (rdev->max_mv != (*levels)[n - 1]) {
|
||||
ERROR("regul %s: max value %u is invalid\n",
|
||||
rdev->desc->node_name, rdev->max_mv);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
while ((n > 1U) && ((*levels[0U]) < rdev->min_mv)) {
|
||||
(*levels)++;
|
||||
n--;
|
||||
}
|
||||
|
||||
/* Verify that min is not too high */
|
||||
if (n == 0U) {
|
||||
ERROR("regul %s set min voltage is too high\n",
|
||||
rdev->desc->node_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Verify that min val is a valid vlue */
|
||||
if (rdev->min_mv != (*levels)[0U]) {
|
||||
ERROR("regul %s: min value %u is invalid\n",
|
||||
rdev->desc->node_name, rdev->min_mv);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*count = n;
|
||||
|
||||
VERBOSE("rdev->min_mv=%u rdev->max_mv=%u\n", rdev->min_mv, rdev->max_mv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get regulator voltages range
|
||||
*
|
||||
* @rdev - pointer to rdev struct
|
||||
* @min_mv - out: min possible millivolt value
|
||||
* @max_mv - out: max possible millivolt value
|
||||
* Return 0 if succeed, non 0 else.
|
||||
*/
|
||||
void regulator_get_range(const struct rdev *rdev, uint16_t *min_mv, uint16_t *max_mv)
|
||||
{
|
||||
assert(rdev != NULL);
|
||||
|
||||
if (min_mv != NULL) {
|
||||
*min_mv = rdev->min_mv;
|
||||
}
|
||||
if (max_mv != NULL) {
|
||||
*max_mv = rdev->max_mv;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set regulator flag
|
||||
*
|
||||
* @rdev - pointer to rdev struct
|
||||
* @flag - flag value to set (eg: REGUL_OCP)
|
||||
* Return 0 if succeed, non 0 else.
|
||||
*/
|
||||
int regulator_set_flag(struct rdev *rdev, uint16_t flag)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* check that only one bit is set on flag */
|
||||
if (__builtin_popcount(flag) != 1) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* REGUL_ALWAYS_ON and REGUL_BOOT_ON are internal properties of the core */
|
||||
if ((flag == REGUL_ALWAYS_ON) || (flag == REGUL_BOOT_ON)) {
|
||||
rdev->flags |= flag;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rdev->desc->ops->set_flag == NULL) {
|
||||
ERROR("%s can not set any flag\n", rdev->desc->node_name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
lock_driver(rdev);
|
||||
|
||||
ret = rdev->desc->ops->set_flag(rdev->desc, flag);
|
||||
|
||||
unlock_driver(rdev);
|
||||
|
||||
if (ret != 0) {
|
||||
ERROR("%s: could not set flag %d ret=%d\n",
|
||||
rdev->desc->node_name, flag, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rdev->flags |= flag;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the device-tree for a regulator
|
||||
*
|
||||
* Read min/max voltage from dt and check its validity
|
||||
* Read the properties, and call the driver to set flags
|
||||
* Read power supply phandle
|
||||
* Read and store low power mode states
|
||||
*
|
||||
* @rdev - pointer to rdev struct
|
||||
* @node - device-tree node offset of the regulator
|
||||
* Return 0 if disabled, 1 if enabled, <0 else.
|
||||
*/
|
||||
static int parse_dt(struct rdev *rdev, int node)
|
||||
{
|
||||
void *fdt;
|
||||
const fdt32_t *cuint;
|
||||
const uint16_t *levels;
|
||||
size_t size;
|
||||
int ret;
|
||||
|
||||
VERBOSE("%s: parse dt\n", rdev->desc->node_name);
|
||||
|
||||
if (fdt_get_address(&fdt) == 0) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
rdev->phandle = fdt_get_phandle(fdt, node);
|
||||
|
||||
cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL);
|
||||
if (cuint != NULL) {
|
||||
uint16_t min_mv;
|
||||
|
||||
min_mv = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U);
|
||||
VERBOSE("%s: min_mv=%d\n", rdev->desc->node_name, (int)min_mv);
|
||||
if (min_mv <= rdev->max_mv) {
|
||||
rdev->min_mv = min_mv;
|
||||
} else {
|
||||
ERROR("%s: min_mv=%d is too high\n",
|
||||
rdev->desc->node_name, (int)min_mv);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
cuint = fdt_getprop(fdt, node, "regulator-max-microvolt", NULL);
|
||||
if (cuint != NULL) {
|
||||
uint16_t max_mv;
|
||||
|
||||
max_mv = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U);
|
||||
VERBOSE("%s: max_mv=%d\n", rdev->desc->node_name, (int)max_mv);
|
||||
if (max_mv >= rdev->min_mv) {
|
||||
rdev->max_mv = max_mv;
|
||||
} else {
|
||||
ERROR("%s: max_mv=%d is too low\n",
|
||||
rdev->desc->node_name, (int)max_mv);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* validate that min and max values can be used */
|
||||
ret = regulator_list_voltages(rdev, &levels, &size);
|
||||
if ((ret != 0) && (ret != -ENODEV)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register a regulator driver in regulator framework.
|
||||
* Initialize voltage range from driver description
|
||||
*
|
||||
* @desc - pointer to the regulator description
|
||||
* @node - device-tree node offset of the regulator
|
||||
* Return 0 if succeed, non 0 else.
|
||||
*/
|
||||
int regulator_register(const struct regul_description *desc, int node)
|
||||
{
|
||||
struct rdev *rdev;
|
||||
|
||||
assert(desc != NULL);
|
||||
|
||||
VERBOSE("register %s\n", desc->node_name);
|
||||
|
||||
for_each_rdev(rdev) {
|
||||
if (rdev->desc == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rdev == rdev_array + PLAT_NB_RDEVS) {
|
||||
WARN("Not enough place for regulators, PLAT_NB_RDEVS should be increased.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rdev->desc = desc;
|
||||
rdev->enable_ramp_delay = rdev->desc->enable_ramp_delay;
|
||||
|
||||
if (rdev->desc->ops->list_voltages != NULL) {
|
||||
int ret;
|
||||
const uint16_t *levels;
|
||||
size_t count;
|
||||
|
||||
lock_driver(rdev);
|
||||
|
||||
ret = rdev->desc->ops->list_voltages(rdev->desc, &levels, &count);
|
||||
|
||||
unlock_driver(rdev);
|
||||
|
||||
if (ret < 0) {
|
||||
ERROR("regul %s set state failed: err:%d\n",
|
||||
rdev->desc->node_name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rdev->min_mv = levels[0];
|
||||
rdev->max_mv = levels[count - 1U];
|
||||
} else {
|
||||
rdev->max_mv = UINT16_MAX;
|
||||
}
|
||||
|
||||
return parse_dt(rdev, node);
|
||||
}
|
87
drivers/st/regulator/regulator_fixed.c
Normal file
87
drivers/st/regulator/regulator_fixed.c
Normal file
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (c) 2021, STMicroelectronics - All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <common/debug.h>
|
||||
#include <common/fdt_wrappers.h>
|
||||
#include <drivers/st/regulator.h>
|
||||
#include <drivers/st/regulator_fixed.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#ifndef PLAT_NB_FIXED_REGS
|
||||
#error "Missing PLAT_NB_FIXED_REGS"
|
||||
#endif
|
||||
|
||||
#define FIXED_NAME_LEN 32
|
||||
|
||||
struct fixed_data {
|
||||
char name[FIXED_NAME_LEN];
|
||||
uint16_t volt;
|
||||
struct regul_description desc;
|
||||
};
|
||||
|
||||
static struct fixed_data data[PLAT_NB_FIXED_REGS];
|
||||
|
||||
static int fixed_set_state(const struct regul_description *desc, bool state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fixed_get_state(const struct regul_description *desc)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct regul_ops fixed_ops = {
|
||||
.set_state = fixed_set_state,
|
||||
.get_state = fixed_get_state,
|
||||
};
|
||||
|
||||
int fixed_regulator_register(void)
|
||||
{
|
||||
uint32_t count = 0;
|
||||
void *fdt;
|
||||
int node;
|
||||
|
||||
VERBOSE("fixed reg init!\n");
|
||||
|
||||
if (fdt_get_address(&fdt) == 0) {
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
}
|
||||
|
||||
fdt_for_each_compatible_node(fdt, node, "regulator-fixed") {
|
||||
int len __unused;
|
||||
int ret;
|
||||
struct fixed_data *d = &data[count];
|
||||
const char *reg_name;
|
||||
|
||||
reg_name = fdt_get_name(fdt, node, NULL);
|
||||
|
||||
VERBOSE("register fixed reg %s!\n", reg_name);
|
||||
|
||||
len = snprintf(d->name, FIXED_NAME_LEN - 1, "%s", reg_name);
|
||||
assert((len > 0) && (len < (FIXED_NAME_LEN - 1)));
|
||||
|
||||
d->desc.node_name = d->name;
|
||||
d->desc.driver_data = d;
|
||||
d->desc.ops = &fixed_ops;
|
||||
|
||||
ret = regulator_register(&d->desc, node);
|
||||
if (ret != 0) {
|
||||
WARN("%s:%d failed to register %s\n", __func__,
|
||||
__LINE__, reg_name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
count++;
|
||||
assert(count <= PLAT_NB_FIXED_REGS);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -135,14 +135,15 @@
|
|||
|
||||
vtt_ddr: ldo3 {
|
||||
regulator-name = "vtt_ddr";
|
||||
regulator-min-microvolt = <500000>;
|
||||
regulator-max-microvolt = <750000>;
|
||||
regulator-always-on;
|
||||
regulator-over-current-protection;
|
||||
st,regulator-sink-source;
|
||||
};
|
||||
|
||||
vdd_usb: ldo4 {
|
||||
regulator-name = "vdd_usb";
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
};
|
||||
|
||||
vdd_sd: ldo5 {
|
||||
|
|
|
@ -131,10 +131,9 @@
|
|||
|
||||
vtt_ddr: ldo3 {
|
||||
regulator-name = "vtt_ddr";
|
||||
regulator-min-microvolt = <500000>;
|
||||
regulator-max-microvolt = <750000>;
|
||||
regulator-always-on;
|
||||
regulator-over-current-protection;
|
||||
st,regulator-sink-source;
|
||||
};
|
||||
|
||||
vdd_usb: ldo4 {
|
||||
|
@ -160,7 +159,6 @@
|
|||
vref_ddr: vref_ddr {
|
||||
regulator-name = "vref_ddr";
|
||||
regulator-always-on;
|
||||
regulator-over-current-protection;
|
||||
};
|
||||
|
||||
bst_out: boost {
|
||||
|
|
108
include/drivers/st/regulator.h
Normal file
108
include/drivers/st/regulator.h
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (c) 2021, STMicroelectronics - All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
#ifndef REGULATOR_H
|
||||
#define REGULATOR_H
|
||||
|
||||
#include <platform_def.h>
|
||||
|
||||
#ifndef PLAT_NB_RDEVS
|
||||
#error "Missing PLAT_NB_RDEVS"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Consumer interface
|
||||
*/
|
||||
|
||||
/* regulator-always-on : regulator should never be disabled */
|
||||
#define REGUL_ALWAYS_ON BIT(0)
|
||||
/*
|
||||
* regulator-boot-on:
|
||||
* It's expected that this regulator was left on by the bootloader.
|
||||
* The core shouldn't prevent it from being turned off later.
|
||||
* The regulator is needed to exit from suspend so it is turned on during suspend entry.
|
||||
*/
|
||||
#define REGUL_BOOT_ON BIT(1)
|
||||
/* regulator-over-current-protection: Enable over current protection. */
|
||||
#define REGUL_OCP BIT(2)
|
||||
/* regulator-active-discharge: enable active discharge. */
|
||||
#define REGUL_ACTIVE_DISCHARGE BIT(3)
|
||||
/* regulator-pull-down: Enable pull down resistor when the regulator is disabled. */
|
||||
#define REGUL_PULL_DOWN BIT(4)
|
||||
/*
|
||||
* st,mask-reset: set mask reset for the regulator, meaning that the regulator
|
||||
* setting is maintained during pmic reset.
|
||||
*/
|
||||
#define REGUL_MASK_RESET BIT(5)
|
||||
/* st,regulator-sink-source: set the regulator in sink source mode */
|
||||
#define REGUL_SINK_SOURCE BIT(6)
|
||||
/* st,regulator-bypass: set the regulator in bypass mode */
|
||||
#define REGUL_ENABLE_BYPASS BIT(7)
|
||||
|
||||
struct rdev *regulator_get_by_name(const char *node_name);
|
||||
|
||||
struct rdev *regulator_get_by_supply_name(const void *fdt, int node, const char *name);
|
||||
|
||||
int regulator_enable(struct rdev *rdev);
|
||||
int regulator_disable(struct rdev *rdev);
|
||||
int regulator_is_enabled(const struct rdev *rdev);
|
||||
|
||||
int regulator_set_voltage(struct rdev *rdev, uint16_t volt);
|
||||
int regulator_set_min_voltage(struct rdev *rdev);
|
||||
int regulator_get_voltage(const struct rdev *rdev);
|
||||
|
||||
int regulator_list_voltages(const struct rdev *rdev, const uint16_t **levels, size_t *count);
|
||||
void regulator_get_range(const struct rdev *rdev, uint16_t *min_mv, uint16_t *max_mv);
|
||||
int regulator_set_flag(struct rdev *rdev, uint16_t flag);
|
||||
|
||||
/*
|
||||
* Driver Interface
|
||||
*/
|
||||
|
||||
/* set_state() arguments */
|
||||
#define STATE_DISABLE false
|
||||
#define STATE_ENABLE true
|
||||
|
||||
struct regul_description {
|
||||
const char *node_name;
|
||||
const struct regul_ops *ops;
|
||||
const void *driver_data;
|
||||
const char *supply_name;
|
||||
const uint32_t enable_ramp_delay;
|
||||
};
|
||||
|
||||
struct regul_ops {
|
||||
int (*set_state)(const struct regul_description *desc, bool state);
|
||||
int (*get_state)(const struct regul_description *desc);
|
||||
int (*set_voltage)(const struct regul_description *desc, uint16_t mv);
|
||||
int (*get_voltage)(const struct regul_description *desc);
|
||||
int (*list_voltages)(const struct regul_description *desc,
|
||||
const uint16_t **levels, size_t *count);
|
||||
int (*set_flag)(const struct regul_description *desc, uint16_t flag);
|
||||
void (*lock)(const struct regul_description *desc);
|
||||
void (*unlock)(const struct regul_description *desc);
|
||||
};
|
||||
|
||||
int regulator_register(const struct regul_description *desc, int node);
|
||||
|
||||
/*
|
||||
* Internal regulator structure
|
||||
* The structure is internal to the core, and the content should not be used
|
||||
* by a consumer nor a driver.
|
||||
*/
|
||||
struct rdev {
|
||||
const struct regul_description *desc;
|
||||
|
||||
int32_t phandle;
|
||||
|
||||
uint16_t min_mv;
|
||||
uint16_t max_mv;
|
||||
|
||||
uint16_t flags;
|
||||
|
||||
uint32_t enable_ramp_delay;
|
||||
};
|
||||
|
||||
#endif /* REGULATOR_H */
|
12
include/drivers/st/regulator_fixed.h
Normal file
12
include/drivers/st/regulator_fixed.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* Copyright (c) 2021, STMicroelectronics - All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef REGULATOR_FIXED_H
|
||||
#define REGULATOR_FIXED_H
|
||||
|
||||
int fixed_regulator_register(void);
|
||||
|
||||
#endif /* REGULATOR_FIXED_H */
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
|
||||
* Copyright (c) 2017-2021, STMicroelectronics - All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
@ -10,6 +10,7 @@
|
|||
#include <stdbool.h>
|
||||
|
||||
#include <drivers/mmc.h>
|
||||
#include <drivers/st/regulator.h>
|
||||
|
||||
struct stm32_sdmmc2_params {
|
||||
uintptr_t reg_base;
|
||||
|
@ -24,6 +25,7 @@ struct stm32_sdmmc2_params {
|
|||
unsigned int reset_id;
|
||||
unsigned int max_freq;
|
||||
bool use_dma;
|
||||
struct rdev *vmmc_regu;
|
||||
};
|
||||
|
||||
unsigned long long stm32_sdmmc2_mmc_get_device_size(void);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
|
||||
* Copyright (c) 2017-2021, STMicroelectronics - All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
@ -19,14 +19,6 @@
|
|||
*/
|
||||
int dt_pmic_status(void);
|
||||
|
||||
/*
|
||||
* dt_pmic_configure_boot_on_regulators - Configure boot-on and always-on
|
||||
* regulators from device tree configuration
|
||||
*
|
||||
* Returns 0 on success, and negative values on errors
|
||||
*/
|
||||
int dt_pmic_configure_boot_on_regulators(void);
|
||||
|
||||
/*
|
||||
* initialize_pmic_i2c - Initialize I2C for the PMIC control
|
||||
*
|
||||
|
@ -41,6 +33,14 @@ bool initialize_pmic_i2c(void);
|
|||
*/
|
||||
void initialize_pmic(void);
|
||||
|
||||
#if DEBUG
|
||||
void print_pmic_info_and_debug(void);
|
||||
#else
|
||||
static inline void print_pmic_info_and_debug(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* pmic_ddr_power_init - Initialize regulators required for DDR
|
||||
*
|
||||
|
|
|
@ -103,6 +103,22 @@
|
|||
#define BUCK4_PULL_DOWN_SHIFT 6
|
||||
#define VREF_DDR_PULL_DOWN_SHIFT 4
|
||||
|
||||
/* ICC register */
|
||||
#define BUCK1_ICC_SHIFT 0
|
||||
#define BUCK2_ICC_SHIFT 1
|
||||
#define BUCK3_ICC_SHIFT 2
|
||||
#define BUCK4_ICC_SHIFT 3
|
||||
#define PWR_SW1_ICC_SHIFT 4
|
||||
#define PWR_SW2_ICC_SHIFT 5
|
||||
#define BOOST_ICC_SHIFT 6
|
||||
|
||||
#define LDO1_ICC_SHIFT 0
|
||||
#define LDO2_ICC_SHIFT 1
|
||||
#define LDO3_ICC_SHIFT 2
|
||||
#define LDO4_ICC_SHIFT 3
|
||||
#define LDO5_ICC_SHIFT 4
|
||||
#define LDO6_ICC_SHIFT 5
|
||||
|
||||
/* Buck Mask reset register */
|
||||
#define BUCK1_MASK_RESET 0
|
||||
#define BUCK2_MASK_RESET 1
|
||||
|
@ -118,6 +134,10 @@
|
|||
#define LDO6_MASK_RESET 5
|
||||
#define VREF_DDR_MASK_RESET 6
|
||||
|
||||
/* LDO3 Special modes */
|
||||
#define LDO3_BYPASS BIT(7)
|
||||
#define LDO3_DDR_SEL 31U
|
||||
|
||||
/* Main PMIC Control Register (MAIN_CONTROL_REG) */
|
||||
#define ICC_EVENT_ENABLED BIT(4)
|
||||
#define PWRCTRL_POLARITY_HIGH BIT(3)
|
||||
|
@ -145,9 +165,12 @@
|
|||
/* USB Control Register */
|
||||
#define BOOST_OVP_DISABLED BIT(7)
|
||||
#define VBUS_OTG_DETECTION_DISABLED BIT(6)
|
||||
#define SW_OUT_DISCHARGE BIT(5)
|
||||
#define VBUS_OTG_DISCHARGE BIT(4)
|
||||
#define OCP_LIMIT_HIGH BIT(3)
|
||||
#define SWIN_SWOUT_ENABLED BIT(2)
|
||||
#define USBSW_OTG_SWITCH_ENABLED BIT(1)
|
||||
#define BOOST_ENABLED BIT(0)
|
||||
|
||||
int stpmic1_powerctrl_on(void);
|
||||
int stpmic1_switch_off(void);
|
||||
|
@ -156,11 +179,17 @@ int stpmic1_register_write(uint8_t register_id, uint8_t value);
|
|||
int stpmic1_register_update(uint8_t register_id, uint8_t value, uint8_t mask);
|
||||
int stpmic1_regulator_enable(const char *name);
|
||||
int stpmic1_regulator_disable(const char *name);
|
||||
uint8_t stpmic1_is_regulator_enabled(const char *name);
|
||||
bool stpmic1_is_regulator_enabled(const char *name);
|
||||
int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts);
|
||||
int stpmic1_regulator_levels_mv(const char *name, const uint16_t **levels,
|
||||
size_t *levels_count);
|
||||
int stpmic1_regulator_voltage_get(const char *name);
|
||||
int stpmic1_regulator_pull_down_set(const char *name);
|
||||
int stpmic1_regulator_mask_reset_set(const char *name);
|
||||
int stpmic1_regulator_icc_set(const char *name);
|
||||
int stpmic1_regulator_sink_mode_set(const char *name);
|
||||
int stpmic1_regulator_bypass_mode_set(const char *name);
|
||||
int stpmic1_active_discharge_mode_set(const char *name);
|
||||
void stpmic1_bind_i2c(struct i2c_handle_s *i2c_handle, uint16_t i2c_addr);
|
||||
|
||||
int stpmic1_get_version(unsigned long *version);
|
||||
|
|
|
@ -37,6 +37,8 @@ int dt_get_stdout_uart_info(struct dt_node_info *info);
|
|||
int dt_match_instance_by_compatible(const char *compatible, uintptr_t address);
|
||||
uint32_t dt_get_ddr_size(void);
|
||||
uint32_t dt_get_pwr_vdd_voltage(void);
|
||||
struct rdev *dt_get_vdd_regulator(void);
|
||||
struct rdev *dt_get_cpu_regulator(void);
|
||||
const char *dt_get_board_model(void);
|
||||
int fdt_get_gpio_bank_pin_count(unsigned int bank);
|
||||
|
||||
|
|
|
@ -7,16 +7,15 @@
|
|||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <libfdt.h>
|
||||
|
||||
#include <platform_def.h>
|
||||
|
||||
#include <common/debug.h>
|
||||
#include <common/fdt_wrappers.h>
|
||||
#include <drivers/st/regulator.h>
|
||||
#include <drivers/st/stm32_gpio.h>
|
||||
#include <drivers/st/stm32mp1_ddr.h>
|
||||
#include <drivers/st/stm32mp1_ram.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include <platform_def.h>
|
||||
#include <stm32mp_dt.h>
|
||||
|
||||
static void *fdt;
|
||||
|
@ -262,37 +261,46 @@ uint32_t dt_get_ddr_size(void)
|
|||
******************************************************************************/
|
||||
uint32_t dt_get_pwr_vdd_voltage(void)
|
||||
{
|
||||
int node, pwr_regulators_node;
|
||||
const fdt32_t *cuint;
|
||||
struct rdev *regul = dt_get_vdd_regulator();
|
||||
uint16_t min;
|
||||
|
||||
if (regul == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
regulator_get_range(regul, &min, NULL);
|
||||
|
||||
return (uint32_t)min * 1000U;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* This function retrieves VDD supply regulator from DT.
|
||||
* Returns an rdev taken from supply node, NULL otherwise.
|
||||
******************************************************************************/
|
||||
struct rdev *dt_get_vdd_regulator(void)
|
||||
{
|
||||
int node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
|
||||
|
||||
node = fdt_node_offset_by_compatible(fdt, -1, DT_PWR_COMPAT);
|
||||
if (node < 0) {
|
||||
INFO("%s: Cannot read PWR node in DT\n", __func__);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pwr_regulators_node = fdt_subnode_offset(fdt, node, "pwr-regulators");
|
||||
if (pwr_regulators_node < 0) {
|
||||
INFO("%s: Cannot read pwr-regulators node in DT\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
return regulator_get_by_supply_name(fdt, node, "vdd");
|
||||
}
|
||||
|
||||
cuint = fdt_getprop(fdt, pwr_regulators_node, "vdd-supply", NULL);
|
||||
if (cuint == NULL) {
|
||||
return 0;
|
||||
}
|
||||
/*******************************************************************************
|
||||
* This function retrieves CPU supply regulator from DT.
|
||||
* Returns an rdev taken from supply node, NULL otherwise.
|
||||
******************************************************************************/
|
||||
struct rdev *dt_get_cpu_regulator(void)
|
||||
{
|
||||
int node = fdt_path_offset(fdt, "/cpus/cpu@0");
|
||||
|
||||
node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
|
||||
if (node < 0) {
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cuint = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL);
|
||||
if (cuint == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return fdt32_to_cpu(*cuint);
|
||||
return regulator_get_by_supply_name(fdt, node, "cpu");
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <drivers/generic_delay_timer.h>
|
||||
#include <drivers/mmc.h>
|
||||
#include <drivers/st/bsec.h>
|
||||
#include <drivers/st/regulator_fixed.h>
|
||||
#include <drivers/st/stm32_iwdg.h>
|
||||
#include <drivers/st/stm32_uart.h>
|
||||
#include <drivers/st/stm32mp1_clk.h>
|
||||
|
@ -130,10 +131,6 @@ void bl2_platform_setup(void)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (dt_pmic_status() > 0) {
|
||||
initialize_pmic();
|
||||
}
|
||||
|
||||
ret = stm32mp1_ddr_probe();
|
||||
if (ret < 0) {
|
||||
ERROR("Invalid DDR init: error %d\n", ret);
|
||||
|
@ -247,8 +244,6 @@ void bl2_el3_plat_arch_setup(void)
|
|||
panic();
|
||||
}
|
||||
|
||||
stm32mp1_syscfg_init();
|
||||
|
||||
stm32_save_boot_interface(boot_context->boot_interface_selected,
|
||||
boot_context->boot_interface_instance);
|
||||
|
||||
|
@ -277,6 +272,17 @@ void bl2_el3_plat_arch_setup(void)
|
|||
}
|
||||
|
||||
skip_console_init:
|
||||
if (fixed_regulator_register() != 0) {
|
||||
panic();
|
||||
}
|
||||
|
||||
if (dt_pmic_status() > 0) {
|
||||
initialize_pmic();
|
||||
print_pmic_info_and_debug();
|
||||
}
|
||||
|
||||
stm32mp1_syscfg_init();
|
||||
|
||||
if (stm32_iwdg_init() < 0) {
|
||||
panic();
|
||||
}
|
||||
|
|
|
@ -201,6 +201,8 @@ PLAT_BL_COMMON_SOURCES += drivers/arm/tzc/tzc400.c \
|
|||
drivers/st/iwdg/stm32_iwdg.c \
|
||||
drivers/st/pmic/stm32mp_pmic.c \
|
||||
drivers/st/pmic/stpmic1.c \
|
||||
drivers/st/regulator/regulator_core.c \
|
||||
drivers/st/regulator/regulator_fixed.c \
|
||||
drivers/st/reset/stm32mp1_reset.c \
|
||||
plat/st/common/stm32mp_dt.c \
|
||||
plat/st/stm32mp1/stm32mp1_dbgmcu.c \
|
||||
|
|
|
@ -460,6 +460,14 @@ static inline uint32_t tamp_bkpr(uint32_t idx)
|
|||
#define STGEN_BASE U(0x5c008000)
|
||||
#define SYSCFG_BASE U(0x50020000)
|
||||
|
||||
/*******************************************************************************
|
||||
* REGULATORS
|
||||
******************************************************************************/
|
||||
/* 3 PWR + 1 VREFBUF + 14 PMIC regulators + 1 FIXED */
|
||||
#define PLAT_NB_RDEVS U(19)
|
||||
/* 1 FIXED */
|
||||
#define PLAT_NB_FIXED_REGS U(1)
|
||||
|
||||
/*******************************************************************************
|
||||
* Device Tree defines
|
||||
******************************************************************************/
|
||||
|
|
Loading…
Add table
Reference in a new issue