summaryrefslogtreecommitdiff
path: root/sys/arch
diff options
context:
space:
mode:
authorUwe Stuehler <uwe@cvs.openbsd.org>2005-05-27 05:09:43 +0000
committerUwe Stuehler <uwe@cvs.openbsd.org>2005-05-27 05:09:43 +0000
commit54541082b11abaf855153b3737de7dcdc4af19fa (patch)
tree964b708dafceb64cb67890e419242f53be33e1d8 /sys/arch
parente1828cccc43dbb1ad6f856afd685a2ecef3d9fa0 (diff)
- raise the "critical" battery level a bit to suspend earlier
- stop charging if the battery compartment is unlocked - control charging while suspended in zapm_poll(), too - avoid panic when rebooting before the driver is attached
Diffstat (limited to 'sys/arch')
-rw-r--r--sys/arch/zaurus/dev/zaurus_apm.c164
1 files changed, 110 insertions, 54 deletions
diff --git a/sys/arch/zaurus/dev/zaurus_apm.c b/sys/arch/zaurus/dev/zaurus_apm.c
index 264d761ffe4..436575dd272 100644
--- a/sys/arch/zaurus/dev/zaurus_apm.c
+++ b/sys/arch/zaurus/dev/zaurus_apm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: zaurus_apm.c,v 1.6 2005/04/13 05:49:57 uwe Exp $ */
+/* $OpenBSD: zaurus_apm.c,v 1.7 2005/05/27 05:09:42 uwe Exp $ */
/*
* Copyright (c) 2005 Uwe Stuehler <uwe@bsdx.de>
@@ -23,6 +23,7 @@
#include <sys/conf.h>
#include <arm/xscale/pxa2x0reg.h>
+#include <arm/xscale/pxa2x0var.h>
#include <arm/xscale/pxa2x0_apm.h>
#include <arm/xscale/pxa2x0_gpio.h>
@@ -75,7 +76,7 @@ extern struct cfdriver apm_cd;
/* battery-related GPIO pins */
#define GPIO_AC_IN_C3000 115 /* 0=AC connected */
#define GPIO_CHRG_CO_C3000 101 /* 1=battery full */
-#define GPIO_BATT_COVER_C3000 90 /* ?=open */
+#define GPIO_BATT_COVER_C3000 90 /* 0=unlocked */
/*
* Battery-specific information
@@ -100,7 +101,7 @@ const struct battery_threshold zaurus_battery_life_c3000[] = {
{188, 75, APM_BATT_HIGH},
{184, 50, APM_BATT_HIGH},
{180, 25, APM_BATT_LOW},
- {176, 5, APM_BATT_LOW},
+ {178, 5, APM_BATT_LOW},
{0, 0, APM_BATT_CRITICAL},
};
@@ -124,8 +125,9 @@ const struct timeval zapm_battchkrate = { 60, 0 };
#if 0
void zapm_shutdown(void *);
-int zapm_acintr(void *);
#endif
+int zapm_acintr(void *);
+int zapm_bcintr(void *);
int zapm_ac_on(void);
int max1111_adc_value(int);
int max1111_adc_value_avg(int, int);
@@ -161,10 +163,10 @@ apm_attach(struct device *parent, struct device *self, void *aux)
pxa2x0_gpio_set_function(GPIO_CHRG_CO_C3000, GPIO_IN);
pxa2x0_gpio_set_function(GPIO_BATT_COVER_C3000, GPIO_IN);
-#if 0
- (void)pxa2x0_gpio_intr_establish(GPIO_AC_IN_C3000, IST_EDGE_BOTH,
- IPL_BIO, zapm_acintr, sc, "apm_ac");
-#endif
+ (void)pxa2x0_gpio_intr_establish(GPIO_AC_IN_C3000,
+ IST_EDGE_BOTH, IPL_BIO, zapm_acintr, sc, "apm_ac");
+ (void)pxa2x0_gpio_intr_establish(GPIO_BATT_COVER_C3000,
+ IST_EDGE_BOTH, IPL_BIO, zapm_bcintr, sc, "apm_bc");
sc->sc_event = APM_NOEVENT;
sc->sc.sc_get_event = zapm_get_event;
@@ -199,13 +201,21 @@ zapm_shutdown(void *v)
zapm_enable_charging(sc, 0);
}
+#endif
int
zapm_acintr(void *v)
{
+ zapm_poll(v);
+ return (1);
+}
+
+int
+zapm_bcintr(void *v)
+{
+ zapm_poll(v);
return (1);
}
-#endif
int
zapm_ac_on(void)
@@ -376,28 +386,40 @@ zapm_charge_complete(struct zapm_softc *sc)
return (sc->sc_batt_full >= MIN_BATT_FULL);
}
+/*
+ * Poll power-management related GPIO inputs, update battery life
+ * in softc, and/or control battery charging.
+ */
void
zapm_poll(void *v)
{
struct zapm_softc *sc = v;
- int ac_on = sc->sc_ac_on;
- int charging = sc->sc_charging;
- int volt = sc->sc_batt_volt;
- int s;
+ int ac_on;
+ int bc_lock;
+ int charging;
+ int volt;
+ int s;
s = splhigh();
+ /* Check positition of battery compartment lock switch. */
+ bc_lock = pxa2x0_gpio_get_bit(GPIO_BATT_COVER_C3000) ? 1 : 0;
+
+ /* Stop discharging. */
if (sc->sc_discharging) {
sc->sc_discharging = 0;
volt = zapm_batt_volt();
ac_on = zapm_ac_on();
- charging = ac_on && sc->sc_batt_full < MIN_BATT_FULL;
- zapm_enable_charging(sc, charging);
+ charging = 0;
DPRINTF(("zapm_poll: discharge off volt %d\n", volt));
- } else
+ } else {
ac_on = zapm_ac_on();
+ charging = sc->sc_charging;
+ volt = sc->sc_batt_volt;
+ }
- if (ac_on) {
+ /* Start or stop charging as necessary. */
+ if (ac_on && bc_lock) {
if (charging) {
if (zapm_charge_complete(sc)) {
DPRINTF(("zapm_poll: batt full\n"));
@@ -410,33 +432,46 @@ zapm_poll(void *v)
zapm_enable_charging(sc, 1);
DPRINTF(("zapm_poll: start charging volt %d\n", volt));
}
-
- if (!sc->sc_suspended && sc->sc_batt_full == 0 &&
- ratecheck(&sc->sc_lastbattchk, &zapm_battchkrate)) {
+ } else {
+ if (charging) {
+ charging = 0;
+ zapm_enable_charging(sc, 0);
+ timerclear(&sc->sc_lastbattchk);
+ DPRINTF(("zapm_poll: stop charging\n"));
+ }
+ sc->sc_batt_full = 0;
+ }
+
+ /*
+ * Restart charging once in a while. Discharge a few milliseconds
+ * before updating the voltage in our softc if A/C is connected.
+ */
+ if (bc_lock && ratecheck(&sc->sc_lastbattchk, &zapm_battchkrate)) {
+ if (sc->sc_suspended) {
+ printf("zapm_poll: suspended %lu %lu\n",
+ sc->sc_lastbattchk.tv_sec,
+ pxa2x0_rtc_getsecs());
+ if (charging) {
+ zapm_enable_charging(sc, 0);
+ delay(15000);
+ zapm_enable_charging(sc, 1);
+ pxa2x0_rtc_setalarm(pxa2x0_rtc_getsecs() +
+ zapm_battchkrate.tv_sec + 1);
+ }
+ } else if (ac_on && sc->sc_batt_full == 0) {
DPRINTF(("zapm_poll: discharge on\n"));
if (charging)
zapm_enable_charging(sc, 0);
sc->sc_discharging = 1;
scoop_discharge_battery(1);
timeout_add(&sc->sc_poll, DISCHARGE_TIMEOUT);
- }
- } else {
- if (sc->sc_ac_on) {
- sc->sc_batt_full = 0;
- charging = 0;
- zapm_enable_charging(sc, 0);
- timerclear(&sc->sc_lastbattchk);
- DPRINTF(("zapm_poll: stop charging\n"));
- } else if (!sc->sc_suspended &&
- ratecheck(&sc->sc_lastbattchk, &zapm_battchkrate)) {
+ } else if (!ac_on) {
volt = zapm_batt_volt();
DPRINTF(("zapm_poll: volt %d\n", volt));
}
-
- if (zapm_batt_state(volt) == APM_BATT_CRITICAL)
- sc->sc_event = APM_CRIT_SUSPEND_REQ;
}
+ /* Update the cached power state in our softc. */
if (ac_on != sc->sc_ac_on || charging != sc->sc_charging ||
volt != sc->sc_batt_volt) {
sc->sc_ac_on = ac_on;
@@ -446,6 +481,14 @@ zapm_poll(void *v)
sc->sc_event = APM_POWER_CHANGE;
}
+ /* Detect battery low conditions. */
+ if (!ac_on) {
+ if (zapm_batt_life(volt) < 5)
+ sc->sc_event = APM_BATTERY_LOW;
+ if (zapm_batt_state(volt) == APM_BATT_CRITICAL)
+ sc->sc_event = APM_CRIT_SUSPEND_REQ;
+ }
+
#ifdef APMDEBUG
if (sc->sc_event != APM_NOEVENT)
printf("zapm_poll: power event %d\n", sc->sc_event);
@@ -513,16 +556,18 @@ zapm_suspend(struct pxa2x0_apm_softc *pxa_sc)
{
struct zapm_softc *sc = (struct zapm_softc *)pxa_sc;
+ /* Poll in suspended mode and forget the discharge timeout. */
sc->sc_suspended = 1;
timeout_del(&sc->sc_poll);
- zapm_poll(sc);
- if (sc->sc_charging) {
- zapm_enable_charging(sc, 0);
- delay(15000);
- zapm_enable_charging(sc, 1);
- }
+ /* Make sure charging is enabled and RTC alarm is set. */
+ timerclear(&sc->sc_lastbattchk);
+
+ zapm_poll(sc);
+#if 0
+ pxa2x0_rtc_setalarm(pxa2x0_rtc_getsecs() + 5);
+#endif
pxa2x0_wakeup_config(PXA2X0_WAKEUP_ALL, 1);
}
@@ -561,9 +606,20 @@ zapm_resume(struct pxa2x0_apm_softc *pxa_sc)
zssp_init();
zapm_poll(sc);
- if (wakeup)
+
+ if (wakeup) {
+ /* Resume normal polling. */
sc->sc_suspended = 0;
+ pxa2x0_rtc_setalarm(0);
+ } else {
+#if 0
+ DPRINTF(("zapm_resume: suspended %lu %lu\n",
+ sc->sc_lastbattchk.tv_sec, pxa2x0_rtc_getsecs()));
+ pxa2x0_rtc_setalarm(pxa2x0_rtc_getsecs() + 5);
+#endif
+ }
+
return (wakeup);
}
@@ -608,20 +664,20 @@ zapm_poweroff(void)
void
zapm_restart(void)
{
- struct pxa2x0_apm_softc *sc;
- int rv;
-
- KASSERT(apm_cd.cd_ndevs > 0 && apm_cd.cd_devs[0] != NULL);
- sc = apm_cd.cd_devs[0];
-
- /*
- * Reduce the ROM Delay Next Access and ROM Delay First Access times
- * for synchronous flash connected to nCS1.
- */
- rv = bus_space_read_4(sc->sc_iot, sc->sc_memctl_ioh, MEMCTL_MSC0);
- if ((rv & 0xffff0000) == 0x7ff00000)
- bus_space_write_4(sc->sc_iot, sc->sc_memctl_ioh,
- MEMCTL_MSC0, (rv & 0xffff) | 0x7ee00000);
+ if (apm_cd.cd_ndevs > 0 && apm_cd.cd_devs[0] != NULL) {
+ struct pxa2x0_apm_softc *sc = apm_cd.cd_devs[0];
+ int rv;
+
+ /*
+ * Reduce the ROM Delay Next Access and ROM Delay First
+ * Access times for synchronous flash connected to nCS1.
+ */
+ rv = bus_space_read_4(sc->sc_iot, sc->sc_memctl_ioh,
+ MEMCTL_MSC0);
+ if ((rv & 0xffff0000) == 0x7ff00000)
+ bus_space_write_4(sc->sc_iot, sc->sc_memctl_ioh,
+ MEMCTL_MSC0, (rv & 0xffff) | 0x7ee00000);
+ }
/* External reset circuit presumably asserts nRESET_GPIO. */
pxa2x0_gpio_set_function(89, GPIO_OUT | GPIO_SET);