Merge changes from topic "allwinner_pmic" into integration
* changes: allwinner: h6: power: Switch to using the AXP driver drivers: allwinner: axp: Add AXP805 support
This commit is contained in:
commit
0d35873c8f
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <drivers/allwinner/axp.h>
|
||||||
|
|
||||||
|
const uint8_t axp_chip_id = AXP805_CHIP_ID;
|
||||||
|
const char *const axp_compatible = "x-powers,axp805";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The "dcdcd" split changes the step size by a factor of 5, not 2;
|
||||||
|
* disallow values above the split to maintain accuracy.
|
||||||
|
*/
|
||||||
|
const struct axp_regulator axp_regulators[] = {
|
||||||
|
{"dcdca", 600, 1520, 10, 50, 0x12, 0x10, 0},
|
||||||
|
{"dcdcb", 1000, 2550, 50, NA, 0x13, 0x10, 1},
|
||||||
|
{"dcdcc", 600, 1520, 10, 50, 0x14, 0x10, 2},
|
||||||
|
{"dcdcd", 600, 1500, 20, NA, 0x15, 0x10, 3},
|
||||||
|
{"dcdce", 1100, 3400, 100, NA, 0x16, 0x10, 4},
|
||||||
|
{"aldo1", 700, 3300, 100, NA, 0x17, 0x10, 5},
|
||||||
|
{"aldo2", 700, 3300, 100, NA, 0x18, 0x10, 6},
|
||||||
|
{"aldo3", 700, 3300, 100, NA, 0x19, 0x10, 7},
|
||||||
|
{"bldo1", 700, 1900, 100, NA, 0x20, 0x11, 0},
|
||||||
|
{"bldo2", 700, 1900, 100, NA, 0x21, 0x11, 1},
|
||||||
|
{"bldo3", 700, 1900, 100, NA, 0x22, 0x11, 2},
|
||||||
|
{"bldo4", 700, 1900, 100, NA, 0x23, 0x11, 3},
|
||||||
|
{"cldo1", 700, 3300, 100, NA, 0x24, 0x11, 4},
|
||||||
|
{"cldo2", 700, 4200, 100, 27, 0x25, 0x11, 5},
|
||||||
|
{"cldo3", 700, 3300, 100, NA, 0x26, 0x11, 6},
|
||||||
|
{}
|
||||||
|
};
|
|
@ -108,7 +108,7 @@ static bool should_enable_regulator(const void *fdt, int node)
|
||||||
void axp_setup_regulators(const void *fdt)
|
void axp_setup_regulators(const void *fdt)
|
||||||
{
|
{
|
||||||
int node;
|
int node;
|
||||||
bool dc1sw = false;
|
bool sw = false;
|
||||||
|
|
||||||
if (fdt == NULL)
|
if (fdt == NULL)
|
||||||
return;
|
return;
|
||||||
|
@ -120,6 +120,7 @@ void axp_setup_regulators(const void *fdt)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This applies to AXP803 only. */
|
||||||
if (fdt_getprop(fdt, node, "x-powers,drive-vbus-en", NULL)) {
|
if (fdt_getprop(fdt, node, "x-powers,drive-vbus-en", NULL)) {
|
||||||
axp_clrbits(0x8f, BIT(4));
|
axp_clrbits(0x8f, BIT(4));
|
||||||
axp_setbits(0x30, BIT(2));
|
axp_setbits(0x30, BIT(2));
|
||||||
|
@ -144,26 +145,31 @@ void axp_setup_regulators(const void *fdt)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
name = fdt_get_name(fdt, node, &length);
|
name = fdt_get_name(fdt, node, &length);
|
||||||
|
|
||||||
|
/* Enable the switch last to avoid overheating. */
|
||||||
|
if (!strncmp(name, "dc1sw", length) ||
|
||||||
|
!strncmp(name, "sw", length)) {
|
||||||
|
sw = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
for (reg = axp_regulators; reg->dt_name; reg++) {
|
for (reg = axp_regulators; reg->dt_name; reg++) {
|
||||||
if (!strncmp(name, reg->dt_name, length)) {
|
if (!strncmp(name, reg->dt_name, length)) {
|
||||||
setup_regulator(fdt, node, reg);
|
setup_regulator(fdt, node, reg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strncmp(name, "dc1sw", length)) {
|
|
||||||
/* Delay DC1SW enablement to avoid overheating. */
|
|
||||||
dc1sw = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If DLDO2 is enabled after DC1SW, the PMIC overheats and shuts
|
* On the AXP803, if DLDO2 is enabled after DC1SW, the PMIC overheats
|
||||||
* down. So always enable DC1SW as the very last regulator.
|
* and shuts down. So always enable DC1SW as the very last regulator.
|
||||||
*/
|
*/
|
||||||
if (dc1sw) {
|
if (sw) {
|
||||||
INFO("PMIC: Enabling DC1SW\n");
|
INFO("PMIC: Enabling DC SW\n");
|
||||||
axp_setbits(0x12, BIT(7));
|
if (axp_chip_id == AXP803_CHIP_ID)
|
||||||
|
axp_setbits(0x12, BIT(7));
|
||||||
|
if (axp_chip_id == AXP805_CHIP_ID)
|
||||||
|
axp_setbits(0x11, BIT(7));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
AXP803_CHIP_ID = 0x41,
|
AXP803_CHIP_ID = 0x41,
|
||||||
|
AXP805_CHIP_ID = 0x40,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct axp_regulator {
|
struct axp_regulator {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#
|
#
|
||||||
# Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
|
# Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD-3-Clause
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
#
|
#
|
||||||
|
@ -20,7 +20,8 @@ PLAT_BL_COMMON_SOURCES := drivers/ti/uart/${ARCH}/16550_console.S \
|
||||||
${AW_PLAT}/common/plat_helpers.S \
|
${AW_PLAT}/common/plat_helpers.S \
|
||||||
${AW_PLAT}/common/sunxi_common.c
|
${AW_PLAT}/common/sunxi_common.c
|
||||||
|
|
||||||
BL31_SOURCES += drivers/arm/gic/common/gic_common.c \
|
BL31_SOURCES += drivers/allwinner/axp/common.c \
|
||||||
|
drivers/arm/gic/common/gic_common.c \
|
||||||
drivers/arm/gic/v2/gicv2_helpers.c \
|
drivers/arm/gic/v2/gicv2_helpers.c \
|
||||||
drivers/arm/gic/v2/gicv2_main.c \
|
drivers/arm/gic/v2/gicv2_main.c \
|
||||||
drivers/delay_timer/delay_timer.c \
|
drivers/delay_timer/delay_timer.c \
|
||||||
|
|
|
@ -8,5 +8,4 @@
|
||||||
include plat/allwinner/common/allwinner-common.mk
|
include plat/allwinner/common/allwinner-common.mk
|
||||||
|
|
||||||
BL31_SOURCES += drivers/allwinner/axp/axp803.c \
|
BL31_SOURCES += drivers/allwinner/axp/axp803.c \
|
||||||
drivers/allwinner/axp/common.c \
|
|
||||||
drivers/allwinner/sunxi_rsb.c
|
drivers/allwinner/sunxi_rsb.c
|
||||||
|
|
|
@ -7,4 +7,5 @@
|
||||||
# The differences between the platform are covered by the include files.
|
# The differences between the platform are covered by the include files.
|
||||||
include plat/allwinner/common/allwinner-common.mk
|
include plat/allwinner/common/allwinner-common.mk
|
||||||
|
|
||||||
BL31_SOURCES += drivers/mentor/i2c/mi2cv.c
|
BL31_SOURCES += drivers/allwinner/axp/axp805.c \
|
||||||
|
drivers/mentor/i2c/mi2cv.c
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
#include <arch_helpers.h>
|
#include <arch_helpers.h>
|
||||||
#include <common/debug.h>
|
#include <common/debug.h>
|
||||||
|
#include <drivers/allwinner/axp.h>
|
||||||
#include <drivers/delay_timer.h>
|
#include <drivers/delay_timer.h>
|
||||||
#include <drivers/mentor/mi2cv.h>
|
#include <drivers/mentor/mi2cv.h>
|
||||||
#include <lib/mmio.h>
|
#include <lib/mmio.h>
|
||||||
|
@ -19,31 +20,33 @@
|
||||||
#include <sunxi_private.h>
|
#include <sunxi_private.h>
|
||||||
|
|
||||||
#define AXP805_ADDR 0x36
|
#define AXP805_ADDR 0x36
|
||||||
#define AXP805_ID 0x03
|
|
||||||
|
|
||||||
static enum pmic_type {
|
static enum pmic_type {
|
||||||
UNKNOWN,
|
UNKNOWN,
|
||||||
AXP805,
|
AXP805,
|
||||||
} pmic;
|
} pmic;
|
||||||
|
|
||||||
int axp_i2c_read(uint8_t chip, uint8_t reg, uint8_t *val)
|
int axp_read(uint8_t reg)
|
||||||
{
|
{
|
||||||
|
uint8_t val;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = i2c_write(chip, 0, 0, ®, 1);
|
ret = i2c_write(AXP805_ADDR, 0, 0, ®, 1);
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
ret = i2c_read(chip, 0, 0, val, 1);
|
ret = i2c_read(AXP805_ADDR, 0, 0, &val, 1);
|
||||||
if (ret)
|
if (ret) {
|
||||||
ERROR("PMIC: Cannot read AXP805 register %02x\n", reg);
|
ERROR("PMIC: Cannot read AXP805 register %02x\n", reg);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val)
|
int axp_write(uint8_t reg, uint8_t val)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = i2c_write(chip, reg, 1, &val, 1);
|
ret = i2c_write(AXP805_ADDR, reg, 1, &val, 1);
|
||||||
if (ret)
|
if (ret)
|
||||||
ERROR("PMIC: Cannot write AXP805 register %02x\n", reg);
|
ERROR("PMIC: Cannot write AXP805 register %02x\n", reg);
|
||||||
|
|
||||||
|
@ -53,23 +56,16 @@ int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val)
|
||||||
static int axp805_probe(void)
|
static int axp805_probe(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
uint8_t val;
|
|
||||||
|
|
||||||
/* Switch the AXP805 to master/single-PMIC mode. */
|
/* Switch the AXP805 to master/single-PMIC mode. */
|
||||||
ret = axp_i2c_write(AXP805_ADDR, 0xff, 0x0);
|
ret = axp_write(0xff, 0x0);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = axp_i2c_read(AXP805_ADDR, AXP805_ID, &val);
|
ret = axp_check_id();
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
val &= 0xcf;
|
|
||||||
if (val != 0x40) {
|
|
||||||
ERROR("PMIC: Found unknown PMIC %02x\n", val);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,22 +87,20 @@ int sunxi_pmic_setup(uint16_t socid, const void *fdt)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
pmic = AXP805;
|
pmic = AXP805;
|
||||||
|
axp_setup_regulators(fdt);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sunxi_power_down(void)
|
void sunxi_power_down(void)
|
||||||
{
|
{
|
||||||
uint8_t val;
|
|
||||||
|
|
||||||
switch (pmic) {
|
switch (pmic) {
|
||||||
case AXP805:
|
case AXP805:
|
||||||
/* Re-initialise after rich OS might have used it. */
|
/* Re-initialise after rich OS might have used it. */
|
||||||
sunxi_init_platform_r_twi(SUNXI_SOC_H6, false);
|
sunxi_init_platform_r_twi(SUNXI_SOC_H6, false);
|
||||||
/* initialise mi2cv driver */
|
/* initialise mi2cv driver */
|
||||||
i2c_init((void *)SUNXI_R_I2C_BASE);
|
i2c_init((void *)SUNXI_R_I2C_BASE);
|
||||||
axp_i2c_read(AXP805_ADDR, 0x32, &val);
|
axp_power_off();
|
||||||
axp_i2c_write(AXP805_ADDR, 0x32, val | 0x80);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue