summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/zaurus/dev/zaurus_apm.c340
1 files changed, 208 insertions, 132 deletions
diff --git a/sys/arch/zaurus/dev/zaurus_apm.c b/sys/arch/zaurus/dev/zaurus_apm.c
index 4adaaed2936..87ba0303e7e 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.3 2005/03/13 05:13:15 uwe Exp $ */
+/* $OpenBSD: zaurus_apm.c,v 1.4 2005/03/30 21:44:08 uwe Exp $ */
/*
* Copyright (c) 2005 Uwe Stuehler <uwe@bsdx.de>
@@ -18,6 +18,8 @@
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/timeout.h>
#include <sys/conf.h>
#include <arm/xscale/pxa2x0reg.h>
@@ -27,6 +29,12 @@
#include <zaurus/dev/zaurus_scoopvar.h>
#include <zaurus/dev/zaurus_sspvar.h>
+#if defined(APMDEBUG)
+#define DPRINTF(x) printf x
+#else
+#define DPRINTF(x) /**/
+#endif
+
int apm_match(struct device *, void *, void *);
void apm_attach(struct device *, struct device *, void *);
@@ -52,21 +60,6 @@ struct cfattach apm_pxaip_ca = {
#define GPIO_CHRG_FULL_C3000 101
#define GPIO_BATT_COVER_C3000 90 /* active low */
-/* battery state */
-#define BATT_RESET 0
-#define BATT_ABSENT 1
-#define BATT_NOT_CHARGING 2
-#define BATT_CHARGING 3
-#define BATT_FULL 4
-
-#ifdef APMDEBUG
-const char *zaurus_batt_state_names[5] = {
- "reset", "absent", "not charging", "charging", "full"
-};
-#endif
-
-int zaurus_batt_state = BATT_RESET;
-
struct battery_threshold {
int bt_volt;
int bt_life;
@@ -91,30 +84,44 @@ const struct battery_threshold zaurus_battery_life_c3000[] = {
};
const struct battery_info zaurus_battery_c3000 = {
- 360 /* minutes */,
+ 180 /* minutes; pessimistic estimate */,
zaurus_battery_life_c3000
};
const struct battery_info *zaurus_main_battery = &zaurus_battery_c3000;
#if 0
-void zaurus_shutdownhook(void *);
+void zapm_shutdown(void *);
+int zapm_acintr(void *);
#endif
+int zapm_ac_on(void);
int max1111_adc_value(int);
int max1111_adc_value_avg(int, int);
#if 0
-int zaurus_jkvad_voltage(void);
-int zaurus_battery_temp(void);
+int zapm_jkvad_voltage(void);
+int zapm_batt_temp(void);
#endif
-int zaurus_battery_voltage(void);
-int zaurus_battery_state(int);
-int zaurus_battery_life(int);
-int zaurus_minutes_left(int);
-int zaurus_ac_present(void);
-int zaurus_charge_complete(void);
-void zaurus_charge_control(int);
-void zaurus_power_check(struct pxa2x0_apm_softc *);
-void zaurus_power_info(struct pxa2x0_apm_softc *,
+int zapm_batt_volt(void);
+int zapm_batt_state(int);
+int zapm_batt_life(int);
+int zapm_batt_minutes(int);
+int zapm_batt_full(void);
+
+int zapm_curbattvolt; /* updated periodically when A/C is on */
+int zapm_battcharging;
+int zapm_battfullcount;
+
+struct timeout zapm_charge_off_to;
+struct timeout zapm_charge_on_to;
+
+void zapm_charge_enable(void);
+void zapm_charge_disable(void);
+void zapm_charge_restart(void);
+void zapm_charge_off(void *);
+void zapm_charge_on(void *);
+
+void zapm_power_check(struct pxa2x0_apm_softc *);
+void zapm_power_info(struct pxa2x0_apm_softc *,
struct apm_power_info *);
int
@@ -134,38 +141,64 @@ apm_attach(struct device *parent, struct device *self, void *aux)
#if 0
(void)pxa2x0_gpio_intr_establish(GPIO_AC_IN_C3000, IST_EDGE_BOTH,
- IPL_BIO, apm_intr, sc, "apm_ac");
+ IPL_BIO, zapm_acintr, sc, "apm_ac");
#endif
- sc->sc_periodic_check = zaurus_power_check;
- sc->sc_power_info = zaurus_power_info;
+ sc->sc_periodic_check = zapm_power_check;
+ sc->sc_power_info = zapm_power_info;
+
+ timeout_set(&zapm_charge_off_to, &zapm_charge_off, NULL);
+ timeout_set(&zapm_charge_on_to, &zapm_charge_on, NULL);
- /* Initialize the battery status before APM is enabled. */
- zaurus_power_check(sc);
+ zapm_charge_disable();
+ zapm_battcharging = 0;
+ zapm_battfullcount = 0;
+
+ /* C3000: discharge 100 ms when AC is on. */
+ if (zapm_ac_on()) {
+ scoop_discharge_battery(1);
+ delay(100000);
+ }
+
+ zapm_curbattvolt = zapm_batt_volt();
+ scoop_discharge_battery(0);
+
+ zapm_power_check(sc);
pxa2x0_apm_attach_sub(sc);
#if 0
- (void)shutdownhook_establish(zaurus_shutdownhook, NULL);
+ (void)shutdownhook_establish(zapm_shutdown, NULL);
#endif
}
#if 0
void
-zaurus_shutdownhook(void *v)
+zapm_shutdown(void *v)
+{
+ zapm_charge_disable();
+}
+
+int
+zapm_acintr(void *v)
{
- /* XXX */
- zaurus_charge_control(BATT_NOT_CHARGING);
+ return 1;
}
#endif
int
+zapm_ac_on(void)
+{
+ return (!pxa2x0_gpio_get_bit(GPIO_AC_IN_C3000));
+}
+
+int
max1111_adc_value(int chan)
{
- return zssp_read_max1111(MAXCTRL_PD0 | MAXCTRL_PD1 |
+ return (zssp_read_max1111(MAXCTRL_PD0 | MAXCTRL_PD1 |
MAXCTRL_SGL | MAXCTRL_UNI | (chan << MAXCTRL_SEL_SHIFT) |
- MAXCTRL_STR);
+ MAXCTRL_STR));
}
/* XXX simplify */
@@ -215,14 +248,14 @@ max1111_adc_value_avg(int chan, int pause)
* unless A/C power is connected.
*/
int
-zaurus_jkvad_voltage(void)
+zapm_jkvad_voltage(void)
{
- return max1111_adc_value_avg(JK_VAD, 10);
+ return (max1111_adc_value_avg(JK_VAD, 10));
}
int
-zaurus_battery_temp(void)
+zapm_batt_temp(void)
{
int temp;
@@ -231,19 +264,19 @@ zaurus_battery_temp(void)
temp = max1111_adc_value_avg(BATT_THM, 1);
scoop_battery_temp_adc(0);
- return temp;
+ return (temp);
}
#endif
int
-zaurus_battery_voltage(void)
+zapm_batt_volt(void)
{
- return max1111_adc_value_avg(BATT_AD, 10);
+ return (max1111_adc_value_avg(BATT_AD, 10));
}
int
-zaurus_battery_state(int volt)
+zapm_batt_state(int volt)
{
const struct battery_threshold *bthr;
int i;
@@ -258,7 +291,7 @@ zaurus_battery_state(int volt)
}
int
-zaurus_battery_life(int volt)
+zapm_batt_life(int volt)
{
const struct battery_threshold *bthr;
int i;
@@ -273,132 +306,175 @@ zaurus_battery_life(int volt)
return (bthr[i].bt_life);
return (bthr[i].bt_life +
- ((bthr[i-1].bt_volt - volt) * 100) /
+ ((volt - bthr[i].bt_volt) * 100) /
(bthr[i-1].bt_volt - bthr[i].bt_volt) *
(bthr[i-1].bt_life - bthr[i].bt_life) / 100);
}
int
-zaurus_minutes_left(int life)
+zapm_batt_minutes(int life)
{
return (zaurus_main_battery->bi_minutes * life / 100);
}
+/*
+ * Return non-zero if the charge complete signal is set. This signal
+ * becomes valid after charging has been stopped and restarted.
+ */
int
-zaurus_ac_present(void)
+zapm_batt_full(void)
{
- return !pxa2x0_gpio_get_bit(GPIO_AC_IN_C3000);
+ return (pxa2x0_gpio_get_bit(GPIO_CHRG_FULL_C3000) ? 1 : 0);
}
-/*
- * Return non-zero if the charge complete signal is set. This signal
- * is valid only after charging is restarted.
- */
-int
-zaurus_charge_complete(void)
+void
+zapm_charge_enable(void)
{
- return pxa2x0_gpio_get_bit(GPIO_CHRG_FULL_C3000);
+ timeout_del(&zapm_charge_off_to);
+ timeout_del(&zapm_charge_on_to);
+
+ scoop_charge_battery(1, 0);
+ scoop_discharge_battery(0);
+ scoop_led_set(SCOOP_LED_ORANGE, 1);
+
+ /* Restart charging and updating curbattvolt. */
+ timeout_add(&zapm_charge_off_to, hz * 60);
+}
+
+void
+zapm_charge_disable(void)
+{
+
+ timeout_del(&zapm_charge_off_to);
+ timeout_del(&zapm_charge_on_to);
+
+ scoop_discharge_battery(0);
+ scoop_charge_battery(0, 0);
+ scoop_led_set(SCOOP_LED_ORANGE, 0);
}
void
-zaurus_charge_control(int state)
+zapm_charge_restart(void)
{
- switch (state) {
- case BATT_RESET:
- case BATT_ABSENT:
- case BATT_NOT_CHARGING:
- case BATT_FULL:
- scoop_charge_battery(0, 0);
- scoop_led_set(SCOOP_LED_ORANGE, 0);
- /* Always force a 15 ms delay before charging again. */
- delay(15000);
- break;
- case BATT_CHARGING:
- scoop_charge_battery(1, 0);
- scoop_led_set(SCOOP_LED_ORANGE, 1);
- break;
- default:
- printf("zaurus_charge_control: bad state %d\n", state);
- break;
+ zapm_charge_disable();
+ delay(15000);
+ zapm_charge_enable();
+}
+
+void
+zapm_charge_off(void *v)
+{
+
+ if (zapm_battcharging)
+ zapm_charge_disable();
+
+ /* Discharge 100 ms before updating curbattvolt. */
+ if (zapm_ac_on()) {
+ scoop_discharge_battery(1);
+ timeout_add(&zapm_charge_on_to, hz / 10);
}
}
+void
+zapm_charge_on(void *v)
+{
+
+ /*
+ * Read battery voltage while the battery is still discharging,
+ * then restart charging or schedule the next curbattvolt update.
+ */
+ if (zapm_ac_on()) {
+ zapm_curbattvolt = zapm_batt_volt();
+ if (zapm_battcharging)
+ zapm_charge_enable();
+ else
+ timeout_add(&zapm_charge_off_to, hz * 60);
+ }
+
+ scoop_discharge_battery(0);
+}
+
/*
* Check A/C power and control battery charging. This gets called once
* from apm_attach(), and once per second from the APM kernel thread.
*/
void
-zaurus_power_check(struct pxa2x0_apm_softc *sc)
+zapm_power_check(struct pxa2x0_apm_softc *sc)
{
- int state = zaurus_batt_state;
-
- switch (state) {
- case BATT_RESET:
- zaurus_charge_control(state);
- /* FALLTHROUGH */
- case BATT_ABSENT:
- state = BATT_NOT_CHARGING;
- /* FALLTHROUGH */
- case BATT_NOT_CHARGING:
- if (zaurus_ac_present())
- state = BATT_CHARGING;
- break;
-
- case BATT_CHARGING:
- if (!zaurus_ac_present())
- state = BATT_NOT_CHARGING;
- else if (zaurus_charge_complete())
- state = BATT_FULL;
- break;
-
- case BATT_FULL:
- if (!zaurus_ac_present())
- state = BATT_NOT_CHARGING;
- break;
-
- default:
- printf("zaurus_power_check: bad state %d\n", state);
- break;
+ int s;
+
+ s = splsoftclock();
+
+ if (zapm_ac_on()) {
+ if (zapm_battcharging) {
+ /*
+ * Read BATT_FULL once per second until it
+ * stablizes; restart charging between reads.
+ */
+ if (zapm_batt_full()) {
+ if (++zapm_battfullcount >= 2) {
+ /* battery full; stop charging. */
+ DPRINTF(("zapm_power_check: battery full\n"));
+ zapm_battcharging = 0;
+ zapm_charge_disable();
+ zapm_charge_off(NULL);
+ } else
+ zapm_charge_restart();
+ } else if (zapm_battfullcount > 0) {
+ /* Ignore BATT_FULL glitch. */
+ DPRINTF(("zapm_power_check: battery almost full?\n"));
+ zapm_battfullcount = 0;
+ zapm_charge_restart();
+ }
+ } else if (zapm_battfullcount == 0) {
+ /* Start charging and updating curbattvolt. */
+ DPRINTF(("zapm_power_check: start charging\n"));
+ zapm_battcharging = 1;
+ zapm_charge_off(NULL);
+ }
+ } else if (zapm_battcharging || zapm_battfullcount != 0) {
+ /* Stop charging and updating curbattvolt. */
+ DPRINTF(("zapm_power_check: stop charging\n"));
+ zapm_battcharging = 0;
+ zapm_battfullcount = 0;
+ zapm_charge_disable();
+ } else {
+ /* Running on battery. */
+ /* XXX detect battery low condition and take measures. */
}
- if (zaurus_batt_state != state) {
-#ifdef APMDEBUG
- printf("%s: battery state %s -> %s volt %d\n",
- sc->sc_dev.dv_xname,
- zaurus_batt_state_names[zaurus_batt_state],
- zaurus_batt_state_names[state],
- zaurus_battery_voltage());
-#endif
- zaurus_charge_control(state);
- zaurus_batt_state = state;
- }
+ splx(s);
}
/*
* Report A/C and battery state in response to a request from apmd.
*/
void
-zaurus_power_info(struct pxa2x0_apm_softc *sc,
+zapm_power_info(struct pxa2x0_apm_softc *sc,
struct apm_power_info *power)
{
+ int s;
int volt;
+ int charging;
+
+ s = splsoftclock();
+ volt = zapm_curbattvolt;
+ charging = zapm_battcharging;
+ splx(s);
+
+ power->ac_state = zapm_ac_on() ? APM_AC_ON : APM_AC_OFF;
+ if (power->ac_state == APM_AC_OFF)
+ volt = zapm_batt_volt();
- if (zaurus_batt_state == BATT_CHARGING) {
- power->ac_state = APM_AC_ON;
+ if (charging)
power->battery_state = APM_BATT_CHARGING;
- power->battery_life = 100;
- power->minutes_left = zaurus_main_battery->bi_minutes;
- } else {
- power->ac_state = zaurus_ac_present() ? APM_AC_ON :
- APM_AC_OFF;
- volt = zaurus_battery_voltage();
- power->battery_state = zaurus_battery_state(volt);
- power->battery_life = zaurus_battery_life(volt);
- power->minutes_left =
- zaurus_minutes_left(power->battery_life);
- }
+ else
+ power->battery_state = zapm_batt_state(volt);
+
+ power->battery_life = zapm_batt_life(volt);
+ power->minutes_left = zapm_batt_minutes(power->battery_life);
}