sunxi: power: add AXP809 support

The A80 uses the AXP809 as its primary PMIC.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index d137536..3c44167 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -41,6 +41,13 @@
 	Select this to enable support for the axp221/axp223 pmic found on most
 	A23 and A31 boards.
 
+config AXP809_POWER
+	boolean "axp809 pmic support"
+	depends on MACH_SUN9I
+	select CMD_POWEROFF
+	---help---
+	Say y here to enable support for the axp809 pmic found on A80 boards.
+
 config AXP818_POWER
 	boolean "axp818 pmic support"
 	depends on MACH_SUN8I_A83T
@@ -60,36 +67,39 @@
 
 config AXP_DCDC1_VOLT
 	int "axp pmic dcdc1 voltage"
-	depends on AXP221_POWER || AXP818_POWER
+	depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
 	default 3300 if AXP818_POWER
-	default 3000 if MACH_SUN6I || MACH_SUN8I
+	default 3000 if MACH_SUN6I || MACH_SUN8I || MACH_SUN9I
 	---help---
 	Set the voltage (mV) to program the axp pmic dcdc1 at, set to 0 to
 	disable dcdc1. On A23 / A31 / A33 (axp221) boards dcdc1 is used for
 	generic 3.3V IO voltage for external devices like the lcd-panal and
 	sdcard interfaces, etc. On most boards dcdc1 is undervolted to 3.0V to
-	safe battery. On A31 devices dcdc1 is also used for VCC-IO. On A83T
-	dcdc1 is used for VCC-IO, nand, usb0, sd , etc.
+	save battery. On A31 devices dcdc1 is also used for VCC-IO. On A83T
+	dcdc1 is used for VCC-IO, nand, usb0, sd , etc. On A80 dcdc1 normally
+	powers some of the pingroups, NAND/eMMC, SD/MMC, and USB OTG.
 
 config AXP_DCDC2_VOLT
 	int "axp pmic dcdc2 voltage"
-	depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP818_POWER
+	depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER
 	default 900 if AXP818_POWER
 	default 1400 if AXP152_POWER || AXP209_POWER
 	default 1200 if MACH_SUN6I
 	default 1100 if MACH_SUN8I
+	default 0 if MACH_SUN9I
 	---help---
 	Set the voltage (mV) to program the axp pmic dcdc2 at, set to 0 to
 	disable dcdc2.
 	On A10(s) / A13 / A20 boards dcdc2 is VDD-CPU and should be 1.4V.
 	On A31 boards dcdc2 is used for VDD-GPU and should be 1.2V.
 	On A23/A33 boards dcdc2 is used for VDD-SYS and should be 1.1V.
+	On A80 boards dcdc2 powers the GPU and can be left off.
 	On A83T boards dcdc2 is used for VDD-CPUA(cluster 0) and should be 0.9V.
 
 config AXP_DCDC3_VOLT
 	int "axp pmic dcdc3 voltage"
-	depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP818_POWER
-	default 900 if AXP818_POWER
+	depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER
+	default 900 if AXP809_POWER || AXP818_POWER
 	default 1500 if AXP152_POWER
 	default 1250 if AXP209_POWER
 	default 1200 if MACH_SUN6I || MACH_SUN8I
@@ -100,51 +110,55 @@
 	should be 1.25V.
 	On A10s boards with an axp152 dcdc3 is VCC-DRAM and should be 1.5V.
 	On A23 / A31 / A33 boards dcdc3 is VDD-CPU and should be 1.2V.
+	On A80 boards dcdc3 is used for VDD-CPUA(cluster 0) and should be 0.9V.
 	On A83T boards dcdc3 is used for VDD-CPUB(cluster 1) and should be 0.9V.
 
 config AXP_DCDC4_VOLT
 	int "axp pmic dcdc4 voltage"
-	depends on AXP152_POWER || AXP221_POWER || AXP818_POWER
+	depends on AXP152_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER
 	default 1250 if AXP152_POWER
 	default 1200 if MACH_SUN6I
 	default 0 if MACH_SUN8I
+	default 900 if MACH_SUN9I
 	---help---
 	Set the voltage (mV) to program the axp pmic dcdc4 at, set to 0 to
 	disable dcdc4.
 	On A10s boards with an axp152 dcdc4 is VDD-INT-DLL and should be 1.25V.
 	On A31 boards dcdc4 is used for VDD-SYS and should be 1.2V.
 	On A23 / A33 boards dcdc4 is unused and should be disabled.
+	On A80 boards dcdc4 powers VDD-SYS, HDMI, USB OTG and should be 0.9V.
 	On A83T boards dcdc4 is used for VDD-GPU.
 
 config AXP_DCDC5_VOLT
 	int "axp pmic dcdc5 voltage"
-	depends on AXP221_POWER || AXP818_POWER
-	default 1500 if MACH_SUN6I || MACH_SUN8I
+	depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
+	default 1500 if MACH_SUN6I || MACH_SUN8I || MACH_SUN9I
 	---help---
 	Set the voltage (mV) to program the axp pmic dcdc5 at, set to 0 to
 	disable dcdc5.
-	On A23 / A31 / A33 / A83T boards dcdc5 is VCC-DRAM and should be 1.5V,
-	1.35V if DDR3L is used.
+	On A23 / A31 / A33 / A80 / A83T boards dcdc5 is VCC-DRAM and
+	should be 1.5V, 1.35V if DDR3L is used.
 
 config AXP_ALDO1_VOLT
 	int "axp pmic (a)ldo1 voltage"
-	depends on AXP221_POWER || AXP818_POWER
+	depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
 	default 0 if MACH_SUN6I
 	default 1800 if MACH_SUN8I_A83T
-	default 3000 if MACH_SUN8I
+	default 3000 if MACH_SUN8I || MACH_SUN9I
 	---help---
 	Set the voltage (mV) to program the axp pmic aldo1 at, set to 0 to
 	disable aldo1.
 	On A31 boards aldo1 is often used to power the wifi module.
 	On A23 / A33 boards aldo1 is used for VCC-IO and should be 3.0V.
+	On A80 boards aldo1 powers the USB hosts and should be 3.0V.
 	On A83T / H8 boards aldo1 is used for MIPI CSI, DSI, HDMI, EFUSE, and
 	should be 1.8V.
 
 config AXP_ALDO2_VOLT
 	int "axp pmic (a)ldo2 voltage"
-	depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP818_POWER
+	depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER
 	default 3000 if AXP152_POWER || AXP209_POWER
-	default 0 if MACH_SUN6I
+	default 0 if MACH_SUN6I || MACH_SUN9I
 	default 1800 if MACH_SUN8I_A83T
 	default 2500 if MACH_SUN8I
 	---help---
@@ -154,19 +168,21 @@
 	On A31 boards aldo2 is typically unused and should be disabled.
 	On A31 boards aldo2 may be used for LPDDR2 then it should be 1.8V.
 	On A23 / A33 boards aldo2 is used for VDD-DLL and should be 2.5V.
+	On A80 boards aldo2 powers PB pingroup and camera IO and can be left off.
 	On A83T / H8 boards aldo2 powers VDD-DLL, VCC18-PLL, CPVDD, VDD18-ADC,
 	LPDDR2, and the codec. It should be 1.8V.
 
 config AXP_ALDO3_VOLT
 	int "axp pmic (a)ldo3 voltage"
-	depends on AXP209_POWER || AXP221_POWER || AXP818_POWER
-	default 0 if AXP209_POWER
+	depends on AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER
+	default 0 if AXP209_POWER || MACH_SUN9I
 	default 3000 if MACH_SUN6I || MACH_SUN8I
 	---help---
 	Set the voltage (mV) to program the axp pmic aldo3 at, set to 0 to
 	disable aldo3.
 	On A10(s) / A13 / A20 boards aldo3 should be 2.8V.
 	On A23 / A31 / A33 boards aldo3 is VCC-PLL and AVCC and should be 3.0V.
+	On A80 boards aldo3 is normally not used.
 	On A83T / H8 boards aldo3 is AVCC, VCC-PL, and VCC-LED, and should be
 	3.0V.
 
@@ -181,21 +197,23 @@
 
 config AXP_DLDO1_VOLT
 	int "axp pmic dldo1 voltage"
-	depends on AXP221_POWER || AXP818_POWER
+	depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
 	default 0
 	---help---
 	Set the voltage (mV) to program the axp pmic dldo1 at, set to 0 to
 	disable dldo1. On sun6i (A31) boards with ethernet dldo1 is often used
-	to power the ethernet phy. On sun8i (A23) boards this is often used to
-	power the wifi.
+	to power the ethernet phy. On A23, A33 and A80 boards this is often
+	used to power the wifi.
 
 config AXP_DLDO2_VOLT
 	int "axp pmic dldo2 voltage"
-	depends on AXP221_POWER || AXP818_POWER
+	depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
+	default 3000 if MACH_SUN9I
 	default 0
 	---help---
 	Set the voltage (mV) to program the axp pmic dldo2 at, set to 0 to
 	disable dldo2.
+	On A80 boards dldo2 normally powers the PL pins and should be 3.0V.
 
 config AXP_DLDO3_VOLT
 	int "axp pmic dldo3 voltage"
@@ -215,7 +233,7 @@
 
 config AXP_ELDO1_VOLT
 	int "axp pmic eldo1 voltage"
-	depends on AXP221_POWER || AXP818_POWER
+	depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
 	default 0
 	---help---
 	Set the voltage (mV) to program the axp pmic eldo1 at, set to 0 to
@@ -223,7 +241,7 @@
 
 config AXP_ELDO2_VOLT
 	int "axp pmic eldo2 voltage"
-	depends on AXP221_POWER || AXP818_POWER
+	depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
 	default 0
 	---help---
 	Set the voltage (mV) to program the axp pmic eldo2 at, set to 0 to
@@ -231,13 +249,15 @@
 
 config AXP_ELDO3_VOLT
 	int "axp pmic eldo3 voltage"
-	depends on AXP221_POWER || AXP818_POWER
+	depends on AXP221_POWER || AXP809_POWER || AXP818_POWER
+	default 3000 if MACH_SUN9I
 	default 0
 	---help---
 	Set the voltage (mV) to program the axp pmic eldo3 at, set to 0 to
 	disable eldo3. On some A31(s) tablets it might be used to supply
 	1.2V for the SSD2828 chip (converter of parallel LCD interface
 	into MIPI DSI).
+	On A80 boards it powers the PM pingroup and should be 3.0V.
 
 config AXP_FLDO1_VOLT
 	int "axp pmic fldo1 voltage"
@@ -268,7 +288,7 @@
 
 config AXP_SW_ON
 	bool "axp pmic sw on"
-	depends on AXP818_POWER
+	depends on AXP809_POWER || AXP818_POWER
 	default n
 	---help---
 	Enable to turn on axp pmic sw.
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 690faa0..b43523e 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -9,6 +9,7 @@
 obj-$(CONFIG_AXP152_POWER)	+= axp152.o
 obj-$(CONFIG_AXP209_POWER)	+= axp209.o
 obj-$(CONFIG_AXP221_POWER)	+= axp221.o
+obj-$(CONFIG_AXP809_POWER)	+= axp809.o
 obj-$(CONFIG_AXP818_POWER)	+= axp818.o
 obj-$(CONFIG_EXYNOS_TMU)	+= exynos-tmu.o
 obj-$(CONFIG_FTPMU010_POWER)	+= ftpmu010.o
diff --git a/drivers/power/axp809.c b/drivers/power/axp809.c
new file mode 100644
index 0000000..c8b76cf
--- /dev/null
+++ b/drivers/power/axp809.c
@@ -0,0 +1,238 @@
+/*
+ * AXP809 driver based on AXP221 driver
+ *
+ *
+ * (C) Copyright 2016 Chen-Yu Tsai <wens@csie.org>
+ *
+ * Based on axp221.c
+ * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ * (C) Copyright 2013 Oliver Schinagl <oliver@schinagl.nl>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/pmic_bus.h>
+#include <axp_pmic.h>
+
+static u8 axp809_mvolt_to_cfg(int mvolt, int min, int max, int div)
+{
+	if (mvolt < min)
+		mvolt = min;
+	else if (mvolt > max)
+		mvolt = max;
+
+	return (mvolt - min) / div;
+}
+
+int axp_set_dcdc1(unsigned int mvolt)
+{
+	int ret;
+	u8 cfg = axp809_mvolt_to_cfg(mvolt, 1600, 3400, 100);
+
+	if (mvolt == 0)
+		return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1,
+					AXP809_OUTPUT_CTRL1_DCDC1_EN);
+
+	ret = pmic_bus_write(AXP809_DCDC1_CTRL, cfg);
+	if (ret)
+		return ret;
+
+	ret = pmic_bus_setbits(AXP809_OUTPUT_CTRL2,
+			       AXP809_OUTPUT_CTRL2_DC1SW_EN);
+	if (ret)
+		return ret;
+
+	return pmic_bus_setbits(AXP809_OUTPUT_CTRL1,
+				AXP809_OUTPUT_CTRL1_DCDC1_EN);
+}
+
+int axp_set_dcdc2(unsigned int mvolt)
+{
+	int ret;
+	u8 cfg = axp809_mvolt_to_cfg(mvolt, 600, 1540, 20);
+
+	if (mvolt == 0)
+		return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1,
+					AXP809_OUTPUT_CTRL1_DCDC2_EN);
+
+	ret = pmic_bus_write(AXP809_DCDC2_CTRL, cfg);
+	if (ret)
+		return ret;
+
+	return pmic_bus_setbits(AXP809_OUTPUT_CTRL1,
+				AXP809_OUTPUT_CTRL1_DCDC2_EN);
+}
+
+int axp_set_dcdc3(unsigned int mvolt)
+{
+	int ret;
+	u8 cfg = axp809_mvolt_to_cfg(mvolt, 600, 1860, 20);
+
+	if (mvolt == 0)
+		return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1,
+					AXP809_OUTPUT_CTRL1_DCDC3_EN);
+
+	ret = pmic_bus_write(AXP809_DCDC3_CTRL, cfg);
+	if (ret)
+		return ret;
+
+	return pmic_bus_setbits(AXP809_OUTPUT_CTRL1,
+				AXP809_OUTPUT_CTRL1_DCDC3_EN);
+}
+
+int axp_set_dcdc4(unsigned int mvolt)
+{
+	int ret;
+	u8 cfg = axp809_mvolt_to_cfg(mvolt, 600, 1540, 20);
+
+	if (mvolt >= 1540)
+		cfg = 0x30 + axp809_mvolt_to_cfg(mvolt, 1800, 2600, 100);
+
+	if (mvolt == 0)
+		return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1,
+					AXP809_OUTPUT_CTRL1_DCDC4_EN);
+
+	ret = pmic_bus_write(AXP809_DCDC5_CTRL, cfg);
+	if (ret)
+		return ret;
+
+	return pmic_bus_setbits(AXP809_OUTPUT_CTRL1,
+				AXP809_OUTPUT_CTRL1_DCDC4_EN);
+}
+
+int axp_set_dcdc5(unsigned int mvolt)
+{
+	int ret;
+	u8 cfg = axp809_mvolt_to_cfg(mvolt, 1000, 2550, 50);
+
+	if (mvolt == 0)
+		return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1,
+					AXP809_OUTPUT_CTRL1_DCDC5_EN);
+
+	ret = pmic_bus_write(AXP809_DCDC5_CTRL, cfg);
+	if (ret)
+		return ret;
+
+	return pmic_bus_setbits(AXP809_OUTPUT_CTRL1,
+				AXP809_OUTPUT_CTRL1_DCDC5_EN);
+}
+
+int axp_set_aldo(int aldo_num, unsigned int mvolt)
+{
+	int ret;
+	u8 cfg;
+
+	if (aldo_num < 1 || aldo_num > 3)
+		return -EINVAL;
+
+	if (mvolt == 0 && aldo_num == 3)
+		return pmic_bus_clrbits(AXP809_OUTPUT_CTRL2,
+					AXP809_OUTPUT_CTRL2_ALDO3_EN);
+	if (mvolt == 0)
+		return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1,
+				AXP809_OUTPUT_CTRL1_ALDO1_EN << (aldo_num - 1));
+
+	cfg = axp809_mvolt_to_cfg(mvolt, 700, 3300, 100);
+	ret = pmic_bus_write(AXP809_ALDO1_CTRL + (aldo_num - 1), cfg);
+	if (ret)
+		return ret;
+
+	if (aldo_num == 3)
+		return pmic_bus_setbits(AXP809_OUTPUT_CTRL2,
+					AXP809_OUTPUT_CTRL2_ALDO3_EN);
+	return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1,
+				AXP809_OUTPUT_CTRL1_ALDO1_EN << (aldo_num - 1));
+}
+
+/* TODO: re-work other AXP drivers to consolidate ALDO functions. */
+int axp_set_aldo1(unsigned int mvolt)
+{
+	return axp_set_aldo(1, mvolt);
+}
+
+int axp_set_aldo2(unsigned int mvolt)
+{
+	return axp_set_aldo(2, mvolt);
+}
+
+int axp_set_aldo3(unsigned int mvolt)
+{
+	return axp_set_aldo(3, mvolt);
+}
+
+int axp_set_dldo(int dldo_num, unsigned int mvolt)
+{
+	u8 cfg = axp809_mvolt_to_cfg(mvolt, 700, 3300, 100);
+	int ret;
+
+	if (dldo_num < 1 || dldo_num > 2)
+		return -EINVAL;
+
+	if (mvolt == 0)
+		return pmic_bus_clrbits(AXP809_OUTPUT_CTRL2,
+				AXP809_OUTPUT_CTRL2_DLDO1_EN << (dldo_num - 1));
+
+	if (dldo_num == 1 && mvolt > 3300)
+		cfg += 1 + axp809_mvolt_to_cfg(mvolt, 3400, 4200, 200);
+	ret = pmic_bus_write(AXP809_DLDO1_CTRL + (dldo_num - 1), cfg);
+	if (ret)
+		return ret;
+
+	return pmic_bus_setbits(AXP809_OUTPUT_CTRL2,
+				AXP809_OUTPUT_CTRL2_DLDO1_EN << (dldo_num - 1));
+}
+
+int axp_set_eldo(int eldo_num, unsigned int mvolt)
+{
+	int ret;
+	u8 cfg = axp809_mvolt_to_cfg(mvolt, 700, 3300, 100);
+
+	if (eldo_num < 1 || eldo_num > 3)
+		return -EINVAL;
+
+	if (mvolt == 0)
+		return pmic_bus_clrbits(AXP809_OUTPUT_CTRL2,
+				AXP809_OUTPUT_CTRL2_ELDO1_EN << (eldo_num - 1));
+
+	ret = pmic_bus_write(AXP809_ELDO1_CTRL + (eldo_num - 1), cfg);
+	if (ret)
+		return ret;
+
+	return pmic_bus_setbits(AXP809_OUTPUT_CTRL2,
+				AXP809_OUTPUT_CTRL2_ELDO1_EN << (eldo_num - 1));
+}
+
+int axp_set_sw(bool on)
+{
+	if (on)
+		return pmic_bus_setbits(AXP809_OUTPUT_CTRL2,
+					AXP809_OUTPUT_CTRL2_SWOUT_EN);
+
+	return pmic_bus_clrbits(AXP809_OUTPUT_CTRL2,
+				AXP809_OUTPUT_CTRL2_SWOUT_EN);
+}
+
+int axp_init(void)
+{
+	int ret;
+
+	ret = pmic_bus_init();
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	pmic_bus_write(AXP809_SHUTDOWN, AXP809_SHUTDOWN_POWEROFF);
+
+	/* infinite loop during shutdown */
+	while (1) {}
+
+	/* not reached */
+	return 0;
+}