void zapm_enable_charging(struct zapm_softc *sc, int enable) { scoop_discharge_battery(0); scoop_charge_battery(enable, 0); scoop_led_set(SCOOP_LED_ORANGE, enable); }
static void zapm_set_charging(struct zapm_softc *sc, int enable) { if (ZAURUS_ISC1000 || ZAURUS_ISC3000) { scoop_discharge_battery(0); scoop_charge_battery(enable, 0); scoop_led_set(SCOOP_LED_ORANGE, enable); } }
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); }
/* * Poll power-management related GPIO inputs, update battery life * in softc, and/or control battery charging. */ static void zapm_poll1(void *v, int do_suspend) { struct zapm_softc *sc = (struct zapm_softc *)v; int ac_state; int bc_lock; int charging; int volt; if (!mutex_tryenter(&sc->sc_mtx)) return; ac_state = zapm_get_ac_state(sc); bc_lock = zapm_get_battery_compartment_state(sc); /* Stop discharging. */ if (sc->discharging) { sc->discharging = 0; charging = 0; volt = zapm_get_battery_volt(); DPRINTF(("zapm_poll: discharge off volt %d\n", volt)); } else { charging = sc->battery_state & APM_BATT_FLAG_CHARGING; volt = sc->battery_volt; } /* Start or stop charging as necessary. */ if (ac_state && bc_lock) { int charge_completed = zapm_charge_complete(sc); if (charging) { if (charge_completed) { DPRINTF(("zapm_poll: battery is full\n")); charging = 0; zapm_set_charging(sc, 0); } } else if (!charge_completed) { charging = APM_BATT_FLAG_CHARGING; volt = zapm_get_battery_volt(); zapm_set_charging(sc, 1); DPRINTF(("zapm_poll: start charging volt %d\n", volt)); } } else { if (charging) { charging = 0; zapm_set_charging(sc, 0); timerclear(&sc->sc_lastbattchk); DPRINTF(("zapm_poll: stop charging\n")); } sc->battery_full_cnt = 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 (do_suspend && sc->suspended) { /* XXX */ #if 0 DPRINTF(("zapm_poll: suspended %lu %lu\n", sc->lastbattchk.tv_sec, pxa2x0_rtc_getsecs())); if (charging) { zapm_set_charging(sc, 0); delay(15000); zapm_set_charging(sc, 1); pxa2x0_rtc_setalarm(pxa2x0_rtc_getsecs() + zapm_battchkrate.tv_sec + 1); } #endif } else if (ac_state && sc->battery_full_cnt == 0) { DPRINTF(("zapm_poll: discharge on\n")); if (charging) zapm_set_charging(sc, 0); sc->discharging = 1; if (ZAURUS_ISC1000 || ZAURUS_ISC3000) scoop_discharge_battery(1); callout_schedule(&sc->sc_discharge_poll, DISCHARGE_TIMEOUT); } else if (!ac_state) { volt = zapm_get_battery_volt(); DPRINTF(("zapm_poll: volt %d\n", volt)); } } /* Update the cached power state in our softc. */ if ((ac_state != sc->ac_state) || (charging != (sc->battery_state & APM_BATT_FLAG_CHARGING))) { config_hook_call(CONFIG_HOOK_PMEVENT, CONFIG_HOOK_PMEVENT_AC, (void *)((ac_state == APM_AC_OFF) ? CONFIG_HOOK_AC_OFF : (charging ? CONFIG_HOOK_AC_ON_CHARGE : CONFIG_HOOK_AC_ON_NOCHARGE))); } if (volt != sc->battery_volt) { sc->battery_volt = volt; sc->battery_life = zapm_battery_life(volt); config_hook_call(CONFIG_HOOK_PMEVENT, CONFIG_HOOK_PMEVENT_BATTERY, (void *)zapm_battery_state(volt)); } mutex_exit(&sc->sc_mtx); }