Home | History | Annotate | Line # | Download | only in i2c
axp20x.c revision 1.4
      1 /* $NetBSD: axp20x.c,v 1.4 2015/10/15 13:48:57 bouyer Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2014 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 <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: axp20x.c,v 1.4 2015/10/15 13:48:57 bouyer Exp $");
     31 
     32 #include <sys/param.h>
     33 #include <sys/systm.h>
     34 #include <sys/device.h>
     35 #include <sys/conf.h>
     36 #include <sys/bus.h>
     37 #include <sys/kmem.h>
     38 
     39 #include <dev/i2c/i2cvar.h>
     40 #include <dev/i2c/axp20xvar.h>
     41 
     42 #include <dev/sysmon/sysmonvar.h>
     43 
     44 #define AXP_INPUT_STATUS	0x00
     45 #define AXP_INPUT_STATUS_AC_PRESENT	__BIT(7)
     46 #define AXP_INPUT_STATUS_AC_OK		__BIT(6)
     47 #define AXP_INPUT_STATUS_VBUS_PRESENT	__BIT(5)
     48 #define AXP_INPUT_STATUS_VBUS_OK	__BIT(4)
     49 
     50 #define AXP_POWER_MODE		0x01
     51 #define AXP_POWER_MODE_OVERTEMP		__BIT(7)
     52 #define AXP_POWER_MODE_CHARGING		__BIT(6)
     53 #define AXP_POWER_MODE_BATTOK		__BIT(5)
     54 
     55 #define AXP_POWEROUT_CTRL	0x12
     56 #define AXP_POWEROUT_CTRL_LDO3		__BIT(6)
     57 #define AXP_POWEROUT_CTRL_DCDC2		__BIT(4)
     58 #define AXP_POWEROUT_CTRL_LDO4		__BIT(3)
     59 #define AXP_POWEROUT_CTRL_LDO2		__BIT(2)
     60 #define AXP_POWEROUT_CTRL_DCDC3		__BIT(1)
     61 #define AXP_POWEROUT_CTRL_EXTEN		__BIT(0)
     62 
     63 #define AXP_DCDC2		0x23
     64 #define AXP_DCDC2_VOLT_MASK		__BITS(0,5)
     65 #define AXP_DCDC2_VOLT_SHIFT		0
     66 
     67 #define AXP_DCDC2_LDO3_VRC	0x25
     68 
     69 #define AXP_DCDC3		0x27
     70 #define AXP_DCDC3_VOLT_MASK		__BITS(0,6)
     71 #define AXP_DCDC3_VOLT_SHIFT		0
     72 
     73 #define AXP_LDO2_4		0x28
     74 #define AXP_LDO2_VOLT_MASK		__BITS(4,7)
     75 #define AXP_LDO2_VOLT_SHIFT		4
     76 #define AXP_LDO4_VOLT_MASK		__BITS(0,3)
     77 #define AXP_LDO4_VOLT_SHIFT		0
     78 static int ldo4_mvV[] = {
     79 	1250,
     80 	1300,
     81 	1400,
     82 	1500,
     83 	1600,
     84 	1700,
     85 	1800,
     86 	1900,
     87 	2000,
     88 	2500,
     89 	2700,
     90 	2800,
     91 	3000,
     92 	3100,
     93 	3200,
     94 	3300
     95 };
     96 
     97 #define AXP_LDO3		0x29
     98 #define AXP_LDO3_TRACK			__BIT(7)
     99 #define AXP_LDO3_VOLT_MASK		__BITS(0,6)
    100 #define AXP_LDO3_VOLT_SHIFT		0
    101 
    102 #define AXP_ACV_MON_REG		0x56	/* 2 bytes */
    103 #define AXP_ACI_MON_REG		0x58	/* 2 bytes */
    104 #define AXP_VBUSV_MON_REG	0x5a	/* 2 bytes */
    105 #define AXP_VBUSI_MON_REG	0x5c	/* 2 bytes */
    106 #define AXP_TEMP_MON_REG	0x5e	/* 2 bytes */
    107 #define AXP_BATTV_MON_REG	0x78	/* 2 bytes */
    108 #define AXP_BATTCI_MON_REG	0x7a	/* 2 bytes */
    109 #define AXP_BATTDI_MON_REG	0x7c	/* 2 bytes */
    110 #define AXP_APSV_MON_REG	0x7e	/* 2 bytes */
    111 
    112 #define AXP_ADC_EN1		0x82
    113 #define AXP_ADC_EN1_BATTV		__BIT(7)
    114 #define AXP_ADC_EN1_BATTI		__BIT(6)
    115 #define AXP_ADC_EN1_ACV			__BIT(5)
    116 #define AXP_ADC_EN1_ACI			__BIT(4)
    117 #define AXP_ADC_EN1_VBUSV		__BIT(3)
    118 #define AXP_ADC_EN1_VBUSI		__BIT(2)
    119 #define AXP_ADC_EN1_APSV		__BIT(1)
    120 #define AXP_ADC_EN1_TS			__BIT(0)
    121 #define AXP_ADC_EN2		0x83
    122 #define AXP_ADC_EN2_TEMP		__BIT(7)
    123 
    124 #define AXP_SENSOR_ACOK		0
    125 #define AXP_SENSOR_ACV		1
    126 #define AXP_SENSOR_ACI		2
    127 #define AXP_SENSOR_VBUSOK	3
    128 #define AXP_SENSOR_VBUSV	4
    129 #define AXP_SENSOR_VBUSI	5
    130 #define AXP_SENSOR_BATTOK	6
    131 #define AXP_SENSOR_BATTV	7
    132 #define AXP_SENSOR_BATTI	8
    133 #define AXP_SENSOR_APSV		9
    134 #define AXP_SENSOR_TEMP		10
    135 #define AXP_NSENSORS (AXP_SENSOR_TEMP + 1)
    136 
    137 /* define per-ADC LSB to uV/uA values */
    138 static int axp20x_sensors_lsb[] = {
    139 	   0, /* AXP_SENSOR_ACOK */
    140 	1700, /* AXP_SENSOR_ACV */
    141 	 625, /* AXP_SENSOR_ACI */
    142 	   0,
    143 	1700, /* AXP_SENSOR_VBUSV */
    144 	 375, /* AXP_SENSOR_VBUSI */
    145 	   0,
    146 	1100, /* AXP_SENSOR_BATTV */
    147 	 500, /* AXP_SENSOR_BATTI */
    148 	1400, /* AXP_SENSOR_APSV */
    149 };
    150 
    151 
    152 struct axp20x_softc {
    153 	device_t	sc_dev;
    154 	i2c_tag_t	sc_i2c;
    155 	i2c_addr_t	sc_addr;
    156 
    157 	uint8_t 	sc_inputstatus;
    158 	uint8_t 	sc_powermode;
    159 
    160 	struct sysmon_envsys *sc_sme;
    161 	envsys_data_t	sc_sensor[AXP_NSENSORS];
    162 };
    163 
    164 static int	axp20x_match(device_t, cfdata_t, void *);
    165 static void	axp20x_attach(device_t, device_t, void *);
    166 
    167 static void	axp20x_sensors_refresh(struct sysmon_envsys *, envsys_data_t *);
    168 static int	axp20x_read(struct axp20x_softc *, uint8_t, uint8_t *, size_t, int);
    169 static int	axp20x_write(struct axp20x_softc *, uint8_t, uint8_t *, size_t, int);
    170 
    171 CFATTACH_DECL_NEW(axp20x, sizeof(struct axp20x_softc),
    172     axp20x_match, axp20x_attach, NULL, NULL);
    173 
    174 static int
    175 axp20x_match(device_t parent, cfdata_t match, void *aux)
    176 {
    177 	return 1;
    178 }
    179 
    180 static void
    181 axp20x_attach(device_t parent, device_t self, void *aux)
    182 {
    183 	struct axp20x_softc *sc = device_private(self);
    184 	struct i2c_attach_args *ia = aux;
    185 	int first;
    186 	int error;
    187 	uint8_t value;
    188 
    189 	sc->sc_dev = self;
    190 	sc->sc_i2c = ia->ia_tag;
    191 	sc->sc_addr = ia->ia_addr;
    192 
    193 	error = axp20x_read(sc, AXP_INPUT_STATUS,
    194 	    &sc->sc_inputstatus, 1, I2C_F_POLL);
    195 	if (error) {
    196 		aprint_error(": can't read status: %d\n", error);
    197 		return;
    198 	}
    199 	error = axp20x_read(sc, AXP_POWER_MODE,
    200 	    &sc->sc_powermode, 1, I2C_F_POLL);
    201 	if (error) {
    202 		aprint_error(": can't read power mode: %d\n", error);
    203 		return;
    204 	}
    205 	value = AXP_ADC_EN1_ACV | AXP_ADC_EN1_ACI | AXP_ADC_EN1_VBUSV | AXP_ADC_EN1_VBUSI | AXP_ADC_EN1_APSV | AXP_ADC_EN1_TS;
    206 	if (sc->sc_powermode & AXP_POWER_MODE_BATTOK)
    207 		value |= AXP_ADC_EN1_BATTV | AXP_ADC_EN1_BATTI;
    208 	error = axp20x_write(sc, AXP_ADC_EN1, &value, 1, I2C_F_POLL);
    209 	if (error) {
    210 		aprint_error(": can't set AXP_ADC_EN1\n");
    211 		return;
    212 	}
    213 	error = axp20x_read(sc, AXP_ADC_EN2, &value, 1, I2C_F_POLL);
    214 	if (error) {
    215 		aprint_error(": can't read AXP_ADC_EN2\n");
    216 		return;
    217 	}
    218 	value |= AXP_ADC_EN2_TEMP;
    219 	error = axp20x_write(sc, AXP_ADC_EN2, &value, 1, I2C_F_POLL);
    220 	if (error) {
    221 		aprint_error(": can't set AXP_ADC_EN2\n");
    222 		return;
    223 	}
    224 
    225 	aprint_naive("\n");
    226 	first = 1;
    227 	if (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK) {
    228 		aprint_verbose(": AC used");
    229 		first = 0;
    230 	} else if (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_PRESENT) {
    231 		aprint_verbose(": AC present (but unused)");
    232 		first = 0;
    233 	}
    234 	if (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK) {
    235 		aprint_verbose("%s VBUS used", first ? ":" : ",");
    236 		first = 0;
    237 	} else if (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_PRESENT) {
    238 		aprint_verbose("%s VBUS present (but unused)", first ? ":" : ",");
    239 		first = 0;
    240 	}
    241 	if (sc->sc_powermode & AXP_POWER_MODE_BATTOK) {
    242 		aprint_verbose("%s battery present", first ? ":" : ",");
    243 	}
    244 	aprint_normal("\n");
    245 
    246 	sc->sc_sme = sysmon_envsys_create();
    247 	sc->sc_sme->sme_name = device_xname(self);
    248 	sc->sc_sme->sme_cookie = sc;
    249 	sc->sc_sme->sme_refresh = axp20x_sensors_refresh;
    250 
    251 	sc->sc_sensor[AXP_SENSOR_ACOK].units = ENVSYS_INDICATOR;
    252 	sc->sc_sensor[AXP_SENSOR_ACOK].state = ENVSYS_SVALID;
    253 	sc->sc_sensor[AXP_SENSOR_ACOK].value_cur =
    254 	    (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK) ? 1 : 0;
    255 	snprintf(sc->sc_sensor[AXP_SENSOR_ACOK].desc,
    256 	    sizeof(sc->sc_sensor[AXP_SENSOR_ACOK].desc), "AC input");
    257 	sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_ACOK]);
    258 	sc->sc_sensor[AXP_SENSOR_ACV].units = ENVSYS_SVOLTS_DC;
    259 	sc->sc_sensor[AXP_SENSOR_ACV].state = ENVSYS_SINVALID;
    260 	sc->sc_sensor[AXP_SENSOR_ACV].flags = ENVSYS_FHAS_ENTROPY;
    261 	snprintf(sc->sc_sensor[AXP_SENSOR_ACV].desc,
    262 	    sizeof(sc->sc_sensor[AXP_SENSOR_ACV].desc), "AC input voltage");
    263 	sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_ACV]);
    264 	sc->sc_sensor[AXP_SENSOR_ACI].units = ENVSYS_SAMPS;
    265 	sc->sc_sensor[AXP_SENSOR_ACI].state = ENVSYS_SINVALID;
    266 	sc->sc_sensor[AXP_SENSOR_ACI].flags = ENVSYS_FHAS_ENTROPY;
    267 	snprintf(sc->sc_sensor[AXP_SENSOR_ACI].desc,
    268 	    sizeof(sc->sc_sensor[AXP_SENSOR_ACI].desc), "AC input current");
    269 	sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_ACI]);
    270 
    271 	sc->sc_sensor[AXP_SENSOR_VBUSOK].units = ENVSYS_INDICATOR;
    272 	sc->sc_sensor[AXP_SENSOR_VBUSOK].state = ENVSYS_SVALID;
    273 	sc->sc_sensor[AXP_SENSOR_VBUSOK].value_cur =
    274 	    (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK) ? 1 : 0;
    275 	snprintf(sc->sc_sensor[AXP_SENSOR_VBUSOK].desc,
    276 	    sizeof(sc->sc_sensor[AXP_SENSOR_VBUSOK].desc), "VBUS input");
    277 	sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_VBUSOK]);
    278 	sc->sc_sensor[AXP_SENSOR_VBUSV].units = ENVSYS_SVOLTS_DC;
    279 	sc->sc_sensor[AXP_SENSOR_VBUSV].state = ENVSYS_SINVALID;
    280 	sc->sc_sensor[AXP_SENSOR_VBUSV].flags = ENVSYS_FHAS_ENTROPY;
    281 	snprintf(sc->sc_sensor[AXP_SENSOR_VBUSV].desc,
    282 	    sizeof(sc->sc_sensor[AXP_SENSOR_VBUSV].desc), "VBUS input voltage");
    283 	sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_VBUSV]);
    284 	sc->sc_sensor[AXP_SENSOR_VBUSI].units = ENVSYS_SAMPS;
    285 	sc->sc_sensor[AXP_SENSOR_VBUSI].state = ENVSYS_SINVALID;
    286 	sc->sc_sensor[AXP_SENSOR_VBUSI].flags = ENVSYS_FHAS_ENTROPY;
    287 	snprintf(sc->sc_sensor[AXP_SENSOR_VBUSI].desc,
    288 	    sizeof(sc->sc_sensor[AXP_SENSOR_VBUSI].desc), "VBUS input current");
    289 	sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_VBUSI]);
    290 
    291 	sc->sc_sensor[AXP_SENSOR_BATTOK].units = ENVSYS_INDICATOR;
    292 	sc->sc_sensor[AXP_SENSOR_BATTOK].state = ENVSYS_SVALID;
    293 	sc->sc_sensor[AXP_SENSOR_BATTOK].value_cur =
    294 	    (sc->sc_powermode & AXP_POWER_MODE_BATTOK) ? 1 : 0;
    295 	snprintf(sc->sc_sensor[AXP_SENSOR_BATTOK].desc,
    296 	    sizeof(sc->sc_sensor[AXP_SENSOR_BATTOK].desc), "battery");
    297 	sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_BATTOK]);
    298 	sc->sc_sensor[AXP_SENSOR_BATTV].units = ENVSYS_SVOLTS_DC;
    299 	sc->sc_sensor[AXP_SENSOR_BATTV].state = ENVSYS_SINVALID;
    300 	sc->sc_sensor[AXP_SENSOR_BATTV].flags = ENVSYS_FHAS_ENTROPY;
    301 	snprintf(sc->sc_sensor[AXP_SENSOR_BATTV].desc,
    302 	    sizeof(sc->sc_sensor[AXP_SENSOR_BATTV].desc), "battery voltage");
    303 	sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_BATTV]);
    304 	sc->sc_sensor[AXP_SENSOR_BATTI].units = ENVSYS_SAMPS;
    305 	sc->sc_sensor[AXP_SENSOR_BATTI].state = ENVSYS_SINVALID;
    306 	sc->sc_sensor[AXP_SENSOR_BATTI].flags = ENVSYS_FHAS_ENTROPY;
    307 	snprintf(sc->sc_sensor[AXP_SENSOR_BATTI].desc,
    308 	    sizeof(sc->sc_sensor[AXP_SENSOR_BATTI].desc), "battery current");
    309 	sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_BATTI]);
    310 
    311 	sc->sc_sensor[AXP_SENSOR_APSV].units = ENVSYS_SVOLTS_DC;
    312 	sc->sc_sensor[AXP_SENSOR_APSV].state = ENVSYS_SINVALID;
    313 	sc->sc_sensor[AXP_SENSOR_APSV].flags = ENVSYS_FHAS_ENTROPY;
    314 	snprintf(sc->sc_sensor[AXP_SENSOR_APSV].desc,
    315 	    sizeof(sc->sc_sensor[AXP_SENSOR_APSV].desc), "APS output voltage");
    316 	sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_APSV]);
    317 	sc->sc_sensor[AXP_SENSOR_TEMP].units = ENVSYS_STEMP;
    318 	sc->sc_sensor[AXP_SENSOR_TEMP].state = ENVSYS_SINVALID;
    319 	sc->sc_sensor[AXP_SENSOR_TEMP].flags = ENVSYS_FHAS_ENTROPY;
    320 	snprintf(sc->sc_sensor[AXP_SENSOR_TEMP].desc,
    321 	    sizeof(sc->sc_sensor[AXP_SENSOR_TEMP].desc),
    322 	    "internal temperature");
    323 	sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_TEMP]);
    324 
    325 	sysmon_envsys_register(sc->sc_sme);
    326 
    327 	if (axp20x_read(sc, AXP_DCDC2, &value, 1, I2C_F_POLL) == 0) {
    328 		aprint_verbose_dev(sc->sc_dev, ": DCDC2 %dmV\n",
    329 		    (int)(700 + (value & AXP_DCDC2_VOLT_MASK) * 25));
    330 	}
    331 	if (axp20x_read(sc, AXP_DCDC3, &value, 1, I2C_F_POLL) == 0) {
    332 		aprint_verbose_dev(sc->sc_dev, ": DCDC3 %dmV\n",
    333 		    (int)(700 + (value & AXP_DCDC3_VOLT_MASK) * 25));
    334 	}
    335 	if (axp20x_read(sc, AXP_LDO2_4, &value, 1, I2C_F_POLL) == 0) {
    336 		aprint_verbose_dev(sc->sc_dev, ": LDO2 %dmV, LDO4 %dmV\n",
    337 		    (int)(1800 +
    338 		    ((value & AXP_LDO2_VOLT_MASK) >> AXP_LDO2_VOLT_SHIFT) * 100
    339 		    ),
    340 		    ldo4_mvV[(value & AXP_LDO4_VOLT_MASK) >> AXP_LDO4_VOLT_SHIFT]);
    341 	}
    342 	if (axp20x_read(sc, AXP_LDO3, &value, 1, I2C_F_POLL) == 0) {
    343 		if (value & AXP_LDO3_TRACK) {
    344 			aprint_verbose_dev(sc->sc_dev, ": LDO3: tracking\n");
    345 		} else {
    346 			aprint_verbose_dev(sc->sc_dev, ": LDO3 %dmV\n",
    347 			    (int)(700 + (value & AXP_LDO3_VOLT_MASK) * 25));
    348 		}
    349 	}
    350 }
    351 
    352 static void
    353 axp20x_sensors_refresh_volt(struct axp20x_softc *sc, int reg,
    354     envsys_data_t *edata)
    355 {
    356 	uint8_t buf[2];
    357 	int error;
    358 
    359 	error = axp20x_read(sc, reg, buf, sizeof(buf), 0);
    360 	if (error) {
    361 		edata->state = ENVSYS_SINVALID;
    362 	} else {
    363 		edata->value_cur = ((buf[0] << 4) | (buf[1] & 0xf)) *
    364 		    axp20x_sensors_lsb[edata->sensor];
    365 		edata->state = ENVSYS_SVALID;
    366 	}
    367 }
    368 
    369 static void
    370 axp20x_sensors_refresh_amp(struct axp20x_softc *sc, int reg,
    371     envsys_data_t *edata)
    372 {
    373 	uint8_t buf[2];
    374 	int error;
    375 
    376 	error = axp20x_read(sc, reg, buf, sizeof(buf), 0);
    377 	if (error) {
    378 		edata->state = ENVSYS_SINVALID;
    379 	} else {
    380 		edata->value_cur = ((buf[0] << 4) | (buf[1] & 0xf)) *
    381 		    axp20x_sensors_lsb[edata->sensor];
    382 		edata->state = ENVSYS_SVALID;
    383 	}
    384 }
    385 
    386 static void
    387 axp20x_sensors_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
    388 {
    389 	struct axp20x_softc *sc = sme->sme_cookie;
    390 	uint8_t buf[2];
    391 	int error;
    392 
    393 	switch(edata->sensor) {
    394 	case AXP_SENSOR_ACOK:
    395 	case AXP_SENSOR_VBUSOK:
    396 		error = axp20x_read(sc, AXP_INPUT_STATUS,
    397 		    &sc->sc_inputstatus, 1, 0);
    398 		if (error) {
    399 			edata->state = ENVSYS_SINVALID;
    400 			return;
    401 		}
    402 		if (edata->sensor == AXP_SENSOR_ACOK) {
    403 		    edata->value_cur =
    404 			(sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK) ? 1 : 0;
    405 		} else {
    406 		    edata->value_cur =
    407 			(sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK) ? 1 : 0;
    408 		}
    409 		edata->state = ENVSYS_SVALID;
    410 		return;
    411 	case AXP_SENSOR_BATTOK:
    412 		error = axp20x_read(sc, AXP_POWER_MODE,
    413 		    &sc->sc_powermode, 1, 0);
    414 		if (error) {
    415 			edata->state = ENVSYS_SINVALID;
    416 			return;
    417 		}
    418 		edata->value_cur =
    419 		    (sc->sc_powermode & AXP_POWER_MODE_BATTOK) ? 1 : 0;
    420 		return;
    421 	case AXP_SENSOR_ACV:
    422 		if (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK)
    423 			axp20x_sensors_refresh_volt(sc, AXP_ACV_MON_REG, edata);
    424 		else
    425 			edata->state = ENVSYS_SINVALID;
    426 		return;
    427 	case AXP_SENSOR_ACI:
    428 		if (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK)
    429 			axp20x_sensors_refresh_amp(sc, AXP_ACI_MON_REG, edata);
    430 		else
    431 			edata->state = ENVSYS_SINVALID;
    432 		return;
    433 	case AXP_SENSOR_VBUSV:
    434 		if (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK)
    435 			axp20x_sensors_refresh_volt(sc, AXP_VBUSV_MON_REG, edata);
    436 		else
    437 			edata->state = ENVSYS_SINVALID;
    438 		return;
    439 	case AXP_SENSOR_VBUSI:
    440 		if (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK)
    441 			axp20x_sensors_refresh_amp(sc, AXP_VBUSI_MON_REG, edata);
    442 		else
    443 			edata->state = ENVSYS_SINVALID;
    444 		return;
    445 	case AXP_SENSOR_BATTV:
    446 		if (sc->sc_powermode & AXP_POWER_MODE_BATTOK)
    447 			axp20x_sensors_refresh_volt(sc, AXP_BATTV_MON_REG, edata);
    448 		else
    449 			edata->state = ENVSYS_SINVALID;
    450 		return;
    451 	case AXP_SENSOR_BATTI:
    452 		if ((sc->sc_powermode & AXP_POWER_MODE_BATTOK) == 0) {
    453 			edata->state = ENVSYS_SINVALID;
    454 			return;
    455 		}
    456 		error = axp20x_read(sc, AXP_POWER_MODE,
    457 		    &sc->sc_inputstatus, 1, 0);
    458 		if (error) {
    459 			edata->state = ENVSYS_SINVALID;
    460 			return;
    461 		}
    462 		if (sc->sc_inputstatus & AXP_POWER_MODE_CHARGING) {
    463 			axp20x_sensors_refresh_amp(sc, AXP_BATTCI_MON_REG,
    464 			    edata);
    465 			edata->value_cur = -edata->value_cur;
    466 		} else {
    467 			axp20x_sensors_refresh_amp(sc, AXP_BATTDI_MON_REG,
    468 			    edata);
    469 		}
    470 		return;
    471 	case AXP_SENSOR_APSV:
    472 		axp20x_sensors_refresh_volt(sc, AXP_APSV_MON_REG, edata);
    473 		return;
    474 	case AXP_SENSOR_TEMP:
    475 		error = axp20x_read(sc, AXP_TEMP_MON_REG, buf, sizeof(buf), 0);
    476 		if (error) {
    477 			edata->state = ENVSYS_SINVALID;
    478 		} else {
    479 			/* between -144.7C and 264.8C, step +0.1C */
    480 			edata->value_cur =
    481 			    (((buf[0] << 4) | (buf[1] & 0xf)) - 1447)
    482 			   * 100000 + 273150000;
    483 			edata->state = ENVSYS_SVALID;
    484 		}
    485 		return;
    486 	default:
    487 		aprint_error_dev(sc->sc_dev, ": invalid sensor %d\n",
    488 		    edata->sensor);
    489 	}
    490 }
    491 
    492 static int
    493 axp20x_read(struct axp20x_softc *sc, uint8_t reg, uint8_t *val, size_t len,
    494     int flags)
    495 {
    496 	int ret;
    497 	iic_acquire_bus(sc->sc_i2c, flags);
    498 	ret =  iic_smbus_block_read(sc->sc_i2c, sc->sc_addr,
    499 	    reg, val, len, flags);
    500 	iic_release_bus(sc->sc_i2c, flags);
    501 	return ret;
    502 
    503 }
    504 
    505 static int
    506 axp20x_write(struct axp20x_softc *sc, uint8_t reg, uint8_t *val, size_t len,
    507     int flags)
    508 {
    509 	int ret;
    510 	iic_acquire_bus(sc->sc_i2c, flags);
    511 	ret = iic_smbus_block_write(sc->sc_i2c, sc->sc_addr,
    512 	    reg, val, len, flags);
    513 	iic_release_bus(sc->sc_i2c, flags);
    514 	return ret;
    515 }
    516 
    517 int
    518 axp20x_set_dcdc(device_t dev, int dcdc, int mvolt, bool poll)
    519 {
    520 	struct axp20x_softc *sc = device_private(dev);
    521 	int ret;
    522 	int value;
    523 	uint8_t reg;
    524 
    525 	KASSERT(sc != NULL);
    526 	value = (mvolt - 700) / 25;
    527 	switch (dcdc) {
    528 	case AXP20X_DCDC2:
    529 		value <<= AXP_DCDC2_VOLT_SHIFT;
    530 		if (value > AXP_DCDC2_VOLT_MASK)
    531 			return EINVAL;
    532 		reg = value & AXP_DCDC2_VOLT_MASK;
    533 		ret = axp20x_write(sc, AXP_DCDC2, &reg, 1,
    534 		    poll ? I2C_F_POLL : 0);
    535 		if (ret)
    536 			return ret;
    537 		if (axp20x_read(sc, AXP_DCDC2, &reg, 1, poll ? I2C_F_POLL : 0)
    538 		  == 0) {
    539 			aprint_verbose_dev(sc->sc_dev,
    540 			    ": DCDC2 changed to %dmV\n",
    541 			    (int)(700 + (reg & AXP_DCDC2_VOLT_MASK) * 25));
    542 		}
    543 		return 0;
    544 
    545 	case AXP20X_DCDC3:
    546 		value <<= AXP_DCDC3_VOLT_SHIFT;
    547 		if (value > AXP_DCDC3_VOLT_MASK)
    548 			return EINVAL;
    549 		reg = value & AXP_DCDC3_VOLT_MASK;
    550 		ret = axp20x_write(sc, AXP_DCDC3, &reg, 1,
    551 		    poll ? I2C_F_POLL : 0);
    552 		if (ret)
    553 			return ret;
    554 		if (axp20x_read(sc, AXP_DCDC3, &reg, 1, poll ? I2C_F_POLL : 0)
    555 		  == 0) {
    556 			aprint_verbose_dev(sc->sc_dev,
    557 			    ": DCDC3 changed to %dmV\n",
    558 			    (int)(700 + (reg & AXP_DCDC3_VOLT_MASK) * 25));
    559 		}
    560 		return 0;
    561 	default:
    562 		aprint_error_dev(dev, "wrong DCDC %d\n", dcdc);
    563 		return EINVAL;
    564 	}
    565 }
    566