svn commit: r351149 - stable/12/sys/arm/allwinner

Emmanuel Vadot manu at FreeBSD.org
Fri Aug 16 21:40:39 UTC 2019


Author: manu
Date: Fri Aug 16 21:40:39 2019
New Revision: 351149
URL: https://svnweb.freebsd.org/changeset/base/351149

Log:
  MFC r343952, r344003, r344219, r344343, r344456
  
  r343952 by ganbold:
  Enable necessary bits when activating interrupts. This allows
  reading some events from the interrupt status registers. These events
  are reported to devd via system "PMU" and subsystem "Battery", "AC"
  and "USB" such as plugged/unplugged, absent, charged and charging.
  
  Reviewed by:	manu
  Differential Revision:	https://reviews.freebsd.org/D19116
  
  r344003 by ganbold:
  Add sensors support for AXP803/AXP813. Sensor values such as
  battery charging, charge state, voltage, charging current, discharging current,
  battery capacity etc. can be obtained via sysctl.
  
  Reviewed by:	manu
  Differential Revision:	https://reviews.freebsd.org/D19145
  
  r344219 by ganbold:
  Add sysctl for setting battery charging current.
  The charging current can be set using steps
  from 0: 200mA to 13: 2800mA (200mA/step).
  While there, fix battery charging current related
  sensor descriptions.
  
  Reviewed by:	manu
  Differential Revision:	https://reviews.freebsd.org/D19212
  
  r344343 by ganbold:
  Clarify notifications when battery capacity ratio
  reaches warning and shutdown thresholds.
  
  r344456 by ganbold:
  Add base to the warning threshold.

Modified:
  stable/12/sys/arm/allwinner/axp81x.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/arm/allwinner/axp81x.c
==============================================================================
--- stable/12/sys/arm/allwinner/axp81x.c	Fri Aug 16 21:36:13 2019	(r351148)
+++ stable/12/sys/arm/allwinner/axp81x.c	Fri Aug 16 21:40:39 2019	(r351149)
@@ -65,9 +65,13 @@ MALLOC_DEFINE(M_AXP8XX_REG, "AXP8xx regulator", "AXP8x
 #define	 AXP_POWERSRC_ACIN	(1 << 7)
 #define	 AXP_POWERSRC_VBUS	(1 << 5)
 #define	 AXP_POWERSRC_VBAT	(1 << 3)
-#define	 AXP_POWERSRC_CHARING	(1 << 2)
+#define	 AXP_POWERSRC_CHARING	(1 << 2)	/* Charging Direction */
 #define	 AXP_POWERSRC_SHORTED	(1 << 1)
 #define	 AXP_POWERSRC_STARTUP	(1 << 0)
+#define	AXP_POWERMODE		0x01
+#define	 AXP_POWERMODE_BAT_CHARGING	(1 << 6)
+#define	 AXP_POWERMODE_BAT_PRESENT	(1 << 5)
+#define	 AXP_POWERMODE_BAT_VALID	(1 << 4)
 #define	AXP_ICTYPE		0x03
 #define	AXP_POWERCTL1		0x10
 #define	 AXP_POWERCTL1_DCDC7	(1 << 6)	/* AXP813/818 only */
@@ -116,15 +120,52 @@ MALLOC_DEFINE(M_AXP8XX_REG, "AXP8xx regulator", "AXP8x
 #define	 AXP_VOLTCTL_MASK	0x7f
 #define	AXP_POWERBAT		0x32
 #define	 AXP_POWERBAT_SHUTDOWN	(1 << 7)
+#define	AXP_CHARGERCTL1		0x33
+#define	 AXP_CHARGERCTL1_MIN	0
+#define	 AXP_CHARGERCTL1_MAX	13
+#define	 AXP_CHARGERCTL1_CMASK	0xf
 #define	AXP_IRQEN1		0x40
+#define	 AXP_IRQEN1_ACIN_HI	(1 << 6)
+#define	 AXP_IRQEN1_ACIN_LO	(1 << 5)
+#define	 AXP_IRQEN1_VBUS_HI	(1 << 3)
+#define	 AXP_IRQEN1_VBUS_LO	(1 << 2)
 #define	AXP_IRQEN2		0x41
+#define	 AXP_IRQEN2_BAT_IN	(1 << 7)
+#define	 AXP_IRQEN2_BAT_NO	(1 << 6)
+#define	 AXP_IRQEN2_BATCHGC	(1 << 3)
+#define	 AXP_IRQEN2_BATCHGD	(1 << 2)
 #define	AXP_IRQEN3		0x42
 #define	AXP_IRQEN4		0x43
+#define	 AXP_IRQEN4_BATLVL_LO1	(1 << 1)
+#define	 AXP_IRQEN4_BATLVL_LO0	(1 << 0)
 #define	AXP_IRQEN5		0x44
 #define	 AXP_IRQEN5_POKSIRQ	(1 << 4)
+#define	 AXP_IRQEN5_POKLIRQ	(1 << 3)
 #define	AXP_IRQEN6		0x45
+#define	AXP_IRQSTAT1		0x48
+#define	 AXP_IRQSTAT1_ACIN_HI	(1 << 6)
+#define	 AXP_IRQSTAT1_ACIN_LO	(1 << 5)
+#define	 AXP_IRQSTAT1_VBUS_HI	(1 << 3)
+#define	 AXP_IRQSTAT1_VBUS_LO	(1 << 2)
+#define	AXP_IRQSTAT2		0x49
+#define	 AXP_IRQSTAT2_BAT_IN	(1 << 7)
+#define	 AXP_IRQSTAT2_BAT_NO	(1 << 6)
+#define	 AXP_IRQSTAT2_BATCHGC	(1 << 3)
+#define	 AXP_IRQSTAT2_BATCHGD	(1 << 2)
+#define	AXP_IRQSTAT3		0x4a
+#define	AXP_IRQSTAT4		0x4b
+#define	 AXP_IRQSTAT4_BATLVL_LO1	(1 << 1)
+#define	 AXP_IRQSTAT4_BATLVL_LO0	(1 << 0)
 #define	AXP_IRQSTAT5		0x4c
 #define	 AXP_IRQSTAT5_POKSIRQ	(1 << 4)
+#define	 AXP_IRQEN5_POKLIRQ	(1 << 3)
+#define	AXP_IRQSTAT6		0x4d
+#define	AXP_BATSENSE_HI		0x78
+#define	AXP_BATSENSE_LO		0x79
+#define	AXP_BATCHG_HI		0x7a
+#define	AXP_BATCHG_LO		0x7b
+#define	AXP_BATDISCHG_HI	0x7c
+#define	AXP_BATDISCHG_LO	0x7d
 #define	AXP_GPIO0_CTRL		0x90
 #define	AXP_GPIO0LDO_CTRL	0x91
 #define	AXP_GPIO1_CTRL		0x92
@@ -138,7 +179,31 @@ MALLOC_DEFINE(M_AXP8XX_REG, "AXP8xx regulator", "AXP8x
 #define	 AXP_GPIO_FUNC_LDO_OFF	4
 #define	AXP_GPIO_SIGBIT		0x94
 #define	AXP_GPIO_PD		0x97
+#define	AXP_FUEL_GAUGECTL	0xb8
+#define	 AXP_FUEL_GAUGECTL_EN	(1 << 7)
 
+#define	AXP_BAT_CAP		0xb9
+#define	 AXP_BAT_CAP_VALID	(1 << 7)
+#define	 AXP_BAT_CAP_PERCENT	0x7f
+
+#define	AXP_BAT_MAX_CAP_HI	0xe0
+#define	 AXP_BAT_MAX_CAP_VALID	(1 << 7)
+#define	AXP_BAT_MAX_CAP_LO	0xe1
+
+#define	AXP_BAT_COULOMB_HI	0xe2
+#define	 AXP_BAT_COULOMB_VALID	(1 << 7)
+#define	AXP_BAT_COULOMB_LO	0xe3
+
+#define	AXP_BAT_CAP_WARN	0xe6
+#define	 AXP_BAT_CAP_WARN_LV1		0xf0	/* Bits 4, 5, 6, 7 */
+#define	 AXP_BAP_CAP_WARN_LV1BASE	5	/* 5-20%, 1% per step */
+#define	 AXP_BAT_CAP_WARN_LV2		0xf	/* Bits 0, 1, 2, 3 */
+
+/* Sensor conversion macros */
+#define	AXP_SENSOR_BAT_H(hi)		((hi) << 4)
+#define	AXP_SENSOR_BAT_L(lo)		((lo) & 0xf)
+#define	AXP_SENSOR_COULOMB(hi, lo)	(((hi & ~(1 << 7)) << 8) | (lo))
+
 static const struct {
 	const char *name;
 	uint8_t	ctrl_reg;
@@ -483,6 +548,123 @@ static struct axp8xx_regdef axp8xx_common_regdefs[] = 
 	},
 };
 
+enum axp8xx_sensor {
+	AXP_SENSOR_ACIN_PRESENT,
+	AXP_SENSOR_VBUS_PRESENT,
+	AXP_SENSOR_BATT_PRESENT,
+	AXP_SENSOR_BATT_CHARGING,
+	AXP_SENSOR_BATT_CHARGE_STATE,
+	AXP_SENSOR_BATT_VOLTAGE,
+	AXP_SENSOR_BATT_CHARGE_CURRENT,
+	AXP_SENSOR_BATT_DISCHARGE_CURRENT,
+	AXP_SENSOR_BATT_CAPACITY_PERCENT,
+	AXP_SENSOR_BATT_MAXIMUM_CAPACITY,
+	AXP_SENSOR_BATT_CURRENT_CAPACITY,
+};
+
+enum battery_capacity_state {
+	BATT_CAPACITY_NORMAL = 1,	/* normal cap in battery */
+	BATT_CAPACITY_WARNING,		/* warning cap in battery */
+	BATT_CAPACITY_CRITICAL,		/* critical cap in battery */
+	BATT_CAPACITY_HIGH,		/* high cap in battery */
+	BATT_CAPACITY_MAX,		/* maximum cap in battery */
+	BATT_CAPACITY_LOW		/* low cap in battery */
+};
+
+struct axp8xx_sensors {
+	int             id;
+	const char      *name;
+	const char      *desc;
+	const char      *format;
+};
+
+static const struct axp8xx_sensors axp8xx_common_sensors[] = {
+	{
+		.id = AXP_SENSOR_ACIN_PRESENT,
+		.name = "acin",
+		.format = "I",
+		.desc = "ACIN Present",
+	},
+	{
+		.id = AXP_SENSOR_VBUS_PRESENT,
+		.name = "vbus",
+		.format = "I",
+		.desc = "VBUS Present",
+	},
+	{
+		.id = AXP_SENSOR_BATT_PRESENT,
+		.name = "bat",
+		.format = "I",
+		.desc = "Battery Present",
+	},
+	{
+		.id = AXP_SENSOR_BATT_CHARGING,
+		.name = "batcharging",
+		.format = "I",
+		.desc = "Battery Charging",
+	},
+	{
+		.id = AXP_SENSOR_BATT_CHARGE_STATE,
+		.name = "batchargestate",
+		.format = "I",
+		.desc = "Battery Charge State",
+	},
+	{
+		.id = AXP_SENSOR_BATT_VOLTAGE,
+		.name = "batvolt",
+		.format = "I",
+		.desc = "Battery Voltage",
+	},
+	{
+		.id = AXP_SENSOR_BATT_CHARGE_CURRENT,
+		.name = "batchargecurrent",
+		.format = "I",
+		.desc = "Average Battery Charging Current",
+	},
+	{
+		.id = AXP_SENSOR_BATT_DISCHARGE_CURRENT,
+		.name = "batdischargecurrent",
+		.format = "I",
+		.desc = "Average Battery Discharging Current",
+	},
+	{
+		.id = AXP_SENSOR_BATT_CAPACITY_PERCENT,
+		.name = "batcapacitypercent",
+		.format = "I",
+		.desc = "Battery Capacity Percentage",
+	},
+	{
+		.id = AXP_SENSOR_BATT_MAXIMUM_CAPACITY,
+		.name = "batmaxcapacity",
+		.format = "I",
+		.desc = "Battery Maximum Capacity",
+	},
+	{
+		.id = AXP_SENSOR_BATT_CURRENT_CAPACITY,
+		.name = "batcurrentcapacity",
+		.format = "I",
+		.desc = "Battery Current Capacity",
+	},
+};
+
+struct axp8xx_config {
+	const char		*name;
+	int			batsense_step;  /* uV */
+	int			charge_step;    /* uA */
+	int			discharge_step; /* uA */
+	int			maxcap_step;    /* uAh */
+	int			coulomb_step;   /* uAh */
+};
+
+static struct axp8xx_config axp803_config = {
+	.name = "AXP803",
+	.batsense_step = 1100,
+	.charge_step = 1000,
+	.discharge_step = 1000,
+	.maxcap_step = 1456,
+	.coulomb_step = 1456,
+};
+
 struct axp8xx_softc;
 
 struct axp8xx_reg_sc {
@@ -503,9 +685,20 @@ struct axp8xx_softc {
 
 	int			type;
 
+	/* Configs */
+	const struct axp8xx_config	*config;
+
+	/* Sensors */
+	const struct axp8xx_sensors	*sensors;
+	int				nsensors;
+
 	/* Regulators */
 	struct axp8xx_reg_sc	**regs;
 	int			nregs;
+
+	/* Warning, shutdown thresholds */
+	int			warn_thres;
+	int			shut_thres;
 };
 
 #define	AXP_LOCK(sc)	mtx_lock(&(sc)->mtx)
@@ -701,6 +894,137 @@ axp8xx_shutdown(void *devp, int howto)
 	axp8xx_write(dev, AXP_POWERBAT, AXP_POWERBAT_SHUTDOWN);
 }
 
+static int
+axp8xx_sysctl_chargecurrent(SYSCTL_HANDLER_ARGS)
+{
+	device_t dev = arg1;
+	uint8_t data;
+	int val, error;
+
+	error = axp8xx_read(dev, AXP_CHARGERCTL1, &data, 1);
+	if (error != 0)
+		return (error);
+
+	if (bootverbose)
+		device_printf(dev, "Raw CHARGECTL1 val: 0x%0x\n", data);
+	val = (data & AXP_CHARGERCTL1_CMASK);
+	error = sysctl_handle_int(oidp, &val, 0, req);
+	if (error || !req->newptr) /* error || read request */
+		return (error);
+
+	if ((val < AXP_CHARGERCTL1_MIN) || (val > AXP_CHARGERCTL1_MAX))
+		return (EINVAL);
+
+	val |= (data & (AXP_CHARGERCTL1_CMASK << 4));
+	axp8xx_write(dev, AXP_CHARGERCTL1, val);
+
+	return (0);
+}
+
+static int
+axp8xx_sysctl(SYSCTL_HANDLER_ARGS)
+{
+	struct axp8xx_softc *sc;
+	device_t dev = arg1;
+	enum axp8xx_sensor sensor = arg2;
+	const struct axp8xx_config *c;
+	uint8_t data;
+	int val, i, found, batt_val;
+	uint8_t lo, hi;
+
+	sc = device_get_softc(dev);
+	c = sc->config;
+
+	for (found = 0, i = 0; i < sc->nsensors; i++) {
+		if (sc->sensors[i].id == sensor) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (found == 0)
+		return (ENOENT);
+
+	switch (sensor) {
+	case AXP_SENSOR_ACIN_PRESENT:
+		if (axp8xx_read(dev, AXP_POWERSRC, &data, 1) == 0)
+			val = !!(data & AXP_POWERSRC_ACIN);
+		break;
+	case AXP_SENSOR_VBUS_PRESENT:
+		if (axp8xx_read(dev, AXP_POWERSRC, &data, 1) == 0)
+			val = !!(data & AXP_POWERSRC_VBUS);
+		break;
+	case AXP_SENSOR_BATT_PRESENT:
+		if (axp8xx_read(dev, AXP_POWERMODE, &data, 1) == 0) {
+			if (data & AXP_POWERMODE_BAT_VALID)
+				val = !!(data & AXP_POWERMODE_BAT_PRESENT);
+		}
+		break;
+	case AXP_SENSOR_BATT_CHARGING:
+		if (axp8xx_read(dev, AXP_POWERMODE, &data, 1) == 0)
+			val = !!(data & AXP_POWERMODE_BAT_CHARGING);
+		break;
+	case AXP_SENSOR_BATT_CHARGE_STATE:
+		if (axp8xx_read(dev, AXP_BAT_CAP, &data, 1) == 0 &&
+		    (data & AXP_BAT_CAP_VALID) != 0) {
+			batt_val = (data & AXP_BAT_CAP_PERCENT);
+			if (batt_val <= sc->shut_thres)
+				val = BATT_CAPACITY_CRITICAL;
+			else if (batt_val <= sc->warn_thres)
+				val = BATT_CAPACITY_WARNING;
+			else
+				val = BATT_CAPACITY_NORMAL;
+		}
+		break;
+	case AXP_SENSOR_BATT_CAPACITY_PERCENT:
+		if (axp8xx_read(dev, AXP_BAT_CAP, &data, 1) == 0 &&
+		    (data & AXP_BAT_CAP_VALID) != 0)
+			val = (data & AXP_BAT_CAP_PERCENT);
+		break;
+	case AXP_SENSOR_BATT_VOLTAGE:
+		if (axp8xx_read(dev, AXP_BATSENSE_HI, &hi, 1) == 0 &&
+		    axp8xx_read(dev, AXP_BATSENSE_LO, &lo, 1) == 0) {
+			val = (AXP_SENSOR_BAT_H(hi) | AXP_SENSOR_BAT_L(lo));
+			val *= c->batsense_step;
+		}
+		break;
+	case AXP_SENSOR_BATT_CHARGE_CURRENT:
+		if (axp8xx_read(dev, AXP_POWERSRC, &data, 1) == 0 &&
+		    (data & AXP_POWERSRC_CHARING) != 0 &&
+		    axp8xx_read(dev, AXP_BATCHG_HI, &hi, 1) == 0 &&
+		    axp8xx_read(dev, AXP_BATCHG_LO, &lo, 1) == 0) {
+			val = (AXP_SENSOR_BAT_H(hi) | AXP_SENSOR_BAT_L(lo));
+			val *= c->charge_step;
+		}
+		break;
+	case AXP_SENSOR_BATT_DISCHARGE_CURRENT:
+		if (axp8xx_read(dev, AXP_POWERSRC, &data, 1) == 0 &&
+		    (data & AXP_POWERSRC_CHARING) == 0 &&
+		    axp8xx_read(dev, AXP_BATDISCHG_HI, &hi, 1) == 0 &&
+		    axp8xx_read(dev, AXP_BATDISCHG_LO, &lo, 1) == 0) {
+			val = (AXP_SENSOR_BAT_H(hi) | AXP_SENSOR_BAT_L(lo));
+			val *= c->discharge_step;
+		}
+		break;
+	case AXP_SENSOR_BATT_MAXIMUM_CAPACITY:
+		if (axp8xx_read(dev, AXP_BAT_MAX_CAP_HI, &hi, 1) == 0 &&
+		    axp8xx_read(dev, AXP_BAT_MAX_CAP_LO, &lo, 1) == 0) {
+			val = AXP_SENSOR_COULOMB(hi, lo);
+			val *= c->maxcap_step;
+		}
+		break;
+	case AXP_SENSOR_BATT_CURRENT_CAPACITY:
+		if (axp8xx_read(dev, AXP_BAT_COULOMB_HI, &hi, 1) == 0 &&
+		    axp8xx_read(dev, AXP_BAT_COULOMB_LO, &lo, 1) == 0) {
+			val = AXP_SENSOR_COULOMB(hi, lo);
+			val *= c->coulomb_step;
+		}
+		break;
+	}
+
+	return sysctl_handle_opaque(oidp, &val, sizeof(val), req);
+}
+
 static void
 axp8xx_intr(void *arg)
 {
@@ -710,6 +1034,68 @@ axp8xx_intr(void *arg)
 
 	dev = arg;
 
+	error = axp8xx_read(dev, AXP_IRQSTAT1, &val, 1);
+	if (error != 0)
+		return;
+
+	if (val) {
+		if (bootverbose)
+			device_printf(dev, "AXP_IRQSTAT1 val: %x\n", val);
+		if (val & AXP_IRQSTAT1_ACIN_HI)
+			devctl_notify("PMU", "AC", "plugged", NULL);
+		if (val & AXP_IRQSTAT1_ACIN_LO)
+			devctl_notify("PMU", "AC", "unplugged", NULL);
+		if (val & AXP_IRQSTAT1_VBUS_HI)
+			devctl_notify("PMU", "USB", "plugged", NULL);
+		if (val & AXP_IRQSTAT1_VBUS_LO)
+			devctl_notify("PMU", "USB", "unplugged", NULL);
+		/* Acknowledge */
+		axp8xx_write(dev, AXP_IRQSTAT1, val);
+	}
+
+	error = axp8xx_read(dev, AXP_IRQSTAT2, &val, 1);
+	if (error != 0)
+		return;
+
+	if (val) {
+		if (bootverbose)
+			device_printf(dev, "AXP_IRQSTAT2 val: %x\n", val);
+		if (val & AXP_IRQSTAT2_BATCHGD)
+			devctl_notify("PMU", "Battery", "charged", NULL);
+		if (val & AXP_IRQSTAT2_BATCHGC)
+			devctl_notify("PMU", "Battery", "charging", NULL);
+		if (val & AXP_IRQSTAT2_BAT_NO)
+			devctl_notify("PMU", "Battery", "absent", NULL);
+		if (val & AXP_IRQSTAT2_BAT_IN)
+			devctl_notify("PMU", "Battery", "plugged", NULL);
+		/* Acknowledge */
+		axp8xx_write(dev, AXP_IRQSTAT2, val);
+	}
+
+	error = axp8xx_read(dev, AXP_IRQSTAT3, &val, 1);
+	if (error != 0)
+		return;
+
+	if (val) {
+		/* Acknowledge */
+		axp8xx_write(dev, AXP_IRQSTAT3, val);
+	}
+
+	error = axp8xx_read(dev, AXP_IRQSTAT4, &val, 1);
+	if (error != 0)
+		return;
+
+	if (val) {
+		if (bootverbose)
+			device_printf(dev, "AXP_IRQSTAT4 val: %x\n", val);
+		if (val & AXP_IRQSTAT4_BATLVL_LO0)
+			devctl_notify("PMU", "Battery", "shutdown threshold", NULL);
+		if (val & AXP_IRQSTAT4_BATLVL_LO1)
+			devctl_notify("PMU", "Battery", "warning threshold", NULL);
+		/* Acknowledge */
+		axp8xx_write(dev, AXP_IRQSTAT4, val);
+	}
+
 	error = axp8xx_read(dev, AXP_IRQSTAT5, &val, 1);
 	if (error != 0)
 		return;
@@ -723,6 +1109,15 @@ axp8xx_intr(void *arg)
 		/* Acknowledge */
 		axp8xx_write(dev, AXP_IRQSTAT5, val);
 	}
+
+	error = axp8xx_read(dev, AXP_IRQSTAT6, &val, 1);
+	if (error != 0)
+		return;
+
+	if (val) {
+		/* Acknowledge */
+		axp8xx_write(dev, AXP_IRQSTAT6, val);
+	}
 }
 
 static device_t
@@ -1031,7 +1426,7 @@ axp8xx_attach(device_t dev)
 {
 	struct axp8xx_softc *sc;
 	struct axp8xx_reg_sc *reg;
-	uint8_t chip_id;
+	uint8_t chip_id, val;
 	phandle_t rnode, child;
 	int error, i;
 
@@ -1061,6 +1456,10 @@ axp8xx_attach(device_t dev)
 		sc->nregs += nitems(axp813_regdefs);
 		break;
 	}
+	sc->config = &axp803_config;
+	sc->sensors = axp8xx_common_sensors;
+	sc->nsensors = nitems(axp8xx_common_sensors);
+
 	sc->regs = malloc(sizeof(struct axp8xx_reg_sc *) * sc->nregs,
 	    M_AXP8XX_REG, M_WAITOK | M_ZERO);
 
@@ -1105,12 +1504,60 @@ axp8xx_attach(device_t dev)
 		}
 	}
 
-	/* Enable IRQ on short power key press */
-	axp8xx_write(dev, AXP_IRQEN1, 0);
-	axp8xx_write(dev, AXP_IRQEN2, 0);
+	/* Add sensors */
+	for (i = 0; i < sc->nsensors; i++) {
+		SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+		    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+		    OID_AUTO, sc->sensors[i].name,
+		    CTLTYPE_INT | CTLFLAG_RD,
+		    dev, sc->sensors[i].id, axp8xx_sysctl,
+		    sc->sensors[i].format,
+		    sc->sensors[i].desc);
+	}
+	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "batchargecurrentstep",
+	    CTLTYPE_INT | CTLFLAG_RW,
+	    dev, 0, axp8xx_sysctl_chargecurrent,
+	    "I", "Battery Charging Current Step, "
+	    "0: 200mA, 1: 400mA, 2: 600mA, 3: 800mA, "
+	    "4: 1000mA, 5: 1200mA, 6: 1400mA, 7: 1600mA, "
+	    "8: 1800mA, 9: 2000mA, 10: 2200mA, 11: 2400mA, "
+	    "12: 2600mA, 13: 2800mA");
+
+	/* Get thresholds */
+	if (axp8xx_read(dev, AXP_BAT_CAP_WARN, &val, 1) == 0) {
+		sc->warn_thres = (val & AXP_BAT_CAP_WARN_LV1) >> 4;
+		sc->warn_thres += AXP_BAP_CAP_WARN_LV1BASE;
+		sc->shut_thres = (val & AXP_BAT_CAP_WARN_LV2);
+		if (bootverbose) {
+			device_printf(dev,
+			    "Raw reg val: 0x%02x\n", val);
+			device_printf(dev,
+			    "Warning threshold: 0x%02x\n", sc->warn_thres);
+			device_printf(dev,
+			    "Shutdown threshold: 0x%02x\n", sc->shut_thres);
+		}
+	}
+
+	/* Enable interrupts */
+	axp8xx_write(dev, AXP_IRQEN1,
+	    AXP_IRQEN1_VBUS_LO |
+	    AXP_IRQEN1_VBUS_HI |
+	    AXP_IRQEN1_ACIN_LO |
+	    AXP_IRQEN1_ACIN_HI);
+	axp8xx_write(dev, AXP_IRQEN2,
+	    AXP_IRQEN2_BATCHGD |
+	    AXP_IRQEN2_BATCHGC |
+	    AXP_IRQEN2_BAT_NO |
+	    AXP_IRQEN2_BAT_IN);
 	axp8xx_write(dev, AXP_IRQEN3, 0);
-	axp8xx_write(dev, AXP_IRQEN4, 0);
-	axp8xx_write(dev, AXP_IRQEN5, AXP_IRQEN5_POKSIRQ);
+	axp8xx_write(dev, AXP_IRQEN4,
+	    AXP_IRQEN4_BATLVL_LO0 |
+	    AXP_IRQEN4_BATLVL_LO1);
+	axp8xx_write(dev, AXP_IRQEN5,
+	    AXP_IRQEN5_POKSIRQ |
+	    AXP_IRQEN5_POKLIRQ);
 	axp8xx_write(dev, AXP_IRQEN6, 0);
 
 	/* Install interrupt handler */


More information about the svn-src-all mailing list