mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-16 17:44:19 +00:00
feat(st-pmic): add STPMIC2 driver
The STPMIC2 embeds 15 regulators with various properties, and is designed to supply the STM32MP2 SOC. This driver handles a minimal set of feature to handle the boot of a board. Signed-off-by: Pascal Paillet <p.paillet@st.com> Signed-off-by: Patrick Delaunay <patrick.delaunay@foss.st.com> Signed-off-by: Maxime Méré <maxime.mere@foss.st.com> Change-Id: Ibe0cacf8aec2871eb9a86ec16cbbd18d3745fe9e
This commit is contained in:
parent
b2c535da56
commit
817f42f07e
6 changed files with 1341 additions and 0 deletions
499
drivers/st/pmic/stm32mp_pmic2.c
Normal file
499
drivers/st/pmic/stm32mp_pmic2.c
Normal file
|
@ -0,0 +1,499 @@
|
|||
/*
|
||||
* Copyright (C) 2024, STMicroelectronics - All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.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_pmic2.h>
|
||||
#include <drivers/st/stpmic2.h>
|
||||
#include <lib/mmio.h>
|
||||
#include <lib/spinlock.h>
|
||||
#include <lib/utils_def.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
#include <platform_def.h>
|
||||
|
||||
#define PMIC_NODE_NOT_FOUND 1
|
||||
|
||||
struct regul_handle_s {
|
||||
const uint32_t id;
|
||||
uint16_t bypass_mv;
|
||||
};
|
||||
|
||||
static struct pmic_handle_s pmic2_handle;
|
||||
static struct i2c_handle_s i2c_handle;
|
||||
|
||||
/* This driver is monoinstance */
|
||||
static struct pmic_handle_s *pmic2;
|
||||
|
||||
static int dt_get_pmic_node(void *fdt)
|
||||
{
|
||||
static int node = -FDT_ERR_BADOFFSET;
|
||||
|
||||
if (node == -FDT_ERR_BADOFFSET) {
|
||||
node = fdt_node_offset_by_compatible(fdt, -1, "st,stpmic2");
|
||||
}
|
||||
|
||||
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) {
|
||||
status = -FDT_ERR_NOTFOUND;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
status = DT_SECURE;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get PMIC and its I2C bus configuration from the device tree.
|
||||
* Return 0 on success, negative on error, 1 if no PMIC node is defined.
|
||||
*/
|
||||
static int dt_pmic2_i2c_config(struct dt_node_info *i2c_info,
|
||||
struct stm32_i2c_init_s *init,
|
||||
uint32_t *i2c_addr)
|
||||
{
|
||||
static int i2c_node = -FDT_ERR_NOTFOUND;
|
||||
void *fdt;
|
||||
|
||||
if (fdt_get_address(&fdt) == 0) {
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
}
|
||||
|
||||
if (i2c_node == -FDT_ERR_NOTFOUND) {
|
||||
int pmic_node;
|
||||
const fdt32_t *cuint;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
*i2c_addr = fdt32_to_cpu(*cuint) << 1;
|
||||
if (*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);
|
||||
if (i2c_info->base == 0U) {
|
||||
return -FDT_ERR_NOTFOUND;
|
||||
}
|
||||
|
||||
i2c_info->status = DT_SECURE;
|
||||
|
||||
return stm32_i2c_get_setup_from_fdt(fdt, i2c_node, init);
|
||||
}
|
||||
|
||||
bool initialize_pmic_i2c(void)
|
||||
{
|
||||
int ret;
|
||||
struct dt_node_info i2c_info;
|
||||
struct i2c_handle_s *i2c = &i2c_handle;
|
||||
uint32_t i2c_addr = 0U;
|
||||
struct stm32_i2c_init_s i2c_init;
|
||||
|
||||
ret = dt_pmic2_i2c_config(&i2c_info, &i2c_init, &i2c_addr);
|
||||
if (ret < 0) {
|
||||
ERROR("I2C configuration failed %d\n", ret);
|
||||
panic();
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Initialize PMIC I2C */
|
||||
i2c->i2c_base_addr = i2c_info.base;
|
||||
i2c->dt_status = i2c_info.status;
|
||||
i2c->clock = i2c_info.clock;
|
||||
i2c->i2c_state = I2C_STATE_RESET;
|
||||
i2c_init.own_address1 = i2c_addr;
|
||||
i2c_init.addressing_mode = I2C_ADDRESSINGMODE_7BIT;
|
||||
i2c_init.dual_address_mode = I2C_DUALADDRESS_DISABLE;
|
||||
i2c_init.own_address2 = 0;
|
||||
i2c_init.own_address2_masks = I2C_OAR2_OA2NOMASK;
|
||||
i2c_init.general_call_mode = I2C_GENERALCALL_DISABLE;
|
||||
i2c_init.no_stretch_mode = I2C_NOSTRETCH_DISABLE;
|
||||
i2c_init.analog_filter = 1;
|
||||
i2c_init.digital_filter_coef = 0;
|
||||
|
||||
ret = stm32_i2c_init(i2c, &i2c_init);
|
||||
if (ret != 0) {
|
||||
ERROR("Cannot initialize I2C %x (%d)\n",
|
||||
i2c->i2c_base_addr, ret);
|
||||
panic();
|
||||
}
|
||||
|
||||
if (!stm32_i2c_is_device_ready(i2c, i2c_addr, 1,
|
||||
I2C_TIMEOUT_BUSY_MS)) {
|
||||
ERROR("I2C device not ready\n");
|
||||
panic();
|
||||
}
|
||||
|
||||
pmic2 = &pmic2_handle;
|
||||
pmic2->i2c_handle = &i2c_handle;
|
||||
pmic2->i2c_addr = i2c_addr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int pmic2_set_state(const struct regul_description *desc, bool enable)
|
||||
{
|
||||
struct regul_handle_s *regul = (struct regul_handle_s *)desc->driver_data;
|
||||
|
||||
VERBOSE("%s: set state to %d\n", desc->node_name, enable);
|
||||
|
||||
return stpmic2_regulator_set_state(pmic2, regul->id, enable);
|
||||
}
|
||||
|
||||
static int pmic2_get_state(const struct regul_description *desc)
|
||||
{
|
||||
struct regul_handle_s *regul = (struct regul_handle_s *)desc->driver_data;
|
||||
bool enabled;
|
||||
|
||||
VERBOSE("%s: get state\n", desc->node_name);
|
||||
|
||||
if (stpmic2_regulator_get_state(pmic2, regul->id, &enabled) < 0) {
|
||||
panic();
|
||||
}
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
static int pmic2_get_voltage(const struct regul_description *desc)
|
||||
{
|
||||
struct regul_handle_s *regul = (struct regul_handle_s *)desc->driver_data;
|
||||
uint16_t mv;
|
||||
|
||||
VERBOSE("%s: get volt\n", desc->node_name);
|
||||
|
||||
if (regul->bypass_mv != 0U) {
|
||||
int ret;
|
||||
|
||||
/* If the regul is in bypass mode, return bypass value */
|
||||
ret = stpmic2_regulator_get_prop(pmic2, regul->id, STPMIC2_BYPASS);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret == 1) {
|
||||
return regul->bypass_mv;
|
||||
}
|
||||
};
|
||||
|
||||
if (stpmic2_regulator_get_voltage(pmic2, regul->id, &mv) < 0) {
|
||||
panic();
|
||||
}
|
||||
|
||||
return mv;
|
||||
}
|
||||
|
||||
static int pmic2_set_voltage(const struct regul_description *desc, uint16_t mv)
|
||||
{
|
||||
struct regul_handle_s *regul = (struct regul_handle_s *)desc->driver_data;
|
||||
|
||||
VERBOSE("%s: set volt\n", desc->node_name);
|
||||
|
||||
if (regul->bypass_mv != 0U) {
|
||||
int ret;
|
||||
|
||||
/* If the regul is in bypass mode, authorize bypass mV */
|
||||
ret = stpmic2_regulator_get_prop(pmic2, regul->id, STPMIC2_BYPASS);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret == 1) && (mv != regul->bypass_mv)) {
|
||||
return -EPERM;
|
||||
}
|
||||
};
|
||||
|
||||
return stpmic2_regulator_set_voltage(pmic2, regul->id, mv);
|
||||
}
|
||||
|
||||
static int pmic2_list_voltages(const struct regul_description *desc,
|
||||
const uint16_t **levels, size_t *count)
|
||||
{
|
||||
struct regul_handle_s *regul = (struct regul_handle_s *)desc->driver_data;
|
||||
|
||||
VERBOSE("%s: list volt\n", desc->node_name);
|
||||
|
||||
if (regul->bypass_mv != 0U) {
|
||||
int ret;
|
||||
|
||||
ret = stpmic2_regulator_get_prop(pmic2, regul->id, STPMIC2_BYPASS);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* bypass is enabled, return a list with only bypass mV */
|
||||
if (ret == 1) {
|
||||
if (count != NULL) {
|
||||
*count = 1U;
|
||||
}
|
||||
if (levels != NULL) {
|
||||
*levels = ®ul->bypass_mv;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
return stpmic2_regulator_levels_mv(pmic2, regul->id, levels, count);
|
||||
}
|
||||
|
||||
static int pmic2_set_flag(const struct regul_description *desc, uint16_t flag)
|
||||
{
|
||||
struct regul_handle_s *regul = (struct regul_handle_s *)desc->driver_data;
|
||||
uint32_t id = regul->id;
|
||||
int ret = -EPERM;
|
||||
|
||||
VERBOSE("%s: set_flag 0x%x\n", desc->node_name, flag);
|
||||
|
||||
switch (flag) {
|
||||
case REGUL_PULL_DOWN:
|
||||
ret = stpmic2_regulator_set_prop(pmic2, id, STPMIC2_PULL_DOWN, 1U);
|
||||
break;
|
||||
case REGUL_OCP:
|
||||
ret = stpmic2_regulator_set_prop(pmic2, id, STPMIC2_OCP, 1U);
|
||||
break;
|
||||
case REGUL_SINK_SOURCE:
|
||||
ret = stpmic2_regulator_set_prop(pmic2, id, STPMIC2_SINK_SOURCE, 1U);
|
||||
break;
|
||||
case REGUL_ENABLE_BYPASS:
|
||||
ret = stpmic2_regulator_set_prop(pmic2, id, STPMIC2_BYPASS, 1U);
|
||||
break;
|
||||
case REGUL_MASK_RESET:
|
||||
ret = stpmic2_regulator_set_prop(pmic2, id, STPMIC2_MASK_RESET, 1U);
|
||||
break;
|
||||
default:
|
||||
ERROR("Invalid flag %u", flag);
|
||||
panic();
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stpmic2_set_prop(const struct regul_description *desc, uint16_t prop, uint32_t value)
|
||||
{
|
||||
struct regul_handle_s *regul = (struct regul_handle_s *)desc->driver_data;
|
||||
int ret;
|
||||
|
||||
VERBOSE("%s: set_prop 0x%x val=%u\n", desc->node_name, prop, value);
|
||||
|
||||
ret = stpmic2_regulator_set_prop(pmic2, regul->id, prop, value);
|
||||
if (ret != 0)
|
||||
return -EPERM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct regul_ops pmic2_ops = {
|
||||
.set_state = pmic2_set_state,
|
||||
.get_state = pmic2_get_state,
|
||||
.set_voltage = pmic2_set_voltage,
|
||||
.get_voltage = pmic2_get_voltage,
|
||||
.list_voltages = pmic2_list_voltages,
|
||||
.set_flag = pmic2_set_flag,
|
||||
};
|
||||
|
||||
#define DEFINE_PMIC_REGUL_HANDLE(rid) \
|
||||
[(rid)] = { \
|
||||
.id = (rid), \
|
||||
}
|
||||
|
||||
static struct regul_handle_s pmic2_regul_handles[STPMIC2_NB_REG] = {
|
||||
DEFINE_PMIC_REGUL_HANDLE(STPMIC2_BUCK1),
|
||||
DEFINE_PMIC_REGUL_HANDLE(STPMIC2_BUCK2),
|
||||
DEFINE_PMIC_REGUL_HANDLE(STPMIC2_BUCK3),
|
||||
DEFINE_PMIC_REGUL_HANDLE(STPMIC2_BUCK4),
|
||||
DEFINE_PMIC_REGUL_HANDLE(STPMIC2_BUCK5),
|
||||
DEFINE_PMIC_REGUL_HANDLE(STPMIC2_BUCK6),
|
||||
DEFINE_PMIC_REGUL_HANDLE(STPMIC2_BUCK7),
|
||||
|
||||
DEFINE_PMIC_REGUL_HANDLE(STPMIC2_LDO1),
|
||||
DEFINE_PMIC_REGUL_HANDLE(STPMIC2_LDO2),
|
||||
DEFINE_PMIC_REGUL_HANDLE(STPMIC2_LDO3),
|
||||
DEFINE_PMIC_REGUL_HANDLE(STPMIC2_LDO4),
|
||||
DEFINE_PMIC_REGUL_HANDLE(STPMIC2_LDO5),
|
||||
DEFINE_PMIC_REGUL_HANDLE(STPMIC2_LDO6),
|
||||
DEFINE_PMIC_REGUL_HANDLE(STPMIC2_LDO7),
|
||||
DEFINE_PMIC_REGUL_HANDLE(STPMIC2_LDO8),
|
||||
|
||||
DEFINE_PMIC_REGUL_HANDLE(STPMIC2_REFDDR),
|
||||
};
|
||||
|
||||
#define DEFINE_REGUL(rid, name) \
|
||||
[rid] = { \
|
||||
.node_name = name, \
|
||||
.ops = &pmic2_ops, \
|
||||
.driver_data = &pmic2_regul_handles[rid], \
|
||||
}
|
||||
|
||||
static const struct regul_description pmic2_descs[STPMIC2_NB_REG] = {
|
||||
DEFINE_REGUL(STPMIC2_BUCK1, "buck1"),
|
||||
DEFINE_REGUL(STPMIC2_BUCK2, "buck2"),
|
||||
DEFINE_REGUL(STPMIC2_BUCK3, "buck3"),
|
||||
DEFINE_REGUL(STPMIC2_BUCK4, "buck4"),
|
||||
DEFINE_REGUL(STPMIC2_BUCK5, "buck5"),
|
||||
DEFINE_REGUL(STPMIC2_BUCK6, "buck6"),
|
||||
DEFINE_REGUL(STPMIC2_BUCK7, "buck7"),
|
||||
|
||||
DEFINE_REGUL(STPMIC2_LDO1, "ldo1"),
|
||||
DEFINE_REGUL(STPMIC2_LDO2, "ldo2"),
|
||||
DEFINE_REGUL(STPMIC2_LDO3, "ldo3"),
|
||||
DEFINE_REGUL(STPMIC2_LDO4, "ldo4"),
|
||||
DEFINE_REGUL(STPMIC2_LDO5, "ldo5"),
|
||||
DEFINE_REGUL(STPMIC2_LDO6, "ldo6"),
|
||||
DEFINE_REGUL(STPMIC2_LDO7, "ldo7"),
|
||||
DEFINE_REGUL(STPMIC2_LDO8, "ldo8"),
|
||||
|
||||
DEFINE_REGUL(STPMIC2_REFDDR, "refddr"),
|
||||
};
|
||||
|
||||
static int register_pmic2(void)
|
||||
{
|
||||
void *fdt;
|
||||
int pmic_node, regulators_node, subnode;
|
||||
|
||||
VERBOSE("Register pmic2\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;
|
||||
const fdt32_t *cuint;
|
||||
|
||||
for (i = 0; i < STPMIC2_NB_REG; i++) {
|
||||
desc = &pmic2_descs[i];
|
||||
if (strcmp(desc->node_name, reg_name) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(i < STPMIC2_NB_REG);
|
||||
|
||||
ret = regulator_register(desc, subnode);
|
||||
if (ret != 0) {
|
||||
WARN("%s:%d failed to register %s\n", __func__,
|
||||
__LINE__, reg_name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
cuint = fdt_getprop(fdt, subnode, "st,regulator-bypass-microvolt", NULL);
|
||||
if (cuint != NULL) {
|
||||
struct regul_handle_s *regul = (struct regul_handle_s *)desc->driver_data;
|
||||
|
||||
regul->bypass_mv = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U);
|
||||
VERBOSE("%s: bypass voltage=%umV\n", desc->node_name,
|
||||
regul->bypass_mv);
|
||||
}
|
||||
|
||||
if (fdt_getprop(fdt, subnode, "st,mask-reset", NULL) != NULL) {
|
||||
VERBOSE("%s: set mask-reset\n", desc->node_name);
|
||||
ret = pmic2_set_flag(desc, REGUL_MASK_RESET);
|
||||
if (ret != 0) {
|
||||
ERROR("set mask-reset failed\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (fdt_getprop(fdt, subnode, "st,regulator-sink-source", NULL) != NULL) {
|
||||
VERBOSE("%s: set regulator-sink-source\n", desc->node_name);
|
||||
ret = pmic2_set_flag(desc, REGUL_SINK_SOURCE);
|
||||
if (ret != 0) {
|
||||
ERROR("set regulator-sink-source failed\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void initialize_pmic(void)
|
||||
{
|
||||
int ret;
|
||||
uint8_t val;
|
||||
|
||||
ret = initialize_pmic_i2c();
|
||||
if (!ret) {
|
||||
VERBOSE("No PMIC2\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (stpmic2_get_version(pmic2, &val) != 0) {
|
||||
ERROR("Failed to access PMIC\n");
|
||||
panic();
|
||||
}
|
||||
INFO("PMIC2 version = 0x%02x\n", val);
|
||||
|
||||
if (stpmic2_get_product_id(pmic2, &val) != 0) {
|
||||
ERROR("Failed to access PMIC\n");
|
||||
panic();
|
||||
}
|
||||
INFO("PMIC2 product ID = 0x%02x\n", val);
|
||||
|
||||
ret = register_pmic2();
|
||||
if (ret < 0) {
|
||||
ERROR("Register pmic2 failed\n");
|
||||
panic();
|
||||
}
|
||||
|
||||
#if EVENT_LOG_LEVEL == LOG_LEVEL_VERBOSE
|
||||
stpmic2_dump_regulators(pmic2);
|
||||
#endif
|
||||
}
|
474
drivers/st/pmic/stpmic2.c
Normal file
474
drivers/st/pmic/stpmic2.c
Normal file
|
@ -0,0 +1,474 @@
|
|||
/*
|
||||
* Copyright (C) 2024, STMicroelectronics - All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <common/debug.h>
|
||||
#include <drivers/st/stpmic2.h>
|
||||
|
||||
#define RET_SUCCESS 0
|
||||
#define RET_ERROR_NOT_SUPPORTED -1
|
||||
#define RET_ERROR_GENERIC -2
|
||||
#define RET_ERROR_BAD_PARAMETERS -3
|
||||
|
||||
#define I2C_TIMEOUT_MS 25
|
||||
|
||||
#define VOLTAGE_INDEX_INVALID ((size_t)~0U)
|
||||
|
||||
struct regul_struct {
|
||||
const char *name;
|
||||
const uint16_t *volt_table;
|
||||
uint8_t volt_table_size;
|
||||
uint8_t volt_cr;
|
||||
uint8_t volt_shift;
|
||||
uint8_t en_cr;
|
||||
uint8_t alt_en_cr;
|
||||
uint8_t msrt_reg;
|
||||
uint8_t msrt_mask;
|
||||
uint8_t pd_reg;
|
||||
uint8_t pd_val;
|
||||
uint8_t ocp_reg;
|
||||
uint8_t ocp_mask;
|
||||
};
|
||||
|
||||
/* Voltage tables in mV */
|
||||
static const uint16_t buck1236_volt_table[] = {
|
||||
500U, 510U, 520U, 530U, 540U, 550U, 560U, 570U, 580U, 590U,
|
||||
600U, 610U, 620U, 630U, 640U, 650U, 660U, 670U, 680U, 690U,
|
||||
700U, 710U, 720U, 730U, 740U, 750U, 760U, 770U, 780U, 790U,
|
||||
800U, 810U, 820U, 830U, 840U, 850U, 860U, 870U, 880U, 890U,
|
||||
900U, 910U, 920U, 930U, 940U, 950U, 960U, 970U, 980U, 990U,
|
||||
1000U, 1010U, 1020U, 1030U, 1040U, 1050U, 1060U, 1070U, 1080U, 1090U,
|
||||
1100U, 1110U, 1120U, 1130U, 1140U, 1150U, 1160U, 1170U, 1180U, 1190U,
|
||||
1200U, 1210U, 1220U, 1230U, 1240U, 1250U, 1260U, 1270U, 1280U, 1290U,
|
||||
1300U, 1310U, 1320U, 1330U, 1340U, 1350U, 1360U, 1370U, 1380U, 1390U,
|
||||
1400U, 1410U, 1420U, 1430U, 1440U, 1450U, 1460U, 1470U, 1480U, 1490U,
|
||||
1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
|
||||
1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
|
||||
1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U
|
||||
};
|
||||
|
||||
static const uint16_t buck457_volt_table[] = {
|
||||
1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
|
||||
1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
|
||||
1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
|
||||
1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
|
||||
1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
|
||||
1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
|
||||
1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
|
||||
1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
|
||||
1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
|
||||
1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U, 1500U,
|
||||
1500U, 1600U, 1700U, 1800U, 1900U, 2000U, 2100U, 2200U, 2300U, 2400U,
|
||||
2500U, 2600U, 2700U, 2800U, 2900U, 3000U, 3100U, 3200U, 3300U, 3400U,
|
||||
3500U, 3600U, 3700U, 3800U, 3900U, 4000U, 4100U, 4200U
|
||||
};
|
||||
|
||||
static const uint16_t ldo235678_volt_table[] = {
|
||||
900U, 1000U, 1100U, 1200U, 1300U, 1400U, 1500U, 1600U, 1700U, 1800U,
|
||||
1900U, 2000U, 2100U, 2200U, 2300U, 2400U, 2500U, 2600U, 2700U, 2800U,
|
||||
2900U, 3000U, 3100U, 3200U, 3300U, 3400U, 3500U, 3600U, 3700U, 3800U,
|
||||
3900U, 4000U
|
||||
};
|
||||
|
||||
static const uint16_t ldo1_volt_table[] = {
|
||||
1800U,
|
||||
};
|
||||
|
||||
static const uint16_t ldo4_volt_table[] = {
|
||||
3300U,
|
||||
};
|
||||
|
||||
static const uint16_t refddr_volt_table[] = {
|
||||
0,
|
||||
};
|
||||
|
||||
#define DEFINE_BUCK(regu_name, ID, pd, table) { \
|
||||
.name = regu_name, \
|
||||
.volt_table = table, \
|
||||
.volt_table_size = ARRAY_SIZE(table), \
|
||||
.en_cr = ID ## _MAIN_CR2, \
|
||||
.volt_cr = ID ## _MAIN_CR1, \
|
||||
.alt_en_cr = ID ## _ALT_CR2, \
|
||||
.msrt_reg = BUCKS_MRST_CR, \
|
||||
.msrt_mask = ID ## _MRST, \
|
||||
.pd_reg = pd, \
|
||||
.pd_val = ID ## _PD_FAST, \
|
||||
.ocp_reg = FS_OCP_CR1, \
|
||||
.ocp_mask = FS_OCP_ ## ID, \
|
||||
}
|
||||
|
||||
#define DEFINE_LDOx(regu_name, ID, table) { \
|
||||
.name = regu_name, \
|
||||
.volt_table = table, \
|
||||
.volt_table_size = ARRAY_SIZE(table), \
|
||||
.volt_shift = LDO_VOLT_SHIFT, \
|
||||
.en_cr = ID ## _MAIN_CR, \
|
||||
.volt_cr = ID ## _MAIN_CR, \
|
||||
.alt_en_cr = ID ## _ALT_CR, \
|
||||
.msrt_reg = LDOS_MRST_CR, \
|
||||
.msrt_mask = ID ## _MRST, \
|
||||
.pd_reg = LDOS_PD_CR1, \
|
||||
.pd_val = ID ## _PD, \
|
||||
.ocp_reg = FS_OCP_CR2, \
|
||||
.ocp_mask = FS_OCP_ ## ID, \
|
||||
}
|
||||
|
||||
#define DEFINE_REFDDR(regu_name, ID, table) { \
|
||||
.name = regu_name, \
|
||||
.volt_table = table, \
|
||||
.volt_table_size = ARRAY_SIZE(table), \
|
||||
.en_cr = ID ## _MAIN_CR, \
|
||||
.volt_cr = ID ## _MAIN_CR, \
|
||||
.alt_en_cr = ID ## _ALT_CR, \
|
||||
.msrt_reg = BUCKS_MRST_CR, \
|
||||
.msrt_mask = ID ## _MRST, \
|
||||
.pd_reg = LDOS_PD_CR2, \
|
||||
.pd_val = ID ## _PD, \
|
||||
.ocp_reg = FS_OCP_CR1, \
|
||||
.ocp_mask = FS_OCP_ ## ID, \
|
||||
}
|
||||
|
||||
/* Table of Regulators in PMIC SoC */
|
||||
static const struct regul_struct regul_table[STPMIC2_NB_REG] = {
|
||||
[STPMIC2_BUCK1] = DEFINE_BUCK("buck1", BUCK1, BUCKS_PD_CR1,
|
||||
buck1236_volt_table),
|
||||
[STPMIC2_BUCK2] = DEFINE_BUCK("buck2", BUCK2, BUCKS_PD_CR1,
|
||||
buck1236_volt_table),
|
||||
[STPMIC2_BUCK3] = DEFINE_BUCK("buck3", BUCK3, BUCKS_PD_CR1,
|
||||
buck1236_volt_table),
|
||||
[STPMIC2_BUCK4] = DEFINE_BUCK("buck4", BUCK4, BUCKS_PD_CR1,
|
||||
buck457_volt_table),
|
||||
[STPMIC2_BUCK5] = DEFINE_BUCK("buck5", BUCK5, BUCKS_PD_CR2,
|
||||
buck457_volt_table),
|
||||
[STPMIC2_BUCK6] = DEFINE_BUCK("buck6", BUCK6, BUCKS_PD_CR2,
|
||||
buck1236_volt_table),
|
||||
[STPMIC2_BUCK7] = DEFINE_BUCK("buck7", BUCK7, BUCKS_PD_CR2,
|
||||
buck457_volt_table),
|
||||
|
||||
[STPMIC2_REFDDR] = DEFINE_REFDDR("refddr", REFDDR, refddr_volt_table),
|
||||
|
||||
[STPMIC2_LDO1] = DEFINE_LDOx("ldo1", LDO1, ldo1_volt_table),
|
||||
[STPMIC2_LDO2] = DEFINE_LDOx("ldo2", LDO2, ldo235678_volt_table),
|
||||
[STPMIC2_LDO3] = DEFINE_LDOx("ldo3", LDO3, ldo235678_volt_table),
|
||||
[STPMIC2_LDO4] = DEFINE_LDOx("ldo4", LDO4, ldo4_volt_table),
|
||||
[STPMIC2_LDO5] = DEFINE_LDOx("ldo5", LDO5, ldo235678_volt_table),
|
||||
[STPMIC2_LDO6] = DEFINE_LDOx("ldo6", LDO6, ldo235678_volt_table),
|
||||
[STPMIC2_LDO7] = DEFINE_LDOx("ldo7", LDO7, ldo235678_volt_table),
|
||||
[STPMIC2_LDO8] = DEFINE_LDOx("ldo8", LDO8, ldo235678_volt_table),
|
||||
|
||||
};
|
||||
|
||||
int stpmic2_register_read(struct pmic_handle_s *pmic,
|
||||
uint8_t register_id, uint8_t *value)
|
||||
{
|
||||
int ret = stm32_i2c_mem_read(pmic->i2c_handle,
|
||||
pmic->i2c_addr,
|
||||
(uint16_t)register_id,
|
||||
I2C_MEMADD_SIZE_8BIT, value,
|
||||
1, I2C_TIMEOUT_MS);
|
||||
if (ret != 0) {
|
||||
ERROR("Failed to read reg:0x%x\n", register_id);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int stpmic2_register_write(struct pmic_handle_s *pmic,
|
||||
uint8_t register_id, uint8_t value)
|
||||
{
|
||||
uint8_t val = value;
|
||||
int ret = stm32_i2c_mem_write(pmic->i2c_handle,
|
||||
pmic->i2c_addr,
|
||||
(uint16_t)register_id,
|
||||
I2C_MEMADD_SIZE_8BIT, &val,
|
||||
1, I2C_TIMEOUT_MS);
|
||||
if (ret != 0) {
|
||||
ERROR("Failed to write reg:0x%x\n", register_id);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int stpmic2_register_update(struct pmic_handle_s *pmic,
|
||||
uint8_t register_id, uint8_t value, uint8_t mask)
|
||||
{
|
||||
int status;
|
||||
uint8_t val = 0U;
|
||||
|
||||
status = stpmic2_register_read(pmic, register_id, &val);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
val = (val & ((uint8_t)~mask)) | (value & mask);
|
||||
|
||||
VERBOSE("REG:0x%x v=0x%x mask=0x%x -> 0x%x\n",
|
||||
register_id, value, mask, val);
|
||||
|
||||
return stpmic2_register_write(pmic, register_id, val);
|
||||
}
|
||||
|
||||
int stpmic2_regulator_set_state(struct pmic_handle_s *pmic,
|
||||
uint8_t id, bool enable)
|
||||
{
|
||||
const struct regul_struct *regul = ®ul_table[id];
|
||||
|
||||
if (enable) {
|
||||
return stpmic2_register_update(pmic, regul->en_cr, 1U, 1U);
|
||||
} else {
|
||||
return stpmic2_register_update(pmic, regul->en_cr, 0, 1U);
|
||||
}
|
||||
}
|
||||
|
||||
int stpmic2_regulator_get_state(struct pmic_handle_s *pmic,
|
||||
uint8_t id, bool *enabled)
|
||||
{
|
||||
const struct regul_struct *regul = ®ul_table[id];
|
||||
uint8_t val;
|
||||
|
||||
if (stpmic2_register_read(pmic, regul->en_cr, &val) != 0) {
|
||||
return RET_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
*enabled = (val & 1U) == 1U;
|
||||
|
||||
return RET_SUCCESS;
|
||||
}
|
||||
|
||||
int stpmic2_regulator_levels_mv(struct pmic_handle_s *pmic,
|
||||
uint8_t id, const uint16_t **levels,
|
||||
size_t *levels_count)
|
||||
{
|
||||
const struct regul_struct *regul = ®ul_table[id];
|
||||
|
||||
if (regul == NULL) {
|
||||
return RET_ERROR_BAD_PARAMETERS;
|
||||
}
|
||||
|
||||
if (levels_count != NULL) {
|
||||
*levels_count = regul->volt_table_size;
|
||||
}
|
||||
if (levels != NULL) {
|
||||
*levels = regul->volt_table;
|
||||
}
|
||||
|
||||
return RET_SUCCESS;
|
||||
}
|
||||
|
||||
int stpmic2_regulator_get_voltage(struct pmic_handle_s *pmic,
|
||||
uint8_t id, uint16_t *val)
|
||||
{
|
||||
const struct regul_struct *regul = ®ul_table[id];
|
||||
uint8_t value = 0U;
|
||||
uint8_t mask;
|
||||
|
||||
if (regul->volt_table_size == 0U) {
|
||||
return RET_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
mask = regul->volt_table_size - 1U;
|
||||
if (mask != 0U) {
|
||||
if (stpmic2_register_read(pmic, regul->volt_cr, &value) != 0) {
|
||||
return RET_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
value = (value >> regul->volt_shift) & mask;
|
||||
}
|
||||
|
||||
if (value > regul->volt_table_size) {
|
||||
return RET_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
*val = regul->volt_table[value];
|
||||
|
||||
return RET_SUCCESS;
|
||||
}
|
||||
|
||||
static size_t voltage_to_index(const struct regul_struct *regul,
|
||||
uint16_t millivolts)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
assert(regul->volt_table);
|
||||
for (i = 0U; i < regul->volt_table_size; i++) {
|
||||
if (regul->volt_table[i] == millivolts) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return VOLTAGE_INDEX_INVALID;
|
||||
}
|
||||
|
||||
int stpmic2_regulator_set_voltage(struct pmic_handle_s *pmic,
|
||||
uint8_t id, uint16_t millivolts)
|
||||
{
|
||||
const struct regul_struct *regul = ®ul_table[id];
|
||||
size_t index;
|
||||
uint8_t mask;
|
||||
|
||||
if (!regul->volt_table_size) {
|
||||
return RET_SUCCESS;
|
||||
}
|
||||
|
||||
mask = regul->volt_table_size - 1U;
|
||||
|
||||
index = voltage_to_index(regul, millivolts);
|
||||
if (index == VOLTAGE_INDEX_INVALID) {
|
||||
return RET_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
return stpmic2_register_update(pmic, regul->volt_cr,
|
||||
index << regul->volt_shift,
|
||||
mask << regul->volt_shift);
|
||||
}
|
||||
|
||||
/* update both normal and alternate register */
|
||||
static int stpmic2_update_en_crs(struct pmic_handle_s *pmic, uint8_t id,
|
||||
uint8_t value, uint8_t mask)
|
||||
{
|
||||
const struct regul_struct *regul = ®ul_table[id];
|
||||
|
||||
if (stpmic2_register_update(pmic, regul->en_cr, value, mask) != 0) {
|
||||
return RET_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
if (stpmic2_register_update(pmic, regul->alt_en_cr, value, mask) != 0) {
|
||||
return RET_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
return RET_SUCCESS;
|
||||
}
|
||||
|
||||
int stpmic2_regulator_get_prop(struct pmic_handle_s *pmic, uint8_t id,
|
||||
enum stpmic2_prop_id prop)
|
||||
{
|
||||
const struct regul_struct *regul = ®ul_table[id];
|
||||
uint8_t val;
|
||||
|
||||
VERBOSE("%s: get prop 0x%x\n", regul->name, prop);
|
||||
|
||||
switch (prop) {
|
||||
case STPMIC2_BYPASS:
|
||||
if ((id <= STPMIC2_BUCK7) || (id == STPMIC2_LDO1) ||
|
||||
(id == STPMIC2_LDO4) || (id == STPMIC2_REFDDR)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stpmic2_register_read(pmic, regul->en_cr, &val) != 0) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if ((val & LDO_BYPASS) != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
ERROR("Invalid prop %u\n", prop);
|
||||
panic();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stpmic2_regulator_set_prop(struct pmic_handle_s *pmic, uint8_t id,
|
||||
enum stpmic2_prop_id prop, uint32_t arg)
|
||||
{
|
||||
const struct regul_struct *regul = ®ul_table[id];
|
||||
|
||||
VERBOSE("%s: set prop 0x%x arg=%u\n", regul->name, prop, arg);
|
||||
|
||||
switch (prop) {
|
||||
case STPMIC2_PULL_DOWN:
|
||||
return stpmic2_register_update(pmic, regul->pd_reg,
|
||||
regul->pd_val,
|
||||
regul->pd_val);
|
||||
case STPMIC2_MASK_RESET:
|
||||
if (!regul->msrt_mask) {
|
||||
return RET_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
/* enable mask reset */
|
||||
return stpmic2_register_update(pmic, regul->msrt_reg,
|
||||
regul->msrt_mask,
|
||||
regul->msrt_mask);
|
||||
case STPMIC2_BYPASS:
|
||||
if ((id <= STPMIC2_BUCK7) || (id == STPMIC2_LDO1) ||
|
||||
(id == STPMIC2_LDO4) || (id == STPMIC2_REFDDR)) {
|
||||
return RET_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* clear sink source mode */
|
||||
if ((id == STPMIC2_LDO3) && (arg != 0U)) {
|
||||
if (stpmic2_update_en_crs(pmic, id, 0, LDO3_SNK_SRC) != 0) {
|
||||
return RET_ERROR_GENERIC;
|
||||
}
|
||||
}
|
||||
|
||||
/* enable bypass mode */
|
||||
return stpmic2_update_en_crs(pmic, id,
|
||||
(arg != 0U) ? LDO_BYPASS : 0,
|
||||
LDO_BYPASS);
|
||||
case STPMIC2_SINK_SOURCE:
|
||||
if (id != STPMIC2_LDO3) {
|
||||
return RET_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* clear bypass mode */
|
||||
if (stpmic2_update_en_crs(pmic, id, 0, LDO_BYPASS) != 0) {
|
||||
return RET_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
return stpmic2_update_en_crs(pmic, id, LDO3_SNK_SRC,
|
||||
LDO3_SNK_SRC);
|
||||
case STPMIC2_OCP:
|
||||
return stpmic2_register_update(pmic, regul->ocp_reg,
|
||||
regul->ocp_mask,
|
||||
regul->ocp_mask);
|
||||
default:
|
||||
ERROR("Invalid prop %u\n", prop);
|
||||
panic();
|
||||
}
|
||||
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
#if EVENT_LOG_LEVEL == LOG_LEVEL_VERBOSE
|
||||
void stpmic2_dump_regulators(struct pmic_handle_s *pmic)
|
||||
{
|
||||
size_t i;
|
||||
char const *name;
|
||||
|
||||
for (i = 0U; i < ARRAY_SIZE(regul_table); i++) {
|
||||
uint16_t val;
|
||||
bool state;
|
||||
|
||||
if (!regul_table[i].volt_cr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
stpmic2_regulator_get_voltage(pmic, i, &val);
|
||||
stpmic2_regulator_get_state(pmic, i, &state);
|
||||
|
||||
name = regul_table[i].name;
|
||||
|
||||
VERBOSE("PMIC regul %s: %s, %dmV\n",
|
||||
name, state ? "EN" : "DIS", val);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int stpmic2_get_version(struct pmic_handle_s *pmic, uint8_t *val)
|
||||
{
|
||||
return stpmic2_register_read(pmic, VERSION_SR, val);
|
||||
}
|
||||
|
||||
int stpmic2_get_product_id(struct pmic_handle_s *pmic, uint8_t *val)
|
||||
{
|
||||
return stpmic2_register_read(pmic, PRODUCT_ID, val);
|
||||
}
|
51
include/drivers/st/stm32mp_pmic2.h
Normal file
51
include/drivers/st/stm32mp_pmic2.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2024, STMicroelectronics - All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef STM32MP_PMIC2_H
|
||||
#define STM32MP_PMIC2_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <drivers/st/regulator.h>
|
||||
|
||||
#include <platform_def.h>
|
||||
|
||||
/*
|
||||
* dt_pmic_status - Check PMIC status from device tree
|
||||
*
|
||||
* Returns the status of the PMIC (secure, non-secure), or a negative value on
|
||||
* error
|
||||
*/
|
||||
int dt_pmic_status(void);
|
||||
|
||||
/*
|
||||
* initialize_pmic_i2c - Initialize I2C for the PMIC control
|
||||
*
|
||||
* Returns true if PMIC is available, false if not found, panics on errors
|
||||
*/
|
||||
bool initialize_pmic_i2c(void);
|
||||
|
||||
/*
|
||||
* initialize_pmic - Main PMIC initialization function, called at platform init
|
||||
*
|
||||
* Panics on errors
|
||||
*/
|
||||
void initialize_pmic(void);
|
||||
|
||||
/*
|
||||
* stpmic2_set_prop - Set PMIC2 proprietary property
|
||||
*
|
||||
* Returns non zero on errors
|
||||
*/
|
||||
int stpmic2_set_prop(const struct regul_description *desc, uint16_t prop, uint32_t value);
|
||||
|
||||
/*
|
||||
* pmic_switch_off - switch off the platform with PMIC
|
||||
*
|
||||
* Panics on errors
|
||||
*/
|
||||
void pmic_switch_off(void);
|
||||
|
||||
#endif /* STM32MP_PMIC2_H */
|
307
include/drivers/st/stpmic2.h
Normal file
307
include/drivers/st/stpmic2.h
Normal file
|
@ -0,0 +1,307 @@
|
|||
/*
|
||||
* Copyright (C) 2024, STMicroelectronics - All Rights Reserved
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef STPMIC2_H
|
||||
#define STPMIC2_H
|
||||
|
||||
#include <drivers/st/stm32_i2c.h>
|
||||
#include <lib/utils_def.h>
|
||||
|
||||
enum {
|
||||
STPMIC2_BUCK1 = 0,
|
||||
STPMIC2_BUCK2,
|
||||
STPMIC2_BUCK3,
|
||||
STPMIC2_BUCK4,
|
||||
STPMIC2_BUCK5,
|
||||
STPMIC2_BUCK6,
|
||||
STPMIC2_BUCK7,
|
||||
STPMIC2_REFDDR,
|
||||
STPMIC2_LDO1,
|
||||
STPMIC2_LDO2,
|
||||
STPMIC2_LDO3,
|
||||
STPMIC2_LDO4,
|
||||
STPMIC2_LDO5,
|
||||
STPMIC2_LDO6,
|
||||
STPMIC2_LDO7,
|
||||
STPMIC2_LDO8,
|
||||
STPMIC2_NB_REG
|
||||
};
|
||||
|
||||
/* Status Registers */
|
||||
#define PRODUCT_ID 0x00
|
||||
#define VERSION_SR 0x01
|
||||
#define TURN_ON_SR 0x02
|
||||
#define TURN_OFF_SR 0x03
|
||||
#define RESTART_SR 0x04
|
||||
#define OCP_SR1 0x05
|
||||
#define OCP_SR2 0x06
|
||||
#define EN_SR1 0x07
|
||||
#define EN_SR2 0x08
|
||||
#define FS_CNT_SR1 0x09
|
||||
#define FS_CNT_SR2 0x0A
|
||||
#define FS_CNT_SR3 0x0B
|
||||
#define MODE_SR 0x0C
|
||||
/* Control Registers */
|
||||
#define MAIN_CR 0x10
|
||||
#define VINLOW_CR 0x11
|
||||
#define PKEY_LKP_CR 0x12
|
||||
#define WDG_CR 0x13
|
||||
#define WDG_TMR_CR 0x14
|
||||
#define WDG_TMR_SR 0x15
|
||||
#define FS_OCP_CR1 0x16
|
||||
#define FS_OCP_CR2 0x17
|
||||
#define PADS_PULL_CR 0x18
|
||||
#define BUCKS_PD_CR1 0x19
|
||||
#define BUCKS_PD_CR2 0x1A
|
||||
#define LDOS_PD_CR1 0x1B
|
||||
#define LDOS_PD_CR2 0x1C
|
||||
#define BUCKS_MRST_CR 0x1D
|
||||
#define LDOS_MRST_CR 0x1E
|
||||
/* Buck CR */
|
||||
#define BUCK1_MAIN_CR1 0x20
|
||||
#define BUCK1_MAIN_CR2 0x21
|
||||
#define BUCK1_ALT_CR1 0x22
|
||||
#define BUCK1_ALT_CR2 0x23
|
||||
#define BUCK1_PWRCTRL_CR 0x24
|
||||
#define BUCK2_MAIN_CR1 0x25
|
||||
#define BUCK2_MAIN_CR2 0x26
|
||||
#define BUCK2_ALT_CR1 0x27
|
||||
#define BUCK2_ALT_CR2 0x28
|
||||
#define BUCK2_PWRCTRL_CR 0x29
|
||||
#define BUCK3_MAIN_CR1 0x2A
|
||||
#define BUCK3_MAIN_CR2 0x2B
|
||||
#define BUCK3_ALT_CR1 0x2C
|
||||
#define BUCK3_ALT_CR2 0x2D
|
||||
#define BUCK3_PWRCTRL_CR 0x2E
|
||||
#define BUCK4_MAIN_CR1 0x2F
|
||||
#define BUCK4_MAIN_CR2 0x30
|
||||
#define BUCK4_ALT_CR1 0x31
|
||||
#define BUCK4_ALT_CR2 0x32
|
||||
#define BUCK4_PWRCTRL_CR 0x33
|
||||
#define BUCK5_MAIN_CR1 0x34
|
||||
#define BUCK5_MAIN_CR2 0x35
|
||||
#define BUCK5_ALT_CR1 0x36
|
||||
#define BUCK5_ALT_CR2 0x37
|
||||
#define BUCK5_PWRCTRL_CR 0x38
|
||||
#define BUCK6_MAIN_CR1 0x39
|
||||
#define BUCK6_MAIN_CR2 0x3A
|
||||
#define BUCK6_ALT_CR1 0x3B
|
||||
#define BUCK6_ALT_CR2 0x3C
|
||||
#define BUCK6_PWRCTRL_CR 0x3D
|
||||
#define BUCK7_MAIN_CR1 0x3E
|
||||
#define BUCK7_MAIN_CR2 0x3F
|
||||
#define BUCK7_ALT_CR1 0x40
|
||||
#define BUCK7_ALT_CR2 0x41
|
||||
#define BUCK7_PWRCTRL_CR 0x42
|
||||
/* LDO CR */
|
||||
#define LDO1_MAIN_CR 0x4C
|
||||
#define LDO1_ALT_CR 0x4D
|
||||
#define LDO1_PWRCTRL_CR 0x4E
|
||||
#define LDO2_MAIN_CR 0x4F
|
||||
#define LDO2_ALT_CR 0x50
|
||||
#define LDO2_PWRCTRL_CR 0x51
|
||||
#define LDO3_MAIN_CR 0x52
|
||||
#define LDO3_ALT_CR 0x53
|
||||
#define LDO3_PWRCTRL_CR 0x54
|
||||
#define LDO4_MAIN_CR 0x55
|
||||
#define LDO4_ALT_CR 0x56
|
||||
#define LDO4_PWRCTRL_CR 0x57
|
||||
#define LDO5_MAIN_CR 0x58
|
||||
#define LDO5_ALT_CR 0x59
|
||||
#define LDO5_PWRCTRL_CR 0x5A
|
||||
#define LDO6_MAIN_CR 0x5B
|
||||
#define LDO6_ALT_CR 0x5C
|
||||
#define LDO6_PWRCTRL_CR 0x5D
|
||||
#define LDO7_MAIN_CR 0x5E
|
||||
#define LDO7_ALT_CR 0x5F
|
||||
#define LDO7_PWRCTRL_CR 0x60
|
||||
#define LDO8_MAIN_CR 0x61
|
||||
#define LDO8_ALT_CR 0x62
|
||||
#define LDO8_PWRCTRL_CR 0x63
|
||||
#define REFDDR_MAIN_CR 0x64
|
||||
#define REFDDR_ALT_CR 0x65
|
||||
#define REFDDR_PWRCTRL_CR 0x66
|
||||
/* INTERRUPT CR */
|
||||
#define INT_PENDING_R1 0x70
|
||||
#define INT_PENDING_R2 0x71
|
||||
#define INT_PENDING_R3 0x72
|
||||
#define INT_PENDING_R4 0x73
|
||||
#define INT_CLEAR_R1 0x74
|
||||
#define INT_CLEAR_R2 0x75
|
||||
#define INT_CLEAR_R3 0x76
|
||||
#define INT_CLEAR_R4 0x77
|
||||
#define INT_MASK_R1 0x78
|
||||
#define INT_MASK_R2 0x79
|
||||
#define INT_MASK_R3 0x7A
|
||||
#define INT_MASK_R4 0x7B
|
||||
#define INT_SRC_R1 0x7C
|
||||
#define INT_SRC_R2 0x7D
|
||||
#define INT_SRC_R3 0x7E
|
||||
#define INT_SRC_R4 0x7F
|
||||
#define INT_DBG_LATCH_R1 0x80
|
||||
#define INT_DBG_LATCH_R2 0x81
|
||||
#define INT_DBG_LATCH_R3 0x82
|
||||
#define INT_DBG_LATCH_R4 0x83
|
||||
|
||||
/* BUCKS_MRST_CR bits definition */
|
||||
#define BUCK1_MRST BIT(0)
|
||||
#define BUCK2_MRST BIT(1)
|
||||
#define BUCK3_MRST BIT(2)
|
||||
#define BUCK4_MRST BIT(3)
|
||||
#define BUCK5_MRST BIT(4)
|
||||
#define BUCK6_MRST BIT(5)
|
||||
#define BUCK7_MRST BIT(6)
|
||||
#define REFDDR_MRST BIT(7)
|
||||
|
||||
/* LDOS_MRST_CR bits definition */
|
||||
#define LDO1_MRST BIT(0)
|
||||
#define LDO2_MRST BIT(1)
|
||||
#define LDO3_MRST BIT(2)
|
||||
#define LDO4_MRST BIT(3)
|
||||
#define LDO5_MRST BIT(4)
|
||||
#define LDO6_MRST BIT(5)
|
||||
#define LDO7_MRST BIT(6)
|
||||
#define LDO8_MRST BIT(7)
|
||||
|
||||
/* LDOx_MAIN_CR */
|
||||
#define LDO_VOLT_SHIFT 1
|
||||
#define LDO_BYPASS BIT(6)
|
||||
#define LDO1_INPUT_SRC BIT(7)
|
||||
#define LDO3_SNK_SRC BIT(7)
|
||||
#define LDO4_INPUT_SRC_SHIFT 6
|
||||
#define LDO4_INPUT_SRC_MASK GENMASK_32(7, 6)
|
||||
|
||||
/* PWRCTRL register bit definition */
|
||||
#define PWRCTRL_EN BIT(0)
|
||||
#define PWRCTRL_RS BIT(1)
|
||||
#define PWRCTRL_SEL_SHIFT 2
|
||||
#define PWRCTRL_SEL_MASK GENMASK_32(3, 2)
|
||||
|
||||
/* BUCKx_MAIN_CR2 */
|
||||
#define PREG_MODE_SHIFT 1
|
||||
#define PREG_MODE_MASK GENMASK_32(2, 1)
|
||||
|
||||
/* BUCKS_PD_CR1 */
|
||||
#define BUCK1_PD_MASK GENMASK_32(1, 0)
|
||||
#define BUCK2_PD_MASK GENMASK_32(3, 2)
|
||||
#define BUCK3_PD_MASK GENMASK_32(5, 4)
|
||||
#define BUCK4_PD_MASK GENMASK_32(7, 6)
|
||||
|
||||
#define BUCK1_PD_FAST BIT(1)
|
||||
#define BUCK2_PD_FAST BIT(3)
|
||||
#define BUCK3_PD_FAST BIT(5)
|
||||
#define BUCK4_PD_FAST BIT(7)
|
||||
|
||||
/* BUCKS_PD_CR2 */
|
||||
#define BUCK5_PD_MASK GENMASK_32(1, 0)
|
||||
#define BUCK6_PD_MASK GENMASK_32(3, 2)
|
||||
#define BUCK7_PD_MASK GENMASK_32(5, 4)
|
||||
|
||||
#define BUCK5_PD_FAST BIT(1)
|
||||
#define BUCK6_PD_FAST BIT(3)
|
||||
#define BUCK7_PD_FAST BIT(5)
|
||||
|
||||
/* LDOS_PD_CR1 */
|
||||
#define LDO1_PD BIT(0)
|
||||
#define LDO2_PD BIT(1)
|
||||
#define LDO3_PD BIT(2)
|
||||
#define LDO4_PD BIT(3)
|
||||
#define LDO5_PD BIT(4)
|
||||
#define LDO6_PD BIT(5)
|
||||
#define LDO7_PD BIT(6)
|
||||
#define LDO8_PD BIT(7)
|
||||
|
||||
/* LDOS_PD_CR2 */
|
||||
#define REFDDR_PD BIT(0)
|
||||
|
||||
/* FS_OCP_CR1 */
|
||||
#define FS_OCP_BUCK1 BIT(0)
|
||||
#define FS_OCP_BUCK2 BIT(1)
|
||||
#define FS_OCP_BUCK3 BIT(2)
|
||||
#define FS_OCP_BUCK4 BIT(3)
|
||||
#define FS_OCP_BUCK5 BIT(4)
|
||||
#define FS_OCP_BUCK6 BIT(5)
|
||||
#define FS_OCP_BUCK7 BIT(6)
|
||||
#define FS_OCP_REFDDR BIT(7)
|
||||
|
||||
/* FS_OCP_CR2 */
|
||||
#define FS_OCP_LDO1 BIT(0)
|
||||
#define FS_OCP_LDO2 BIT(1)
|
||||
#define FS_OCP_LDO3 BIT(2)
|
||||
#define FS_OCP_LDO4 BIT(3)
|
||||
#define FS_OCP_LDO5 BIT(4)
|
||||
#define FS_OCP_LDO6 BIT(5)
|
||||
#define FS_OCP_LDO7 BIT(6)
|
||||
#define FS_OCP_LDO8 BIT(7)
|
||||
|
||||
/* IRQ definitions */
|
||||
#define IT_PONKEY_F 0
|
||||
#define IT_PONKEY_R 1
|
||||
#define IT_BUCK1_OCP 16
|
||||
#define IT_BUCK2_OCP 17
|
||||
#define IT_BUCK3_OCP 18
|
||||
#define IT_BUCK4_OCP 19
|
||||
#define IT_BUCK5_OCP 20
|
||||
#define IT_BUCK6_OCP 21
|
||||
#define IT_BUCK7_OCP 22
|
||||
#define IT_REFDDR_OCP 23
|
||||
#define IT_LDO1_OCP 24
|
||||
#define IT_LDO2_OCP 25
|
||||
#define IT_LDO3_OCP 26
|
||||
#define IT_LDO4_OCP 27
|
||||
#define IT_LDO5_OCP 28
|
||||
#define IT_LDO6_OCP 29
|
||||
#define IT_LDO7_OCP 30
|
||||
#define IT_LDO8_OCP 31
|
||||
|
||||
enum stpmic2_prop_id {
|
||||
STPMIC2_MASK_RESET = 0,
|
||||
STPMIC2_PULL_DOWN,
|
||||
STPMIC2_BYPASS, /* arg: 1=set 0=reset */
|
||||
STPMIC2_SINK_SOURCE,
|
||||
STPMIC2_OCP,
|
||||
};
|
||||
|
||||
struct pmic_handle_s {
|
||||
struct i2c_handle_s *i2c_handle;
|
||||
uint32_t i2c_addr;
|
||||
unsigned int pmic_status;
|
||||
};
|
||||
|
||||
int stpmic2_register_read(struct pmic_handle_s *pmic,
|
||||
uint8_t register_id, uint8_t *value);
|
||||
int stpmic2_register_write(struct pmic_handle_s *pmic,
|
||||
uint8_t register_id, uint8_t value);
|
||||
int stpmic2_register_update(struct pmic_handle_s *pmic,
|
||||
uint8_t register_id, uint8_t value, uint8_t mask);
|
||||
|
||||
int stpmic2_regulator_set_state(struct pmic_handle_s *pmic,
|
||||
uint8_t id, bool enable);
|
||||
int stpmic2_regulator_get_state(struct pmic_handle_s *pmic,
|
||||
uint8_t id, bool *enabled);
|
||||
|
||||
int stpmic2_regulator_levels_mv(struct pmic_handle_s *pmic,
|
||||
uint8_t id, const uint16_t **levels,
|
||||
size_t *levels_count);
|
||||
int stpmic2_regulator_get_voltage(struct pmic_handle_s *pmic,
|
||||
uint8_t id, uint16_t *val);
|
||||
int stpmic2_regulator_set_voltage(struct pmic_handle_s *pmic,
|
||||
uint8_t id, uint16_t millivolts);
|
||||
|
||||
#if EVENT_LOG_LEVEL == LOG_LEVEL_VERBOSE
|
||||
void stpmic2_dump_regulators(struct pmic_handle_s *pmic);
|
||||
#endif
|
||||
|
||||
int stpmic2_get_version(struct pmic_handle_s *pmic, uint8_t *val);
|
||||
int stpmic2_get_product_id(struct pmic_handle_s *pmic, uint8_t *val);
|
||||
|
||||
int stpmic2_regulator_get_prop(struct pmic_handle_s *pmic, uint8_t id,
|
||||
enum stpmic2_prop_id prop);
|
||||
|
||||
int stpmic2_regulator_set_prop(struct pmic_handle_s *pmic, uint8_t id,
|
||||
enum stpmic2_prop_id prop, uint32_t arg);
|
||||
|
||||
#endif /*STPMIC2_H*/
|
|
@ -15,6 +15,7 @@
|
|||
#include <drivers/mmc.h>
|
||||
#include <drivers/st/regulator_fixed.h>
|
||||
#include <drivers/st/stm32mp2_ddr_helpers.h>
|
||||
#include <drivers/st/stm32mp_pmic2.h>
|
||||
#include <drivers/st/stm32mp_risab_regs.h>
|
||||
#include <lib/fconf/fconf.h>
|
||||
#include <lib/fconf/fconf_dyn_cfg_getter.h>
|
||||
|
@ -230,6 +231,10 @@ skip_console_init:
|
|||
panic();
|
||||
}
|
||||
|
||||
if (dt_pmic_status() > 0) {
|
||||
initialize_pmic();
|
||||
}
|
||||
|
||||
fconf_populate("TB_FW", STM32MP_DTB_BASE);
|
||||
|
||||
stm32mp_io_setup();
|
||||
|
|
|
@ -110,6 +110,11 @@ PLAT_BL_COMMON_SOURCES += lib/cpus/${ARCH}/cortex_a35.S
|
|||
PLAT_BL_COMMON_SOURCES += drivers/st/uart/${ARCH}/stm32_console.S
|
||||
PLAT_BL_COMMON_SOURCES += plat/st/stm32mp2/${ARCH}/stm32mp2_helper.S
|
||||
|
||||
PLAT_BL_COMMON_SOURCES += drivers/st/pmic/stm32mp_pmic2.c \
|
||||
drivers/st/pmic/stpmic2.c \
|
||||
|
||||
PLAT_BL_COMMON_SOURCES += drivers/st/i2c/stm32_i2c.c
|
||||
|
||||
PLAT_BL_COMMON_SOURCES += plat/st/stm32mp2/stm32mp2_private.c
|
||||
|
||||
PLAT_BL_COMMON_SOURCES += drivers/st/bsec/bsec3.c \
|
||||
|
|
Loading…
Add table
Reference in a new issue