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