mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-25 06:19:56 +00:00
feat(allwinner): h616: add I2C PMIC support
The X-Powers AXP305 PMIC can be controlled via both I2C or RSB (an Allwinner specific bus similar to I2C), but we chose to use only RSB, because that's easier to program and also used by Linux. The AXP313a PMIC however supports only I2C, so we need to support both buses, and need to decide which to use at runtime. Prepare the PMIC code to add (back) I2C support. We initially used I2C on the H6/AXP805 combination, but replaced that later with RSB. So this patch is bringing some of that older code back. The decision whether to use I2C or RSB is made by the devicetree, since on some boards even RSB capable PMICs are controlled via I2C, since they share the bus with only I2C capable devices, for instance RTCs. At the moment this will still use RSB to drive the AXP305, but the (dynamic) I2C code will be used shortly to support the AXP313. This increases the code size by one 4K page, but with 80K out of the reserved 256K we are still very far away from our limit. Change-Id: I65c1e7df93dbd2dcd171b3fc486533a2948cc75b Signed-off-by: Andre Przywara <andre.przywara@arm.com>
This commit is contained in:
parent
a0597ba2d8
commit
044458981f
2 changed files with 68 additions and 15 deletions
|
@ -21,3 +21,4 @@ endif
|
|||
BL31_SOURCES += common/fdt_wrappers.c \
|
||||
drivers/allwinner/axp/axp805.c \
|
||||
drivers/allwinner/sunxi_rsb.c \
|
||||
drivers/mentor/i2c/mi2cv.c
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <common/fdt_wrappers.h>
|
||||
#include <drivers/allwinner/axp.h>
|
||||
#include <drivers/allwinner/sunxi_rsb.h>
|
||||
#include <drivers/mentor/mi2cv.h>
|
||||
#include <lib/mmio.h>
|
||||
#include <libfdt.h>
|
||||
|
||||
|
@ -24,6 +25,11 @@
|
|||
static uint16_t pmic_bus_addr;
|
||||
static uint8_t rsb_rt_addr;
|
||||
|
||||
static bool is_using_rsb(void)
|
||||
{
|
||||
return rsb_rt_addr != 0;
|
||||
}
|
||||
|
||||
static enum pmic_type {
|
||||
UNKNOWN,
|
||||
AXP305,
|
||||
|
@ -40,12 +46,39 @@ static uint8_t get_rsb_rt_address(uint16_t hw_addr)
|
|||
|
||||
int axp_read(uint8_t reg)
|
||||
{
|
||||
return rsb_read(rsb_rt_addr, reg);
|
||||
uint8_t val;
|
||||
int ret;
|
||||
|
||||
if (is_using_rsb()) {
|
||||
return rsb_read(rsb_rt_addr, reg);
|
||||
}
|
||||
|
||||
ret = i2c_write(pmic_bus_addr, 0, 0, ®, 1);
|
||||
if (ret == 0) {
|
||||
ret = i2c_read(pmic_bus_addr, 0, 0, &val, 1);
|
||||
}
|
||||
if (ret) {
|
||||
ERROR("PMIC: Cannot read PMIC register %02x\n", reg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
int axp_write(uint8_t reg, uint8_t val)
|
||||
{
|
||||
return rsb_write(rsb_rt_addr, reg, val);
|
||||
int ret;
|
||||
|
||||
if (is_using_rsb()) {
|
||||
return rsb_write(rsb_rt_addr, reg, val);
|
||||
}
|
||||
|
||||
ret = i2c_write(pmic_bus_addr, reg, 1, &val, 1);
|
||||
if (ret) {
|
||||
ERROR("PMIC: Cannot write PMIC register %02x\n", reg);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rsb_init(int rsb_hw_addr)
|
||||
|
@ -82,17 +115,22 @@ static int pmic_bus_init(uint16_t socid, uint16_t rsb_hw_addr)
|
|||
{
|
||||
int ret;
|
||||
|
||||
ret = sunxi_init_platform_r_twi(socid, true);
|
||||
ret = sunxi_init_platform_r_twi(socid, is_using_rsb());
|
||||
if (ret) {
|
||||
INFO("Could not init platform bus: %d\n", ret);
|
||||
pmic = UNKNOWN;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = rsb_init(rsb_hw_addr);
|
||||
if (ret) {
|
||||
pmic = UNKNOWN;
|
||||
return ret;
|
||||
if (is_using_rsb()) {
|
||||
ret = rsb_init(rsb_hw_addr);
|
||||
if (ret) {
|
||||
pmic = UNKNOWN;
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
/* initialise mi2cv driver */
|
||||
i2c_init((void *)SUNXI_R_I2C_BASE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -100,7 +138,7 @@ static int pmic_bus_init(uint16_t socid, uint16_t rsb_hw_addr)
|
|||
|
||||
int sunxi_pmic_setup(uint16_t socid, const void *fdt)
|
||||
{
|
||||
int node, ret;
|
||||
int node, parent, ret;
|
||||
uint32_t reg;
|
||||
|
||||
node = fdt_node_offset_by_compatible(fdt, 0, "x-powers,axp806");
|
||||
|
@ -119,13 +157,18 @@ int sunxi_pmic_setup(uint16_t socid, const void *fdt)
|
|||
}
|
||||
|
||||
pmic_bus_addr = reg;
|
||||
rsb_rt_addr = get_rsb_rt_address(pmic_bus_addr);
|
||||
if (rsb_rt_addr == 0) {
|
||||
ERROR("PMIC: no mapping for RSB address 0x%x\n", reg);
|
||||
return -EINVAL;
|
||||
parent = fdt_parent_offset(fdt, node);
|
||||
ret = fdt_node_check_compatible(fdt, parent, "allwinner,sun8i-a23-rsb");
|
||||
if (ret == 0) {
|
||||
rsb_rt_addr = get_rsb_rt_address(pmic_bus_addr);
|
||||
if (rsb_rt_addr == 0) {
|
||||
ERROR("PMIC: no mapping for RSB address 0x%x\n",
|
||||
pmic_bus_addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
INFO("Probing for PMIC on RSB:\n");
|
||||
INFO("Probing for PMIC on %s:\n", is_using_rsb() ? "RSB" : "I2C");
|
||||
|
||||
ret = pmic_bus_init(socid, pmic_bus_addr);
|
||||
if (ret) {
|
||||
|
@ -144,8 +187,17 @@ int sunxi_pmic_setup(uint16_t socid, const void *fdt)
|
|||
break;
|
||||
}
|
||||
|
||||
/* Switch the PMIC back to I2C mode. */
|
||||
return rsb_write(rsb_rt_addr, AXP20X_MODE_REG, AXP20X_MODE_I2C);
|
||||
if (is_using_rsb()) {
|
||||
/* Switch the PMIC back to I2C mode. */
|
||||
return rsb_write(rsb_rt_addr, AXP20X_MODE_REG, AXP20X_MODE_I2C);
|
||||
}
|
||||
|
||||
if (pmic == UNKNOWN) {
|
||||
INFO("Incompatible or unknown PMIC found.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sunxi_power_down(void)
|
||||
|
|
Loading…
Add table
Reference in a new issue