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