From owner-svn-src-stable@freebsd.org Fri Aug 16 21:40:39 2019 Return-Path: Delivered-To: svn-src-stable@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id CAA8CB0057; Fri, 16 Aug 2019 21:40:39 +0000 (UTC) (envelope-from manu@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 469Gvq5lQBz4pZN; Fri, 16 Aug 2019 21:40:39 +0000 (UTC) (envelope-from manu@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id A6E6C786E; Fri, 16 Aug 2019 21:40:39 +0000 (UTC) (envelope-from manu@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x7GLedYA054305; Fri, 16 Aug 2019 21:40:39 GMT (envelope-from manu@FreeBSD.org) Received: (from manu@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x7GLedm7054304; Fri, 16 Aug 2019 21:40:39 GMT (envelope-from manu@FreeBSD.org) Message-Id: <201908162140.x7GLedm7054304@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: manu set sender to manu@FreeBSD.org using -f From: Emmanuel Vadot Date: Fri, 16 Aug 2019 21:40:39 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org Subject: svn commit: r351149 - stable/12/sys/arm/allwinner X-SVN-Group: stable-12 X-SVN-Commit-Author: manu X-SVN-Commit-Paths: stable/12/sys/arm/allwinner X-SVN-Commit-Revision: 351149 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 16 Aug 2019 21:40:39 -0000 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 */