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@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
axp20x_match(device_t parent,cfdata_t match,void * aux)175 axp20x_match(device_t parent, cfdata_t match, void *aux)
176 {
177 	return 1;
178 }
179 
180 static void
axp20x_attach(device_t parent,device_t self,void * aux)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
axp20x_sensors_refresh_volt(struct axp20x_softc * sc,int reg,envsys_data_t * edata)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
axp20x_sensors_refresh_amp(struct axp20x_softc * sc,int reg,envsys_data_t * edata)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
axp20x_sensors_refresh(struct sysmon_envsys * sme,envsys_data_t * edata)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
axp20x_read(struct axp20x_softc * sc,uint8_t reg,uint8_t * val,size_t len,int flags)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
axp20x_write(struct axp20x_softc * sc,uint8_t reg,uint8_t * val,size_t len,int flags)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
axp20x_set_dcdc(device_t dev,int dcdc,int mvolt,bool poll)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