xref: /OK3568_Linux_fs/u-boot/drivers/power/axp209.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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, &current)) == 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, &reg);
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, &reg);
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