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