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