Module Name:    src
Committed By:   jmcneill
Date:           Sat May 26 14:39:20 UTC 2018

Modified Files:
        src/sys/dev/i2c: axppmic.c

Log Message:
Add battery voltage, charge current, and discharge current sensors for
AXP803.


To generate a diff of this commit:
cvs rdiff -u -r1.9 -r1.10 src/sys/dev/i2c/axppmic.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/i2c/axppmic.c
diff -u src/sys/dev/i2c/axppmic.c:1.9 src/sys/dev/i2c/axppmic.c:1.10
--- src/sys/dev/i2c/axppmic.c:1.9	Sun May 13 22:58:58 2018
+++ src/sys/dev/i2c/axppmic.c	Sat May 26 14:39:20 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: axppmic.c,v 1.9 2018/05/13 22:58:58 jmcneill Exp $ */
+/* $NetBSD: axppmic.c,v 1.10 2018/05/26 14:39:20 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2014-2018 Jared McNeill <jmcne...@invisible.ca>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: axppmic.c,v 1.9 2018/05/13 22:58:58 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: axppmic.c,v 1.10 2018/05/26 14:39:20 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -47,6 +47,7 @@ __KERNEL_RCSID(0, "$NetBSD: axppmic.c,v 
 #define	AXP_POWER_SOURCE_REG	0x00
 #define	 AXP_POWER_SOURCE_ACIN_PRESENT	__BIT(7)
 #define	 AXP_POWER_SOURCE_VBUS_PRESENT	__BIT(5)
+#define	 AXP_POWER_SOURCE_CHARGE_DIRECTION __BIT(2)
 
 #define	AXP_POWER_MODE_REG	0x01
 #define	 AXP_POWER_MODE_BATT_VALID	__BIT(4)
@@ -63,8 +64,21 @@ __KERNEL_RCSID(0, "$NetBSD: axppmic.c,v 
 #define	 AXP_IRQ1_VBUS_LOWER	__BIT(2)
 #define AXP_IRQ_STATUS_REG(n)	(0x48 + (n) - 1)
 
+#define	AXP_BATSENSE_HI_REG	0x78
+#define	AXP_BATSENSE_LO_REG	0x79
+
+#define	AXP_BATTCHG_HI_REG	0x7a
+#define	AXP_BATTCHG_LO_REG	0x7b
+
+#define	AXP_BATTDISCHG_HI_REG	0x7c
+#define	AXP_BATTDISCHG_LO_REG	0x7d
+
+#define	AXP_ADC_RAW(_hi, _lo)	\
+	(((u_int)(_hi) << 4) | ((lo) & 0xf))
+
 #define	AXP_FUEL_GAUGE_CTRL_REG	0xb8
 #define	 AXP_FUEL_GAUGE_CTRL_EN	__BIT(7)
+
 #define	AXP_BATT_CAP_REG	0xb9
 #define	 AXP_BATT_CAP_VALID	__BIT(7)
 #define	 AXP_BATT_CAP_PERCENT	__BITS(6,0)
@@ -198,6 +212,11 @@ struct axppmic_config {
 	struct axppmic_irq battirq;
 	struct axppmic_irq chargeirq;
 	struct axppmic_irq chargestirq;
+	u_int batsense_step;	/* uV */
+	u_int charge_step;	/* uA */
+	u_int discharge_step;	/* uA */
+	u_int maxcap_step;	/* uAh */
+	u_int coulomb_step;	/* uAh */
 };
 
 enum axppmic_sensor {
@@ -206,7 +225,10 @@ enum axppmic_sensor {
 	AXP_SENSOR_BATT_PRESENT,
 	AXP_SENSOR_BATT_CHARGING,
 	AXP_SENSOR_BATT_CHARGE_STATE,
-	AXP_SENSOR_BATT_CAPACITY,
+	AXP_SENSOR_BATT_VOLTAGE,
+	AXP_SENSOR_BATT_CHARGE_CURRENT,
+	AXP_SENSOR_BATT_DISCHARGE_CURRENT,
+	AXP_SENSOR_BATT_CAPACITY_PERCENT,
 	AXP_NSENSORS
 };
 
@@ -249,6 +271,9 @@ static const struct axppmic_config axp80
 	.irq_regs = 6,
 	.has_battery = true,
 	.has_fuel_gauge = true,
+	.batsense_step = 1100,
+	.charge_step = 1000,
+	.discharge_step = 1000,
 	.poklirq = AXPPMIC_IRQ(5, __BIT(3)),
 	.acinirq = AXPPMIC_IRQ(1, __BITS(6,5)),
 	.vbusirq = AXPPMIC_IRQ(1, __BITS(3,2)),
@@ -380,11 +405,16 @@ static void
 axppmic_sensor_update(struct sysmon_envsys *sme, envsys_data_t *e)
 {
 	struct axppmic_softc *sc = sme->sme_cookie;
+	const struct axppmic_config *c = sc->sc_conf;
 	const int flags = I2C_F_POLL;
-	uint8_t val;
+	uint8_t val, lo, hi;
 
 	e->state = ENVSYS_SINVALID;
 
+	const bool battery_present =
+	    sc->sc_sensor[AXP_SENSOR_BATT_PRESENT].state == ENVSYS_SVALID &&
+	    sc->sc_sensor[AXP_SENSOR_BATT_PRESENT].value_cur == 1;
+
 	switch (e->private) {
 	case AXP_SENSOR_ACIN_PRESENT:
 		if (axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_POWER_SOURCE_REG, &val, flags) == 0) {
@@ -413,9 +443,7 @@ axppmic_sensor_update(struct sysmon_envs
 		}
 		break;
 	case AXP_SENSOR_BATT_CHARGE_STATE:
-		if (axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_POWER_MODE_REG, &val, flags) == 0 &&
-		    (val & AXP_POWER_MODE_BATT_VALID) != 0 &&
-		    (val & AXP_POWER_MODE_BATT_PRESENT) != 0 &&
+		if (battery_present &&
 		    axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATT_CAP_REG, &val, flags) == 0 &&
 		    (val & AXP_BATT_CAP_VALID) != 0) {
 			const u_int batt_val = __SHIFTOUT(val, AXP_BATT_CAP_PERCENT);
@@ -431,16 +459,42 @@ axppmic_sensor_update(struct sysmon_envs
 			}
 		}
 		break;
-	case AXP_SENSOR_BATT_CAPACITY:
-		if (axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_POWER_MODE_REG, &val, flags) == 0 &&
-		    (val & AXP_POWER_MODE_BATT_VALID) != 0 &&
-		    (val & AXP_POWER_MODE_BATT_PRESENT) != 0 &&
+	case AXP_SENSOR_BATT_CAPACITY_PERCENT:
+		if (battery_present &&
 		    axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATT_CAP_REG, &val, flags) == 0 &&
 		    (val & AXP_BATT_CAP_VALID) != 0) {
 			e->state = ENVSYS_SVALID;
 			e->value_cur = __SHIFTOUT(val, AXP_BATT_CAP_PERCENT);
 		}
 		break;
+	case AXP_SENSOR_BATT_VOLTAGE:
+		if (battery_present &&
+		    axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATSENSE_HI_REG, &hi, flags) == 0 &&
+		    axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATSENSE_LO_REG, &lo, flags) == 0) {
+			e->state = ENVSYS_SVALID;
+			e->value_cur = AXP_ADC_RAW(hi, lo) * c->batsense_step;
+		}
+		break;
+	case AXP_SENSOR_BATT_CHARGE_CURRENT:
+		if (battery_present &&
+		    axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_POWER_SOURCE_REG, &val, flags) == 0 &&
+		    (val & AXP_POWER_SOURCE_CHARGE_DIRECTION) != 0 &&
+		    axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATTCHG_HI_REG, &hi, flags) == 0 &&
+		    axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATTCHG_LO_REG, &lo, flags) == 0) {
+			e->state = ENVSYS_SVALID;
+			e->value_cur = AXP_ADC_RAW(hi, lo) * c->charge_step;
+		}
+		break;
+	case AXP_SENSOR_BATT_DISCHARGE_CURRENT:
+		if (battery_present &&
+		    axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_POWER_SOURCE_REG, &val, flags) == 0 &&
+		    (val & AXP_POWER_SOURCE_CHARGE_DIRECTION) == 0 &&
+		    axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATTDISCHG_HI_REG, &hi, flags) == 0 &&
+		    axppmic_read(sc->sc_i2c, sc->sc_addr, AXP_BATTDISCHG_LO_REG, &lo, flags) == 0) {
+			e->state = ENVSYS_SVALID;
+			e->value_cur = AXP_ADC_RAW(hi, lo) * c->discharge_step;
+		}
+		break;
 	}
 }
 
@@ -451,8 +505,11 @@ axppmic_sensor_refresh(struct sysmon_env
 	const int flags = I2C_F_POLL;
 
 	switch (e->private) {
-	case AXP_SENSOR_BATT_CAPACITY:
-		/* Always update battery capacity (fuel gauge) */
+	case AXP_SENSOR_BATT_CAPACITY_PERCENT:
+	case AXP_SENSOR_BATT_VOLTAGE:
+	case AXP_SENSOR_BATT_CHARGE_CURRENT:
+	case AXP_SENSOR_BATT_DISCHARGE_CURRENT:
+		/* Always update battery capacity and ADCs */
 		iic_acquire_bus(sc->sc_i2c, flags);
 		axppmic_sensor_update(sme, e);
 		iic_release_bus(sc->sc_i2c, flags);
@@ -526,6 +583,7 @@ axppmic_attach_acadapter(struct axppmic_
 static void
 axppmic_attach_battery(struct axppmic_softc *sc)
 {
+	const struct axppmic_config *c = sc->sc_conf;
 	envsys_data_t *e;
 	uint8_t val;
 
@@ -559,9 +617,36 @@ axppmic_attach_battery(struct axppmic_so
 	strlcpy(e->desc, "charge state", sizeof(e->desc));
 	sysmon_envsys_sensor_attach(sc->sc_sme, e);
 
-	if (sc->sc_conf->has_fuel_gauge) {
-		e = &sc->sc_sensor[AXP_SENSOR_BATT_CAPACITY];
-		e->private = AXP_SENSOR_BATT_CAPACITY;
+	if (c->batsense_step) {
+		e = &sc->sc_sensor[AXP_SENSOR_BATT_VOLTAGE];
+		e->private = AXP_SENSOR_BATT_VOLTAGE;
+		e->units = ENVSYS_SVOLTS_DC;
+		e->state = ENVSYS_SINVALID;
+		strlcpy(e->desc, "battery voltage", sizeof(e->desc));
+		sysmon_envsys_sensor_attach(sc->sc_sme, e);
+	}
+
+	if (c->charge_step) {
+		e = &sc->sc_sensor[AXP_SENSOR_BATT_CHARGE_CURRENT];
+		e->private = AXP_SENSOR_BATT_CHARGE_CURRENT;
+		e->units = ENVSYS_SAMPS;
+		e->state = ENVSYS_SINVALID;
+		strlcpy(e->desc, "battery charge current", sizeof(e->desc));
+		sysmon_envsys_sensor_attach(sc->sc_sme, e);
+	}
+
+	if (c->discharge_step) {
+		e = &sc->sc_sensor[AXP_SENSOR_BATT_DISCHARGE_CURRENT];
+		e->private = AXP_SENSOR_BATT_DISCHARGE_CURRENT;
+		e->units = ENVSYS_SAMPS;
+		e->state = ENVSYS_SINVALID;
+		strlcpy(e->desc, "battery discharge current", sizeof(e->desc));
+		sysmon_envsys_sensor_attach(sc->sc_sme, e);
+	}
+
+	if (c->has_fuel_gauge) {
+		e = &sc->sc_sensor[AXP_SENSOR_BATT_CAPACITY_PERCENT];
+		e->private = AXP_SENSOR_BATT_CAPACITY_PERCENT;
 		e->units = ENVSYS_INTEGER;
 		e->state = ENVSYS_SINVALID;
 		e->flags = ENVSYS_FPERCENT;

Reply via email to