axp809.c revision 1.1 1 /* $NetBSD: axp809.c,v 1.1 2014/12/07 00:33:26 jmcneill Exp $ */
2
3 /*-
4 * Copyright (c) 2014 Jared D. McNeill <jmcneill (at) invisible.ca>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #define AXP_DEBUG
30
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: axp809.c,v 1.1 2014/12/07 00:33:26 jmcneill Exp $");
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/device.h>
38 #include <sys/conf.h>
39 #include <sys/bus.h>
40 #include <sys/kmem.h>
41
42 #include <dev/i2c/i2cvar.h>
43 #include <dev/i2c/axp809.h>
44
45 #define AXP_GPIO1_CTRL_REG 0x92
46 #define AXP_GPIO1LDO_CTRL_REG 0x93
47
48 struct axp809_ctrl {
49 device_t c_dev;
50
51 const char * c_name;
52 u_int c_min;
53 u_int c_max;
54 u_int c_step1;
55 u_int c_step1cnt;
56 u_int c_step2;
57 u_int c_step2cnt;
58
59 uint8_t c_enable_reg;
60 uint8_t c_enable_mask;
61
62 uint8_t c_voltage_reg;
63 uint8_t c_voltage_mask;
64 };
65
66 #define AXP_CTRL(name, min, max, step, ereg, emask, vreg, vmask) \
67 { .c_name = (name), .c_min = (min), .c_max = (max), \
68 .c_step1 = (step), .c_step1cnt = (((max) - (min)) / (step)) + 1, \
69 .c_step2 = 0, .c_step2cnt = 0, \
70 .c_enable_reg = AXP_##ereg##_REG, .c_enable_mask = (emask), \
71 .c_voltage_reg = AXP_##vreg##_REG, .c_voltage_mask = (vmask) }
72
73 #define AXP_CTRL2(name, min, max, step1, step1cnt, step2, step2cnt, ereg, emask, vreg, vmask) \
74 { .c_name = (name), .c_min = (min), .c_max = (max), \
75 .c_step1 = (step1), .c_step1cnt = (step1cnt), \
76 .c_step2 = (step2), .c_step2cnt = (step2cnt), \
77 .c_enable_reg = AXP_##ereg##_REG, .c_enable_mask = (emask), \
78 .c_voltage_reg = AXP_##vreg##_REG, .c_voltage_mask = (vmask) }
79
80 static const struct axp809_ctrl axp809_ctrls[] = {
81 AXP_CTRL("GPIO1", 700, 3300, 100,
82 GPIO1_CTRL, __BIT(0), GPIO1LDO_CTRL, __BITS(4,0)),
83 };
84
85 struct axp809_softc {
86 device_t sc_dev;
87 i2c_tag_t sc_i2c;
88 i2c_addr_t sc_addr;
89
90 u_int sc_nctrl;
91 struct axp809_ctrl *sc_ctrl;
92 };
93
94 static int axp809_match(device_t, cfdata_t, void *);
95 static void axp809_attach(device_t, device_t, void *);
96
97 static int axp809_read(struct axp809_softc *, uint8_t, uint8_t *);
98 static int axp809_write(struct axp809_softc *, uint8_t, uint8_t);
99
100 static void axp809_print(struct axp809_ctrl *c);
101
102 CFATTACH_DECL_NEW(axp809pm, sizeof(struct axp809_softc),
103 axp809_match, axp809_attach, NULL, NULL);
104
105 static int
106 axp809_match(device_t parent, cfdata_t match, void *aux)
107 {
108 return 1;
109 }
110
111 static void
112 axp809_attach(device_t parent, device_t self, void *aux)
113 {
114 struct axp809_softc *sc = device_private(self);
115 struct i2c_attach_args *ia = aux;
116 u_int n;
117
118 sc->sc_dev = self;
119 sc->sc_i2c = ia->ia_tag;
120 sc->sc_addr = ia->ia_addr;
121
122 aprint_naive("\n");
123 aprint_normal("\n");
124
125 sc->sc_nctrl = __arraycount(axp809_ctrls);
126 sc->sc_ctrl = kmem_alloc(sizeof(axp809_ctrls), KM_SLEEP);
127 memcpy(sc->sc_ctrl, axp809_ctrls, sizeof(axp809_ctrls));
128 for (n = 0; n < sc->sc_nctrl; n++) {
129 sc->sc_ctrl[n].c_dev = self;
130 }
131
132 #ifdef AXP_DEBUG
133 for (n = 0; n < sc->sc_nctrl; n++) {
134 axp809_print(&sc->sc_ctrl[n]);
135 }
136 #endif
137 }
138
139 static int
140 axp809_read(struct axp809_softc *sc, uint8_t reg, uint8_t *val)
141 {
142 return iic_smbus_read_byte(sc->sc_i2c, sc->sc_addr, reg, val,
143 cold ? I2C_F_POLL : 0);
144 }
145
146 static int
147 axp809_write(struct axp809_softc *sc, uint8_t reg, uint8_t val)
148 {
149 return iic_smbus_write_byte(sc->sc_i2c, sc->sc_addr, reg, val,
150 cold ? I2C_F_POLL : 0);
151 }
152
153 static void
154 axp809_print(struct axp809_ctrl *c)
155 {
156 struct axp809_softc *sc = device_private(c->c_dev);
157 u_int voltage;
158 bool enabled;
159
160 device_printf(sc->sc_dev, "%s:", c->c_name);
161 if (c->c_voltage_reg) {
162 if (axp809_get_voltage(c, &voltage)) {
163 printf(" [??? V]");
164 } else {
165 printf(" [%d.%03dV]", voltage / 1000,
166 voltage % 1000);
167 }
168 }
169 if (c->c_enable_reg) {
170 if (axp809_is_enabled(c, &enabled)) {
171 printf(" [unknown state]");
172 } else {
173 printf(" [%s]", enabled ? "ON" : "OFF");
174 }
175 }
176 printf("\n");
177 }
178
179 struct axp809_ctrl *
180 axp809_lookup(device_t dev, const char *name)
181 {
182 struct axp809_softc *sc = device_private(dev);
183 struct axp809_ctrl *c;
184 u_int n;
185
186 for (n = 0; n < sc->sc_nctrl; n++) {
187 c = &sc->sc_ctrl[n];
188 if (strcmp(c->c_name, name) == 0) {
189 return c;
190 }
191 }
192
193 return NULL;
194 }
195
196 int
197 axp809_set_voltage(struct axp809_ctrl *c, u_int min, u_int max)
198 {
199 struct axp809_softc *sc = device_private(c->c_dev);
200 u_int vol, reg_val;
201 int nstep, error;
202 uint8_t val;
203
204 if (!c->c_voltage_mask)
205 return EINVAL;
206
207 if (min < c->c_min || min > c->c_max)
208 return EINVAL;
209
210 reg_val = 0;
211 nstep = 1;
212 vol = c->c_min;
213
214 for (nstep = 0; nstep < c->c_step1cnt && vol < min; nstep++) {
215 ++reg_val;
216 vol += c->c_step1;
217 }
218 for (nstep = 0; nstep < c->c_step2cnt && vol < min; nstep++) {
219 ++reg_val;
220 vol += c->c_step2;
221 }
222
223 if (vol > max)
224 return EINVAL;
225
226 iic_acquire_bus(sc->sc_i2c, 0);
227 if ((error = axp809_read(sc, c->c_voltage_reg, &val)) != 0)
228 goto done;
229 val &= ~c->c_voltage_mask;
230 val |= __SHIFTIN(reg_val, c->c_voltage_mask);
231 error = axp809_write(sc, c->c_voltage_reg, val);
232 done:
233 iic_release_bus(sc->sc_i2c, 0);
234 #ifdef AXP_DEBUG
235 if (error == 0)
236 axp809_print(c);
237 #endif
238
239 return error;
240 }
241
242 int
243 axp809_get_voltage(struct axp809_ctrl *c, u_int *pvol)
244 {
245 struct axp809_softc *sc = device_private(c->c_dev);
246 int reg_val, error;
247 uint8_t val;
248
249 if (!c->c_voltage_mask)
250 return EINVAL;
251
252 iic_acquire_bus(sc->sc_i2c, 0);
253 error = axp809_read(sc, c->c_voltage_reg, &val);
254 iic_release_bus(sc->sc_i2c, 0);
255 if (error)
256 return error;
257
258 reg_val = __SHIFTOUT(val, c->c_voltage_mask);
259 if (reg_val < c->c_step1cnt) {
260 *pvol = c->c_min + reg_val * c->c_step1;
261 } else {
262 *pvol = c->c_min + (c->c_step1cnt * c->c_step1) +
263 ((reg_val - c->c_step1cnt) * c->c_step2);
264 }
265
266 return 0;
267 }
268
269 int
270 axp809_is_enabled(struct axp809_ctrl *c, bool *penabled)
271 {
272 struct axp809_softc *sc = device_private(c->c_dev);
273 uint8_t val;
274 int error;
275
276 if (!c->c_enable_mask)
277 return EINVAL;
278
279 iic_acquire_bus(sc->sc_i2c, 0);
280 error = axp809_read(sc, c->c_enable_reg, &val);
281 iic_release_bus(sc->sc_i2c, 0);
282 if (error)
283 return error;
284
285 *penabled = !!(val & c->c_enable_mask);
286 return 0;
287 }
288
289 int
290 axp809_enable(struct axp809_ctrl *c)
291 {
292 struct axp809_softc *sc = device_private(c->c_dev);
293 uint8_t val;
294 int error;
295
296 if (!c->c_enable_mask)
297 return EINVAL;
298
299 iic_acquire_bus(sc->sc_i2c, 0);
300 if ((error = axp809_read(sc, c->c_enable_reg, &val)) != 0)
301 goto done;
302 val |= c->c_enable_mask;
303 error = axp809_write(sc, c->c_enable_reg, val);
304 done:
305 iic_release_bus(sc->sc_i2c, 0);
306 #ifdef AXP_DEBUG
307 if (error == 0)
308 axp809_print(c);
309 #endif
310
311 return error;
312 }
313
314 int
315 axp809_disable(struct axp809_ctrl *c)
316 {
317 struct axp809_softc *sc = device_private(c->c_dev);
318 uint8_t val;
319 int error;
320
321 if (!c->c_enable_mask)
322 return EINVAL;
323
324 iic_acquire_bus(sc->sc_i2c, 0);
325 if ((error = axp809_read(sc, c->c_enable_reg, &val)) != 0)
326 goto done;
327 val &= ~c->c_enable_mask;
328 error = axp809_write(sc, c->c_enable_reg, val);
329 done:
330 iic_release_bus(sc->sc_i2c, 0);
331 #ifdef AXP_DEBUG
332 if (error == 0)
333 axp809_print(c);
334 #endif
335
336 return error;
337 }
338