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