blob: 09ecb5b1ec2880d0417a1799b606af14cfe02532 [file] [log] [blame]
Andre Przywara107d1ae2023-07-30 01:11:01 +01001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * AXP313(a) driver
4 *
5 * (C) Copyright 2023 Arm Ltd.
6 *
7 * Based on axp305.c
8 * (C) Copyright 2020 Jernej Skrabec <jernej.skrabec@siol.net>
9 * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
10 * (C) Copyright 2013 Oliver Schinagl <oliver@schinagl.nl>
11 */
12
Andre Przywara107d1ae2023-07-30 01:11:01 +010013#include <command.h>
14#include <errno.h>
15#include <asm/arch/pmic_bus.h>
16#include <axp_pmic.h>
17
18enum axp313_reg {
19 AXP313_CHIP_VERSION = 0x03,
20 AXP313_OUTPUT_CTRL = 0x10,
21 AXP313_DCDC1_CTRL = 0x13,
22 AXP313_SHUTDOWN = 0x1a,
23};
24
25#define AXP313_CHIP_VERSION_MASK 0xcf
26#define AXP313_CHIP_VERSION_AXP1530 0x48
27#define AXP313_CHIP_VERSION_AXP313A 0x4b
28#define AXP313_CHIP_VERSION_AXP313B 0x4c
29
30#define AXP313_DCDC_SPLIT_OFFSET 71
31#define AXP313_DCDC_SPLIT_MVOLT 1200
32
33#define AXP313_POWEROFF BIT(7)
34
35static u8 mvolt_to_cfg(int mvolt, int min, int max, int div)
36{
37 if (mvolt < min)
38 mvolt = min;
39 else if (mvolt > max)
40 mvolt = max;
41
42 return (mvolt - min) / div;
43}
44
45static int axp_set_dcdc(int dcdc_num, unsigned int mvolt)
46{
47 int ret;
48 u8 cfg, enable_mask = 1U << (dcdc_num - 1);
49 int volt_reg = AXP313_DCDC1_CTRL + dcdc_num - 1;
50 int max_mV;
51
52 switch (dcdc_num) {
53 case 1:
54 case 2:
55 max_mV = 1540;
56 break;
57 case 3:
58 /*
59 * The manual defines a different split point, but tests
60 * show that it's the same 1200mV as for DCDC1/2.
61 */
62 max_mV = 1840;
63 break;
64 default:
65 return -EINVAL;
66 }
67
68 if (mvolt > AXP313_DCDC_SPLIT_MVOLT)
69 cfg = AXP313_DCDC_SPLIT_OFFSET + mvolt_to_cfg(mvolt,
70 AXP313_DCDC_SPLIT_MVOLT + 20, max_mV, 20);
71 else
72 cfg = mvolt_to_cfg(mvolt, 500, AXP313_DCDC_SPLIT_MVOLT, 10);
73
74 if (mvolt == 0)
75 return pmic_bus_clrbits(AXP313_OUTPUT_CTRL, enable_mask);
76
77 debug("DCDC%d: writing 0x%x to reg 0x%x\n", dcdc_num, cfg, volt_reg);
78 ret = pmic_bus_write(volt_reg, cfg);
79 if (ret)
80 return ret;
81
82 return pmic_bus_setbits(AXP313_OUTPUT_CTRL, enable_mask);
83}
84
85int axp_set_dcdc2(unsigned int mvolt)
86{
87 return axp_set_dcdc(2, mvolt);
88}
89
90int axp_set_dcdc3(unsigned int mvolt)
91{
92 return axp_set_dcdc(3, mvolt);
93}
94
95int axp_init(void)
96{
97 u8 axp_chip_id;
98 int ret;
99
100 ret = pmic_bus_init();
101 if (ret)
102 return ret;
103
104 ret = pmic_bus_read(AXP313_CHIP_VERSION, &axp_chip_id);
105 if (ret)
106 return ret;
107
108 axp_chip_id &= AXP313_CHIP_VERSION_MASK;
109 switch (axp_chip_id) {
110 case AXP313_CHIP_VERSION_AXP1530:
111 case AXP313_CHIP_VERSION_AXP313A:
112 case AXP313_CHIP_VERSION_AXP313B:
113 break;
114 default:
115 debug("unknown PMIC: 0x%x\n", axp_chip_id);
116 return -EINVAL;
117 }
118
119 return ret;
120}
121
122#if !CONFIG_IS_ENABLED(ARM_PSCI_FW) && !IS_ENABLED(CONFIG_SYSRESET_CMD_POWEROFF)
123int do_poweroff(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
124{
125 pmic_bus_write(AXP313_SHUTDOWN, AXP313_POWEROFF);
126
127 /* infinite loop during shutdown */
128 while (1) {}
129
130 /* not reached */
131 return 0;
132}
133#endif