Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/i2c Implement sensor reports for power supplies (vol...



details:   https://anonhg.NetBSD.org/src/rev/8dbb8f7e29d2
branches:  trunk
changeset: 341047:8dbb8f7e29d2
user:      bouyer <bouyer%NetBSD.org@localhost>
date:      Thu Oct 15 13:41:11 2015 +0000

description:
Implement sensor reports for power supplies (voltage and intensities).
Implement a callback to change DCDC2 and DCDC3 voltages, so that
CPU management can change CPU core voltage when changing frequency.

diffstat:

 sys/dev/i2c/axp20x.c    |  486 +++++++++++++++++++++++++++++++++++++++++++++--
 sys/dev/i2c/axp20xvar.h |   35 +++
 2 files changed, 499 insertions(+), 22 deletions(-)

diffs (truncated from 597 to 300 lines):

diff -r 1d057490c779 -r 8dbb8f7e29d2 sys/dev/i2c/axp20x.c
--- a/sys/dev/i2c/axp20x.c      Thu Oct 15 13:35:30 2015 +0000
+++ b/sys/dev/i2c/axp20x.c      Thu Oct 15 13:41:11 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: axp20x.c,v 1.2 2014/09/09 23:39:16 jmcneill Exp $ */
+/* $NetBSD: axp20x.c,v 1.3 2015/10/15 13:41:11 bouyer Exp $ */
 
 /*-
  * Copyright (c) 2014 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: axp20x.c,v 1.2 2014/09/09 23:39:16 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: axp20x.c,v 1.3 2015/10/15 13:41:11 bouyer Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -37,25 +37,136 @@
 #include <sys/kmem.h>
 
 #include <dev/i2c/i2cvar.h>
+#include <dev/i2c/axp20xvar.h>
 
 #include <dev/sysmon/sysmonvar.h>
 
+#define AXP_INPUT_STATUS       0x00
+#define AXP_INPUT_STATUS_AC_PRESENT    __BIT(7)
+#define AXP_INPUT_STATUS_AC_OK         __BIT(6)
+#define AXP_INPUT_STATUS_VBUS_PRESENT  __BIT(5)
+#define AXP_INPUT_STATUS_VBUS_OK       __BIT(4)
+
+#define AXP_POWER_MODE         0x01
+#define AXP_POWER_MODE_OVERTEMP                __BIT(7)
+#define AXP_POWER_MODE_CHARGING                __BIT(6)
+#define AXP_POWER_MODE_BATTOK          __BIT(5)
+
+#define AXP_POWEROUT_CTRL      0x12
+#define AXP_POWEROUT_CTRL_LDO3         __BIT(6)
+#define AXP_POWEROUT_CTRL_DCDC2                __BIT(4)
+#define AXP_POWEROUT_CTRL_LDO4         __BIT(3)
+#define AXP_POWEROUT_CTRL_LDO2         __BIT(2)
+#define AXP_POWEROUT_CTRL_DCDC3                __BIT(1)
+#define AXP_POWEROUT_CTRL_EXTEN                __BIT(0)
+
+#define AXP_DCDC2              0x23
+#define AXP_DCDC2_VOLT_MASK            __BITS(0,5)
+#define AXP_DCDC2_VOLT_SHIFT           0
+
+#define AXP_DCDC2_LDO3_VRC     0x25
+
+#define AXP_DCDC3              0x27
+#define AXP_DCDC3_VOLT_MASK            __BITS(0,6)
+#define AXP_DCDC3_VOLT_SHIFT           0
+
+#define AXP_LDO2_4             0x28
+#define AXP_LDO2_VOLT_MASK             __BITS(4,7)
+#define AXP_LDO2_VOLT_SHIFT            4
+#define AXP_LDO4_VOLT_MASK             __BITS(0,3)
+#define AXP_LDO4_VOLT_SHIFT            0
+static int ldo4_mvV[] = {
+       1250,
+       1300,
+       1400,
+       1500,
+       1600,
+       1700,
+       1800,
+       1900,
+       2000,
+       2500,
+       2700,
+       2800,
+       3000,
+       3100,
+       3200,
+       3300
+};
+
+#define AXP_LDO3               0x29
+#define AXP_LDO3_TRACK                 __BIT(7)
+#define AXP_LDO3_VOLT_MASK             __BITS(0,6)
+#define AXP_LDO3_VOLT_SHIFT            0
+
+#define AXP_ACV_MON_REG                0x56    /* 2 bytes */
+#define AXP_ACI_MON_REG                0x58    /* 2 bytes */
+#define AXP_VBUSV_MON_REG      0x5a    /* 2 bytes */
+#define AXP_VBUSI_MON_REG      0x5c    /* 2 bytes */
 #define AXP_TEMP_MON_REG       0x5e    /* 2 bytes */
+#define AXP_BATTV_MON_REG      0x78    /* 2 bytes */
+#define AXP_BATTCI_MON_REG     0x7a    /* 2 bytes */
+#define AXP_BATTDI_MON_REG     0x7c    /* 2 bytes */
+#define AXP_APSV_MON_REG       0x7e    /* 2 bytes */
+
+#define AXP_ADC_EN1            0x82
+#define AXP_ADC_EN1_BATTV              __BIT(7)
+#define AXP_ADC_EN1_BATTI              __BIT(6)
+#define AXP_ADC_EN1_ACV                        __BIT(5)
+#define AXP_ADC_EN1_ACI                        __BIT(4)
+#define AXP_ADC_EN1_VBUSV              __BIT(3)
+#define AXP_ADC_EN1_VBUSI              __BIT(2)
+#define AXP_ADC_EN1_APSV               __BIT(1)
+#define AXP_ADC_EN1_TS                 __BIT(0)
+#define AXP_ADC_EN2            0x83
+#define AXP_ADC_EN2_TEMP               __BIT(7)
+
+#define AXP_SENSOR_ACOK                0
+#define AXP_SENSOR_ACV         1
+#define AXP_SENSOR_ACI         2
+#define AXP_SENSOR_VBUSOK      3
+#define AXP_SENSOR_VBUSV       4
+#define AXP_SENSOR_VBUSI       5
+#define AXP_SENSOR_BATTOK      6
+#define AXP_SENSOR_BATTV       7
+#define AXP_SENSOR_BATTI       8
+#define AXP_SENSOR_APSV                9
+#define AXP_SENSOR_TEMP                10
+#define AXP_NSENSORS (AXP_SENSOR_TEMP + 1)
+
+/* define per-ADC LSB to uV/uA values */
+static int axp20x_sensors_lsb[] = {
+          0, /* AXP_SENSOR_ACOK */
+       1700, /* AXP_SENSOR_ACV */
+        625, /* AXP_SENSOR_ACI */
+          0,
+       1700, /* AXP_SENSOR_VBUSV */
+        375, /* AXP_SENSOR_VBUSI */
+          0,
+       1100, /* AXP_SENSOR_BATTV */
+        500, /* AXP_SENSOR_BATTI */
+       1400, /* AXP_SENSOR_APSV */
+};
+
 
 struct axp20x_softc {
        device_t        sc_dev;
        i2c_tag_t       sc_i2c;
        i2c_addr_t      sc_addr;
 
+       uint8_t         sc_inputstatus;
+       uint8_t         sc_powermode;
+
        struct sysmon_envsys *sc_sme;
-       envsys_data_t   sc_sensor_temp;
+       envsys_data_t   sc_sensor[AXP_NSENSORS];
 };
 
 static int     axp20x_match(device_t, cfdata_t, void *);
 static void    axp20x_attach(device_t, device_t, void *);
 
 static void    axp20x_sensors_refresh(struct sysmon_envsys *, envsys_data_t *);
-static int     axp20x_read(struct axp20x_softc *, uint8_t, uint8_t *, size_t);
+static int     axp20x_read(struct axp20x_softc *, uint8_t, uint8_t *, size_t, int);
+static int     axp20x_write(struct axp20x_softc *, uint8_t, uint8_t *, size_t, int);
 
 CFATTACH_DECL_NEW(axp20x, sizeof(struct axp20x_softc),
     axp20x_match, axp20x_attach, NULL, NULL);
@@ -71,12 +182,65 @@
 {
        struct axp20x_softc *sc = device_private(self);
        struct i2c_attach_args *ia = aux;
+       int first;
+       int error;
+       uint8_t value;
 
        sc->sc_dev = self;
        sc->sc_i2c = ia->ia_tag;
        sc->sc_addr = ia->ia_addr;
 
+       error = axp20x_read(sc, AXP_INPUT_STATUS,
+           &sc->sc_inputstatus, 1, I2C_F_POLL);
+       if (error) {
+               aprint_error(": can't read status: %d\n", error);
+               return;
+       }
+       error = axp20x_read(sc, AXP_POWER_MODE,
+           &sc->sc_powermode, 1, I2C_F_POLL);
+       if (error) {
+               aprint_error(": can't read power mode: %d\n", error);
+               return;
+       }
+       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;
+       if (sc->sc_powermode & AXP_POWER_MODE_BATTOK)
+               value |= AXP_ADC_EN1_BATTV | AXP_ADC_EN1_BATTI;
+       error = axp20x_write(sc, AXP_ADC_EN1, &value, 1, I2C_F_POLL);
+       if (error) {
+               aprint_error(": can't set AXP_ADC_EN1\n");
+               return;
+       }
+       error = axp20x_read(sc, AXP_ADC_EN2, &value, 1, I2C_F_POLL);
+       if (error) {
+               aprint_error(": can't read AXP_ADC_EN2\n");
+               return;
+       }
+       value |= AXP_ADC_EN2_TEMP;
+       error = axp20x_write(sc, AXP_ADC_EN2, &value, 1, I2C_F_POLL);
+       if (error) {
+               aprint_error(": can't set AXP_ADC_EN2\n");
+               return;
+       }
+
        aprint_naive("\n");
+       first = 1;
+       if (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK) {
+               aprint_normal(": AC used");
+               first = 0;
+       } else if (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_PRESENT) {
+               aprint_normal(": AC present (but unused)");
+               first = 0;
+       }
+       if (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK) {
+               aprint_normal("%s VBUS used", first ? ":" : ",");
+               first = 0;
+       } else if (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_PRESENT) {
+               aprint_normal("%s VBUS present (but unused)", first ? ":" : ",");
+               first = 0;
+       }
+       if (sc->sc_powermode & AXP_POWER_MODE_BATTOK) {
+               aprint_normal("%s battery present", first ? ":" : ",");
+       }
        aprint_normal("\n");
 
        sc->sc_sme = sysmon_envsys_create();
@@ -84,14 +248,139 @@
        sc->sc_sme->sme_cookie = sc;
        sc->sc_sme->sme_refresh = axp20x_sensors_refresh;
 
-       sc->sc_sensor_temp.units = ENVSYS_STEMP;
-       sc->sc_sensor_temp.state = ENVSYS_SINVALID;
-       sc->sc_sensor_temp.flags = ENVSYS_FHAS_ENTROPY;
-       snprintf(sc->sc_sensor_temp.desc, sizeof(sc->sc_sensor_temp.desc),
+       sc->sc_sensor[AXP_SENSOR_ACOK].units = ENVSYS_INDICATOR;
+       sc->sc_sensor[AXP_SENSOR_ACOK].state = ENVSYS_SVALID;
+       sc->sc_sensor[AXP_SENSOR_ACOK].value_cur =
+           (sc->sc_inputstatus & AXP_INPUT_STATUS_AC_OK) ? 1 : 0;
+       snprintf(sc->sc_sensor[AXP_SENSOR_ACOK].desc,
+           sizeof(sc->sc_sensor[AXP_SENSOR_ACOK].desc), "AC input");
+       sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_ACOK]);
+       sc->sc_sensor[AXP_SENSOR_ACV].units = ENVSYS_SVOLTS_DC;
+       sc->sc_sensor[AXP_SENSOR_ACV].state = ENVSYS_SINVALID;
+       sc->sc_sensor[AXP_SENSOR_ACV].flags = ENVSYS_FHAS_ENTROPY;
+       snprintf(sc->sc_sensor[AXP_SENSOR_ACV].desc,
+           sizeof(sc->sc_sensor[AXP_SENSOR_ACV].desc), "AC input voltage");
+       sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_ACV]);
+       sc->sc_sensor[AXP_SENSOR_ACI].units = ENVSYS_SAMPS;
+       sc->sc_sensor[AXP_SENSOR_ACI].state = ENVSYS_SINVALID;
+       sc->sc_sensor[AXP_SENSOR_ACI].flags = ENVSYS_FHAS_ENTROPY;
+       snprintf(sc->sc_sensor[AXP_SENSOR_ACI].desc,
+           sizeof(sc->sc_sensor[AXP_SENSOR_ACI].desc), "AC input current");
+       sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_ACI]);
+
+       sc->sc_sensor[AXP_SENSOR_VBUSOK].units = ENVSYS_INDICATOR;
+       sc->sc_sensor[AXP_SENSOR_VBUSOK].state = ENVSYS_SVALID;
+       sc->sc_sensor[AXP_SENSOR_VBUSOK].value_cur =
+           (sc->sc_inputstatus & AXP_INPUT_STATUS_VBUS_OK) ? 1 : 0;
+       snprintf(sc->sc_sensor[AXP_SENSOR_VBUSOK].desc,
+           sizeof(sc->sc_sensor[AXP_SENSOR_VBUSOK].desc), "VBUS input");
+       sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_VBUSOK]);
+       sc->sc_sensor[AXP_SENSOR_VBUSV].units = ENVSYS_SVOLTS_DC;
+       sc->sc_sensor[AXP_SENSOR_VBUSV].state = ENVSYS_SINVALID;
+       sc->sc_sensor[AXP_SENSOR_VBUSV].flags = ENVSYS_FHAS_ENTROPY;
+       snprintf(sc->sc_sensor[AXP_SENSOR_VBUSV].desc,
+           sizeof(sc->sc_sensor[AXP_SENSOR_VBUSV].desc), "VBUS input voltage");
+       sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_VBUSV]);
+       sc->sc_sensor[AXP_SENSOR_VBUSI].units = ENVSYS_SAMPS;
+       sc->sc_sensor[AXP_SENSOR_VBUSI].state = ENVSYS_SINVALID;
+       sc->sc_sensor[AXP_SENSOR_VBUSI].flags = ENVSYS_FHAS_ENTROPY;
+       snprintf(sc->sc_sensor[AXP_SENSOR_VBUSI].desc,
+           sizeof(sc->sc_sensor[AXP_SENSOR_VBUSI].desc), "VBUS input current");
+       sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_VBUSI]);
+
+       sc->sc_sensor[AXP_SENSOR_BATTOK].units = ENVSYS_INDICATOR;
+       sc->sc_sensor[AXP_SENSOR_BATTOK].state = ENVSYS_SVALID;
+       sc->sc_sensor[AXP_SENSOR_BATTOK].value_cur =
+           (sc->sc_powermode & AXP_POWER_MODE_BATTOK) ? 1 : 0;
+       snprintf(sc->sc_sensor[AXP_SENSOR_BATTOK].desc,
+           sizeof(sc->sc_sensor[AXP_SENSOR_BATTOK].desc), "battery");
+       sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_BATTOK]);
+       sc->sc_sensor[AXP_SENSOR_BATTV].units = ENVSYS_SVOLTS_DC;
+       sc->sc_sensor[AXP_SENSOR_BATTV].state = ENVSYS_SINVALID;
+       sc->sc_sensor[AXP_SENSOR_BATTV].flags = ENVSYS_FHAS_ENTROPY;
+       snprintf(sc->sc_sensor[AXP_SENSOR_BATTV].desc,
+           sizeof(sc->sc_sensor[AXP_SENSOR_BATTV].desc), "battery voltage");
+       sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_BATTV]);
+       sc->sc_sensor[AXP_SENSOR_BATTI].units = ENVSYS_SAMPS;
+       sc->sc_sensor[AXP_SENSOR_BATTI].state = ENVSYS_SINVALID;
+       sc->sc_sensor[AXP_SENSOR_BATTI].flags = ENVSYS_FHAS_ENTROPY;
+       snprintf(sc->sc_sensor[AXP_SENSOR_BATTI].desc,
+           sizeof(sc->sc_sensor[AXP_SENSOR_BATTI].desc), "battery current");
+       sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_BATTI]);
+
+       sc->sc_sensor[AXP_SENSOR_APSV].units = ENVSYS_SVOLTS_DC;
+       sc->sc_sensor[AXP_SENSOR_APSV].state = ENVSYS_SINVALID;
+       sc->sc_sensor[AXP_SENSOR_APSV].flags = ENVSYS_FHAS_ENTROPY;
+       snprintf(sc->sc_sensor[AXP_SENSOR_APSV].desc,
+           sizeof(sc->sc_sensor[AXP_SENSOR_APSV].desc), "APS output voltage");
+       sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[AXP_SENSOR_APSV]);
+       sc->sc_sensor[AXP_SENSOR_TEMP].units = ENVSYS_STEMP;
+       sc->sc_sensor[AXP_SENSOR_TEMP].state = ENVSYS_SINVALID;
+       sc->sc_sensor[AXP_SENSOR_TEMP].flags = ENVSYS_FHAS_ENTROPY;



Home | Main Index | Thread Index | Old Index