Select this to enable support for the axp305 pmic found on most
H616 boards.
+config AXP313_POWER
+ bool "axp313 pmic support"
+ depends on MACH_SUN50I_H616
+ select AXP_PMIC_BUS
+ select CMD_POWEROFF
+ ---help---
+ Select this to enable support for the AXP313 PMIC found on some
+ H616 boards.
+
config AXP809_POWER
bool "axp809 pmic support"
depends on MACH_SUN9I
config AXP_DCDC2_VOLT
int "axp pmic dcdc2 voltage"
- depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER
+ depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER || AXP313_POWER
default 900 if AXP818_POWER
default 1400 if AXP152_POWER || AXP209_POWER
+ default 1000 if AXP313_POWER
default 1200 if MACH_SUN6I
default 1100 if MACH_SUN8I
default 0 if MACH_SUN9I
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.
On R40 boards dcdc2 is VDD-CPU and should be 1.1V
+ On boards using the AXP313 it's often VDD-CPU.
config AXP_DCDC3_VOLT
int "axp pmic dcdc3 voltage"
- depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER
+ depends on AXP152_POWER || AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER || AXP313_POWER
default 900 if AXP809_POWER || AXP818_POWER
default 1500 if AXP152_POWER
default 1250 if AXP209_POWER
+ default 1100 if AXP313_POWER
default 1100 if MACH_SUN8I_R40
default 1200 if MACH_SUN6I || MACH_SUN8I
---help---
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.
On R40 boards dcdc3 is VDD-SYS and VDD-GPU and should be 1.1V.
+ On boards using the AXP313 it's often VDD-DRAM and should be 1.1V for LPDDR4.
config AXP_DCDC4_VOLT
int "axp pmic dcdc4 voltage"
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * AXP313(a) driver
+ *
+ * (C) Copyright 2023 Arm Ltd.
+ *
+ * Based on axp305.c
+ * (C) Copyright 2020 Jernej Skrabec <jernej.skrabec@siol.net>
+ * (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>
+
+enum axp313_reg {
+ AXP313_CHIP_VERSION = 0x03,
+ AXP313_OUTPUT_CTRL = 0x10,
+ AXP313_DCDC1_CTRL = 0x13,
+ AXP313_SHUTDOWN = 0x1a,
+};
+
+#define AXP313_CHIP_VERSION_MASK 0xcf
+#define AXP313_CHIP_VERSION_AXP1530 0x48
+#define AXP313_CHIP_VERSION_AXP313A 0x4b
+#define AXP313_CHIP_VERSION_AXP313B 0x4c
+
+#define AXP313_DCDC_SPLIT_OFFSET 71
+#define AXP313_DCDC_SPLIT_MVOLT 1200
+
+#define AXP313_POWEROFF BIT(7)
+
+static u8 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;
+}
+
+static int axp_set_dcdc(int dcdc_num, unsigned int mvolt)
+{
+ int ret;
+ u8 cfg, enable_mask = 1U << (dcdc_num - 1);
+ int volt_reg = AXP313_DCDC1_CTRL + dcdc_num - 1;
+ int max_mV;
+
+ switch (dcdc_num) {
+ case 1:
+ case 2:
+ max_mV = 1540;
+ break;
+ case 3:
+ /*
+ * The manual defines a different split point, but tests
+ * show that it's the same 1200mV as for DCDC1/2.
+ */
+ max_mV = 1840;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (mvolt > AXP313_DCDC_SPLIT_MVOLT)
+ cfg = AXP313_DCDC_SPLIT_OFFSET + mvolt_to_cfg(mvolt,
+ AXP313_DCDC_SPLIT_MVOLT + 20, max_mV, 20);
+ else
+ cfg = mvolt_to_cfg(mvolt, 500, AXP313_DCDC_SPLIT_MVOLT, 10);
+
+ if (mvolt == 0)
+ return pmic_bus_clrbits(AXP313_OUTPUT_CTRL, enable_mask);
+
+ debug("DCDC%d: writing 0x%x to reg 0x%x\n", dcdc_num, cfg, volt_reg);
+ ret = pmic_bus_write(volt_reg, cfg);
+ if (ret)
+ return ret;
+
+ return pmic_bus_setbits(AXP313_OUTPUT_CTRL, enable_mask);
+}
+
+int axp_set_dcdc2(unsigned int mvolt)
+{
+ return axp_set_dcdc(2, mvolt);
+}
+
+int axp_set_dcdc3(unsigned int mvolt)
+{
+ return axp_set_dcdc(3, mvolt);
+}
+
+int axp_init(void)
+{
+ u8 axp_chip_id;
+ int ret;
+
+ ret = pmic_bus_init();
+ if (ret)
+ return ret;
+
+ ret = pmic_bus_read(AXP313_CHIP_VERSION, &axp_chip_id);
+ if (ret)
+ return ret;
+
+ axp_chip_id &= AXP313_CHIP_VERSION_MASK;
+ switch (axp_chip_id) {
+ case AXP313_CHIP_VERSION_AXP1530:
+ case AXP313_CHIP_VERSION_AXP313A:
+ case AXP313_CHIP_VERSION_AXP313B:
+ break;
+ default:
+ debug("unknown PMIC: 0x%x\n", axp_chip_id);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+#if !CONFIG_IS_ENABLED(ARM_PSCI_FW) && !IS_ENABLED(CONFIG_SYSRESET_CMD_POWEROFF)
+int do_poweroff(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+ pmic_bus_write(AXP313_SHUTDOWN, AXP313_POWEROFF);
+
+ /* infinite loop during shutdown */
+ while (1) {}
+
+ /* not reached */
+ return 0;
+}
+#endif