1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * AXP809 driver based on AXP221 driver
4  *
5  *
6  * (C) Copyright 2016 Chen-Yu Tsai <wens@csie.org>
7  *
8  * Based on axp221.c
9  * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
10  * (C) Copyright 2013 Oliver Schinagl <oliver@schinagl.nl>
11  */
12 
13 #include <common.h>
14 #include <command.h>
15 #include <errno.h>
16 #include <asm/arch/gpio.h>
17 #include <asm/arch/pmic_bus.h>
18 #include <axp_pmic.h>
19 
axp809_mvolt_to_cfg(int mvolt,int min,int max,int div)20 static u8 axp809_mvolt_to_cfg(int mvolt, int min, int max, int div)
21 {
22 	if (mvolt < min)
23 		mvolt = min;
24 	else if (mvolt > max)
25 		mvolt = max;
26 
27 	return (mvolt - min) / div;
28 }
29 
axp_set_dcdc1(unsigned int mvolt)30 int axp_set_dcdc1(unsigned int mvolt)
31 {
32 	int ret;
33 	u8 cfg = axp809_mvolt_to_cfg(mvolt, 1600, 3400, 100);
34 
35 	if (mvolt == 0)
36 		return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1,
37 					AXP809_OUTPUT_CTRL1_DCDC1_EN);
38 
39 	ret = pmic_bus_write(AXP809_DCDC1_CTRL, cfg);
40 	if (ret)
41 		return ret;
42 
43 	ret = pmic_bus_setbits(AXP809_OUTPUT_CTRL2,
44 			       AXP809_OUTPUT_CTRL2_DC1SW_EN);
45 	if (ret)
46 		return ret;
47 
48 	return pmic_bus_setbits(AXP809_OUTPUT_CTRL1,
49 				AXP809_OUTPUT_CTRL1_DCDC1_EN);
50 }
51 
axp_set_dcdc2(unsigned int mvolt)52 int axp_set_dcdc2(unsigned int mvolt)
53 {
54 	int ret;
55 	u8 cfg = axp809_mvolt_to_cfg(mvolt, 600, 1540, 20);
56 
57 	if (mvolt == 0)
58 		return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1,
59 					AXP809_OUTPUT_CTRL1_DCDC2_EN);
60 
61 	ret = pmic_bus_write(AXP809_DCDC2_CTRL, cfg);
62 	if (ret)
63 		return ret;
64 
65 	return pmic_bus_setbits(AXP809_OUTPUT_CTRL1,
66 				AXP809_OUTPUT_CTRL1_DCDC2_EN);
67 }
68 
axp_set_dcdc3(unsigned int mvolt)69 int axp_set_dcdc3(unsigned int mvolt)
70 {
71 	int ret;
72 	u8 cfg = axp809_mvolt_to_cfg(mvolt, 600, 1860, 20);
73 
74 	if (mvolt == 0)
75 		return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1,
76 					AXP809_OUTPUT_CTRL1_DCDC3_EN);
77 
78 	ret = pmic_bus_write(AXP809_DCDC3_CTRL, cfg);
79 	if (ret)
80 		return ret;
81 
82 	return pmic_bus_setbits(AXP809_OUTPUT_CTRL1,
83 				AXP809_OUTPUT_CTRL1_DCDC3_EN);
84 }
85 
axp_set_dcdc4(unsigned int mvolt)86 int axp_set_dcdc4(unsigned int mvolt)
87 {
88 	int ret;
89 	u8 cfg = axp809_mvolt_to_cfg(mvolt, 600, 1540, 20);
90 
91 	if (mvolt >= 1540)
92 		cfg = 0x30 + axp809_mvolt_to_cfg(mvolt, 1800, 2600, 100);
93 
94 	if (mvolt == 0)
95 		return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1,
96 					AXP809_OUTPUT_CTRL1_DCDC4_EN);
97 
98 	ret = pmic_bus_write(AXP809_DCDC5_CTRL, cfg);
99 	if (ret)
100 		return ret;
101 
102 	return pmic_bus_setbits(AXP809_OUTPUT_CTRL1,
103 				AXP809_OUTPUT_CTRL1_DCDC4_EN);
104 }
105 
axp_set_dcdc5(unsigned int mvolt)106 int axp_set_dcdc5(unsigned int mvolt)
107 {
108 	int ret;
109 	u8 cfg = axp809_mvolt_to_cfg(mvolt, 1000, 2550, 50);
110 
111 	if (mvolt == 0)
112 		return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1,
113 					AXP809_OUTPUT_CTRL1_DCDC5_EN);
114 
115 	ret = pmic_bus_write(AXP809_DCDC5_CTRL, cfg);
116 	if (ret)
117 		return ret;
118 
119 	return pmic_bus_setbits(AXP809_OUTPUT_CTRL1,
120 				AXP809_OUTPUT_CTRL1_DCDC5_EN);
121 }
122 
axp_set_aldo(int aldo_num,unsigned int mvolt)123 int axp_set_aldo(int aldo_num, unsigned int mvolt)
124 {
125 	int ret;
126 	u8 cfg;
127 
128 	if (aldo_num < 1 || aldo_num > 3)
129 		return -EINVAL;
130 
131 	if (mvolt == 0 && aldo_num == 3)
132 		return pmic_bus_clrbits(AXP809_OUTPUT_CTRL2,
133 					AXP809_OUTPUT_CTRL2_ALDO3_EN);
134 	if (mvolt == 0)
135 		return pmic_bus_clrbits(AXP809_OUTPUT_CTRL1,
136 				AXP809_OUTPUT_CTRL1_ALDO1_EN << (aldo_num - 1));
137 
138 	cfg = axp809_mvolt_to_cfg(mvolt, 700, 3300, 100);
139 	ret = pmic_bus_write(AXP809_ALDO1_CTRL + (aldo_num - 1), cfg);
140 	if (ret)
141 		return ret;
142 
143 	if (aldo_num == 3)
144 		return pmic_bus_setbits(AXP809_OUTPUT_CTRL2,
145 					AXP809_OUTPUT_CTRL2_ALDO3_EN);
146 	return pmic_bus_setbits(AXP809_OUTPUT_CTRL1,
147 				AXP809_OUTPUT_CTRL1_ALDO1_EN << (aldo_num - 1));
148 }
149 
150 /* TODO: re-work other AXP drivers to consolidate ALDO functions. */
axp_set_aldo1(unsigned int mvolt)151 int axp_set_aldo1(unsigned int mvolt)
152 {
153 	return axp_set_aldo(1, mvolt);
154 }
155 
axp_set_aldo2(unsigned int mvolt)156 int axp_set_aldo2(unsigned int mvolt)
157 {
158 	return axp_set_aldo(2, mvolt);
159 }
160 
axp_set_aldo3(unsigned int mvolt)161 int axp_set_aldo3(unsigned int mvolt)
162 {
163 	return axp_set_aldo(3, mvolt);
164 }
165 
axp_set_dldo(int dldo_num,unsigned int mvolt)166 int axp_set_dldo(int dldo_num, unsigned int mvolt)
167 {
168 	u8 cfg = axp809_mvolt_to_cfg(mvolt, 700, 3300, 100);
169 	int ret;
170 
171 	if (dldo_num < 1 || dldo_num > 2)
172 		return -EINVAL;
173 
174 	if (mvolt == 0)
175 		return pmic_bus_clrbits(AXP809_OUTPUT_CTRL2,
176 				AXP809_OUTPUT_CTRL2_DLDO1_EN << (dldo_num - 1));
177 
178 	if (dldo_num == 1 && mvolt > 3300)
179 		cfg += 1 + axp809_mvolt_to_cfg(mvolt, 3400, 4200, 200);
180 	ret = pmic_bus_write(AXP809_DLDO1_CTRL + (dldo_num - 1), cfg);
181 	if (ret)
182 		return ret;
183 
184 	return pmic_bus_setbits(AXP809_OUTPUT_CTRL2,
185 				AXP809_OUTPUT_CTRL2_DLDO1_EN << (dldo_num - 1));
186 }
187 
axp_set_eldo(int eldo_num,unsigned int mvolt)188 int axp_set_eldo(int eldo_num, unsigned int mvolt)
189 {
190 	int ret;
191 	u8 cfg = axp809_mvolt_to_cfg(mvolt, 700, 3300, 100);
192 
193 	if (eldo_num < 1 || eldo_num > 3)
194 		return -EINVAL;
195 
196 	if (mvolt == 0)
197 		return pmic_bus_clrbits(AXP809_OUTPUT_CTRL2,
198 				AXP809_OUTPUT_CTRL2_ELDO1_EN << (eldo_num - 1));
199 
200 	ret = pmic_bus_write(AXP809_ELDO1_CTRL + (eldo_num - 1), cfg);
201 	if (ret)
202 		return ret;
203 
204 	return pmic_bus_setbits(AXP809_OUTPUT_CTRL2,
205 				AXP809_OUTPUT_CTRL2_ELDO1_EN << (eldo_num - 1));
206 }
207 
axp_set_sw(bool on)208 int axp_set_sw(bool on)
209 {
210 	if (on)
211 		return pmic_bus_setbits(AXP809_OUTPUT_CTRL2,
212 					AXP809_OUTPUT_CTRL2_SWOUT_EN);
213 
214 	return pmic_bus_clrbits(AXP809_OUTPUT_CTRL2,
215 				AXP809_OUTPUT_CTRL2_SWOUT_EN);
216 }
217 
axp_init(void)218 int axp_init(void)
219 {
220 	return pmic_bus_init();
221 }
222 
do_poweroff(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])223 int do_poweroff(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
224 {
225 	pmic_bus_write(AXP809_SHUTDOWN, AXP809_SHUTDOWN_POWEROFF);
226 
227 	/* infinite loop during shutdown */
228 	while (1) {}
229 
230 	/* not reached */
231 	return 0;
232 }
233