blob: 3b1a6a73aed8ecfd8f748c1ffc37db8fff747e2e [file] [log] [blame]
Henrik Nordstrom14bc66b2014-06-13 22:55:50 +02001/*
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
12enum 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,
Hans de Goede6c727e02014-12-24 19:34:38 +010021 AXP209_GPIO0_CTRL = 0x90,
22 AXP209_GPIO1_CTRL = 0x92,
23 AXP209_GPIO2_CTRL = 0x93,
24 AXP209_GPIO_STATE = 0x94,
25 AXP209_GPIO3_CTRL = 0x95,
Henrik Nordstrom14bc66b2014-06-13 22:55:50 +020026};
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
Hans de Goede6c727e02014-12-24 19:34:38 +010035#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
Henrik Nordstrom14bc66b2014-06-13 22:55:50 +020044static int axp209_write(enum axp209_reg reg, u8 val)
45{
46 return i2c_write(0x34, reg, 1, &val, 1);
47}
48
49static int axp209_read(enum axp209_reg reg, u8 *val)
50{
51 return i2c_read(0x34, reg, 1, val, 1);
52}
53
54static 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
64int 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
87int 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
94int 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
110int 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
122int 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
143int 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
161int 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
171int 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}
Hans de Goede6c727e02014-12-24 19:34:38 +0100182
183static 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
194int 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
203int 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
218int 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
236int axp_gpio_set_value(unsigned int pin, unsigned int val)
237{
238 return axp_gpio_direction_output(pin, val);
239}