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