void zapm_shutdown(void *v) { struct zapm_softc *sc = v; zapm_enable_charging(sc, 0); }
/* * Return non-zero if the charge complete signal indicates that the * battery is fully charged. Restart charging to clear this signal. */ int zapm_charge_complete(struct zapm_softc *sc) { if (sc->sc_charging && sc->sc_batt_full < MIN_BATT_FULL) { if (pxa2x0_gpio_get_bit(GPIO_CHRG_CO_C3000) != 0) { if (++sc->sc_batt_full < MIN_BATT_FULL) { DPRINTF(("battery almost full\n")); zapm_enable_charging(sc, 0); delay(15000); zapm_enable_charging(sc, 1); } } else if (sc->sc_batt_full > 0) { /* false alarm */ sc->sc_batt_full = 0; zapm_enable_charging(sc, 0); delay(15000); zapm_enable_charging(sc, 1); } } return (sc->sc_batt_full >= MIN_BATT_FULL); }
int apm_activate(struct device *self, int act) { struct zapm_softc *sc = (struct zapm_softc *)self; int ret = 0; switch (act) { case DVACT_POWERDOWN: zapm_enable_charging(sc, 0); break; } return (ret); }
void apm_attach(struct device *parent, struct device *self, void *aux) { struct zapm_softc *sc = (struct zapm_softc *)self; pxa2x0_gpio_set_function(GPIO_AC_IN_C3000, GPIO_IN); pxa2x0_gpio_set_function(GPIO_CHRG_CO_C3000, GPIO_IN); pxa2x0_gpio_set_function(GPIO_BATT_COVER_C3000, GPIO_IN); (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; sc->sc.sc_power_info = zapm_power_info; sc->sc.sc_suspend = zapm_suspend; sc->sc.sc_resume = zapm_resume; timeout_set(&sc->sc_poll, &zapm_poll, sc); /* Get initial battery voltage. */ zapm_enable_charging(sc, 0); if (zapm_ac_on()) { /* C3000: discharge 100 ms when AC is on. */ scoop_discharge_battery(1); delay(100000); } sc->sc_batt_volt = zapm_batt_volt(); scoop_discharge_battery(0); pxa2x0_apm_attach_sub(&sc->sc); #if 0 (void)shutdownhook_establish(zapm_shutdown, NULL); #endif cpu_setperf = pxa2x0_setperf; cpu_cpuspeed = pxa2x0_cpuspeed; }
/* * 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; 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 = 0; DPRINTF(("zapm_poll: discharge off volt %d\n", volt)); } else { ac_on = zapm_ac_on(); charging = sc->sc_charging; volt = sc->sc_batt_volt; } /* Start or stop charging as necessary. */ if (ac_on && bc_lock) { if (charging) { if (zapm_charge_complete(sc)) { DPRINTF(("zapm_poll: batt full\n")); charging = 0; zapm_enable_charging(sc, 0); } } else if (!zapm_charge_complete(sc)) { charging = 1; volt = zapm_batt_volt(); zapm_enable_charging(sc, 1); DPRINTF(("zapm_poll: start charging volt %d\n", volt)); } } 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) { DPRINTF(("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 (!ac_on) { volt = zapm_batt_volt(); DPRINTF(("zapm_poll: volt %d\n", volt)); } } /* 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; sc->sc_charging = charging; sc->sc_batt_volt = volt; if (sc->sc_event == APM_NOEVENT) 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) DPRINTF(("zapm_poll: power event %d\n", sc->sc_event)); #endif splx(s); }