xref: /rk3399_rockchip-uboot/drivers/power/axp209.c (revision ebd468b2d26660ff7811e37cc64fa2369d4b5fff)
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 <i2c.h>
10 #include <asm/arch/gpio.h>
11 #include <axp209.h>
12 
13 enum axp209_reg {
14 	AXP209_POWER_STATUS = 0x00,
15 	AXP209_CHIP_VERSION = 0x03,
16 	AXP209_DCDC2_VOLTAGE = 0x23,
17 	AXP209_DCDC3_VOLTAGE = 0x27,
18 	AXP209_LDO24_VOLTAGE = 0x28,
19 	AXP209_LDO3_VOLTAGE = 0x29,
20 	AXP209_IRQ_ENABLE1 = 0x40,
21 	AXP209_IRQ_ENABLE2 = 0x41,
22 	AXP209_IRQ_ENABLE3 = 0x42,
23 	AXP209_IRQ_ENABLE4 = 0x43,
24 	AXP209_IRQ_ENABLE5 = 0x44,
25 	AXP209_IRQ_STATUS5 = 0x4c,
26 	AXP209_SHUTDOWN = 0x32,
27 	AXP209_GPIO0_CTRL = 0x90,
28 	AXP209_GPIO1_CTRL = 0x92,
29 	AXP209_GPIO2_CTRL = 0x93,
30 	AXP209_GPIO_STATE = 0x94,
31 	AXP209_GPIO3_CTRL = 0x95,
32 };
33 
34 #define AXP209_POWER_STATUS_ON_BY_DC	(1 << 0)
35 #define AXP209_POWER_STATUS_VBUS_USABLE	(1 << 4)
36 
37 #define AXP209_IRQ5_PEK_UP		(1 << 6)
38 #define AXP209_IRQ5_PEK_DOWN		(1 << 5)
39 
40 #define AXP209_POWEROFF			(1 << 7)
41 
42 #define AXP209_GPIO_OUTPUT_LOW		0x00 /* Drive pin low */
43 #define AXP209_GPIO_OUTPUT_HIGH		0x01 /* Drive pin high */
44 #define AXP209_GPIO_INPUT		0x02 /* Float pin */
45 
46 /* GPIO3 is different from the others */
47 #define AXP209_GPIO3_OUTPUT_LOW		0x00 /* Drive pin low, Output mode */
48 #define AXP209_GPIO3_OUTPUT_HIGH	0x02 /* Float pin, Output mode */
49 #define AXP209_GPIO3_INPUT		0x06 /* Float pin, Input mode */
50 
51 static int axp209_write(enum axp209_reg reg, u8 val)
52 {
53 	return i2c_write(0x34, reg, 1, &val, 1);
54 }
55 
56 static int axp209_read(enum axp209_reg reg, u8 *val)
57 {
58 	return i2c_read(0x34, reg, 1, val, 1);
59 }
60 
61 static u8 axp209_mvolt_to_cfg(int mvolt, int min, int max, int div)
62 {
63 	if (mvolt < min)
64 		mvolt = min;
65 	else if (mvolt > max)
66 		mvolt = max;
67 
68 	return (mvolt - min) / div;
69 }
70 
71 int axp209_set_dcdc2(int mvolt)
72 {
73 	int rc;
74 	u8 cfg, current;
75 
76 	cfg = axp209_mvolt_to_cfg(mvolt, 700, 2275, 25);
77 
78 	/* Do we really need to be this gentle? It has built-in voltage slope */
79 	while ((rc = axp209_read(AXP209_DCDC2_VOLTAGE, &current)) == 0 &&
80 	       current != cfg) {
81 		if (current < cfg)
82 			current++;
83 		else
84 			current--;
85 
86 		rc = axp209_write(AXP209_DCDC2_VOLTAGE, current);
87 		if (rc)
88 			break;
89 	}
90 
91 	return rc;
92 }
93 
94 int axp209_set_dcdc3(int mvolt)
95 {
96 	u8 cfg = axp209_mvolt_to_cfg(mvolt, 700, 3500, 25);
97 
98 	return axp209_write(AXP209_DCDC3_VOLTAGE, cfg);
99 }
100 
101 int axp209_set_ldo2(int mvolt)
102 {
103 	int rc;
104 	u8 cfg, reg;
105 
106 	cfg = axp209_mvolt_to_cfg(mvolt, 1800, 3300, 100);
107 
108 	rc = axp209_read(AXP209_LDO24_VOLTAGE, &reg);
109 	if (rc)
110 		return rc;
111 
112 	/* LDO2 configuration is in upper 4 bits */
113 	reg = (reg & 0x0f) | (cfg << 4);
114 	return axp209_write(AXP209_LDO24_VOLTAGE, reg);
115 }
116 
117 int axp209_set_ldo3(int mvolt)
118 {
119 	u8 cfg;
120 
121 	if (mvolt == -1)
122 		cfg = 0x80;	/* determined by LDO3IN pin */
123 	else
124 		cfg = axp209_mvolt_to_cfg(mvolt, 700, 3500, 25);
125 
126 	return axp209_write(AXP209_LDO3_VOLTAGE, cfg);
127 }
128 
129 int axp209_set_ldo4(int mvolt)
130 {
131 	int rc;
132 	static const int vindex[] = {
133 		1250, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2500,
134 		2700, 2800, 3000, 3100, 3200, 3300
135 	};
136 	u8 cfg, reg;
137 
138 	/* Translate mvolt to register cfg value, requested <= selected */
139 	for (cfg = 15; vindex[cfg] > mvolt && cfg > 0; cfg--);
140 
141 	rc = axp209_read(AXP209_LDO24_VOLTAGE, &reg);
142 	if (rc)
143 		return rc;
144 
145 	/* LDO4 configuration is in lower 4 bits */
146 	reg = (reg & 0xf0) | (cfg << 0);
147 	return axp209_write(AXP209_LDO24_VOLTAGE, reg);
148 }
149 
150 int axp209_init(void)
151 {
152 	u8 ver;
153 	int i, rc;
154 
155 	rc = axp209_read(AXP209_CHIP_VERSION, &ver);
156 	if (rc)
157 		return rc;
158 
159 	/* Low 4 bits is chip version */
160 	ver &= 0x0f;
161 
162 	if (ver != 0x1)
163 		return -1;
164 
165 	/* Mask all interrupts */
166 	for (i = AXP209_IRQ_ENABLE1; i <= AXP209_IRQ_ENABLE5; i++) {
167 		rc = axp209_write(i, 0);
168 		if (rc)
169 			return rc;
170 	}
171 
172 	return 0;
173 }
174 
175 int axp209_poweron_by_dc(void)
176 {
177 	u8 v;
178 
179 	if (axp209_read(AXP209_POWER_STATUS, &v))
180 		return 0;
181 
182 	return (v & AXP209_POWER_STATUS_ON_BY_DC);
183 }
184 
185 int axp209_power_button(void)
186 {
187 	u8 v;
188 
189 	if (axp209_read(AXP209_IRQ_STATUS5, &v))
190 		return 0;
191 
192 	axp209_write(AXP209_IRQ_STATUS5, AXP209_IRQ5_PEK_DOWN);
193 
194 	return v & AXP209_IRQ5_PEK_DOWN;
195 }
196 
197 static u8 axp209_get_gpio_ctrl_reg(unsigned int pin)
198 {
199 	switch (pin) {
200 	case 0: return AXP209_GPIO0_CTRL;
201 	case 1: return AXP209_GPIO1_CTRL;
202 	case 2: return AXP209_GPIO2_CTRL;
203 	case 3: return AXP209_GPIO3_CTRL;
204 	}
205 	return 0;
206 }
207 
208 int axp_gpio_direction_input(unsigned int pin)
209 {
210 	if (pin == SUNXI_GPIO_AXP0_VBUS_DETECT)
211 		return 0;
212 
213 	u8 reg = axp209_get_gpio_ctrl_reg(pin);
214 	/* GPIO3 is "special" */
215 	u8 val = (pin == 3) ? AXP209_GPIO3_INPUT : AXP209_GPIO_INPUT;
216 
217 	return axp209_write(reg, val);
218 }
219 
220 int axp_gpio_direction_output(unsigned int pin, unsigned int val)
221 {
222 	u8 reg = axp209_get_gpio_ctrl_reg(pin);
223 
224 	if (val) {
225 		val = (pin == 3) ? AXP209_GPIO3_OUTPUT_HIGH :
226 				   AXP209_GPIO_OUTPUT_HIGH;
227 	} else {
228 		val = (pin == 3) ? AXP209_GPIO3_OUTPUT_LOW :
229 				   AXP209_GPIO_OUTPUT_LOW;
230 	}
231 
232 	return axp209_write(reg, val);
233 }
234 
235 int axp_gpio_get_value(unsigned int pin)
236 {
237 	u8 val, mask;
238 	int rc;
239 
240 	if (pin == SUNXI_GPIO_AXP0_VBUS_DETECT) {
241 		rc = axp209_read(AXP209_POWER_STATUS, &val);
242 		mask = AXP209_POWER_STATUS_VBUS_USABLE;
243 	} else if (pin == 3) {
244 		rc = axp209_read(AXP209_GPIO3_CTRL, &val);
245 		mask = 1;
246 	} else {
247 		rc = axp209_read(AXP209_GPIO_STATE, &val);
248 		mask = 1 << (pin + 4);
249 	}
250 	if (rc)
251 		return rc;
252 
253 	return (val & mask) ? 1 : 0;
254 }
255 
256 int axp_gpio_set_value(unsigned int pin, unsigned int val)
257 {
258 	return axp_gpio_direction_output(pin, val);
259 }
260