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 ®, 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 ®, 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, ®, 1); 607 if (ret) 608 return ret; 609 if (axp20x_read(sc, AXP_DCDC2, ®, 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, ®, 1); 622 if (ret) 623 return ret; 624 if (axp20x_read(sc, AXP_DCDC3, ®, 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, ®, 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, ®, 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, ®, 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, ®, NULL, CFARGS_NONE); 817 } 818} 819