1/* $NetBSD: axp20x.c,v 1.21 2021/08/07 16:19:11 thorpej Exp $ */
2
3/*-
4 * Copyright (c) 2014-2017 Jared 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.21 2021/08/07 16:19:11 thorpej 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
41#include <dev/sysmon/sysmonvar.h>
42
43#include <dev/fdt/fdtvar.h>
44
45#define AXP20X_DCDC2    2
46#define AXP20X_DCDC3    3
47
48#define	AXP209_I2C_ADDR		0x34
49
50#define AXP_INPUT_STATUS	0x00
51#define AXP_INPUT_STATUS_AC_PRESENT	__BIT(7)
52#define AXP_INPUT_STATUS_AC_OK		__BIT(6)
53#define AXP_INPUT_STATUS_VBUS_PRESENT	__BIT(5)
54#define AXP_INPUT_STATUS_VBUS_OK	__BIT(4)
55
56#define AXP_POWER_MODE		0x01
57#define AXP_POWER_MODE_OVERTEMP		__BIT(7)
58#define AXP_POWER_MODE_CHARGING		__BIT(6)
59#define AXP_POWER_MODE_BATTOK		__BIT(5)
60
61#define AXP_POWEROUT_CTRL	0x12
62#define AXP_POWEROUT_CTRL_LDO3		__BIT(6)
63#define AXP_POWEROUT_CTRL_DCDC2		__BIT(4)
64#define AXP_POWEROUT_CTRL_LDO4		__BIT(3)
65#define AXP_POWEROUT_CTRL_LDO2		__BIT(2)
66#define AXP_POWEROUT_CTRL_DCDC3		__BIT(1)
67#define AXP_POWEROUT_CTRL_EXTEN		__BIT(0)
68
69#define AXP_DCDC2		0x23
70#define AXP_DCDC2_VOLT_MASK		__BITS(0,5)
71#define AXP_DCDC2_VOLT_SHIFT		0
72
73#define AXP_DCDC2_LDO3_VRC	0x25
74
75#define AXP_DCDC3		0x27
76#define AXP_DCDC3_VOLT_MASK		__BITS(0,6)
77#define AXP_DCDC3_VOLT_SHIFT		0
78
79#define AXP_LDO2_4		0x28
80#define AXP_LDO2_VOLT_MASK		__BITS(4,7)
81#define AXP_LDO2_VOLT_SHIFT		4
82#define AXP_LDO4_VOLT_MASK		__BITS(0,3)
83#define AXP_LDO4_VOLT_SHIFT		0
84static int ldo4_mvV[] = {
85	1250,
86	1300,
87	1400,
88	1500,
89	1600,
90	1700,
91	1800,
92	1900,
93	2000,
94	2500,
95	2700,
96	2800,
97	3000,
98	3100,
99	3200,
100	3300
101};
102
103#define AXP_LDO3		0x29
104#define AXP_LDO3_TRACK			__BIT(7)
105#define AXP_LDO3_VOLT_MASK		__BITS(0,6)
106#define AXP_LDO3_VOLT_SHIFT		0
107
108#define	AXP_SHUTDOWN		0x32
109#define	AXP_SHUTDOWN_CTRL	__BIT(7)
110
111#define AXP_BKUP_CTRL			0x35
112#define AXP_BKUP_CTRL_ENABLE		__BIT(7)
113#define AXP_BKUP_CTRL_VOLT_MASK		__BITS(5,6)
114#define AXP_BKUP_CTRL_VOLT_SHIFT	5
115#define AXP_BKUP_CTRL_VOLT_3V1		0
116#define AXP_BKUP_CTRL_VOLT_3V0		1
117#define AXP_BKUP_CTRL_VOLT_3V6		2
118#define AXP_BKUP_CTRL_VOLT_2V5		3
119static int bkup_volt[] = {
120	3100,
121	3000,
122	3600,
123	2500
124};
125#define AXP_BKUP_CTRL_CURR_MASK		__BITS(0,1)
126#define AXP_BKUP_CTRL_CURR_SHIFT	0
127#define AXP_BKUP_CTRL_CURR_50U		0
128#define AXP_BKUP_CTRL_CURR_100U		1
129#define AXP_BKUP_CTRL_CURR_200U		2
130#define AXP_BKUP_CTRL_CURR_400U		3
131static int bkup_curr[] = {
132	50,
133	100,
134	200,
135	400
136};
137
138#define AXP_ACV_MON_REG		0x56	/* 2 bytes */
139#define AXP_ACI_MON_REG		0x58	/* 2 bytes */
140#define AXP_VBUSV_MON_REG	0x5a	/* 2 bytes */
141#define AXP_VBUSI_MON_REG	0x5c	/* 2 bytes */
142#define AXP_TEMP_MON_REG	0x5e	/* 2 bytes */
143#define AXP_BATTV_MON_REG	0x78	/* 2 bytes */
144#define AXP_BATTCI_MON_REG	0x7a	/* 2 bytes */
145#define AXP_BATTDI_MON_REG	0x7c	/* 2 bytes */
146#define AXP_APSV_MON_REG	0x7e	/* 2 bytes */
147
148#define AXP_ADC_EN1		0x82
149#define AXP_ADC_EN1_BATTV		__BIT(7)
150#define AXP_ADC_EN1_BATTI		__BIT(6)
151#define AXP_ADC_EN1_ACV			__BIT(5)
152#define AXP_ADC_EN1_ACI			__BIT(4)
153#define AXP_ADC_EN1_VBUSV		__BIT(3)
154#define AXP_ADC_EN1_VBUSI		__BIT(2)
155#define AXP_ADC_EN1_APSV		__BIT(1)
156#define AXP_ADC_EN1_TS			__BIT(0)
157#define AXP_ADC_EN2		0x83
158#define AXP_ADC_EN2_TEMP		__BIT(7)
159
160#define AXP_SENSOR_ACOK		0
161#define AXP_SENSOR_ACV		1
162#define AXP_SENSOR_ACI		2
163#define AXP_SENSOR_VBUSOK	3
164#define AXP_SENSOR_VBUSV	4
165#define AXP_SENSOR_VBUSI	5
166#define AXP_SENSOR_BATTOK	6
167#define AXP_SENSOR_BATTV	7
168#define AXP_SENSOR_BATTI	8
169#define AXP_SENSOR_APSV		9
170#define AXP_SENSOR_TEMP		10
171#define AXP_NSENSORS (AXP_SENSOR_TEMP + 1)
172
173/* define per-ADC LSB to uV/uA values */
174static int axp20x_sensors_lsb[] = {
175	   0, /* AXP_SENSOR_ACOK */
176	1700, /* AXP_SENSOR_ACV */
177	 625, /* AXP_SENSOR_ACI */
178	   0,
179	1700, /* AXP_SENSOR_VBUSV */
180	 375, /* AXP_SENSOR_VBUSI */
181	   0,
182	1100, /* AXP_SENSOR_BATTV */
183	 500, /* AXP_SENSOR_BATTI */
184	1400, /* AXP_SENSOR_APSV */
185};
186
187
188struct axp20x_softc {
189	device_t	sc_dev;
190	i2c_tag_t	sc_i2c;
191	i2c_addr_t	sc_addr;
192	int		sc_phandle;
193
194	uint8_t 	sc_inputstatus;
195	uint8_t 	sc_powermode;
196
197	struct sysmon_envsys *sc_sme;
198	envsys_data_t	sc_sensor[AXP_NSENSORS];
199};
200
201static int	axp20x_match(device_t, cfdata_t, void *);
202static void	axp20x_attach(device_t, device_t, void *);
203
204static void	axp20x_sensors_refresh(struct sysmon_envsys *, envsys_data_t *);
205static int	axp20x_read(struct axp20x_softc *, uint8_t, uint8_t *, size_t);
206static int	axp20x_write(struct axp20x_softc *, uint8_t, uint8_t *, size_t);
207
208static void	axp20x_fdt_attach(struct axp20x_softc *);
209
210CFATTACH_DECL_NEW(axp20x, sizeof(struct axp20x_softc),
211    axp20x_match, axp20x_attach, NULL, NULL);
212
213static const struct device_compatible_entry compat_data[] = {
214	{ .compat = "x-powers,axp209" },
215	DEVICE_COMPAT_EOL
216};
217
218static int
219axp20x_match(device_t parent, cfdata_t match, void *aux)
220{
221	struct i2c_attach_args * const ia = aux;
222	int match_result;
223
224	if (iic_use_direct_match(ia, match, compat_data, &match_result))
225		return match_result;
226
227	/* This device is direct-config only. */
228
229	return 0;
230}
231
232static void
233axp20x_attach(device_t parent, device_t self, void *aux)
234{
235	struct axp20x_softc *sc = device_private(self);
236	struct i2c_attach_args *ia = aux;
237	int first;
238	int error;
239	uint8_t value;
240
241	sc->sc_dev = self;
242	sc->sc_i2c = ia->ia_tag;
243	sc->sc_addr = ia->ia_addr;
244	sc->sc_phandle = ia->ia_cookie;
245
246	error = axp20x_read(sc, AXP_INPUT_STATUS,
247	    &sc->sc_inputstatus, 1);
248	if (error) {
249		aprint_error(": can't read status: %d\n", error);
250		return;
251	}
252	error = axp20x_read(sc, AXP_POWER_MODE,
253	    &sc->sc_powermode, 1);
254	if (error) {
255		aprint_error(": can't read power mode: %d\n", error);
256		return;
257	}
258	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;
259	if (sc->sc_powermode & AXP_POWER_MODE_BATTOK)
260		value |= AXP_ADC_EN1_BATTV | AXP_ADC_EN1_BATTI;
261	error = axp20x_write(sc, AXP_ADC_EN1, &value, 1);
262	if (error) {
263		aprint_error(": can't set AXP_ADC_EN1\n");
264		return;
265	}
266	error = axp20x_read(sc, AXP_ADC_EN2, &value, 1);
267	if (error) {
268		aprint_error(": can't read AXP_ADC_EN2\n");
269		return;
270	}
271	value |= AXP_ADC_EN2_TEMP;
272	error = axp20x_write(sc, AXP_ADC_EN2, &value, 1);
273	if (error) {
274		aprint_error(": can't set AXP_ADC_EN2\n");
275		return;
276	}
277
278	aprint_naive("\n");
279	first = 1;
280	if (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK) {
281		aprint_verbose(": AC used");
282		first = 0;
283	} else if (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_PRESENT) {
284		aprint_verbose(": AC present (but unused)");
285		first = 0;
286	}
287	if (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK) {
288		aprint_verbose("%s VBUS used", first ? ":" : ",");
289		first = 0;
290	} else if (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_PRESENT) {
291		aprint_verbose("%s VBUS present (but unused)", first ? ":" : ",");
292		first = 0;
293	}
294	if (sc->sc_powermode & AXP_POWER_MODE_BATTOK) {
295		aprint_verbose("%s battery present", first ? ":" : ",");
296	}
297	aprint_normal("\n");
298
299	sc->sc_sme = sysmon_envsys_create();
300	sc->sc_sme->sme_name = device_xname(self);
301	sc->sc_sme->sme_cookie = sc;
302	sc->sc_sme->sme_refresh = axp20x_sensors_refresh;
303
304	sc->sc_sensor[AXP_SENSOR_ACOK].units = ENVSYS_INDICATOR;
305	sc->sc_sensor[AXP_SENSOR_ACOK].state = ENVSYS_SVALID;
306	sc->sc_sensor[AXP_SENSOR_ACOK].value_cur =
307	    (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK) ? 1 : 0;
308	snprintf(sc->sc_sensor[AXP_SENSOR_ACOK].desc,
309	    sizeof(sc->sc_sensor[AXP_SENSOR_ACOK].desc), "AC input");
310	sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_ACOK]);
311	sc->sc_sensor[AXP_SENSOR_ACV].units = ENVSYS_SVOLTS_DC;
312	sc->sc_sensor[AXP_SENSOR_ACV].state = ENVSYS_SINVALID;
313	sc->sc_sensor[AXP_SENSOR_ACV].flags = ENVSYS_FHAS_ENTROPY;
314	snprintf(sc->sc_sensor[AXP_SENSOR_ACV].desc,
315	    sizeof(sc->sc_sensor[AXP_SENSOR_ACV].desc), "AC input voltage");
316	sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_ACV]);
317	sc->sc_sensor[AXP_SENSOR_ACI].units = ENVSYS_SAMPS;
318	sc->sc_sensor[AXP_SENSOR_ACI].state = ENVSYS_SINVALID;
319	sc->sc_sensor[AXP_SENSOR_ACI].flags = ENVSYS_FHAS_ENTROPY;
320	snprintf(sc->sc_sensor[AXP_SENSOR_ACI].desc,
321	    sizeof(sc->sc_sensor[AXP_SENSOR_ACI].desc), "AC input current");
322	sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_ACI]);
323
324	sc->sc_sensor[AXP_SENSOR_VBUSOK].units = ENVSYS_INDICATOR;
325	sc->sc_sensor[AXP_SENSOR_VBUSOK].state = ENVSYS_SVALID;
326	sc->sc_sensor[AXP_SENSOR_VBUSOK].value_cur =
327	    (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK) ? 1 : 0;
328	snprintf(sc->sc_sensor[AXP_SENSOR_VBUSOK].desc,
329	    sizeof(sc->sc_sensor[AXP_SENSOR_VBUSOK].desc), "VBUS input");
330	sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_VBUSOK]);
331	sc->sc_sensor[AXP_SENSOR_VBUSV].units = ENVSYS_SVOLTS_DC;
332	sc->sc_sensor[AXP_SENSOR_VBUSV].state = ENVSYS_SINVALID;
333	sc->sc_sensor[AXP_SENSOR_VBUSV].flags = ENVSYS_FHAS_ENTROPY;
334	snprintf(sc->sc_sensor[AXP_SENSOR_VBUSV].desc,
335	    sizeof(sc->sc_sensor[AXP_SENSOR_VBUSV].desc), "VBUS input voltage");
336	sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_VBUSV]);
337	sc->sc_sensor[AXP_SENSOR_VBUSI].units = ENVSYS_SAMPS;
338	sc->sc_sensor[AXP_SENSOR_VBUSI].state = ENVSYS_SINVALID;
339	sc->sc_sensor[AXP_SENSOR_VBUSI].flags = ENVSYS_FHAS_ENTROPY;
340	snprintf(sc->sc_sensor[AXP_SENSOR_VBUSI].desc,
341	    sizeof(sc->sc_sensor[AXP_SENSOR_VBUSI].desc), "VBUS input current");
342	sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_VBUSI]);
343
344	sc->sc_sensor[AXP_SENSOR_BATTOK].units = ENVSYS_INDICATOR;
345	sc->sc_sensor[AXP_SENSOR_BATTOK].state = ENVSYS_SVALID;
346	sc->sc_sensor[AXP_SENSOR_BATTOK].value_cur =
347	    (sc->sc_powermode & AXP_POWER_MODE_BATTOK) ? 1 : 0;
348	snprintf(sc->sc_sensor[AXP_SENSOR_BATTOK].desc,
349	    sizeof(sc->sc_sensor[AXP_SENSOR_BATTOK].desc), "battery");
350	sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_BATTOK]);
351	sc->sc_sensor[AXP_SENSOR_BATTV].units = ENVSYS_SVOLTS_DC;
352	sc->sc_sensor[AXP_SENSOR_BATTV].state = ENVSYS_SINVALID;
353	sc->sc_sensor[AXP_SENSOR_BATTV].flags = ENVSYS_FHAS_ENTROPY;
354	snprintf(sc->sc_sensor[AXP_SENSOR_BATTV].desc,
355	    sizeof(sc->sc_sensor[AXP_SENSOR_BATTV].desc), "battery voltage");
356	sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_BATTV]);
357	sc->sc_sensor[AXP_SENSOR_BATTI].units = ENVSYS_SAMPS;
358	sc->sc_sensor[AXP_SENSOR_BATTI].state = ENVSYS_SINVALID;
359	sc->sc_sensor[AXP_SENSOR_BATTI].flags = ENVSYS_FHAS_ENTROPY;
360	snprintf(sc->sc_sensor[AXP_SENSOR_BATTI].desc,
361	    sizeof(sc->sc_sensor[AXP_SENSOR_BATTI].desc), "battery current");
362	sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_BATTI]);
363
364	sc->sc_sensor[AXP_SENSOR_APSV].units = ENVSYS_SVOLTS_DC;
365	sc->sc_sensor[AXP_SENSOR_APSV].state = ENVSYS_SINVALID;
366	sc->sc_sensor[AXP_SENSOR_APSV].flags = ENVSYS_FHAS_ENTROPY;
367	snprintf(sc->sc_sensor[AXP_SENSOR_APSV].desc,
368	    sizeof(sc->sc_sensor[AXP_SENSOR_APSV].desc), "APS output voltage");
369	sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_APSV]);
370	sc->sc_sensor[AXP_SENSOR_TEMP].units = ENVSYS_STEMP;
371	sc->sc_sensor[AXP_SENSOR_TEMP].state = ENVSYS_SINVALID;
372	sc->sc_sensor[AXP_SENSOR_TEMP].flags = ENVSYS_FHAS_ENTROPY;
373	snprintf(sc->sc_sensor[AXP_SENSOR_TEMP].desc,
374	    sizeof(sc->sc_sensor[AXP_SENSOR_TEMP].desc),
375	    "internal temperature");
376	sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_TEMP]);
377
378	sysmon_envsys_register(sc->sc_sme);
379
380	if (axp20x_read(sc, AXP_DCDC2, &value, 1) == 0) {
381		aprint_verbose_dev(sc->sc_dev, "DCDC2 %dmV\n",
382		    (int)(700 + (value & AXP_DCDC2_VOLT_MASK) * 25));
383	}
384	if (axp20x_read(sc, AXP_DCDC3, &value, 1) == 0) {
385		aprint_verbose_dev(sc->sc_dev, "DCDC3 %dmV\n",
386		    (int)(700 + (value & AXP_DCDC3_VOLT_MASK) * 25));
387	}
388	if (axp20x_read(sc, AXP_LDO2_4, &value, 1) == 0) {
389		aprint_verbose_dev(sc->sc_dev, "LDO2 %dmV, LDO4 %dmV\n",
390		    (int)(1800 +
391		    ((value & AXP_LDO2_VOLT_MASK) >> AXP_LDO2_VOLT_SHIFT) * 100
392		    ),
393		    ldo4_mvV[(value & AXP_LDO4_VOLT_MASK) >> AXP_LDO4_VOLT_SHIFT]);
394	}
395	if (axp20x_read(sc, AXP_LDO3, &value, 1) == 0) {
396		if (value & AXP_LDO3_TRACK) {
397			aprint_verbose_dev(sc->sc_dev, "LDO3: tracking\n");
398		} else {
399			aprint_verbose_dev(sc->sc_dev, "LDO3 %dmV\n",
400			    (int)(700 + (value & AXP_LDO3_VOLT_MASK) * 25));
401		}
402	}
403
404	if (axp20x_read(sc, AXP_BKUP_CTRL, &value, 1) == 0) {
405		if (value & AXP_BKUP_CTRL_ENABLE) {
406			aprint_verbose_dev(sc->sc_dev,
407			    "RTC supercap charger enabled: %dmV at %duA\n",
408			    bkup_volt[(value & AXP_BKUP_CTRL_VOLT_MASK) >>
409			    AXP_BKUP_CTRL_VOLT_SHIFT],
410			    bkup_curr[(value & AXP_BKUP_CTRL_CURR_MASK) >>
411			    AXP_BKUP_CTRL_CURR_SHIFT]
412			);
413		}
414	}
415
416	axp20x_fdt_attach(sc);
417}
418
419static void
420axp20x_sensors_refresh_volt(struct axp20x_softc *sc, int reg,
421    envsys_data_t *edata)
422{
423	uint8_t buf[2];
424	int error;
425
426	error = axp20x_read(sc, reg, buf, sizeof(buf));
427	if (error) {
428		edata->state = ENVSYS_SINVALID;
429	} else {
430		edata->value_cur = ((buf[0] << 4) | (buf[1] & 0xf)) *
431		    axp20x_sensors_lsb[edata->sensor];
432		edata->state = ENVSYS_SVALID;
433	}
434}
435
436static void
437axp20x_sensors_refresh_amp(struct axp20x_softc *sc, int reg,
438    envsys_data_t *edata)
439{
440	uint8_t buf[2];
441	int error;
442
443	error = axp20x_read(sc, reg, buf, sizeof(buf));
444	if (error) {
445		edata->state = ENVSYS_SINVALID;
446	} else {
447		edata->value_cur = ((buf[0] << 4) | (buf[1] & 0xf)) *
448		    axp20x_sensors_lsb[edata->sensor];
449		edata->state = ENVSYS_SVALID;
450	}
451}
452
453static void
454axp20x_sensors_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
455{
456	struct axp20x_softc *sc = sme->sme_cookie;
457	uint8_t buf[2];
458	int error;
459
460	switch(edata->sensor) {
461	case AXP_SENSOR_ACOK:
462	case AXP_SENSOR_VBUSOK:
463		error = axp20x_read(sc, AXP_INPUT_STATUS,
464		    &sc->sc_inputstatus, 1);
465		if (error) {
466			edata->state = ENVSYS_SINVALID;
467			return;
468		}
469		if (edata->sensor == AXP_SENSOR_ACOK) {
470		    edata->value_cur =
471			(sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK) ? 1 : 0;
472		} else {
473		    edata->value_cur =
474			(sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK) ? 1 : 0;
475		}
476		edata->state = ENVSYS_SVALID;
477		return;
478	case AXP_SENSOR_BATTOK:
479		error = axp20x_read(sc, AXP_POWER_MODE,
480		    &sc->sc_powermode, 1);
481		if (error) {
482			edata->state = ENVSYS_SINVALID;
483			return;
484		}
485		edata->value_cur =
486		    (sc->sc_powermode & AXP_POWER_MODE_BATTOK) ? 1 : 0;
487		return;
488	case AXP_SENSOR_ACV:
489		if (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK)
490			axp20x_sensors_refresh_volt(sc, AXP_ACV_MON_REG, edata);
491		else
492			edata->state = ENVSYS_SINVALID;
493		return;
494	case AXP_SENSOR_ACI:
495		if (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK)
496			axp20x_sensors_refresh_amp(sc, AXP_ACI_MON_REG, edata);
497		else
498			edata->state = ENVSYS_SINVALID;
499		return;
500	case AXP_SENSOR_VBUSV:
501		if (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK)
502			axp20x_sensors_refresh_volt(sc, AXP_VBUSV_MON_REG, edata);
503		else
504			edata->state = ENVSYS_SINVALID;
505		return;
506	case AXP_SENSOR_VBUSI:
507		if (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK)
508			axp20x_sensors_refresh_amp(sc, AXP_VBUSI_MON_REG, edata);
509		else
510			edata->state = ENVSYS_SINVALID;
511		return;
512	case AXP_SENSOR_BATTV:
513		if (sc->sc_powermode & AXP_POWER_MODE_BATTOK)
514			axp20x_sensors_refresh_volt(sc, AXP_BATTV_MON_REG, edata);
515		else
516			edata->state = ENVSYS_SINVALID;
517		return;
518	case AXP_SENSOR_BATTI:
519		if ((sc->sc_powermode & AXP_POWER_MODE_BATTOK) == 0) {
520			edata->state = ENVSYS_SINVALID;
521			return;
522		}
523		error = axp20x_read(sc, AXP_POWER_MODE,
524		    &sc->sc_inputstatus, 1);
525		if (error) {
526			edata->state = ENVSYS_SINVALID;
527			return;
528		}
529		if (sc->sc_inputstatus & AXP_POWER_MODE_CHARGING) {
530			axp20x_sensors_refresh_amp(sc, AXP_BATTCI_MON_REG,
531			    edata);
532			edata->value_cur = -edata->value_cur;
533		} else {
534			axp20x_sensors_refresh_amp(sc, AXP_BATTDI_MON_REG,
535			    edata);
536		}
537		return;
538	case AXP_SENSOR_APSV:
539		axp20x_sensors_refresh_volt(sc, AXP_APSV_MON_REG, edata);
540		return;
541	case AXP_SENSOR_TEMP:
542		error = axp20x_read(sc, AXP_TEMP_MON_REG, buf, sizeof(buf));
543		if (error) {
544			edata->state = ENVSYS_SINVALID;
545		} else {
546			/* between -144.7C and 264.8C, step +0.1C */
547			edata->value_cur =
548			    (((buf[0] << 4) | (buf[1] & 0xf)) - 1447)
549			   * 100000 + 273150000;
550			edata->state = ENVSYS_SVALID;
551		}
552		return;
553	default:
554		aprint_error_dev(sc->sc_dev, "invalid sensor %d\n",
555		    edata->sensor);
556	}
557}
558
559static int
560axp20x_read(struct axp20x_softc *sc, uint8_t reg, uint8_t *val, size_t len)
561{
562	int ret;
563
564	ret = iic_acquire_bus(sc->sc_i2c, 0);
565	if (ret == 0) {
566		ret = iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP, sc->sc_addr,
567		    &reg, 1, val, len, 0);
568		iic_release_bus(sc->sc_i2c, 0);
569	}
570
571	return ret;
572
573}
574
575static int
576axp20x_write(struct axp20x_softc *sc, uint8_t reg, uint8_t *val, size_t len)
577{
578	int ret;
579
580	ret = iic_acquire_bus(sc->sc_i2c, 0);
581	if (ret == 0) {
582		ret = iic_exec(sc->sc_i2c, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
583		    &reg, 1, val, len, 0);
584		iic_release_bus(sc->sc_i2c, 0);
585	}
586
587	return ret;
588}
589
590static int
591axp20x_set_dcdc(device_t dev, int dcdc, int mvolt)
592{
593	struct axp20x_softc *sc = device_private(dev);
594	int ret;
595	int value;
596	uint8_t reg;
597
598	KASSERT(sc != NULL);
599	value = (mvolt - 700) / 25;
600	switch (dcdc) {
601	case AXP20X_DCDC2:
602		value <<= AXP_DCDC2_VOLT_SHIFT;
603		if (value > AXP_DCDC2_VOLT_MASK)
604			return EINVAL;
605		reg = value & AXP_DCDC2_VOLT_MASK;
606		ret = axp20x_write(sc, AXP_DCDC2, &reg, 1);
607		if (ret)
608			return ret;
609		if (axp20x_read(sc, AXP_DCDC2, &reg, 1) == 0) {
610			aprint_debug_dev(sc->sc_dev,
611			    "DCDC2 changed to %dmV\n",
612			    (int)(700 + (reg & AXP_DCDC2_VOLT_MASK) * 25));
613		}
614		return 0;
615
616	case AXP20X_DCDC3:
617		value <<= AXP_DCDC3_VOLT_SHIFT;
618		if (value > AXP_DCDC3_VOLT_MASK)
619			return EINVAL;
620		reg = value & AXP_DCDC3_VOLT_MASK;
621		ret = axp20x_write(sc, AXP_DCDC3, &reg, 1);
622		if (ret)
623			return ret;
624		if (axp20x_read(sc, AXP_DCDC3, &reg, 1) == 0) {
625			aprint_debug_dev(sc->sc_dev,
626			    "DCDC3 changed to %dmV\n",
627			    (int)(700 + (reg & AXP_DCDC3_VOLT_MASK) * 25));
628		}
629		return 0;
630	default:
631		aprint_error_dev(dev, "wrong DCDC %d\n", dcdc);
632		return EINVAL;
633	}
634}
635
636static int
637axp20x_get_dcdc(device_t dev, int dcdc, int *pmvolt)
638{
639	struct axp20x_softc *sc = device_private(dev);
640	uint8_t reg;
641	int error;
642
643	switch (dcdc) {
644	case AXP20X_DCDC2:
645		error = axp20x_read(sc, AXP_DCDC2, &reg, 1);
646		if (error != 0)
647			return error;
648		*pmvolt = __SHIFTOUT(reg, AXP_DCDC2_VOLT_MASK) * 25 + 700;
649		return 0;
650	case AXP20X_DCDC3:
651		error = axp20x_read(sc, AXP_DCDC3, &reg, 1);
652		if (error != 0)
653			return error;
654		*pmvolt = __SHIFTOUT(reg, AXP_DCDC3_VOLT_MASK) * 25 + 700;
655		return 0;
656	default:
657		return EINVAL;
658	}
659}
660
661static void
662axp20x_poweroff(device_t dev)
663{
664	struct axp20x_softc * const sc = device_private(dev);
665	uint8_t reg = AXP_SHUTDOWN_CTRL;
666	int error;
667
668	error = axp20x_write(sc, AXP_SHUTDOWN, &reg, 1);
669	if (error) {
670		device_printf(dev, "WARNING: unable to power off, error %d\n",
671		    error);
672	}
673}
674
675static const struct axp20xregdef {
676	const char *name;
677	int dcdc;
678} axp20x_regdefs[] = {
679	{ "dcdc2", AXP20X_DCDC2 },
680	{ "dcdc3", AXP20X_DCDC3 },
681};
682
683struct axp20xreg_softc {
684	device_t	sc_dev;
685	int		sc_phandle;
686	const struct axp20xregdef *sc_regdef;
687};
688
689struct axp20xreg_attach_args {
690	int		reg_phandle;
691};
692
693static int
694axp20xreg_acquire(device_t dev)
695{
696	return 0;
697}
698
699static void
700axp20xreg_release(device_t dev)
701{
702}
703
704static int
705axp20xreg_enable(device_t dev, bool enable)
706{
707	/* TODO */
708	return enable ? 0 : EINVAL;
709}
710
711static int
712axp20xreg_set_voltage(device_t dev, u_int min_uvol, u_int max_uvol)
713{
714	struct axp20xreg_softc * const sc = device_private(dev);
715
716	return axp20x_set_dcdc(device_parent(dev), sc->sc_regdef->dcdc, min_uvol / 1000);
717}
718
719static int
720axp20xreg_get_voltage(device_t dev, u_int *puvol)
721{
722	struct axp20xreg_softc * const sc = device_private(dev);
723	int mvol, error;
724
725	error = axp20x_get_dcdc(device_parent(dev), sc->sc_regdef->dcdc, &mvol);
726	if (error != 0)
727		return error;
728
729	*puvol = mvol * 1000;
730	return 0;
731}
732
733static struct fdtbus_regulator_controller_func axp20xreg_funcs = {
734	.acquire = axp20xreg_acquire,
735	.release = axp20xreg_release,
736	.enable = axp20xreg_enable,
737	.set_voltage = axp20xreg_set_voltage,
738	.get_voltage = axp20xreg_get_voltage,
739};
740
741static const struct axp20xregdef *
742axp20xreg_lookup(int phandle)
743{
744	const char *name;
745	int n;
746
747	name = fdtbus_get_string(phandle, "name");
748	if (name == NULL)
749		return NULL;
750
751	for (n = 0; n < __arraycount(axp20x_regdefs); n++)
752		if (strcmp(name, axp20x_regdefs[n].name) == 0)
753			return &axp20x_regdefs[n];
754
755	return NULL;
756}
757
758static int
759axp20xreg_match(device_t parent, cfdata_t match, void *aux)
760{
761	const struct axp20xreg_attach_args *reg = aux;
762
763	return axp20xreg_lookup(reg->reg_phandle) != NULL;
764}
765
766static void
767axp20xreg_attach(device_t parent, device_t self, void *aux)
768{
769	struct axp20xreg_softc * const sc = device_private(self);
770	const struct axp20xreg_attach_args *reg = aux;
771	const char *regulator_name;
772
773	sc->sc_dev = self;
774	sc->sc_phandle = reg->reg_phandle;
775	sc->sc_regdef = axp20xreg_lookup(reg->reg_phandle);
776
777	regulator_name = fdtbus_get_string(reg->reg_phandle, "regulator-name");
778
779	aprint_naive("\n");
780	if (regulator_name)
781		aprint_normal(": %s (%s)\n", sc->sc_regdef->name, regulator_name);
782	else
783		aprint_normal(": %s\n", sc->sc_regdef->name);
784
785	fdtbus_register_regulator_controller(self, sc->sc_phandle, &axp20xreg_funcs);
786}
787
788CFATTACH_DECL_NEW(axp20xreg, sizeof(struct axp20xreg_softc),
789    axp20xreg_match, axp20xreg_attach, NULL, NULL);
790
791static void
792axp20x_fdt_poweroff(device_t dev)
793{
794	delay(1000000);
795	axp20x_poweroff(dev);
796}
797
798static struct fdtbus_power_controller_func axp20x_fdt_power_funcs = {
799	.poweroff = axp20x_fdt_poweroff,
800};
801
802static void
803axp20x_fdt_attach(struct axp20x_softc *sc)
804{
805	int regulators_phandle, child;
806
807	fdtbus_register_power_controller(sc->sc_dev, sc->sc_phandle,
808	    &axp20x_fdt_power_funcs);
809
810	regulators_phandle = of_find_firstchild_byname(sc->sc_phandle, "regulators");
811	if (regulators_phandle == -1)
812		return;
813
814	for (child = OF_child(regulators_phandle); child; child = OF_peer(child)) {
815		struct axp20xreg_attach_args reg = { .reg_phandle = child };
816		config_found(sc->sc_dev, &reg, NULL, CFARGS_NONE);
817	}
818}
819