1 1.22 thorpej /* $NetBSD: axp20x.c,v 1.22 2025/09/17 13:42:42 thorpej 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.1 jmcneill #include <sys/cdefs.h> 30 1.22 thorpej __KERNEL_RCSID(0, "$NetBSD: axp20x.c,v 1.22 2025/09/17 13:42:42 thorpej Exp $"); 31 1.1 jmcneill 32 1.1 jmcneill #include <sys/param.h> 33 1.1 jmcneill #include <sys/systm.h> 34 1.1 jmcneill #include <sys/device.h> 35 1.1 jmcneill #include <sys/conf.h> 36 1.1 jmcneill #include <sys/bus.h> 37 1.1 jmcneill #include <sys/kmem.h> 38 1.1 jmcneill 39 1.1 jmcneill #include <dev/i2c/i2cvar.h> 40 1.1 jmcneill 41 1.1 jmcneill #include <dev/sysmon/sysmonvar.h> 42 1.1 jmcneill 43 1.7 jmcneill #include <dev/fdt/fdtvar.h> 44 1.16 thorpej 45 1.16 thorpej #define AXP20X_DCDC2 2 46 1.16 thorpej #define AXP20X_DCDC3 3 47 1.7 jmcneill 48 1.11 thorpej #define AXP209_I2C_ADDR 0x34 49 1.11 thorpej 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.16 thorpej static int axp20x_read(struct axp20x_softc *, uint8_t, uint8_t *, size_t); 206 1.16 thorpej static int axp20x_write(struct axp20x_softc *, uint8_t, uint8_t *, size_t); 207 1.1 jmcneill 208 1.7 jmcneill static void axp20x_fdt_attach(struct axp20x_softc *); 209 1.7 jmcneill 210 1.1 jmcneill CFATTACH_DECL_NEW(axp20x, sizeof(struct axp20x_softc), 211 1.1 jmcneill axp20x_match, axp20x_attach, NULL, NULL); 212 1.1 jmcneill 213 1.13 thorpej static const struct device_compatible_entry compat_data[] = { 214 1.17 thorpej { .compat = "x-powers,axp209" }, 215 1.19 thorpej DEVICE_COMPAT_EOL 216 1.12 thorpej }; 217 1.12 thorpej 218 1.1 jmcneill static int 219 1.1 jmcneill axp20x_match(device_t parent, cfdata_t match, void *aux) 220 1.1 jmcneill { 221 1.6 jmcneill struct i2c_attach_args * const ia = aux; 222 1.11 thorpej int match_result; 223 1.11 thorpej 224 1.13 thorpej if (iic_use_direct_match(ia, match, compat_data, &match_result)) 225 1.11 thorpej return match_result; 226 1.6 jmcneill 227 1.11 thorpej /* This device is direct-config only. */ 228 1.6 jmcneill 229 1.11 thorpej return 0; 230 1.1 jmcneill } 231 1.1 jmcneill 232 1.1 jmcneill static void 233 1.1 jmcneill axp20x_attach(device_t parent, device_t self, void *aux) 234 1.1 jmcneill { 235 1.1 jmcneill struct axp20x_softc *sc = device_private(self); 236 1.1 jmcneill struct i2c_attach_args *ia = aux; 237 1.3 bouyer int first; 238 1.3 bouyer int error; 239 1.3 bouyer uint8_t value; 240 1.1 jmcneill 241 1.1 jmcneill sc->sc_dev = self; 242 1.1 jmcneill sc->sc_i2c = ia->ia_tag; 243 1.1 jmcneill sc->sc_addr = ia->ia_addr; 244 1.22 thorpej sc->sc_phandle = devhandle_to_of(device_handle(self)); 245 1.1 jmcneill 246 1.3 bouyer error = axp20x_read(sc, AXP_INPUT_STATUS, 247 1.16 thorpej &sc->sc_inputstatus, 1); 248 1.3 bouyer if (error) { 249 1.3 bouyer aprint_error(": can't read status: %d\n", error); 250 1.3 bouyer return; 251 1.3 bouyer } 252 1.3 bouyer error = axp20x_read(sc, AXP_POWER_MODE, 253 1.16 thorpej &sc->sc_powermode, 1); 254 1.3 bouyer if (error) { 255 1.3 bouyer aprint_error(": can't read power mode: %d\n", error); 256 1.3 bouyer return; 257 1.3 bouyer } 258 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; 259 1.3 bouyer if (sc->sc_powermode & AXP_POWER_MODE_BATTOK) 260 1.3 bouyer value |= AXP_ADC_EN1_BATTV | AXP_ADC_EN1_BATTI; 261 1.16 thorpej error = axp20x_write(sc, AXP_ADC_EN1, &value, 1); 262 1.3 bouyer if (error) { 263 1.3 bouyer aprint_error(": can't set AXP_ADC_EN1\n"); 264 1.3 bouyer return; 265 1.3 bouyer } 266 1.16 thorpej error = axp20x_read(sc, AXP_ADC_EN2, &value, 1); 267 1.3 bouyer if (error) { 268 1.3 bouyer aprint_error(": can't read AXP_ADC_EN2\n"); 269 1.3 bouyer return; 270 1.3 bouyer } 271 1.3 bouyer value |= AXP_ADC_EN2_TEMP; 272 1.16 thorpej error = axp20x_write(sc, AXP_ADC_EN2, &value, 1); 273 1.3 bouyer if (error) { 274 1.3 bouyer aprint_error(": can't set AXP_ADC_EN2\n"); 275 1.3 bouyer return; 276 1.3 bouyer } 277 1.3 bouyer 278 1.1 jmcneill aprint_naive("\n"); 279 1.3 bouyer first = 1; 280 1.3 bouyer if (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK) { 281 1.4 bouyer aprint_verbose(": AC used"); 282 1.3 bouyer first = 0; 283 1.3 bouyer } else if (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_PRESENT) { 284 1.4 bouyer aprint_verbose(": AC present (but unused)"); 285 1.3 bouyer first = 0; 286 1.3 bouyer } 287 1.3 bouyer if (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK) { 288 1.4 bouyer aprint_verbose("%s VBUS used", first ? ":" : ","); 289 1.3 bouyer first = 0; 290 1.3 bouyer } else if (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_PRESENT) { 291 1.4 bouyer aprint_verbose("%s VBUS present (but unused)", first ? ":" : ","); 292 1.3 bouyer first = 0; 293 1.3 bouyer } 294 1.3 bouyer if (sc->sc_powermode & AXP_POWER_MODE_BATTOK) { 295 1.4 bouyer aprint_verbose("%s battery present", first ? ":" : ","); 296 1.3 bouyer } 297 1.1 jmcneill aprint_normal("\n"); 298 1.1 jmcneill 299 1.1 jmcneill sc->sc_sme = sysmon_envsys_create(); 300 1.1 jmcneill sc->sc_sme->sme_name = device_xname(self); 301 1.1 jmcneill sc->sc_sme->sme_cookie = sc; 302 1.1 jmcneill sc->sc_sme->sme_refresh = axp20x_sensors_refresh; 303 1.1 jmcneill 304 1.3 bouyer sc->sc_sensor[AXP_SENSOR_ACOK].units = ENVSYS_INDICATOR; 305 1.3 bouyer sc->sc_sensor[AXP_SENSOR_ACOK].state = ENVSYS_SVALID; 306 1.3 bouyer sc->sc_sensor[AXP_SENSOR_ACOK].value_cur = 307 1.3 bouyer (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK) ? 1 : 0; 308 1.3 bouyer snprintf(sc->sc_sensor[AXP_SENSOR_ACOK].desc, 309 1.3 bouyer sizeof(sc->sc_sensor[AXP_SENSOR_ACOK].desc), "AC input"); 310 1.3 bouyer sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_ACOK]); 311 1.3 bouyer sc->sc_sensor[AXP_SENSOR_ACV].units = ENVSYS_SVOLTS_DC; 312 1.3 bouyer sc->sc_sensor[AXP_SENSOR_ACV].state = ENVSYS_SINVALID; 313 1.3 bouyer sc->sc_sensor[AXP_SENSOR_ACV].flags = ENVSYS_FHAS_ENTROPY; 314 1.3 bouyer snprintf(sc->sc_sensor[AXP_SENSOR_ACV].desc, 315 1.3 bouyer sizeof(sc->sc_sensor[AXP_SENSOR_ACV].desc), "AC input voltage"); 316 1.3 bouyer sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_ACV]); 317 1.3 bouyer sc->sc_sensor[AXP_SENSOR_ACI].units = ENVSYS_SAMPS; 318 1.3 bouyer sc->sc_sensor[AXP_SENSOR_ACI].state = ENVSYS_SINVALID; 319 1.3 bouyer sc->sc_sensor[AXP_SENSOR_ACI].flags = ENVSYS_FHAS_ENTROPY; 320 1.3 bouyer snprintf(sc->sc_sensor[AXP_SENSOR_ACI].desc, 321 1.3 bouyer sizeof(sc->sc_sensor[AXP_SENSOR_ACI].desc), "AC input current"); 322 1.3 bouyer sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_ACI]); 323 1.3 bouyer 324 1.3 bouyer sc->sc_sensor[AXP_SENSOR_VBUSOK].units = ENVSYS_INDICATOR; 325 1.3 bouyer sc->sc_sensor[AXP_SENSOR_VBUSOK].state = ENVSYS_SVALID; 326 1.3 bouyer sc->sc_sensor[AXP_SENSOR_VBUSOK].value_cur = 327 1.3 bouyer (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK) ? 1 : 0; 328 1.3 bouyer snprintf(sc->sc_sensor[AXP_SENSOR_VBUSOK].desc, 329 1.3 bouyer sizeof(sc->sc_sensor[AXP_SENSOR_VBUSOK].desc), "VBUS input"); 330 1.3 bouyer sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_VBUSOK]); 331 1.3 bouyer sc->sc_sensor[AXP_SENSOR_VBUSV].units = ENVSYS_SVOLTS_DC; 332 1.3 bouyer sc->sc_sensor[AXP_SENSOR_VBUSV].state = ENVSYS_SINVALID; 333 1.3 bouyer sc->sc_sensor[AXP_SENSOR_VBUSV].flags = ENVSYS_FHAS_ENTROPY; 334 1.3 bouyer snprintf(sc->sc_sensor[AXP_SENSOR_VBUSV].desc, 335 1.3 bouyer sizeof(sc->sc_sensor[AXP_SENSOR_VBUSV].desc), "VBUS input voltage"); 336 1.3 bouyer sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_VBUSV]); 337 1.3 bouyer sc->sc_sensor[AXP_SENSOR_VBUSI].units = ENVSYS_SAMPS; 338 1.3 bouyer sc->sc_sensor[AXP_SENSOR_VBUSI].state = ENVSYS_SINVALID; 339 1.3 bouyer sc->sc_sensor[AXP_SENSOR_VBUSI].flags = ENVSYS_FHAS_ENTROPY; 340 1.3 bouyer snprintf(sc->sc_sensor[AXP_SENSOR_VBUSI].desc, 341 1.3 bouyer sizeof(sc->sc_sensor[AXP_SENSOR_VBUSI].desc), "VBUS input current"); 342 1.3 bouyer sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_VBUSI]); 343 1.3 bouyer 344 1.3 bouyer sc->sc_sensor[AXP_SENSOR_BATTOK].units = ENVSYS_INDICATOR; 345 1.3 bouyer sc->sc_sensor[AXP_SENSOR_BATTOK].state = ENVSYS_SVALID; 346 1.3 bouyer sc->sc_sensor[AXP_SENSOR_BATTOK].value_cur = 347 1.3 bouyer (sc->sc_powermode & AXP_POWER_MODE_BATTOK) ? 1 : 0; 348 1.3 bouyer snprintf(sc->sc_sensor[AXP_SENSOR_BATTOK].desc, 349 1.3 bouyer sizeof(sc->sc_sensor[AXP_SENSOR_BATTOK].desc), "battery"); 350 1.3 bouyer sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_BATTOK]); 351 1.3 bouyer sc->sc_sensor[AXP_SENSOR_BATTV].units = ENVSYS_SVOLTS_DC; 352 1.3 bouyer sc->sc_sensor[AXP_SENSOR_BATTV].state = ENVSYS_SINVALID; 353 1.3 bouyer sc->sc_sensor[AXP_SENSOR_BATTV].flags = ENVSYS_FHAS_ENTROPY; 354 1.3 bouyer snprintf(sc->sc_sensor[AXP_SENSOR_BATTV].desc, 355 1.3 bouyer sizeof(sc->sc_sensor[AXP_SENSOR_BATTV].desc), "battery voltage"); 356 1.3 bouyer sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_BATTV]); 357 1.3 bouyer sc->sc_sensor[AXP_SENSOR_BATTI].units = ENVSYS_SAMPS; 358 1.3 bouyer sc->sc_sensor[AXP_SENSOR_BATTI].state = ENVSYS_SINVALID; 359 1.3 bouyer sc->sc_sensor[AXP_SENSOR_BATTI].flags = ENVSYS_FHAS_ENTROPY; 360 1.3 bouyer snprintf(sc->sc_sensor[AXP_SENSOR_BATTI].desc, 361 1.3 bouyer sizeof(sc->sc_sensor[AXP_SENSOR_BATTI].desc), "battery current"); 362 1.3 bouyer sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_BATTI]); 363 1.3 bouyer 364 1.3 bouyer sc->sc_sensor[AXP_SENSOR_APSV].units = ENVSYS_SVOLTS_DC; 365 1.3 bouyer sc->sc_sensor[AXP_SENSOR_APSV].state = ENVSYS_SINVALID; 366 1.3 bouyer sc->sc_sensor[AXP_SENSOR_APSV].flags = ENVSYS_FHAS_ENTROPY; 367 1.3 bouyer snprintf(sc->sc_sensor[AXP_SENSOR_APSV].desc, 368 1.3 bouyer sizeof(sc->sc_sensor[AXP_SENSOR_APSV].desc), "APS output voltage"); 369 1.3 bouyer sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_APSV]); 370 1.3 bouyer sc->sc_sensor[AXP_SENSOR_TEMP].units = ENVSYS_STEMP; 371 1.3 bouyer sc->sc_sensor[AXP_SENSOR_TEMP].state = ENVSYS_SINVALID; 372 1.3 bouyer sc->sc_sensor[AXP_SENSOR_TEMP].flags = ENVSYS_FHAS_ENTROPY; 373 1.3 bouyer snprintf(sc->sc_sensor[AXP_SENSOR_TEMP].desc, 374 1.3 bouyer sizeof(sc->sc_sensor[AXP_SENSOR_TEMP].desc), 375 1.1 jmcneill "internal temperature"); 376 1.3 bouyer sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_TEMP]); 377 1.1 jmcneill 378 1.1 jmcneill sysmon_envsys_register(sc->sc_sme); 379 1.3 bouyer 380 1.16 thorpej if (axp20x_read(sc, AXP_DCDC2, &value, 1) == 0) { 381 1.9 jmcneill aprint_verbose_dev(sc->sc_dev, "DCDC2 %dmV\n", 382 1.3 bouyer (int)(700 + (value & AXP_DCDC2_VOLT_MASK) * 25)); 383 1.3 bouyer } 384 1.16 thorpej if (axp20x_read(sc, AXP_DCDC3, &value, 1) == 0) { 385 1.9 jmcneill aprint_verbose_dev(sc->sc_dev, "DCDC3 %dmV\n", 386 1.3 bouyer (int)(700 + (value & AXP_DCDC3_VOLT_MASK) * 25)); 387 1.3 bouyer } 388 1.16 thorpej if (axp20x_read(sc, AXP_LDO2_4, &value, 1) == 0) { 389 1.9 jmcneill aprint_verbose_dev(sc->sc_dev, "LDO2 %dmV, LDO4 %dmV\n", 390 1.3 bouyer (int)(1800 + 391 1.3 bouyer ((value & AXP_LDO2_VOLT_MASK) >> AXP_LDO2_VOLT_SHIFT) * 100 392 1.3 bouyer ), 393 1.3 bouyer ldo4_mvV[(value & AXP_LDO4_VOLT_MASK) >> AXP_LDO4_VOLT_SHIFT]); 394 1.3 bouyer } 395 1.16 thorpej if (axp20x_read(sc, AXP_LDO3, &value, 1) == 0) { 396 1.3 bouyer if (value & AXP_LDO3_TRACK) { 397 1.9 jmcneill aprint_verbose_dev(sc->sc_dev, "LDO3: tracking\n"); 398 1.3 bouyer } else { 399 1.9 jmcneill aprint_verbose_dev(sc->sc_dev, "LDO3 %dmV\n", 400 1.3 bouyer (int)(700 + (value & AXP_LDO3_VOLT_MASK) * 25)); 401 1.3 bouyer } 402 1.3 bouyer } 403 1.5 tnn 404 1.16 thorpej if (axp20x_read(sc, AXP_BKUP_CTRL, &value, 1) == 0) { 405 1.5 tnn if (value & AXP_BKUP_CTRL_ENABLE) { 406 1.5 tnn aprint_verbose_dev(sc->sc_dev, 407 1.5 tnn "RTC supercap charger enabled: %dmV at %duA\n", 408 1.5 tnn bkup_volt[(value & AXP_BKUP_CTRL_VOLT_MASK) >> 409 1.5 tnn AXP_BKUP_CTRL_VOLT_SHIFT], 410 1.5 tnn bkup_curr[(value & AXP_BKUP_CTRL_CURR_MASK) >> 411 1.5 tnn AXP_BKUP_CTRL_CURR_SHIFT] 412 1.5 tnn ); 413 1.5 tnn } 414 1.5 tnn } 415 1.7 jmcneill 416 1.7 jmcneill axp20x_fdt_attach(sc); 417 1.1 jmcneill } 418 1.1 jmcneill 419 1.1 jmcneill static void 420 1.3 bouyer axp20x_sensors_refresh_volt(struct axp20x_softc *sc, int reg, 421 1.3 bouyer envsys_data_t *edata) 422 1.1 jmcneill { 423 1.1 jmcneill uint8_t buf[2]; 424 1.1 jmcneill int error; 425 1.1 jmcneill 426 1.16 thorpej error = axp20x_read(sc, reg, buf, sizeof(buf)); 427 1.3 bouyer if (error) { 428 1.3 bouyer edata->state = ENVSYS_SINVALID; 429 1.3 bouyer } else { 430 1.3 bouyer edata->value_cur = ((buf[0] << 4) | (buf[1] & 0xf)) * 431 1.3 bouyer axp20x_sensors_lsb[edata->sensor]; 432 1.3 bouyer edata->state = ENVSYS_SVALID; 433 1.3 bouyer } 434 1.3 bouyer } 435 1.3 bouyer 436 1.3 bouyer static void 437 1.3 bouyer axp20x_sensors_refresh_amp(struct axp20x_softc *sc, int reg, 438 1.3 bouyer envsys_data_t *edata) 439 1.3 bouyer { 440 1.3 bouyer uint8_t buf[2]; 441 1.3 bouyer int error; 442 1.1 jmcneill 443 1.16 thorpej error = axp20x_read(sc, reg, buf, sizeof(buf)); 444 1.1 jmcneill if (error) { 445 1.1 jmcneill edata->state = ENVSYS_SINVALID; 446 1.1 jmcneill } else { 447 1.3 bouyer edata->value_cur = ((buf[0] << 4) | (buf[1] & 0xf)) * 448 1.3 bouyer axp20x_sensors_lsb[edata->sensor]; 449 1.1 jmcneill edata->state = ENVSYS_SVALID; 450 1.1 jmcneill } 451 1.1 jmcneill } 452 1.1 jmcneill 453 1.3 bouyer static void 454 1.3 bouyer axp20x_sensors_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 455 1.3 bouyer { 456 1.3 bouyer struct axp20x_softc *sc = sme->sme_cookie; 457 1.3 bouyer uint8_t buf[2]; 458 1.3 bouyer int error; 459 1.3 bouyer 460 1.3 bouyer switch(edata->sensor) { 461 1.3 bouyer case AXP_SENSOR_ACOK: 462 1.3 bouyer case AXP_SENSOR_VBUSOK: 463 1.3 bouyer error = axp20x_read(sc, AXP_INPUT_STATUS, 464 1.16 thorpej &sc->sc_inputstatus, 1); 465 1.3 bouyer if (error) { 466 1.3 bouyer edata->state = ENVSYS_SINVALID; 467 1.3 bouyer return; 468 1.3 bouyer } 469 1.3 bouyer if (edata->sensor == AXP_SENSOR_ACOK) { 470 1.3 bouyer edata->value_cur = 471 1.3 bouyer (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK) ? 1 : 0; 472 1.3 bouyer } else { 473 1.3 bouyer edata->value_cur = 474 1.3 bouyer (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK) ? 1 : 0; 475 1.3 bouyer } 476 1.3 bouyer edata->state = ENVSYS_SVALID; 477 1.3 bouyer return; 478 1.3 bouyer case AXP_SENSOR_BATTOK: 479 1.3 bouyer error = axp20x_read(sc, AXP_POWER_MODE, 480 1.16 thorpej &sc->sc_powermode, 1); 481 1.3 bouyer if (error) { 482 1.3 bouyer edata->state = ENVSYS_SINVALID; 483 1.3 bouyer return; 484 1.3 bouyer } 485 1.3 bouyer edata->value_cur = 486 1.3 bouyer (sc->sc_powermode & AXP_POWER_MODE_BATTOK) ? 1 : 0; 487 1.3 bouyer return; 488 1.3 bouyer case AXP_SENSOR_ACV: 489 1.3 bouyer if (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK) 490 1.3 bouyer axp20x_sensors_refresh_volt(sc, AXP_ACV_MON_REG, edata); 491 1.3 bouyer else 492 1.3 bouyer edata->state = ENVSYS_SINVALID; 493 1.3 bouyer return; 494 1.3 bouyer case AXP_SENSOR_ACI: 495 1.3 bouyer if (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK) 496 1.3 bouyer axp20x_sensors_refresh_amp(sc, AXP_ACI_MON_REG, edata); 497 1.3 bouyer else 498 1.3 bouyer edata->state = ENVSYS_SINVALID; 499 1.3 bouyer return; 500 1.3 bouyer case AXP_SENSOR_VBUSV: 501 1.3 bouyer if (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK) 502 1.3 bouyer axp20x_sensors_refresh_volt(sc, AXP_VBUSV_MON_REG, edata); 503 1.3 bouyer else 504 1.3 bouyer edata->state = ENVSYS_SINVALID; 505 1.3 bouyer return; 506 1.3 bouyer case AXP_SENSOR_VBUSI: 507 1.3 bouyer if (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK) 508 1.3 bouyer axp20x_sensors_refresh_amp(sc, AXP_VBUSI_MON_REG, edata); 509 1.3 bouyer else 510 1.3 bouyer edata->state = ENVSYS_SINVALID; 511 1.3 bouyer return; 512 1.3 bouyer case AXP_SENSOR_BATTV: 513 1.3 bouyer if (sc->sc_powermode & AXP_POWER_MODE_BATTOK) 514 1.3 bouyer axp20x_sensors_refresh_volt(sc, AXP_BATTV_MON_REG, edata); 515 1.3 bouyer else 516 1.3 bouyer edata->state = ENVSYS_SINVALID; 517 1.3 bouyer return; 518 1.3 bouyer case AXP_SENSOR_BATTI: 519 1.3 bouyer if ((sc->sc_powermode & AXP_POWER_MODE_BATTOK) == 0) { 520 1.3 bouyer edata->state = ENVSYS_SINVALID; 521 1.3 bouyer return; 522 1.3 bouyer } 523 1.3 bouyer error = axp20x_read(sc, AXP_POWER_MODE, 524 1.16 thorpej &sc->sc_inputstatus, 1); 525 1.3 bouyer if (error) { 526 1.3 bouyer edata->state = ENVSYS_SINVALID; 527 1.3 bouyer return; 528 1.3 bouyer } 529 1.3 bouyer if (sc->sc_inputstatus & AXP_POWER_MODE_CHARGING) { 530 1.3 bouyer axp20x_sensors_refresh_amp(sc, AXP_BATTCI_MON_REG, 531 1.3 bouyer edata); 532 1.3 bouyer edata->value_cur = -edata->value_cur; 533 1.3 bouyer } else { 534 1.3 bouyer axp20x_sensors_refresh_amp(sc, AXP_BATTDI_MON_REG, 535 1.3 bouyer edata); 536 1.3 bouyer } 537 1.3 bouyer return; 538 1.3 bouyer case AXP_SENSOR_APSV: 539 1.3 bouyer axp20x_sensors_refresh_volt(sc, AXP_APSV_MON_REG, edata); 540 1.3 bouyer return; 541 1.3 bouyer case AXP_SENSOR_TEMP: 542 1.16 thorpej error = axp20x_read(sc, AXP_TEMP_MON_REG, buf, sizeof(buf)); 543 1.3 bouyer if (error) { 544 1.3 bouyer edata->state = ENVSYS_SINVALID; 545 1.3 bouyer } else { 546 1.3 bouyer /* between -144.7C and 264.8C, step +0.1C */ 547 1.3 bouyer edata->value_cur = 548 1.3 bouyer (((buf[0] << 4) | (buf[1] & 0xf)) - 1447) 549 1.3 bouyer * 100000 + 273150000; 550 1.3 bouyer edata->state = ENVSYS_SVALID; 551 1.3 bouyer } 552 1.3 bouyer return; 553 1.3 bouyer default: 554 1.9 jmcneill aprint_error_dev(sc->sc_dev, "invalid sensor %d\n", 555 1.3 bouyer edata->sensor); 556 1.3 bouyer } 557 1.3 bouyer } 558 1.3 bouyer 559 1.3 bouyer static int 560 1.16 thorpej axp20x_read(struct axp20x_softc *sc, uint8_t reg, uint8_t *val, size_t len) 561 1.3 bouyer { 562 1.3 bouyer int ret; 563 1.15 thorpej 564 1.16 thorpej ret = iic_acquire_bus(sc->sc_i2c, 0); 565 1.15 thorpej if (ret == 0) { 566 1.15 thorpej ret = iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP, sc->sc_addr, 567 1.16 thorpej ®, 1, val, len, 0); 568 1.16 thorpej iic_release_bus(sc->sc_i2c, 0); 569 1.15 thorpej } 570 1.15 thorpej 571 1.3 bouyer return ret; 572 1.3 bouyer 573 1.3 bouyer } 574 1.3 bouyer 575 1.1 jmcneill static int 576 1.16 thorpej axp20x_write(struct axp20x_softc *sc, uint8_t reg, uint8_t *val, size_t len) 577 1.1 jmcneill { 578 1.3 bouyer int ret; 579 1.15 thorpej 580 1.16 thorpej ret = iic_acquire_bus(sc->sc_i2c, 0); 581 1.15 thorpej if (ret == 0) { 582 1.15 thorpej ret = iic_exec(sc->sc_i2c, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, 583 1.16 thorpej ®, 1, val, len, 0); 584 1.16 thorpej iic_release_bus(sc->sc_i2c, 0); 585 1.15 thorpej } 586 1.15 thorpej 587 1.3 bouyer return ret; 588 1.3 bouyer } 589 1.3 bouyer 590 1.16 thorpej static int 591 1.16 thorpej axp20x_set_dcdc(device_t dev, int dcdc, int mvolt) 592 1.3 bouyer { 593 1.3 bouyer struct axp20x_softc *sc = device_private(dev); 594 1.3 bouyer int ret; 595 1.3 bouyer int value; 596 1.3 bouyer uint8_t reg; 597 1.3 bouyer 598 1.3 bouyer KASSERT(sc != NULL); 599 1.3 bouyer value = (mvolt - 700) / 25; 600 1.3 bouyer switch (dcdc) { 601 1.3 bouyer case AXP20X_DCDC2: 602 1.3 bouyer value <<= AXP_DCDC2_VOLT_SHIFT; 603 1.3 bouyer if (value > AXP_DCDC2_VOLT_MASK) 604 1.3 bouyer return EINVAL; 605 1.3 bouyer reg = value & AXP_DCDC2_VOLT_MASK; 606 1.16 thorpej ret = axp20x_write(sc, AXP_DCDC2, ®, 1); 607 1.3 bouyer if (ret) 608 1.3 bouyer return ret; 609 1.16 thorpej if (axp20x_read(sc, AXP_DCDC2, ®, 1) == 0) { 610 1.9 jmcneill aprint_debug_dev(sc->sc_dev, 611 1.9 jmcneill "DCDC2 changed to %dmV\n", 612 1.3 bouyer (int)(700 + (reg & AXP_DCDC2_VOLT_MASK) * 25)); 613 1.3 bouyer } 614 1.3 bouyer return 0; 615 1.3 bouyer 616 1.3 bouyer case AXP20X_DCDC3: 617 1.4 bouyer value <<= AXP_DCDC3_VOLT_SHIFT; 618 1.4 bouyer if (value > AXP_DCDC3_VOLT_MASK) 619 1.3 bouyer return EINVAL; 620 1.4 bouyer reg = value & AXP_DCDC3_VOLT_MASK; 621 1.16 thorpej ret = axp20x_write(sc, AXP_DCDC3, ®, 1); 622 1.3 bouyer if (ret) 623 1.3 bouyer return ret; 624 1.16 thorpej if (axp20x_read(sc, AXP_DCDC3, ®, 1) == 0) { 625 1.9 jmcneill aprint_debug_dev(sc->sc_dev, 626 1.9 jmcneill "DCDC3 changed to %dmV\n", 627 1.4 bouyer (int)(700 + (reg & AXP_DCDC3_VOLT_MASK) * 25)); 628 1.3 bouyer } 629 1.3 bouyer return 0; 630 1.3 bouyer default: 631 1.3 bouyer aprint_error_dev(dev, "wrong DCDC %d\n", dcdc); 632 1.3 bouyer return EINVAL; 633 1.3 bouyer } 634 1.1 jmcneill } 635 1.7 jmcneill 636 1.16 thorpej static int 637 1.16 thorpej axp20x_get_dcdc(device_t dev, int dcdc, int *pmvolt) 638 1.8 jmcneill { 639 1.8 jmcneill struct axp20x_softc *sc = device_private(dev); 640 1.8 jmcneill uint8_t reg; 641 1.8 jmcneill int error; 642 1.8 jmcneill 643 1.8 jmcneill switch (dcdc) { 644 1.8 jmcneill case AXP20X_DCDC2: 645 1.16 thorpej error = axp20x_read(sc, AXP_DCDC2, ®, 1); 646 1.8 jmcneill if (error != 0) 647 1.8 jmcneill return error; 648 1.8 jmcneill *pmvolt = __SHIFTOUT(reg, AXP_DCDC2_VOLT_MASK) * 25 + 700; 649 1.8 jmcneill return 0; 650 1.8 jmcneill case AXP20X_DCDC3: 651 1.16 thorpej error = axp20x_read(sc, AXP_DCDC3, ®, 1); 652 1.8 jmcneill if (error != 0) 653 1.8 jmcneill return error; 654 1.8 jmcneill *pmvolt = __SHIFTOUT(reg, AXP_DCDC3_VOLT_MASK) * 25 + 700; 655 1.8 jmcneill return 0; 656 1.8 jmcneill default: 657 1.8 jmcneill return EINVAL; 658 1.8 jmcneill } 659 1.8 jmcneill } 660 1.8 jmcneill 661 1.16 thorpej static void 662 1.7 jmcneill axp20x_poweroff(device_t dev) 663 1.7 jmcneill { 664 1.7 jmcneill struct axp20x_softc * const sc = device_private(dev); 665 1.7 jmcneill uint8_t reg = AXP_SHUTDOWN_CTRL; 666 1.15 thorpej int error; 667 1.7 jmcneill 668 1.16 thorpej error = axp20x_write(sc, AXP_SHUTDOWN, ®, 1); 669 1.15 thorpej if (error) { 670 1.15 thorpej device_printf(dev, "WARNING: unable to power off, error %d\n", 671 1.15 thorpej error); 672 1.15 thorpej } 673 1.7 jmcneill } 674 1.7 jmcneill 675 1.8 jmcneill static const struct axp20xregdef { 676 1.8 jmcneill const char *name; 677 1.8 jmcneill int dcdc; 678 1.8 jmcneill } axp20x_regdefs[] = { 679 1.8 jmcneill { "dcdc2", AXP20X_DCDC2 }, 680 1.8 jmcneill { "dcdc3", AXP20X_DCDC3 }, 681 1.8 jmcneill }; 682 1.8 jmcneill 683 1.8 jmcneill struct axp20xreg_softc { 684 1.8 jmcneill device_t sc_dev; 685 1.8 jmcneill int sc_phandle; 686 1.8 jmcneill const struct axp20xregdef *sc_regdef; 687 1.8 jmcneill }; 688 1.8 jmcneill 689 1.8 jmcneill struct axp20xreg_attach_args { 690 1.8 jmcneill int reg_phandle; 691 1.8 jmcneill }; 692 1.8 jmcneill 693 1.8 jmcneill static int 694 1.8 jmcneill axp20xreg_acquire(device_t dev) 695 1.8 jmcneill { 696 1.8 jmcneill return 0; 697 1.8 jmcneill } 698 1.8 jmcneill 699 1.8 jmcneill static void 700 1.8 jmcneill axp20xreg_release(device_t dev) 701 1.8 jmcneill { 702 1.8 jmcneill } 703 1.8 jmcneill 704 1.8 jmcneill static int 705 1.8 jmcneill axp20xreg_enable(device_t dev, bool enable) 706 1.8 jmcneill { 707 1.8 jmcneill /* TODO */ 708 1.8 jmcneill return enable ? 0 : EINVAL; 709 1.8 jmcneill } 710 1.8 jmcneill 711 1.8 jmcneill static int 712 1.8 jmcneill axp20xreg_set_voltage(device_t dev, u_int min_uvol, u_int max_uvol) 713 1.8 jmcneill { 714 1.8 jmcneill struct axp20xreg_softc * const sc = device_private(dev); 715 1.8 jmcneill 716 1.16 thorpej return axp20x_set_dcdc(device_parent(dev), sc->sc_regdef->dcdc, min_uvol / 1000); 717 1.8 jmcneill } 718 1.8 jmcneill 719 1.8 jmcneill static int 720 1.8 jmcneill axp20xreg_get_voltage(device_t dev, u_int *puvol) 721 1.8 jmcneill { 722 1.8 jmcneill struct axp20xreg_softc * const sc = device_private(dev); 723 1.8 jmcneill int mvol, error; 724 1.8 jmcneill 725 1.16 thorpej error = axp20x_get_dcdc(device_parent(dev), sc->sc_regdef->dcdc, &mvol); 726 1.8 jmcneill if (error != 0) 727 1.8 jmcneill return error; 728 1.8 jmcneill 729 1.8 jmcneill *puvol = mvol * 1000; 730 1.8 jmcneill return 0; 731 1.8 jmcneill } 732 1.8 jmcneill 733 1.8 jmcneill static struct fdtbus_regulator_controller_func axp20xreg_funcs = { 734 1.8 jmcneill .acquire = axp20xreg_acquire, 735 1.8 jmcneill .release = axp20xreg_release, 736 1.8 jmcneill .enable = axp20xreg_enable, 737 1.8 jmcneill .set_voltage = axp20xreg_set_voltage, 738 1.8 jmcneill .get_voltage = axp20xreg_get_voltage, 739 1.8 jmcneill }; 740 1.8 jmcneill 741 1.8 jmcneill static const struct axp20xregdef * 742 1.8 jmcneill axp20xreg_lookup(int phandle) 743 1.8 jmcneill { 744 1.8 jmcneill const char *name; 745 1.8 jmcneill int n; 746 1.8 jmcneill 747 1.8 jmcneill name = fdtbus_get_string(phandle, "name"); 748 1.8 jmcneill if (name == NULL) 749 1.8 jmcneill return NULL; 750 1.8 jmcneill 751 1.8 jmcneill for (n = 0; n < __arraycount(axp20x_regdefs); n++) 752 1.8 jmcneill if (strcmp(name, axp20x_regdefs[n].name) == 0) 753 1.8 jmcneill return &axp20x_regdefs[n]; 754 1.8 jmcneill 755 1.8 jmcneill return NULL; 756 1.8 jmcneill } 757 1.8 jmcneill 758 1.8 jmcneill static int 759 1.8 jmcneill axp20xreg_match(device_t parent, cfdata_t match, void *aux) 760 1.8 jmcneill { 761 1.8 jmcneill const struct axp20xreg_attach_args *reg = aux; 762 1.8 jmcneill 763 1.8 jmcneill return axp20xreg_lookup(reg->reg_phandle) != NULL; 764 1.8 jmcneill } 765 1.8 jmcneill 766 1.8 jmcneill static void 767 1.8 jmcneill axp20xreg_attach(device_t parent, device_t self, void *aux) 768 1.8 jmcneill { 769 1.8 jmcneill struct axp20xreg_softc * const sc = device_private(self); 770 1.8 jmcneill const struct axp20xreg_attach_args *reg = aux; 771 1.8 jmcneill const char *regulator_name; 772 1.8 jmcneill 773 1.8 jmcneill sc->sc_dev = self; 774 1.8 jmcneill sc->sc_phandle = reg->reg_phandle; 775 1.8 jmcneill sc->sc_regdef = axp20xreg_lookup(reg->reg_phandle); 776 1.8 jmcneill 777 1.8 jmcneill regulator_name = fdtbus_get_string(reg->reg_phandle, "regulator-name"); 778 1.8 jmcneill 779 1.8 jmcneill aprint_naive("\n"); 780 1.8 jmcneill if (regulator_name) 781 1.8 jmcneill aprint_normal(": %s (%s)\n", sc->sc_regdef->name, regulator_name); 782 1.8 jmcneill else 783 1.8 jmcneill aprint_normal(": %s\n", sc->sc_regdef->name); 784 1.8 jmcneill 785 1.8 jmcneill fdtbus_register_regulator_controller(self, sc->sc_phandle, &axp20xreg_funcs); 786 1.8 jmcneill } 787 1.8 jmcneill 788 1.8 jmcneill CFATTACH_DECL_NEW(axp20xreg, sizeof(struct axp20xreg_softc), 789 1.8 jmcneill axp20xreg_match, axp20xreg_attach, NULL, NULL); 790 1.8 jmcneill 791 1.7 jmcneill static void 792 1.7 jmcneill axp20x_fdt_poweroff(device_t dev) 793 1.7 jmcneill { 794 1.7 jmcneill delay(1000000); 795 1.7 jmcneill axp20x_poweroff(dev); 796 1.7 jmcneill } 797 1.7 jmcneill 798 1.7 jmcneill static struct fdtbus_power_controller_func axp20x_fdt_power_funcs = { 799 1.7 jmcneill .poweroff = axp20x_fdt_poweroff, 800 1.7 jmcneill }; 801 1.7 jmcneill 802 1.7 jmcneill static void 803 1.7 jmcneill axp20x_fdt_attach(struct axp20x_softc *sc) 804 1.7 jmcneill { 805 1.8 jmcneill int regulators_phandle, child; 806 1.8 jmcneill 807 1.7 jmcneill fdtbus_register_power_controller(sc->sc_dev, sc->sc_phandle, 808 1.7 jmcneill &axp20x_fdt_power_funcs); 809 1.8 jmcneill 810 1.8 jmcneill regulators_phandle = of_find_firstchild_byname(sc->sc_phandle, "regulators"); 811 1.8 jmcneill if (regulators_phandle == -1) 812 1.8 jmcneill return; 813 1.8 jmcneill 814 1.8 jmcneill for (child = OF_child(regulators_phandle); child; child = OF_peer(child)) { 815 1.8 jmcneill struct axp20xreg_attach_args reg = { .reg_phandle = child }; 816 1.21 thorpej config_found(sc->sc_dev, ®, NULL, CFARGS_NONE); 817 1.8 jmcneill } 818 1.7 jmcneill } 819