[U-Boot] [PATCH 1/2 RFT] sunxi: power: Add AXP806 and AXP808 support

Rask Ingemann Lambertsen rask at formelder.dk
Sun Feb 26 19:01:17 UTC 2017


An X-Powers AXP806 or AXP808 PMIC is usually found on boards using the
Allwinner A80 ARM SoC. This patch adds support for the PMIC's regulators
and sets up the runtime address and master/slave mode in pmic_bus_init().

AXP806/AXP808 support is enabled by default on all MACH_SUN9I boards.

Because there are boards with both an AXP806 and an AXP809,
drivers/power/Kconfig and arch/arm/mach-sunxi/pmic_bus.c are changed to
make it possible to have more than one PMIC enabled at a time.

Signed-off-by: Rask Ingemann Lambertsen <rask at formelder.dk>
---
This patch needs to be tested on the following boards which I don't have:
Cubietech Cubieboard4
Merrii A80 Optimus

 arch/arm/include/asm/arch-sunxi/pmic_bus.h |   4 +
 arch/arm/mach-sunxi/Makefile               |   1 +
 arch/arm/mach-sunxi/pmic_bus.c             | 107 ++++++++++---
 board/sunxi/board.c                        |  20 +++
 drivers/power/Kconfig                      | 226 +++++++++++++++++++++++++++-
 drivers/power/Makefile                     |   1 +
 drivers/power/axp806.c                     | 231 +++++++++++++++++++++++++++++
 include/axp806.h                           |  50 +++++++
 include/axp_pmic.h                         |  13 ++
 9 files changed, 623 insertions(+), 30 deletions(-)
 create mode 100644 drivers/power/axp806.c
 create mode 100644 include/axp806.h

diff --git a/arch/arm/include/asm/arch-sunxi/pmic_bus.h b/arch/arm/include/asm/arch-sunxi/pmic_bus.h
index 9c4372a..d143d54 100644
--- a/arch/arm/include/asm/arch-sunxi/pmic_bus.h
+++ b/arch/arm/include/asm/arch-sunxi/pmic_bus.h
@@ -14,5 +14,9 @@ int pmic_bus_read(u8 reg, u8 *data);
 int pmic_bus_write(u8 reg, u8 data);
 int pmic_bus_setbits(u8 reg, u8 bits);
 int pmic_bus_clrbits(u8 reg, u8 bits);
+int pmic2_bus_read(u8 reg, u8 *data);
+int pmic2_bus_write(u8 reg, u8 data);
+int pmic2_bus_setbits(u8 reg, u8 bits);
+int pmic2_bus_clrbits(u8 reg, u8 bits);
 
 #endif
diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile
index 7daba11..410fb49 100644
--- a/arch/arm/mach-sunxi/Makefile
+++ b/arch/arm/mach-sunxi/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_MACH_SUN9I)	+= clock_sun9i.o gtbus_sun9i.o
 obj-$(CONFIG_AXP152_POWER)	+= pmic_bus.o
 obj-$(CONFIG_AXP209_POWER)	+= pmic_bus.o
 obj-$(CONFIG_AXP221_POWER)	+= pmic_bus.o
+obj-$(CONFIG_AXP806_POWER)	+= pmic_bus.o
 obj-$(CONFIG_AXP809_POWER)	+= pmic_bus.o
 obj-$(CONFIG_AXP818_POWER)	+= pmic_bus.o
 
diff --git a/arch/arm/mach-sunxi/pmic_bus.c b/arch/arm/mach-sunxi/pmic_bus.c
index 7c57f02..a2da40c 100644
--- a/arch/arm/mach-sunxi/pmic_bus.c
+++ b/arch/arm/mach-sunxi/pmic_bus.c
@@ -27,6 +27,15 @@
 #define AXP223_DEVICE_ADDR		0x3a3
 #define AXP223_RUNTIME_ADDR		0x2d
 
+/* AXP806 and AXP808 use the same addresses. */
+#define AXP806_DEVICE_ADDR		0x745
+#define AXP806_RUNTIME_ADDR		0x3a
+
+/* AXP806 and AXP808 address space extension. */
+#define AXP806_REG_ADDR_EXT			0xff
+#define AXP806_REG_ADDR_EXT_ADDR_MASTER_MODE	0
+#define AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE	BIT(4)
+
 int pmic_bus_init(void)
 {
 	/* This cannot be 0 because it is used in SPL before BSS is ready */
@@ -36,7 +45,8 @@ int pmic_bus_init(void)
 	if (!needs_init)
 		return 0;
 
-#if defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER
+#if defined CONFIG_AXP221_POWER || defined CONFIG_AXP806_POWER || \
+	defined CONFIG_AXP809_POWER || defined CONFIG_AXP818_POWER
 # ifdef CONFIG_MACH_SUN6I
 	p2wi_init();
 	ret = p2wi_change_to_p2wi_mode(AXP221_CHIP_ADDR, AXP221_CTRL_ADDR,
@@ -46,16 +56,70 @@ int pmic_bus_init(void)
 	if (ret)
 		return ret;
 
+#  if defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || \
+	defined CONFIG_AXP818_POWER
 	ret = rsb_set_device_address(AXP223_DEVICE_ADDR, AXP223_RUNTIME_ADDR);
-# endif
 	if (ret)
 		return ret;
+#  endif
+#  ifdef CONFIG_AXP806_POWER
+	ret = rsb_set_device_address(AXP806_DEVICE_ADDR, AXP806_RUNTIME_ADDR);
+	if (ret)
+		return ret;
+#  endif
+# endif
+
+# ifdef CONFIG_AXP806_POWER
+	/*
+	 * An AXP806 or AXP808 can be wired for either master mode or slave
+	 * mode. The AXP806_REG_ADDR_EXT register must be set accordingly for
+	 * the chip to repond to access to its other registers.
+	 */
+#  ifdef CONFIG_AXP806_POWER_SLAVE_MODE
+	ret = pmic2_bus_write(AXP806_REG_ADDR_EXT,
+			      AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE);
+#  else
+	ret = pmic2_bus_write(AXP806_REG_ADDR_EXT,
+			      AXP806_REG_ADDR_EXT_ADDR_MASTER_MODE);
+#  endif
+	if (ret)
+		return ret;
+# endif
 #endif
 
 	needs_init = 0;
 	return 0;
 }
 
+#define PMIC_BUS_SETBITS(pmic_bus_read, pmic_bus_write, reg, bits) \
+{						\
+	int ret;				\
+	u8 val;					\
+						\
+	ret = pmic_bus_read(reg, &val);		\
+	if (ret)				\
+		return ret;			\
+						\
+	val |= bits;				\
+	return pmic_bus_write(reg, val);	\
+}
+
+#define PMIC_BUS_CLRBITS(pmic_bus_read, pmic_bus_write, reg, bits) \
+{						\
+	int ret;				\
+	u8 val;					\
+						\
+	ret = pmic_bus_read(reg, &val);		\
+	if (ret)				\
+		return ret;			\
+						\
+	val &= ~bits;				\
+	return pmic_bus_write(reg, val);	\
+}
+
+#if defined CONFIG_AXP152_POWER || defined CONFIG_AXP209_POWER || \
+	defined CONFIG_AXP221_POWER || defined CONFIG_AXP809_POWER || \
+	defined CONFIG_AXP818_POWER
 int pmic_bus_read(u8 reg, u8 *data)
 {
 #ifdef CONFIG_AXP152_POWER
@@ -87,27 +151,26 @@ int pmic_bus_write(u8 reg, u8 data)
 }
 
 int pmic_bus_setbits(u8 reg, u8 bits)
-{
-	int ret;
-	u8 val;
-
-	ret = pmic_bus_read(reg, &val);
-	if (ret)
-		return ret;
-
-	val |= bits;
-	return pmic_bus_write(reg, val);
-}
+PMIC_BUS_SETBITS(pmic_bus_read, pmic_bus_write, reg, bits)
 
 int pmic_bus_clrbits(u8 reg, u8 bits)
+PMIC_BUS_CLRBITS(pmic_bus_read, pmic_bus_write, reg, bits)
+#endif
+
+#ifdef CONFIG_AXP806_POWER
+int pmic2_bus_read(u8 reg, u8 *data)
 {
-	int ret;
-	u8 val;
-
-	ret = pmic_bus_read(reg, &val);
-	if (ret)
-		return ret;
-
-	val &= ~bits;
-	return pmic_bus_write(reg, val);
+	return rsb_read(AXP806_RUNTIME_ADDR, reg, data);
 }
+
+int pmic2_bus_write(u8 reg, u8 data)
+{
+	return rsb_write(AXP806_RUNTIME_ADDR, reg, data);
+}
+
+int pmic2_bus_setbits(u8 reg, u8 bits)
+PMIC_BUS_SETBITS(pmic2_bus_read, pmic2_bus_write, reg, bits)
+
+int pmic2_bus_clrbits(u8 reg, u8 bits)
+PMIC_BUS_CLRBITS(pmic2_bus_read, pmic2_bus_write, reg, bits)
+#endif
diff --git a/board/sunxi/board.c b/board/sunxi/board.c
index 5365638..7847837 100644
--- a/board/sunxi/board.c
+++ b/board/sunxi/board.c
@@ -540,6 +540,26 @@ void sunxi_board_init(void)
 	power_failed |= axp_set_sw(IS_ENABLED(CONFIG_AXP_SW_ON));
 #endif
 #endif
+#ifdef CONFIG_AXP806_POWER
+	power_failed |= axp2_init();
+
+	power_failed |= axp_set_dcdca(CONFIG_AXP_DCDCA_VOLT);
+	power_failed |= axp_set_dcdcb(CONFIG_AXP_DCDCB_VOLT);
+	power_failed |= axp_set_dcdcc(CONFIG_AXP_DCDCC_VOLT);
+	power_failed |= axp_set_dcdcd(CONFIG_AXP_DCDCD_VOLT);
+	power_failed |= axp_set_dcdce(CONFIG_AXP_DCDCE_VOLT);
+	power_failed |= axp2_set_aldo(1, CONFIG_AXP2_ALDO1_VOLT);
+	power_failed |= axp2_set_aldo(2, CONFIG_AXP2_ALDO2_VOLT);
+	power_failed |= axp2_set_aldo(3, CONFIG_AXP2_ALDO3_VOLT);
+	power_failed |= axp_set_bldo(1, CONFIG_AXP_BLDO1_VOLT);
+	power_failed |= axp_set_bldo(2, CONFIG_AXP_BLDO2_VOLT);
+	power_failed |= axp_set_bldo(3, CONFIG_AXP_BLDO3_VOLT);
+	power_failed |= axp_set_bldo(4, CONFIG_AXP_BLDO4_VOLT);
+	power_failed |= axp_set_cldo(1, CONFIG_AXP_CLDO1_VOLT);
+	power_failed |= axp_set_cldo(2, CONFIG_AXP_CLDO2_VOLT);
+	power_failed |= axp_set_cldo(3, CONFIG_AXP_CLDO3_VOLT);
+	power_failed |= axp2_set_sw(IS_ENABLED(CONFIG_AXP2_SW_ON));
+#endif
 	printf("DRAM:");
 	ramsize = sunxi_dram_init();
 	printf(" %d MiB\n", (int)(ramsize >> 20));
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index f2c5629..aa32e5a 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -6,19 +6,18 @@ source "drivers/power/pmic/Kconfig"
 
 source "drivers/power/regulator/Kconfig"
 
-choice
-	prompt "Select Sunxi PMIC Variant"
-	depends on ARCH_SUNXI
-	default AXP209_POWER if MACH_SUN4I || MACH_SUN5I || MACH_SUN7I
-	default AXP221_POWER if MACH_SUN6I || MACH_SUN8I_A23 || MACH_SUN8I_A33
-	default AXP818_POWER if MACH_SUN8I_A83T
-	default SUNXI_NO_PMIC if MACH_SUN8I_H3 || MACH_SUN50I
+if ARCH_SUNXI
+
+comment "Select Sunxi PMIC Variant"
 
 config SUNXI_NO_PMIC
 	bool "board without a pmic"
+	default MACH_SUN8I_H3 || MACH_SUN50I
 	---help---
 	Select this for boards which do not use a PMIC.
 
+if !SUNXI_NO_PMIC
+
 config AXP152_POWER
 	bool "axp152 pmic support"
 	depends on MACH_SUN5I
@@ -30,6 +29,7 @@ config AXP152_POWER
 config AXP209_POWER
 	bool "axp209 pmic support"
 	depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I
+	default MACH_SUN4I || MACH_SUN5I || MACH_SUN7I
 	select CMD_POWEROFF
 	---help---
 	Select this to enable support for the axp209 pmic found on most
@@ -38,11 +38,31 @@ config AXP209_POWER
 config AXP221_POWER
 	bool "axp221 / axp223 pmic support"
 	depends on MACH_SUN6I || MACH_SUN8I_A23 || MACH_SUN8I_A33
+	default MACH_SUN6I || MACH_SUN8I_A23 || MACH_SUN8I_A33
 	select CMD_POWEROFF
 	---help---
 	Select this to enable support for the axp221/axp223 pmic found on most
 	A23 and A31 boards.
 
+config AXP806_POWER
+	bool "axp806 / axp808 pmic support"
+	depends on MACH_SUN9I
+	default MACH_SUN9I
+	select CMD_POWEROFF
+	---help---
+	Say y here to enable support for the axp806 or axp808 pmic found
+	on A80 boards.
+
+config AXP806_POWER_SLAVE_MODE
+	bool "axp806 / axp808 pmic slave mode"
+	depends on AXP806_POWER
+	default AXP806_POWER && AXP809_POWER
+	---help---
+	Say y here to address an axp806 / axp808 in slave mode.
+	This is used on all currently supported boards with both an axp806
+	and an axp809. You should probably say n here if your board only has
+	an axp806 or axp808.
+
 config AXP809_POWER
 	bool "axp809 pmic support"
 	depends on MACH_SUN9I
@@ -53,6 +73,7 @@ config AXP809_POWER
 config AXP818_POWER
 	bool "axp818 pmic support"
 	depends on MACH_SUN8I_A83T
+	default MACH_SUN8I_A83T
 	select CMD_POWEROFF
 	---help---
 	Say y here to enable support for the axp818 pmic found on
@@ -65,7 +86,9 @@ config SY8106A_POWER
 	Select this to enable support for the SY8106A pmic found on some
 	H3 boards.
 
-endchoice
+endif
+
+endif
 
 config AXP_DCDC1_VOLT
 	int "axp pmic dcdc1 voltage"
@@ -141,6 +164,63 @@ config AXP_DCDC5_VOLT
 	On A23 / A31 / A33 / A80 / A83T boards dcdc5 is VCC-DRAM and
 	should be 1.5V, 1.35V if DDR3L is used.
 
+config AXP_DCDCA_VOLT
+	int "axp pmic dcdca voltage"
+	depends on AXP806_POWER
+	default 900 if MACH_SUN9I
+	---help---
+	Set the voltage (mV) to program the axp pmic dcdca at, set to 0 to
+	disable dcdca.
+	On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, dcdca
+	powers the Cortex-A15 cores (VDD-CPUB) and should be 0.9 V.
+	On the Sunchip CX-A99 board, dcdca powers the Cortex-A7 cores
+	(VDD-CPUA) and should be 0.9 V at the default 1008 MHz clock frequency.
+
+config AXP_DCDCB_VOLT
+	int "axp pmic dcdcb voltage"
+	depends on AXP806_POWER
+	default 0 if MACH_SUN9I && AXP806_POWER && AXP809_POWER
+	default 1500 if MACH_SUN9I && AXP806_POWER && !AXP809_POWER
+	---help---
+	Set the voltage (mV) to program the axp pmic dcdcb at, set to 0 to
+	disable dcdcb.
+	On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, dcdcb
+	is unused and can be left off.
+	On the Sunchip CX-A99 board, dcdcb powers VCC-DRAM and should be 1.5 V.
+
+config AXP_DCDCC_VOLT
+	int "axp pmic dcdcc voltage"
+	depends on AXP806_POWER
+	default 0 if MACH_SUN9I
+	---help---
+	Set the voltage (mV) to program the axp pmic dcdcc at, set to 0 to
+	disable dcdcc.
+	On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, dcdcb
+	is unused and can be left off.
+	On the Sunchip CX-A99 board, dcdcc powers VDD-GPU and can be left off.
+
+config AXP_DCDCD_VOLT
+	int "axp pmic dcdcd voltage"
+	depends on AXP806_POWER
+	default 900 if MACH_SUN9I
+	---help---
+	Set the voltage (mV) to program the axp pmic dcdcd at, set to 0 to
+	disable dcdcd.
+	On A80 boards dcdcd powers VDD-SYS or VDD-VPU and should be 0.9 V.
+
+config AXP_DCDCE_VOLT
+	int "axp pmic dcdce voltage"
+	depends on AXP806_POWER
+	default 2100 if MACH_SUN9I && AXP806_POWER && AXP809_POWER
+	default 3300 if MACH_SUN9I && AXP806_POWER && !AXP809_POWER
+	---help---
+	Set the voltage (mV) to program the axp pmic dcdce at, set to 0 to
+	disable dcdce.
+	On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, dcdce
+	should be 2.1 V.
+	On the Sunchip CX-A99, dcdce powers several parts which need 3.3 V,
+	such as pin groups B-F and H, the eMMC card and the SD card slot.
+
 config AXP_ALDO1_VOLT
 	int "axp pmic (a)ldo1 voltage"
 	depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
@@ -197,6 +277,126 @@ config AXP_ALDO4_VOLT
 	disable aldo4.
 	On A10(s) / A13 / A20 boards aldo4 should be 2.8V.
 
+config AXP2_ALDO1_VOLT
+	int "axp pmic (2) aldo1 voltage"
+	depends on AXP806_POWER
+	default 3000 if MACH_SUN9I && AXP806_POWER && AXP809_POWER
+	default 0 if MACH_SUN9I && AXP806_POWER && !AXP809_POWER
+	---help---
+	Set the voltage (mV) to program the axp pmic aldo1 at, set to 0 to
+	disable aldo1.
+	On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, aldo1
+	powers AVCC and should be 3.0 V.
+	On the Sunchip CX-A99, it is unknown what aldo1 powers and it can be
+	left off.
+
+config AXP2_ALDO2_VOLT
+	int "axp pmic (2) aldo2 voltage"
+	depends on AXP806_POWER
+	default 0 if MACH_SUN9I && AXP806_POWER && AXP809_POWER
+	default 1800 if MACH_SUN9I && AXP806_POWER && !AXP809_POWER
+	---help---
+	Set the voltage (mV) to program the axp pmic aldo2 at, set to 0 to
+	disable aldo2.
+	On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, aldo2 is
+	unused and can be left off.
+	On the Sunchip CX-A99, aldo2 powers pin groups G and M, Wifi I/O and
+	codec I/O and should be 1.8 V.
+
+config AXP2_ALDO3_VOLT
+	int "axp pmic (2) aldo3 voltage"
+	depends on AXP806_POWER
+	default 0 if MACH_SUN9I
+	---help---
+	Set the voltage (mV) to program the axp pmic aldo3 at, set to 0 to
+	disable aldo3.
+	On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, aldo3 is
+	unused and can be left off.
+	On the Sunchip CX-A99, aldo3 powers GMAC 2.5 V I/O and can be left off.
+
+config AXP_BLDO1_VOLT
+	int "axp pmic bldo1 voltage"
+	depends on AXP806_POWER
+	default 1800 if MACH_SUN9I
+	---help---
+	Set the voltage (mV) to program the axp pmic bldo1 at, set to 0 to
+	disable bldo1.
+	On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, bldo1
+	powers efuse, ADC, display and camera interface and should be 1.8 V.
+	On the Sunchip CX-A99, bldo1 powers A80 DLLs and PLLs and should be
+	1.8 V.
+
+config AXP_BLDO2_VOLT
+	int "axp pmic bldo2 voltage"
+	depends on AXP806_POWER
+	default 1800 if MACH_SUN9I && AXP806_POWER && AXP809_POWER
+	default 900 if MACH_SUN9I && AXP806_POWER && !AXP809_POWER
+	---help---
+	Set the voltage (mV) to program the axp pmic bldo2 at, set to 0 to
+	disable bldo2.
+	On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, bldo2
+	powers PLLs which need 1.8 V.
+	On the Sunchip CX-A99, bldo2 powers A80 subsystems which need 0.9 V.
+
+config AXP_BLDO3_VOLT
+	int "axp pmic bldo3 voltage"
+	depends on AXP806_POWER
+	default 0 if MACH_SUN9I
+	---help---
+	Set the voltage (mV) to program the axp pmic bldo3 at, set to 0 to
+	disable bldo3.
+	On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, bldo3 is
+	unused and can be left off.
+	On the Sunchip CX-A99, bldo2 powers the unused USB HSIC interface and
+	can be left off.
+
+config AXP_BLDO4_VOLT
+	int "axp pmic bldo4 voltage"
+	depends on AXP806_POWER
+	default 1800 if MACH_SUN9I && AXP806_POWER && AXP809_POWER
+	default 0 if MACH_SUN9I && AXP806_POWER && !AXP809_POWER
+	---help---
+	Set the voltage (mV) to program the axp pmic bldo4 at, set to 0 to
+	disable bldo4.
+	On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, bldo4
+	powers VCC12-HSIC and should be 1.2 V.
+	On the Sunchip CX-A99, bldo powers VDD09-HDMI and can be left off.
+
+config AXP_CLDO1_VOLT
+	int "axp pmic cldo1 voltage"
+	depends on AXP806_POWER
+	default 0 if MACH_SUN9I && AXP806_POWER && AXP809_POWER
+	default 3300 if MACH_SUN9I && AXP806_POWER && !AXP809_POWER
+	---help---
+	Set the voltage (mV) to program the axp pmic cldo at, set to 0 to
+	disable cldo.
+	On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, cldo1
+	supplies the unsupported GMAC 3.3 V and can be left off.
+	On the Sunchip CX-A99, cldo1 powers pin group L and the LEDs and
+	should be 3.3 V.
+
+config AXP_CLDO2_VOLT
+	int "axp pmic cldo2 voltage"
+	depends on AXP806_POWER
+	default 0 if MACH_SUN9I
+	---help---
+	Set the voltage (mV) to program the axp pmic cldo2 at, set to 0 to
+	disable cldo2.
+	On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, cldo2
+	powers the camera and can be left off.
+	On the Sunchip CX-A99, cldo2 powers Wifi+Bluetooth and can be left off.
+
+config AXP_CLDO3_VOLT
+	int "axp pmic cldo3 voltage"
+	depends on AXP806_POWER
+	default 0 if MACH_SUN9I
+	---help---
+	Set the voltage (mV) to program the axp pmic cldo3 at, set to 0 to
+	disable cldo3.
+	On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, cldo3
+	powers Wifi I/O and codec I/O and can be left off.
+	On the Sunchip CX-A99, cldo3 powers Wifi+Bluetooth and can be left off.
+
 config AXP_DLDO1_VOLT
 	int "axp pmic dldo1 voltage"
 	depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
@@ -295,6 +495,16 @@ config AXP_SW_ON
 	---help---
 	Enable to turn on axp pmic sw.
 
+config AXP2_SW_ON
+	bool "axp pmic (2) sw on"
+	depends on AXP806_POWER
+	default n
+	---help---
+	Enable to turn on axp pmic sw.
+	On the Cubietech Cubieboard4 and Merrii A80 Optimus boards, sw is unused
+	and can be left off.
+	On the Sunchip CX-A99, sw powers GMAC and codec and can be left off.
+
 config SY8106A_VOUT1_VOLT
 	int "SY8106A pmic VOUT1 voltage"
 	depends on SY8106A_POWER
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index b43523e..aaf8248 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_AS3722_POWER)	+= as3722.o
 obj-$(CONFIG_AXP152_POWER)	+= axp152.o
 obj-$(CONFIG_AXP209_POWER)	+= axp209.o
 obj-$(CONFIG_AXP221_POWER)	+= axp221.o
+obj-$(CONFIG_AXP806_POWER)	+= axp806.o
 obj-$(CONFIG_AXP809_POWER)	+= axp809.o
 obj-$(CONFIG_AXP818_POWER)	+= axp818.o
 obj-$(CONFIG_EXYNOS_TMU)	+= exynos-tmu.o
diff --git a/drivers/power/axp806.c b/drivers/power/axp806.c
new file mode 100644
index 0000000..be6a9a8
--- /dev/null
+++ b/drivers/power/axp806.c
@@ -0,0 +1,231 @@
+/*
+ * AXP806 and AXP808 driver based on AXP221 and AXP223 driver
+ *
+ * Copyright (C) 2017 Rask Ingemann Lambertsen <rask at formelder.dk>
+ *
+ * Based on axp221.c which is
+ * (C) Copyright 2014 Hans de Goede <hdegoede at redhat.com>
+ * (C) Copyright 2013 Oliver Schinagl <oliver at schinagl.nl>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <errno.h>
+#include <asm/arch/pmic_bus.h>
+#include <axp_pmic.h>
+
+/*
+ * Return cfg for a regulator with a linear range from `min' to `max' in steps
+ * of `div' and an optional second linear range from `max' to `max2' in steps
+ * of `div2'. Pass `max2' == `max' and `div2' == `div' for a single range.
+ */
+static u8 axp_mvolt_to_cfg(int mvolt, int min, int max, int div,
+			   int max2, int div2)
+{
+	if (mvolt < min) {
+		mvolt = min;
+	} else if (mvolt > max) {
+		if (mvolt > max2)
+			mvolt = max2;
+		return (mvolt - max) / div2 + (max - min) / div;
+	}
+	return (mvolt - min) / div;
+}
+
+int axp_set_dcdca(unsigned int mvolt)
+{
+	int ret;
+	u8 cfg = axp_mvolt_to_cfg(mvolt, 600, 1100, 10, 1520, 20);
+
+	if (mvolt == 0)
+		return pmic2_bus_clrbits(AXP806_OUTPUT_CTRL1,
+					 AXP806_OUTPUT_CTRL1_DCDCA_EN);
+
+	ret = pmic2_bus_write(AXP806_DCDCA_CTRL, cfg);
+	if (ret)
+		return ret;
+
+	return pmic2_bus_setbits(AXP806_OUTPUT_CTRL1,
+				 AXP806_OUTPUT_CTRL1_DCDCA_EN);
+}
+
+int axp_set_dcdcb(unsigned int mvolt)
+{
+	int ret;
+	u8 cfg = axp_mvolt_to_cfg(mvolt, 1000, 2550, 50, 2550, 50);
+
+	if (mvolt == 0)
+		return pmic2_bus_clrbits(AXP806_OUTPUT_CTRL1,
+					 AXP806_OUTPUT_CTRL1_DCDCB_EN);
+
+	ret = pmic2_bus_write(AXP806_DCDCB_CTRL, cfg);
+	if (ret)
+		return ret;
+
+	return pmic2_bus_setbits(AXP806_OUTPUT_CTRL1,
+				 AXP806_OUTPUT_CTRL1_DCDCB_EN);
+}
+
+int axp_set_dcdcc(unsigned int mvolt)
+{
+	int ret;
+	u8 cfg = axp_mvolt_to_cfg(mvolt, 600, 1100, 10, 1520, 20);
+
+	if (mvolt == 0)
+		return pmic2_bus_clrbits(AXP806_OUTPUT_CTRL1,
+					 AXP806_OUTPUT_CTRL1_DCDCC_EN);
+
+	ret = pmic2_bus_write(AXP806_DCDCC_CTRL, cfg);
+	if (ret)
+		return ret;
+
+	return pmic2_bus_setbits(AXP806_OUTPUT_CTRL1,
+				 AXP806_OUTPUT_CTRL1_DCDCC_EN);
+}
+
+int axp_set_dcdcd(unsigned int mvolt)
+{
+	int ret;
+	u8 cfg = axp_mvolt_to_cfg(mvolt, 600, 1500, 20, 3300, 100);
+
+	if (mvolt == 0)
+		return pmic2_bus_clrbits(AXP806_OUTPUT_CTRL1,
+					 AXP806_OUTPUT_CTRL1_DCDCD_EN);
+
+	ret = pmic2_bus_write(AXP806_DCDCD_CTRL, cfg);
+	if (ret)
+		return ret;
+
+	return pmic2_bus_setbits(AXP806_OUTPUT_CTRL1,
+				 AXP806_OUTPUT_CTRL1_DCDCD_EN);
+}
+
+int axp_set_dcdce(unsigned int mvolt)
+{
+	int ret;
+	u8 cfg = axp_mvolt_to_cfg(mvolt, 1100, 3400, 100, 3400, 100);
+
+	if (mvolt == 0)
+		return pmic2_bus_clrbits(AXP806_OUTPUT_CTRL1,
+					 AXP806_OUTPUT_CTRL1_DCDCE_EN);
+
+	ret = pmic2_bus_write(AXP806_DCDCE_CTRL, cfg);
+	if (ret)
+		return ret;
+
+	return pmic2_bus_setbits(AXP806_OUTPUT_CTRL1,
+				 AXP806_OUTPUT_CTRL1_DCDCE_EN);
+}
+
+int axp2_set_aldo(int ldo_num, unsigned int mvolt)
+{
+	int ret;
+	unsigned int ldo = ldo_num - 1;
+	u8 cfg = axp_mvolt_to_cfg(mvolt, 700, 3300, 100, 3300, 100);
+
+	if (ldo_num < 1 || ldo_num > 3)
+		return -EINVAL;
+
+	if (mvolt == 0)
+		return pmic2_bus_clrbits(AXP806_OUTPUT_CTRL1,
+					 AXP806_OUTPUT_CTRL1_ALDO1_EN << ldo);
+
+	ret = pmic2_bus_write(AXP806_ALDO1_CTRL + ldo, cfg);
+	if (ret)
+		return ret;
+
+	return pmic2_bus_setbits(AXP806_OUTPUT_CTRL1,
+				 AXP806_OUTPUT_CTRL1_ALDO1_EN << ldo);
+}
+
+int axp_set_bldo(int ldo_num, unsigned int mvolt)
+{
+	int ret;
+	unsigned int ldo = ldo_num - 1;
+	u8 cfg = axp_mvolt_to_cfg(mvolt, 700, 1900, 100, 1900, 100);
+
+	if (ldo_num < 1 || ldo_num > 4)
+		return -EINVAL;
+
+	if (mvolt == 0)
+		return pmic2_bus_clrbits(AXP806_OUTPUT_CTRL2,
+					AXP806_OUTPUT_CTRL2_BLDO1_EN << ldo);
+
+	ret = pmic2_bus_write(AXP806_BLDO1_CTRL + ldo, cfg);
+	if (ret)
+		return ret;
+
+	return pmic2_bus_setbits(AXP806_OUTPUT_CTRL2,
+				AXP806_OUTPUT_CTRL2_BLDO1_EN << ldo);
+}
+
+int axp_set_cldo(int ldo_num, unsigned int mvolt)
+{
+	int ret;
+	unsigned int ldo = ldo_num - 1;
+	u8 cfg;
+
+	if (ldo_num < 1 || ldo_num > 3)
+		return -EINVAL;
+
+	if (ldo_num == 2)
+		cfg = axp_mvolt_to_cfg(mvolt, 700, 3400, 100, 4200, 200);
+	else
+		cfg = axp_mvolt_to_cfg(mvolt, 700, 3300, 100, 3300, 100);
+
+	if (mvolt == 0)
+		return pmic2_bus_clrbits(AXP806_OUTPUT_CTRL2,
+					AXP806_OUTPUT_CTRL2_CLDO1_EN << ldo);
+
+	ret = pmic2_bus_write(AXP806_CLDO1_CTRL + ldo, cfg);
+	if (ret)
+		return ret;
+
+	return pmic2_bus_setbits(AXP806_OUTPUT_CTRL2,
+				AXP806_OUTPUT_CTRL2_CLDO1_EN << ldo);
+}
+
+int axp2_set_sw(bool on)
+{
+	if (!on)
+		return pmic2_bus_clrbits(AXP806_OUTPUT_CTRL2,
+					AXP806_OUTPUT_CTRL2_SW_EN);
+	return pmic2_bus_setbits(AXP806_OUTPUT_CTRL2,
+				AXP806_OUTPUT_CTRL2_SW_EN);
+}
+
+int axp2_init(void)
+{
+	u8 axp_chip_id;
+	int ret;
+
+	ret = pmic_bus_init();
+	if (ret)
+		return ret;
+
+	ret = pmic2_bus_read(AXP806_CHIP_ID, &axp_chip_id);
+	if (ret)
+		return ret;
+
+	if ((axp_chip_id & 0xcf) != 0x40)
+		return -ENODEV;
+
+	return 0;
+}
+
+/* The AXP809 driver also implements do_poweroff() and we can't have both. */
+#ifndef CONFIG_AXP809_POWER
+int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	pmic2_bus_setbits(AXP806_SHUTDOWN_CTRL, AXP806_SHUTDOWN_POWEROFF);
+
+	/* infinite loop during shutdown */
+	while (1)
+		;
+
+	/* not reached */
+	return 0;
+}
+#endif
diff --git a/include/axp806.h b/include/axp806.h
new file mode 100644
index 0000000..d7f7f2b
--- /dev/null
+++ b/include/axp806.h
@@ -0,0 +1,50 @@
+/*
+ * X-Powers AXP806 and AXP808 Power Management IC driver
+ *
+ * Copyright (C) 2017 Rask Ingemann Lambertsen <rask at formelder.dk>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <linux/bitops.h>
+
+#define AXP806_CHIP_ID		0x03
+#define AXP806_OUTPUT_CTRL1	0x10
+#define AXP806_OUTPUT_CTRL2	0x11
+#define AXP806_DCDCA_CTRL	0x12
+#define AXP806_DCDCB_CTRL	0x13
+#define AXP806_DCDCC_CTRL	0x14
+#define AXP806_DCDCD_CTRL	0x15
+#define AXP806_DCDCE_CTRL	0x16
+#define AXP806_ALDO1_CTRL	0x17
+#define AXP806_ALDO2_CTRL	0x18
+#define AXP806_ALDO3_CTRL	0x19
+/* Unused registers here. */
+#define AXP806_BLDO1_CTRL	0x20
+#define AXP806_BLDO2_CTRL	0x21
+#define AXP806_BLDO3_CTRL	0x22
+#define AXP806_BLDO4_CTRL	0x23
+#define AXP806_CLDO1_CTRL	0x24
+#define AXP806_CLDO2_CTRL	0x25
+#define AXP806_CLDO3_CTRL	0x26
+#define AXP806_SHUTDOWN_CTRL	0x32
+
+#define AXP806_OUTPUT_CTRL1_DCDCA_EN	BIT(0)
+#define AXP806_OUTPUT_CTRL1_DCDCB_EN	BIT(1)
+#define AXP806_OUTPUT_CTRL1_DCDCC_EN	BIT(2)
+#define AXP806_OUTPUT_CTRL1_DCDCD_EN	BIT(3)
+#define AXP806_OUTPUT_CTRL1_DCDCE_EN	BIT(4)
+#define AXP806_OUTPUT_CTRL1_ALDO1_EN	BIT(5)
+#define AXP806_OUTPUT_CTRL1_ALDO2_EN	BIT(6)
+#define AXP806_OUTPUT_CTRL1_ALDO3_EN	BIT(7)
+
+#define AXP806_OUTPUT_CTRL2_BLDO1_EN	BIT(0)
+#define AXP806_OUTPUT_CTRL2_BLDO2_EN	BIT(1)
+#define AXP806_OUTPUT_CTRL2_BLDO3_EN	BIT(2)
+#define AXP806_OUTPUT_CTRL2_BLDO4_EN	BIT(3)
+#define AXP806_OUTPUT_CTRL2_CLDO1_EN	BIT(4)
+#define AXP806_OUTPUT_CTRL2_CLDO2_EN	BIT(5)
+#define AXP806_OUTPUT_CTRL2_CLDO3_EN	BIT(6)
+#define AXP806_OUTPUT_CTRL2_SW_EN	BIT(7)
+
+#define AXP806_SHUTDOWN_POWEROFF	BIT(7)
diff --git a/include/axp_pmic.h b/include/axp_pmic.h
index d789ad8..7d5dad7 100644
--- a/include/axp_pmic.h
+++ b/include/axp_pmic.h
@@ -16,6 +16,9 @@
 #ifdef CONFIG_AXP221_POWER
 #include <axp221.h>
 #endif
+#ifdef CONFIG_AXP806_POWER
+#include <axp806.h>
+#endif
 #ifdef CONFIG_AXP809_POWER
 #include <axp809.h>
 #endif
@@ -28,15 +31,25 @@ int axp_set_dcdc2(unsigned int mvolt);
 int axp_set_dcdc3(unsigned int mvolt);
 int axp_set_dcdc4(unsigned int mvolt);
 int axp_set_dcdc5(unsigned int mvolt);
+int axp_set_dcdca(unsigned int mvolt);
+int axp_set_dcdcb(unsigned int mvolt);
+int axp_set_dcdcc(unsigned int mvolt);
+int axp_set_dcdcd(unsigned int mvolt);
+int axp_set_dcdce(unsigned int mvolt);
 int axp_set_aldo1(unsigned int mvolt);
 int axp_set_aldo2(unsigned int mvolt);
 int axp_set_aldo3(unsigned int mvolt);
 int axp_set_aldo4(unsigned int mvolt);
+int axp2_set_aldo(int aldo_num, unsigned int mvolt);
+int axp_set_bldo(int bldo_num, unsigned int mvolt);
+int axp_set_cldo(int cldo_num, unsigned int mvolt);
 int axp_set_dldo(int dldo_num, unsigned int mvolt);
 int axp_set_eldo(int eldo_num, unsigned int mvolt);
 int axp_set_fldo(int fldo_num, unsigned int mvolt);
 int axp_set_sw(bool on);
+int axp2_set_sw(bool on);
 int axp_init(void);
+int axp2_init(void);
 int axp_get_sid(unsigned int *sid);
 
 #endif
-- 
2.10.2



More information about the U-Boot mailing list