1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * (C) Copyright 2012
3*4882a593Smuzhiyun * Henrik Nordstrom <henrik@henriknordstrom.net>
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <common.h>
9*4882a593Smuzhiyun #include <command.h>
10*4882a593Smuzhiyun #include <asm/arch/pmic_bus.h>
11*4882a593Smuzhiyun #include <axp_pmic.h>
12*4882a593Smuzhiyun
axp209_mvolt_to_cfg(int mvolt,int min,int max,int div)13*4882a593Smuzhiyun static u8 axp209_mvolt_to_cfg(int mvolt, int min, int max, int div)
14*4882a593Smuzhiyun {
15*4882a593Smuzhiyun if (mvolt < min)
16*4882a593Smuzhiyun mvolt = min;
17*4882a593Smuzhiyun else if (mvolt > max)
18*4882a593Smuzhiyun mvolt = max;
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun return (mvolt - min) / div;
21*4882a593Smuzhiyun }
22*4882a593Smuzhiyun
axp_set_dcdc2(unsigned int mvolt)23*4882a593Smuzhiyun int axp_set_dcdc2(unsigned int mvolt)
24*4882a593Smuzhiyun {
25*4882a593Smuzhiyun int rc;
26*4882a593Smuzhiyun u8 cfg, current;
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun if (mvolt == 0)
29*4882a593Smuzhiyun return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
30*4882a593Smuzhiyun AXP209_OUTPUT_CTRL_DCDC2);
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun rc = pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_DCDC2);
33*4882a593Smuzhiyun if (rc)
34*4882a593Smuzhiyun return rc;
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun cfg = axp209_mvolt_to_cfg(mvolt, 700, 2275, 25);
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun /* Do we really need to be this gentle? It has built-in voltage slope */
39*4882a593Smuzhiyun while ((rc = pmic_bus_read(AXP209_DCDC2_VOLTAGE, ¤t)) == 0 &&
40*4882a593Smuzhiyun current != cfg) {
41*4882a593Smuzhiyun if (current < cfg)
42*4882a593Smuzhiyun current++;
43*4882a593Smuzhiyun else
44*4882a593Smuzhiyun current--;
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun rc = pmic_bus_write(AXP209_DCDC2_VOLTAGE, current);
47*4882a593Smuzhiyun if (rc)
48*4882a593Smuzhiyun break;
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun return rc;
52*4882a593Smuzhiyun }
53*4882a593Smuzhiyun
axp_set_dcdc3(unsigned int mvolt)54*4882a593Smuzhiyun int axp_set_dcdc3(unsigned int mvolt)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun u8 cfg = axp209_mvolt_to_cfg(mvolt, 700, 3500, 25);
57*4882a593Smuzhiyun int rc;
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun if (mvolt == 0)
60*4882a593Smuzhiyun return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
61*4882a593Smuzhiyun AXP209_OUTPUT_CTRL_DCDC3);
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun rc = pmic_bus_write(AXP209_DCDC3_VOLTAGE, cfg);
64*4882a593Smuzhiyun if (rc)
65*4882a593Smuzhiyun return rc;
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_DCDC3);
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun
axp_set_aldo2(unsigned int mvolt)70*4882a593Smuzhiyun int axp_set_aldo2(unsigned int mvolt)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun int rc;
73*4882a593Smuzhiyun u8 cfg, reg;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun if (mvolt == 0)
76*4882a593Smuzhiyun return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
77*4882a593Smuzhiyun AXP209_OUTPUT_CTRL_LDO2);
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun cfg = axp209_mvolt_to_cfg(mvolt, 1800, 3300, 100);
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun rc = pmic_bus_read(AXP209_LDO24_VOLTAGE, ®);
82*4882a593Smuzhiyun if (rc)
83*4882a593Smuzhiyun return rc;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun /* LDO2 configuration is in upper 4 bits */
86*4882a593Smuzhiyun reg = (reg & 0x0f) | (cfg << 4);
87*4882a593Smuzhiyun rc = pmic_bus_write(AXP209_LDO24_VOLTAGE, reg);
88*4882a593Smuzhiyun if (rc)
89*4882a593Smuzhiyun return rc;
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO2);
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun
axp_set_aldo3(unsigned int mvolt)94*4882a593Smuzhiyun int axp_set_aldo3(unsigned int mvolt)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun u8 cfg;
97*4882a593Smuzhiyun int rc;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun if (mvolt == 0)
100*4882a593Smuzhiyun return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
101*4882a593Smuzhiyun AXP209_OUTPUT_CTRL_LDO3);
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun if (mvolt == -1)
104*4882a593Smuzhiyun cfg = 0x80; /* determined by LDO3IN pin */
105*4882a593Smuzhiyun else
106*4882a593Smuzhiyun cfg = axp209_mvolt_to_cfg(mvolt, 700, 3500, 25);
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun rc = pmic_bus_write(AXP209_LDO3_VOLTAGE, cfg);
109*4882a593Smuzhiyun if (rc)
110*4882a593Smuzhiyun return rc;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO3);
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun
axp_set_aldo4(unsigned int mvolt)115*4882a593Smuzhiyun int axp_set_aldo4(unsigned int mvolt)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun int rc;
118*4882a593Smuzhiyun static const unsigned int vindex[] = {
119*4882a593Smuzhiyun 1250, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2500,
120*4882a593Smuzhiyun 2700, 2800, 3000, 3100, 3200, 3300
121*4882a593Smuzhiyun };
122*4882a593Smuzhiyun u8 cfg, reg;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun if (mvolt == 0)
125*4882a593Smuzhiyun return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
126*4882a593Smuzhiyun AXP209_OUTPUT_CTRL_LDO4);
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun /* Translate mvolt to register cfg value, requested <= selected */
129*4882a593Smuzhiyun for (cfg = 15; vindex[cfg] > mvolt && cfg > 0; cfg--);
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun rc = pmic_bus_read(AXP209_LDO24_VOLTAGE, ®);
132*4882a593Smuzhiyun if (rc)
133*4882a593Smuzhiyun return rc;
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun /* LDO4 configuration is in lower 4 bits */
136*4882a593Smuzhiyun reg = (reg & 0xf0) | (cfg << 0);
137*4882a593Smuzhiyun rc = pmic_bus_write(AXP209_LDO24_VOLTAGE, reg);
138*4882a593Smuzhiyun if (rc)
139*4882a593Smuzhiyun return rc;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO4);
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
axp_init(void)144*4882a593Smuzhiyun int axp_init(void)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun u8 ver;
147*4882a593Smuzhiyun int i, rc;
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun rc = pmic_bus_init();
150*4882a593Smuzhiyun if (rc)
151*4882a593Smuzhiyun return rc;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun rc = pmic_bus_read(AXP209_CHIP_VERSION, &ver);
154*4882a593Smuzhiyun if (rc)
155*4882a593Smuzhiyun return rc;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun /* Low 4 bits is chip version */
158*4882a593Smuzhiyun ver &= 0x0f;
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun if (ver != 0x1)
161*4882a593Smuzhiyun return -EINVAL;
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun /* Mask all interrupts */
164*4882a593Smuzhiyun for (i = AXP209_IRQ_ENABLE1; i <= AXP209_IRQ_ENABLE5; i++) {
165*4882a593Smuzhiyun rc = pmic_bus_write(i, 0);
166*4882a593Smuzhiyun if (rc)
167*4882a593Smuzhiyun return rc;
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun /*
171*4882a593Smuzhiyun * Turn off LDOIO regulators / tri-state GPIO pins, when rebooting
172*4882a593Smuzhiyun * from android these are sometimes on.
173*4882a593Smuzhiyun */
174*4882a593Smuzhiyun rc = pmic_bus_write(AXP_GPIO0_CTRL, AXP_GPIO_CTRL_INPUT);
175*4882a593Smuzhiyun if (rc)
176*4882a593Smuzhiyun return rc;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun rc = pmic_bus_write(AXP_GPIO1_CTRL, AXP_GPIO_CTRL_INPUT);
179*4882a593Smuzhiyun if (rc)
180*4882a593Smuzhiyun return rc;
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun rc = pmic_bus_write(AXP_GPIO2_CTRL, AXP_GPIO_CTRL_INPUT);
183*4882a593Smuzhiyun if (rc)
184*4882a593Smuzhiyun return rc;
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun return 0;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun
do_poweroff(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])189*4882a593Smuzhiyun int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun pmic_bus_write(AXP209_SHUTDOWN, AXP209_POWEROFF);
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun /* infinite loop during shutdown */
194*4882a593Smuzhiyun while (1) {}
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun /* not reached */
197*4882a593Smuzhiyun return 0;
198*4882a593Smuzhiyun }
199