as3722.c revision 1.10 1 /* $NetBSD: as3722.c,v 1.10 2017/04/29 19:56:59 jakllsch Exp $ */
2
3 /*-
4 * Copyright (c) 2015 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 #include "opt_fdt.h"
30
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: as3722.c,v 1.10 2017/04/29 19:56:59 jakllsch 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 #include <sys/wdog.h>
42
43 #include <dev/clock_subr.h>
44
45 #include <dev/sysmon/sysmonvar.h>
46
47 #include <dev/i2c/i2cvar.h>
48 #include <dev/i2c/as3722.h>
49
50 #ifdef FDT
51 #include <dev/fdt/fdtvar.h>
52 #endif
53
54 #define AS3722_START_YEAR 2000
55
56 #define AS3722_SD0_VOLTAGE_REG 0x00
57
58 #define AS3722_SD4_VOLTAGE_REG 0x04
59
60 #define AS3722_GPIO0_CTRL_REG 0x08
61 #define AS3722_GPIO0_CTRL_INVERT __BIT(7)
62 #define AS3722_GPIO0_CTRL_IOSF __BITS(6,3)
63 #define AS3722_GPIO0_CTRL_IOSF_GPIO 0
64 #define AS3722_GPIO0_CTRL_IOSF_WATCHDOG 9
65 #define AS3722_GPIO0_CTRL_MODE __BITS(2,0)
66 #define AS3722_GPIO0_CTRL_MODE_PULLDOWN 5
67
68 #define AS3722_LDO6_VOLTAGE_REG 0x16
69
70 #define AS3722_RESET_CTRL_REG 0x36
71 #define AS3722_RESET_CTRL_POWER_OFF __BIT(1)
72 #define AS3722_RESET_CTRL_FORCE_RESET __BIT(0)
73
74 #define AS3722_WATCHDOG_CTRL_REG 0x38
75 #define AS3722_WATCHDOG_CTRL_MODE __BITS(2,1)
76 #define AS3722_WATCHDOG_CTRL_ON __BIT(0)
77
78 #define AS3722_WATCHDOG_TIMER_REG 0x46
79 #define AS3722_WATCHDOG_TIMER_TIMER __BITS(6,0)
80
81 #define AS3722_WATCHDOG_SIGNAL_REG 0x48
82 #define AS3722_WATCHDOG_SIGNAL_PWM_DIV __BITS(7,6)
83 #define AS3722_WATCHDOG_SIGNAL_SW_SIG __BIT(0)
84
85 #define AS3722_SDCONTROL_REG 0x4d
86 #define AS3722_SDCONTROL_SD4_ENABLE __BIT(4)
87
88 #define AS3722_LDOCONTROL0_REG 0x4e
89
90 #define AS3722_RTC_CONTROL_REG 0x60
91 #define AS3722_RTC_CONTROL_RTC_ON __BIT(2)
92
93 #define AS3722_RTC_SECOND_REG 0x61
94 #define AS3722_RTC_MINUTE_REG 0x62
95 #define AS3722_RTC_HOUR_REG 0x63
96 #define AS3722_RTC_DAY_REG 0x64
97 #define AS3722_RTC_MONTH_REG 0x65
98 #define AS3722_RTC_YEAR_REG 0x66
99 #define AS3722_RTC_ACCESS_REG 0x6f
100
101 #define AS3722_ASIC_ID1_REG 0x90
102 #define AS3722_ASIC_ID2_REG 0x91
103
104 struct as3722_softc {
105 device_t sc_dev;
106 i2c_tag_t sc_i2c;
107 i2c_addr_t sc_addr;
108 int sc_phandle;
109
110 struct sysmon_wdog sc_smw;
111 struct todr_chip_handle sc_todr;
112 };
113
114 #ifdef FDT
115 static int as3722reg_set_voltage_sd0(device_t, u_int, u_int);
116 static int as3722reg_get_voltage_sd0(device_t, u_int *);
117 static int as3722reg_set_voltage_sd4(device_t, u_int, u_int);
118 static int as3722reg_get_voltage_sd4(device_t, u_int *);
119 static int as3722reg_set_voltage_ldo(device_t, u_int, u_int);
120 static int as3722reg_get_voltage_ldo(device_t, u_int *);
121
122 static const struct as3722regdef {
123 const char *name;
124 u_int vsel_reg;
125 u_int vsel_mask;
126 u_int enable_reg;
127 u_int enable_mask;
128 int (*set)(device_t, u_int, u_int);
129 int (*get)(device_t, u_int *);
130 } as3722regdefs[] = {
131 { .name = "sd0",
132 .vsel_reg = AS3722_SD0_VOLTAGE_REG,
133 .vsel_mask = 0x7f,
134 .set = as3722reg_set_voltage_sd0,
135 .get = as3722reg_get_voltage_sd0 },
136 { .name = "sd4",
137 .vsel_reg = AS3722_SD4_VOLTAGE_REG,
138 .vsel_mask = 0x7f,
139 .enable_reg = AS3722_SDCONTROL_REG,
140 .enable_mask = AS3722_SDCONTROL_SD4_ENABLE,
141 .set = as3722reg_set_voltage_sd4,
142 .get = as3722reg_get_voltage_sd4 },
143 { .name = "ldo6",
144 .vsel_reg = AS3722_LDO6_VOLTAGE_REG,
145 .vsel_mask = 0x7f,
146 .enable_reg = AS3722_LDOCONTROL0_REG,
147 .enable_mask = 0x40,
148 .set = as3722reg_set_voltage_ldo,
149 .get = as3722reg_get_voltage_ldo },
150 };
151
152 struct as3722reg_softc {
153 device_t sc_dev;
154 int sc_phandle;
155 const struct as3722regdef *sc_regdef;
156 };
157
158 struct as3722reg_attach_args {
159 const struct as3722regdef *reg_def;
160 int reg_phandle;
161 };
162 #endif
163
164 #define AS3722_WATCHDOG_DEFAULT_PERIOD 10
165
166 static int as3722_match(device_t, cfdata_t, void *);
167 static void as3722_attach(device_t, device_t, void *);
168
169 static void as3722_wdt_attach(struct as3722_softc *);
170 static int as3722_wdt_setmode(struct sysmon_wdog *);
171 static int as3722_wdt_tickle(struct sysmon_wdog *);
172
173 static void as3722_rtc_attach(struct as3722_softc *);
174 static int as3722_rtc_gettime(todr_chip_handle_t, struct clock_ymdhms *);
175 static int as3722_rtc_settime(todr_chip_handle_t, struct clock_ymdhms *);
176
177 #ifdef FDT
178 static void as3722_regulator_attach(struct as3722_softc *);
179 static int as3722reg_match(device_t, cfdata_t, void *);
180 static void as3722reg_attach(device_t, device_t, void *);
181
182 static int as3722reg_acquire(device_t);
183 static void as3722reg_release(device_t);
184 static int as3722reg_enable(device_t, bool);
185 static int as3722reg_set_voltage(device_t, u_int, u_int);
186 static int as3722reg_get_voltage(device_t, u_int *);
187
188 static struct fdtbus_regulator_controller_func as3722reg_funcs = {
189 .acquire = as3722reg_acquire,
190 .release = as3722reg_release,
191 .enable = as3722reg_enable,
192 .set_voltage = as3722reg_set_voltage,
193 .get_voltage = as3722reg_get_voltage,
194 };
195 #endif
196
197 static int as3722_read(struct as3722_softc *, uint8_t, uint8_t *, int);
198 static int as3722_write(struct as3722_softc *, uint8_t, uint8_t, int);
199 static int as3722_set_clear(struct as3722_softc *, uint8_t, uint8_t,
200 uint8_t, int);
201
202 CFATTACH_DECL_NEW(as3722pmic, sizeof(struct as3722_softc),
203 as3722_match, as3722_attach, NULL, NULL);
204
205 #ifdef FDT
206 CFATTACH_DECL_NEW(as3722reg, sizeof(struct as3722reg_softc),
207 as3722reg_match, as3722reg_attach, NULL, NULL);
208 #endif
209
210 static const char * as3722_compats[] = {
211 "ams,as3722",
212 NULL
213 };
214
215 static int
216 as3722_match(device_t parent, cfdata_t match, void *aux)
217 {
218 struct i2c_attach_args *ia = aux;
219 uint8_t reg, id1;
220 int error;
221
222 if (ia->ia_name == NULL) {
223 iic_acquire_bus(ia->ia_tag, I2C_F_POLL);
224 reg = AS3722_ASIC_ID1_REG;
225 error = iic_exec(ia->ia_tag, I2C_OP_READ_WITH_STOP, ia->ia_addr,
226 ®, 1, &id1, 1, I2C_F_POLL);
227 iic_release_bus(ia->ia_tag, I2C_F_POLL);
228
229 if (error == 0 && id1 == 0x0c)
230 return 1;
231
232 return 0;
233 } else {
234 return iic_compat_match(ia, as3722_compats);
235 }
236 }
237
238 static void
239 as3722_attach(device_t parent, device_t self, void *aux)
240 {
241 struct as3722_softc * const sc = device_private(self);
242 struct i2c_attach_args *ia = aux;
243
244 sc->sc_dev = self;
245 sc->sc_i2c = ia->ia_tag;
246 sc->sc_addr = ia->ia_addr;
247 sc->sc_phandle = ia->ia_cookie;
248
249 aprint_naive("\n");
250 aprint_normal(": AMS AS3722\n");
251
252 as3722_wdt_attach(sc);
253 as3722_rtc_attach(sc);
254 #ifdef FDT
255 as3722_regulator_attach(sc);
256 #endif
257 }
258
259 static void
260 as3722_wdt_attach(struct as3722_softc *sc)
261 {
262 int error;
263
264 iic_acquire_bus(sc->sc_i2c, I2C_F_POLL);
265 error = as3722_write(sc, AS3722_GPIO0_CTRL_REG,
266 __SHIFTIN(AS3722_GPIO0_CTRL_IOSF_GPIO,
267 AS3722_GPIO0_CTRL_IOSF) |
268 __SHIFTIN(AS3722_GPIO0_CTRL_MODE_PULLDOWN,
269 AS3722_GPIO0_CTRL_MODE),
270 I2C_F_POLL);
271 error += as3722_set_clear(sc, AS3722_WATCHDOG_CTRL_REG,
272 __SHIFTIN(1, AS3722_WATCHDOG_CTRL_MODE), 0, I2C_F_POLL);
273 iic_release_bus(sc->sc_i2c, I2C_F_POLL);
274
275 if (error) {
276 aprint_error_dev(sc->sc_dev, "couldn't setup watchdog\n");
277 return;
278 }
279
280 sc->sc_smw.smw_name = device_xname(sc->sc_dev);
281 sc->sc_smw.smw_cookie = sc;
282 sc->sc_smw.smw_setmode = as3722_wdt_setmode;
283 sc->sc_smw.smw_tickle = as3722_wdt_tickle;
284 sc->sc_smw.smw_period = AS3722_WATCHDOG_DEFAULT_PERIOD;
285
286 aprint_normal_dev(sc->sc_dev, "default watchdog period is %u seconds\n",
287 sc->sc_smw.smw_period);
288
289 if (sysmon_wdog_register(&sc->sc_smw) != 0)
290 aprint_error_dev(sc->sc_dev, "couldn't register with sysmon\n");
291 }
292
293 static void
294 as3722_rtc_attach(struct as3722_softc *sc)
295 {
296 int error;
297
298 iic_acquire_bus(sc->sc_i2c, I2C_F_POLL);
299 error = as3722_set_clear(sc, AS3722_RTC_CONTROL_REG,
300 AS3722_RTC_CONTROL_RTC_ON, 0, I2C_F_POLL);
301 iic_release_bus(sc->sc_i2c, I2C_F_POLL);
302
303 if (error) {
304 aprint_error_dev(sc->sc_dev, "couldn't setup RTC\n");
305 return;
306 }
307
308 sc->sc_todr.todr_gettime_ymdhms = as3722_rtc_gettime;
309 sc->sc_todr.todr_settime_ymdhms = as3722_rtc_settime;
310 sc->sc_todr.cookie = sc;
311 #ifdef FDT
312 fdtbus_todr_attach(sc->sc_dev, sc->sc_phandle, &sc->sc_todr);
313 #else
314 todr_attach(&sc->sc_todr);
315 #endif
316 }
317
318 static int
319 as3722_read(struct as3722_softc *sc, uint8_t reg, uint8_t *val, int flags)
320 {
321 return iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP, sc->sc_addr,
322 ®, 1, val, 1, flags);
323 }
324
325 static int
326 as3722_write(struct as3722_softc *sc, uint8_t reg, uint8_t val, int flags)
327 {
328 uint8_t buf[2] = { reg, val };
329 return iic_exec(sc->sc_i2c, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
330 NULL, 0, buf, 2, flags);
331 }
332
333 static int
334 as3722_set_clear(struct as3722_softc *sc, uint8_t reg, uint8_t set,
335 uint8_t clr, int flags)
336 {
337 uint8_t old, new;
338 int error;
339
340 error = as3722_read(sc, reg, &old, flags);
341 if (error) {
342 return error;
343 }
344 new = set | (old & ~clr);
345
346 return as3722_write(sc, reg, new, flags);
347 }
348
349 static int
350 as3722_wdt_setmode(struct sysmon_wdog *smw)
351 {
352 struct as3722_softc * const sc = smw->smw_cookie;
353 int error;
354
355 const int flags = (cold ? I2C_F_POLL : 0);
356
357 if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) {
358 iic_acquire_bus(sc->sc_i2c, flags);
359 error = as3722_set_clear(sc, AS3722_WATCHDOG_CTRL_REG,
360 0, AS3722_WATCHDOG_CTRL_ON, flags);
361 iic_release_bus(sc->sc_i2c, flags);
362 return error;
363 }
364
365 if (smw->smw_period == WDOG_PERIOD_DEFAULT) {
366 smw->smw_period = AS3722_WATCHDOG_DEFAULT_PERIOD;
367 }
368 if (smw->smw_period < 1 || smw->smw_period > 128) {
369 return EINVAL;
370 }
371 sc->sc_smw.smw_period = smw->smw_period;
372
373 iic_acquire_bus(sc->sc_i2c, flags);
374 error = as3722_set_clear(sc, AS3722_WATCHDOG_TIMER_REG,
375 __SHIFTIN(sc->sc_smw.smw_period - 1, AS3722_WATCHDOG_TIMER_TIMER),
376 AS3722_WATCHDOG_TIMER_TIMER, flags);
377 if (error == 0) {
378 error = as3722_set_clear(sc, AS3722_WATCHDOG_CTRL_REG,
379 AS3722_WATCHDOG_CTRL_ON, 0, flags);
380 }
381 iic_release_bus(sc->sc_i2c, flags);
382
383 return error;
384 }
385
386 static int
387 as3722_wdt_tickle(struct sysmon_wdog *smw)
388 {
389 struct as3722_softc * const sc = smw->smw_cookie;
390 int error;
391
392 const int flags = (cold ? I2C_F_POLL : 0);
393
394 iic_acquire_bus(sc->sc_i2c, flags);
395 error = as3722_set_clear(sc, AS3722_WATCHDOG_SIGNAL_REG,
396 AS3722_WATCHDOG_SIGNAL_SW_SIG, 0, flags);
397 iic_release_bus(sc->sc_i2c, flags);
398
399 return error;
400 }
401
402 static int
403 as3722_rtc_gettime(todr_chip_handle_t tch, struct clock_ymdhms *dt)
404 {
405 struct as3722_softc * const sc = tch->cookie;
406 uint8_t buf[6];
407 int error = 0;
408
409 const int flags = (cold ? I2C_F_POLL : 0);
410
411 iic_acquire_bus(sc->sc_i2c, flags);
412 error += as3722_read(sc, AS3722_RTC_SECOND_REG, &buf[0], flags);
413 error += as3722_read(sc, AS3722_RTC_MINUTE_REG, &buf[1], flags);
414 error += as3722_read(sc, AS3722_RTC_HOUR_REG, &buf[2], flags);
415 error += as3722_read(sc, AS3722_RTC_DAY_REG, &buf[3], flags);
416 error += as3722_read(sc, AS3722_RTC_MONTH_REG, &buf[4], flags);
417 error += as3722_read(sc, AS3722_RTC_YEAR_REG, &buf[5], flags);
418 iic_release_bus(sc->sc_i2c, flags);
419
420 if (error)
421 return error;
422
423 dt->dt_sec = bcdtobin(buf[0] & 0x7f);
424 dt->dt_min = bcdtobin(buf[1] & 0x7f);
425 dt->dt_hour = bcdtobin(buf[2] & 0x3f);
426 dt->dt_day = bcdtobin(buf[3] & 0x3f);
427 dt->dt_mon = bcdtobin(buf[4] & 0x1f) - 1;
428 dt->dt_year = AS3722_START_YEAR + bcdtobin(buf[5] & 0x7f);
429 dt->dt_wday = 0;
430
431 return 0;
432 }
433
434 static int
435 as3722_rtc_settime(todr_chip_handle_t tch, struct clock_ymdhms *dt)
436 {
437 struct as3722_softc * const sc = tch->cookie;
438 uint8_t buf[6];
439 int error = 0;
440
441 if (dt->dt_year < AS3722_START_YEAR)
442 return EINVAL;
443
444 buf[0] = bintobcd(dt->dt_sec) & 0x7f;
445 buf[1] = bintobcd(dt->dt_min) & 0x7f;
446 buf[2] = bintobcd(dt->dt_hour) & 0x3f;
447 buf[3] = bintobcd(dt->dt_day) & 0x3f;
448 buf[4] = bintobcd(dt->dt_mon + 1) & 0x1f;
449 buf[5] = bintobcd(dt->dt_year - AS3722_START_YEAR) & 0x7f;
450
451 const int flags = (cold ? I2C_F_POLL : 0);
452
453 iic_acquire_bus(sc->sc_i2c, flags);
454 error += as3722_write(sc, AS3722_RTC_SECOND_REG, buf[0], flags);
455 error += as3722_write(sc, AS3722_RTC_MINUTE_REG, buf[1], flags);
456 error += as3722_write(sc, AS3722_RTC_HOUR_REG, buf[2], flags);
457 error += as3722_write(sc, AS3722_RTC_DAY_REG, buf[3], flags);
458 error += as3722_write(sc, AS3722_RTC_MONTH_REG, buf[4], flags);
459 error += as3722_write(sc, AS3722_RTC_YEAR_REG, buf[5], flags);
460 iic_release_bus(sc->sc_i2c, flags);
461
462 return error;
463 }
464
465 #ifdef FDT
466 static void
467 as3722_regulator_attach(struct as3722_softc *sc)
468 {
469 struct as3722reg_attach_args raa;
470 int phandle, child;
471
472 phandle = of_find_firstchild_byname(sc->sc_phandle, "regulators");
473 if (phandle <= 0)
474 return;
475
476 for (int i = 0; i < __arraycount(as3722regdefs); i++) {
477 const struct as3722regdef *regdef = &as3722regdefs[i];
478 child = of_find_firstchild_byname(phandle, regdef->name);
479 if (child <= 0)
480 continue;
481 raa.reg_def = regdef;
482 raa.reg_phandle = child;
483 config_found(sc->sc_dev, &raa, NULL);
484 }
485 }
486
487 static int
488 as3722reg_match(device_t parent, cfdata_t match, void *aux)
489 {
490 return 1;
491 }
492
493 static void
494 as3722reg_attach(device_t parent, device_t self, void *aux)
495 {
496 struct as3722reg_softc *sc = device_private(self);
497 struct as3722reg_attach_args *raa = aux;
498 char *name = NULL;
499 int len;
500
501 sc->sc_dev = self;
502 sc->sc_phandle = raa->reg_phandle;
503 sc->sc_regdef = raa->reg_def;
504
505 fdtbus_register_regulator_controller(self, sc->sc_phandle,
506 &as3722reg_funcs);
507
508 len = OF_getproplen(sc->sc_phandle, "regulator-name");
509 if (len > 0) {
510 name = kmem_zalloc(len, KM_SLEEP);
511 OF_getprop(sc->sc_phandle, "regulator-name", name, len);
512 }
513
514 aprint_naive("\n");
515 if (name)
516 aprint_normal(": %s\n", name);
517 else
518 aprint_normal("\n");
519
520 if (name)
521 kmem_free(name, len);
522 }
523
524 static int
525 as3722reg_acquire(device_t dev)
526 {
527 return 0;
528 }
529
530 static void
531 as3722reg_release(device_t dev)
532 {
533 }
534
535 static int
536 as3722reg_enable(device_t dev, bool enable)
537 {
538 struct as3722reg_softc *sc = device_private(dev);
539 struct as3722_softc *asc = device_private(device_parent(dev));
540 const struct as3722regdef *regdef = sc->sc_regdef;
541 const int flags = (cold ? I2C_F_POLL : 0);
542 int error;
543
544 if (!regdef->enable_mask)
545 return enable ? 0 : EINVAL;
546
547 iic_acquire_bus(asc->sc_i2c, flags);
548 if (enable)
549 error = as3722_set_clear(asc, regdef->enable_reg,
550 regdef->enable_mask, 0, flags);
551 else
552 error = as3722_set_clear(asc, regdef->enable_reg,
553 0, regdef->enable_mask, flags);
554 iic_release_bus(asc->sc_i2c, flags);
555
556 return error;
557 }
558
559 static int
560 as3722reg_set_voltage_ldo(device_t dev, u_int min_uvol, u_int max_uvol)
561 {
562 struct as3722reg_softc *sc = device_private(dev);
563 struct as3722_softc *asc = device_private(device_parent(dev));
564 const struct as3722regdef *regdef = sc->sc_regdef;
565 const int flags = (cold ? I2C_F_POLL : 0);
566 uint8_t set_v = 0x00;
567 u_int uvol;
568 int error;
569
570 for (uint8_t v = 0x01; v <= 0x24; v++) {
571 uvol = 800000 + (v * 25000);
572 if (uvol >= min_uvol && uvol <= max_uvol) {
573 set_v = v;
574 goto done;
575 }
576 }
577 for (uint8_t v = 0x40; v <= 0x7f; v++) {
578 uvol = 1725000 + ((v - 0x40) * 25000);
579 if (uvol >= min_uvol && uvol <= max_uvol) {
580 set_v = v;
581 goto done;
582 }
583 }
584 if (set_v == 0)
585 return ERANGE;
586
587 done:
588 iic_acquire_bus(asc->sc_i2c, flags);
589 error = as3722_set_clear(asc, regdef->vsel_reg, set_v,
590 regdef->vsel_mask, flags);
591 iic_release_bus(asc->sc_i2c, flags);
592
593 return error;
594 }
595
596 static int
597 as3722reg_get_voltage_ldo(device_t dev, u_int *puvol)
598 {
599 struct as3722reg_softc *sc = device_private(dev);
600 struct as3722_softc *asc = device_private(device_parent(dev));
601 const struct as3722regdef *regdef = sc->sc_regdef;
602 const int flags = (cold ? I2C_F_POLL : 0);
603 uint8_t v;
604 int error;
605
606 iic_acquire_bus(asc->sc_i2c, flags);
607 error = as3722_read(asc, regdef->vsel_reg, &v, flags);
608 iic_release_bus(asc->sc_i2c, flags);
609 if (error != 0)
610 return error;
611
612 v &= regdef->vsel_mask;
613
614 if (v == 0)
615 *puvol = 0; /* LDO off */
616 else if (v >= 0x01 && v <= 0x24)
617 *puvol = 800000 + (v * 25000);
618 else if (v >= 0x40 && v <= 0x7f)
619 *puvol = 1725000 + ((v - 0x40) * 25000);
620 else
621 return EINVAL;
622
623 return 0;
624 }
625
626 static int
627 as3722reg_set_voltage_sd0(device_t dev, u_int min_uvol, u_int max_uvol)
628 {
629 struct as3722reg_softc *sc = device_private(dev);
630 struct as3722_softc *asc = device_private(device_parent(dev));
631 const struct as3722regdef *regdef = sc->sc_regdef;
632 const int flags = (cold ? I2C_F_POLL : 0);
633 uint8_t set_v = 0x00;
634 u_int uvol;
635 int error;
636
637 for (uint8_t v = 0x01; v <= 0x5a; v++) {
638 uvol = 600000 + (v * 10000);
639 if (uvol >= min_uvol && uvol <= max_uvol) {
640 set_v = v;
641 goto done;
642 }
643 }
644 if (set_v == 0)
645 return ERANGE;
646
647 done:
648 iic_acquire_bus(asc->sc_i2c, flags);
649 error = as3722_set_clear(asc, regdef->vsel_reg, set_v,
650 regdef->vsel_mask, flags);
651 iic_release_bus(asc->sc_i2c, flags);
652
653 return error;
654 }
655
656 static int
657 as3722reg_get_voltage_sd0(device_t dev, u_int *puvol)
658 {
659 struct as3722reg_softc *sc = device_private(dev);
660 struct as3722_softc *asc = device_private(device_parent(dev));
661 const struct as3722regdef *regdef = sc->sc_regdef;
662 const int flags = (cold ? I2C_F_POLL : 0);
663 uint8_t v;
664 int error;
665
666 iic_acquire_bus(asc->sc_i2c, flags);
667 error = as3722_read(asc, regdef->vsel_reg, &v, flags);
668 iic_release_bus(asc->sc_i2c, flags);
669 if (error != 0)
670 return error;
671
672 v &= regdef->vsel_mask;
673
674 if (v == 0)
675 *puvol = 0; /* DC/DC powered down */
676 else if (v >= 0x01 && v <= 0x5a)
677 *puvol = 600000 + (v * 10000);
678 else
679 return EINVAL;
680
681 return 0;
682 }
683
684 static int
685 as3722reg_set_voltage_sd4(device_t dev, u_int min_uvol, u_int max_uvol)
686 {
687 struct as3722reg_softc *sc = device_private(dev);
688 struct as3722_softc *asc = device_private(device_parent(dev));
689 const struct as3722regdef *regdef = sc->sc_regdef;
690 const int flags = (cold ? I2C_F_POLL : 0);
691 uint8_t set_v = 0x00;
692 u_int uvol;
693 int error;
694
695
696 for (uint8_t v = 0x01; v <= 0x40; v++) {
697 uvol = 600000 + (v * 12500);
698 if (uvol >= min_uvol && uvol <= max_uvol) {
699 set_v = v;
700 goto done;
701 }
702 }
703 for (uint8_t v = 0x41; v <= 0x70; v++) {
704 uvol = 1400000 + ((v - 0x40) * 25000);
705 if (uvol >= min_uvol && uvol <= max_uvol) {
706 set_v = v;
707 goto done;
708 }
709 }
710 for (uint8_t v = 0x71; v <= 0x7f; v++) {
711 uvol = 2600000 + ((v - 0x70) * 50000);
712 if (uvol >= min_uvol && uvol <= max_uvol) {
713 set_v = v;
714 goto done;
715 }
716 }
717 if (set_v == 0)
718 return ERANGE;
719
720 done:
721 iic_acquire_bus(asc->sc_i2c, flags);
722 error = as3722_set_clear(asc, regdef->vsel_reg, set_v,
723 regdef->vsel_mask, flags);
724 iic_release_bus(asc->sc_i2c, flags);
725
726 return error;
727 }
728
729 static int
730 as3722reg_get_voltage_sd4(device_t dev, u_int *puvol)
731 {
732 struct as3722reg_softc *sc = device_private(dev);
733 struct as3722_softc *asc = device_private(device_parent(dev));
734 const struct as3722regdef *regdef = sc->sc_regdef;
735 const int flags = (cold ? I2C_F_POLL : 0);
736 uint8_t v;
737 int error;
738
739 iic_acquire_bus(asc->sc_i2c, flags);
740 error = as3722_read(asc, regdef->vsel_reg, &v, flags);
741 iic_release_bus(asc->sc_i2c, flags);
742 if (error != 0)
743 return error;
744
745 v &= regdef->vsel_mask;
746
747 if (v == 0)
748 *puvol = 0; /* DC/DC powered down */
749 else if (v >= 0x01 && v <= 0x40)
750 *puvol = 600000 + (v * 12500);
751 else if (v >= 0x41 && v <= 0x70)
752 *puvol = 1400000 + (v - 0x40) * 25000;
753 else if (v >= 0x71 && v <= 0x7f)
754 *puvol = 2600000 + (v - 0x70) * 50000;
755 else
756 return EINVAL;
757
758 return 0;
759 }
760
761 static int
762 as3722reg_set_voltage(device_t dev, u_int min_uvol, u_int max_uvol)
763 {
764 struct as3722reg_softc *sc = device_private(dev);
765 const struct as3722regdef *regdef = sc->sc_regdef;
766
767 return regdef->set(dev, min_uvol, max_uvol);
768 }
769
770 static int
771 as3722reg_get_voltage(device_t dev, u_int *puvol)
772 {
773 struct as3722reg_softc *sc = device_private(dev);
774 const struct as3722regdef *regdef = sc->sc_regdef;
775
776 return regdef->get(dev, puvol);
777 }
778 #endif
779
780 int
781 as3722_poweroff(device_t dev)
782 {
783 struct as3722_softc * const sc = device_private(dev);
784 int error;
785
786 const int flags = I2C_F_POLL;
787
788 iic_acquire_bus(sc->sc_i2c, flags);
789 error = as3722_write(sc, AS3722_RESET_CTRL_REG,
790 AS3722_RESET_CTRL_POWER_OFF, flags);
791 iic_release_bus(sc->sc_i2c, flags);
792
793 return error;
794 }
795
796 int
797 as3722_reboot(device_t dev)
798 {
799 struct as3722_softc * const sc = device_private(dev);
800 int error;
801
802 const int flags = I2C_F_POLL;
803
804 iic_acquire_bus(sc->sc_i2c, flags);
805 error = as3722_write(sc, AS3722_RESET_CTRL_REG,
806 AS3722_RESET_CTRL_FORCE_RESET, flags);
807 iic_release_bus(sc->sc_i2c, flags);
808
809 return error;
810 }
811