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