sunxi: Add support for AXP305 PMIC

This PMIC can be found on H616 boards and it's very similar to AXP805
and AXP806.

Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Jaehoon Chung <jh80.chung@samsung.com>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 02050f6..d17cf2d 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -48,6 +48,15 @@
 	Select this to enable support for the axp221/axp223 pmic found on most
 	A23 and A31 boards.
 
+config AXP305_POWER
+	bool "axp305 pmic support"
+	depends on MACH_SUN50I_H616
+	select AXP_PMIC_BUS
+	select CMD_POWEROFF
+	---help---
+	Select this to enable support for the axp305 pmic found on most
+	H616 boards.
+
 config AXP809_POWER
 	bool "axp809 pmic support"
 	depends on MACH_SUN9I
@@ -127,11 +136,12 @@
 
 config AXP_DCDC4_VOLT
 	int "axp pmic dcdc4 voltage"
-	depends on AXP152_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER
+	depends on AXP152_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER || AXP305_POWER
 	default 1250 if AXP152_POWER
 	default 1200 if MACH_SUN6I
 	default 0 if MACH_SUN8I
 	default 900 if MACH_SUN9I
+	default 1500 if AXP305_POWER
 	---help---
 	Set the voltage (mV) to program the axp pmic dcdc4 at, set to 0 to
 	disable dcdc4.
@@ -140,6 +150,7 @@
 	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.
+	On H616 boards dcdcd is used for VCC-DRAM.
 
 config AXP_DCDC5_VOLT
 	int "axp pmic dcdc5 voltage"
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 2dcc7bb..0bef069 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -6,6 +6,7 @@
 obj-$(CONFIG_AXP152_POWER)	+= axp152.o
 obj-$(CONFIG_AXP209_POWER)	+= axp209.o
 obj-$(CONFIG_AXP221_POWER)	+= axp221.o
+obj-$(CONFIG_AXP305_POWER)	+= axp305.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/axp305.c b/drivers/power/axp305.c
new file mode 100644
index 0000000..0191e4d
--- /dev/null
+++ b/drivers/power/axp305.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * AXP305 driver
+ *
+ * (C) Copyright 2020 Jernej Skrabec <jernej.skrabec@siol.net>
+ *
+ * Based on axp221.c
+ * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ * (C) Copyright 2013 Oliver Schinagl <oliver@schinagl.nl>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <errno.h>
+#include <asm/arch/pmic_bus.h>
+#include <axp_pmic.h>
+
+#define AXP305_DCDC4_1600MV_OFFSET 46
+
+static u8 axp305_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_dcdc4(unsigned int mvolt)
+{
+	int ret;
+	u8 cfg;
+
+	if (mvolt >= 1600)
+		cfg = AXP305_DCDC4_1600MV_OFFSET +
+			axp305_mvolt_to_cfg(mvolt, 1600, 3300, 100);
+	else
+		cfg = axp305_mvolt_to_cfg(mvolt, 600, 1500, 20);
+
+	if (mvolt == 0)
+		return pmic_bus_clrbits(AXP305_OUTPUT_CTRL1,
+					AXP305_OUTPUT_CTRL1_DCDCD_EN);
+
+	ret = pmic_bus_write(AXP305_DCDCD_VOLTAGE, cfg);
+	if (ret)
+		return ret;
+
+	return pmic_bus_setbits(AXP305_OUTPUT_CTRL1,
+				AXP305_OUTPUT_CTRL1_DCDCD_EN);
+}
+
+int axp_init(void)
+{
+	u8 axp_chip_id;
+	int ret;
+
+	ret = pmic_bus_init();
+	if (ret)
+		return ret;
+
+	ret = pmic_bus_read(AXP305_CHIP_VERSION, &axp_chip_id);
+	if (ret)
+		return ret;
+
+	if ((axp_chip_id & AXP305_CHIP_VERSION_MASK) != 0x40)
+		return -ENODEV;
+
+	return ret;
+}
+
+#ifndef CONFIG_PSCI_RESET
+int do_poweroff(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+	pmic_bus_write(AXP305_SHUTDOWN, AXP305_POWEROFF);
+
+	/* infinite loop during shutdown */
+	while (1) {}
+
+	/* not reached */
+	return 0;
+}
+#endif