summaryrefslogtreecommitdiff
path: root/sys/arch/zaurus/dev/zaurus_apm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/zaurus/dev/zaurus_apm.c')
-rw-r--r--sys/arch/zaurus/dev/zaurus_apm.c357
1 files changed, 357 insertions, 0 deletions
diff --git a/sys/arch/zaurus/dev/zaurus_apm.c b/sys/arch/zaurus/dev/zaurus_apm.c
new file mode 100644
index 00000000000..2fc758ea385
--- /dev/null
+++ b/sys/arch/zaurus/dev/zaurus_apm.c
@@ -0,0 +1,357 @@
+/* $OpenBSD: zaurus_apm.c,v 1.1 2005/01/26 06:34:54 uwe Exp $ */
+
+/*
+ * Copyright (c) 2005 Uwe Stuehler <uwe@bsdx.de>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+
+#include <arm/xscale/pxa2x0reg.h>
+#include <arm/xscale/pxa2x0_apm.h>
+#include <arm/xscale/pxa2x0_gpio.h>
+
+#include <zaurus/dev/zaurus_scoopvar.h>
+#include <zaurus/dev/zaurus_sspvar.h>
+
+int apm_match(struct device *, void *, void *);
+void apm_attach(struct device *, struct device *, void *);
+
+struct cfattach apm_pxaip_ca = {
+ sizeof (struct pxa2x0_apm_softc), apm_match, apm_attach
+};
+
+/* MAX1111 command word */
+#define MAXCTRL_PD0 (1<<0)
+#define MAXCTRL_PD1 (1<<1)
+#define MAXCTRL_SGL (1<<2)
+#define MAXCTRL_UNI (1<<3)
+#define MAXCTRL_SEL_SHIFT 4
+#define MAXCTRL_STR (1<<7)
+
+/* MAX1111 ADC channels */
+#define BATT_THM 2
+#define BATT_AD 4
+#define JK_VAD 6
+
+/* Battery-related GPIO pins */
+#define GPIO_AC_IN_C3000 115 /* active low */
+#define GPIO_CHRG_FULL_C3000 101
+#define GPIO_BATT_COVER_C3000 90 /* active low */
+
+/* Internal software power states */
+#define PS_UNKNOWN 0
+#define PS_BATT_ABSENT 1
+#define PS_NOT_CHARGING 2
+#define PS_CHARGING 3
+#define PS_BATT_FULL 4
+
+#ifdef APMDEBUG
+const char *zaurus_power_state_names[5] = {
+ "unknown", "absent", "not charging", "charging", "full"
+};
+#endif
+
+int zaurus_power_state = PS_UNKNOWN;
+
+struct battery_voltage_threshold {
+ int voltage;
+ int life;
+ int state;
+};
+
+struct battery_voltage_threshold zaurus_battery_c3000[] = {
+ {194, 100, APM_BATT_HIGH},
+ {188, 75, APM_BATT_HIGH},
+ {184, 50, APM_BATT_HIGH},
+ {180, 25, APM_BATT_LOW},
+ {176, 5, APM_BATT_LOW},
+ {0, 0, APM_BATT_CRITICAL},
+};
+
+struct battery_voltage_threshold *zaurus_main_battery =
+ zaurus_battery_c3000;
+
+int max1111_adc_value(int);
+int max1111_adc_value_avg(int, int);
+#if 0
+int zaurus_jkvad_voltage(void);
+int zaurus_battery_temp(void);
+#endif
+int zaurus_battery_voltage(void);
+int zaurus_battery_life(void);
+int zaurus_battery_state(void);
+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 *,
+ struct apm_power_info *);
+
+int
+apm_match(struct device *parent, void *match, void *aux)
+{
+ return 1;
+}
+
+void
+apm_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct pxa2x0_apm_softc *sc = (struct pxa2x0_apm_softc *)self;
+
+ pxa2x0_gpio_set_function(GPIO_AC_IN_C3000, GPIO_IN);
+ pxa2x0_gpio_set_function(GPIO_CHRG_FULL_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, apm_intr, sc, "apm_ac");
+#endif
+
+ sc->sc_periodic_check = zaurus_power_check;
+ sc->sc_power_info = zaurus_power_info;
+
+ /* Initialize the battery status before APM is enabled. */
+ zaurus_power_check(sc);
+
+ pxa2x0_apm_attach_sub(sc);
+}
+
+int
+max1111_adc_value(int chan)
+{
+
+ return zssp_read_max1111(MAXCTRL_PD0 | MAXCTRL_PD1 |
+ MAXCTRL_SGL | MAXCTRL_UNI | (chan << MAXCTRL_SEL_SHIFT) |
+ MAXCTRL_STR);
+}
+
+/* XXX simplify */
+int
+max1111_adc_value_avg(int chan, int pause)
+{
+ int val[5];
+ int i, j, k, x;
+ int sum = 0;
+
+ for (i = 0; i < 5; i++) {
+ val[i] = max1111_adc_value(chan);
+ if (i != 4)
+ delay(pause * 1000);
+ }
+
+ x = val[0];
+ j = 0;
+ for (i = 1; i < 5; i++) {
+ if (x < val[i]) {
+ x = val[i];
+ j = i;
+ }
+ }
+
+ x = val[4];
+ k = 4;
+ for (i = 3; i >= 0; i--) {
+ if (x > val[i]) {
+ x = val[i];
+ k = i;
+ }
+ }
+
+ for (i = 0; i < 5; i++) {
+ if (i == j || i == k)
+ continue;
+ sum += val[i];
+ }
+
+ return (sum / 3);
+}
+
+#if 0
+/*
+ * Return the voltage available for charging. This will be zero,
+ * unless A/C power is connected.
+ */
+int
+zaurus_jkvad_voltage(void)
+{
+
+ return max1111_adc_value_avg(JK_VAD, 10);
+}
+
+int
+zaurus_battery_temp(void)
+{
+ int temp;
+
+ scoop_battery_temp_adc(1);
+ delay(10000);
+ temp = max1111_adc_value_avg(BATT_THM, 1);
+ scoop_battery_temp_adc(0);
+
+ return temp;
+}
+#endif
+
+int
+zaurus_battery_voltage(void)
+{
+
+ return max1111_adc_value_avg(BATT_AD, 10);
+}
+
+int
+zaurus_battery_life(void)
+{
+ int i;
+ int voltage;
+
+ voltage = zaurus_battery_voltage();
+
+ for (i = 0; zaurus_main_battery[i].voltage > 0; i++) {
+ if (voltage >= zaurus_main_battery[i].voltage)
+ break;
+ }
+
+ return zaurus_main_battery[i].life;
+}
+
+int
+zaurus_battery_state(void)
+{
+ int i;
+ int voltage;
+
+ voltage = zaurus_battery_voltage();
+
+ for (i = 0; zaurus_main_battery[i].voltage > 0; i++) {
+ if (voltage >= zaurus_main_battery[i].voltage)
+ break;
+ }
+
+ return zaurus_main_battery[i].state;
+}
+
+int
+zaurus_ac_present(void)
+{
+
+ return !pxa2x0_gpio_get_bit(GPIO_AC_IN_C3000);
+}
+
+/*
+ * Return non-zero if the charge complete signal is set. This signal
+ * is valid only after charging is restarted.
+ */
+int
+zaurus_charge_complete(void)
+{
+
+ return pxa2x0_gpio_get_bit(GPIO_CHRG_FULL_C3000);
+}
+
+void
+zaurus_charge_control(int state)
+{
+
+ switch (state) {
+ case PS_CHARGING:
+ scoop_charge_battery(1, 0);
+ scoop_led_set(SCOOP_LED_ORANGE, 1);
+ break;
+ case PS_NOT_CHARGING:
+ case PS_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;
+ default:
+ printf("zaurus_charge_control: bad state %d\n", state);
+ break;
+ }
+
+ zaurus_power_state = state;
+}
+
+/*
+ * 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)
+{
+ int state = zaurus_power_state;
+
+ switch (state) {
+ case PS_UNKNOWN:
+ case PS_BATT_ABSENT:
+ state = PS_NOT_CHARGING;
+ zaurus_charge_control(state);
+ /* FALLTHROUGH */
+
+ case PS_NOT_CHARGING:
+ if (zaurus_ac_present())
+ state = PS_CHARGING;
+ break;
+
+ case PS_CHARGING:
+ if (!zaurus_ac_present())
+ state = PS_NOT_CHARGING;
+ else if (zaurus_charge_complete())
+ state = PS_BATT_FULL;
+ break;
+
+ case PS_BATT_FULL:
+ if (!zaurus_ac_present())
+ state = PS_NOT_CHARGING;
+ break;
+
+ default:
+ printf("zaurus_power_check: bad state %d\n", state);
+ break;
+ }
+
+ if (state != zaurus_power_state) {
+#ifdef APMDEBUG
+ printf("zaurus_power_check: battery state %s -> %s volt %d\n",
+ zaurus_power_state_names[zaurus_power_state],
+ zaurus_power_state_names[state],
+ zaurus_battery_voltage());
+#endif
+ zaurus_charge_control(state);
+ }
+}
+
+/*
+ * Report A/C and battery state in response to a request from apmd.
+ */
+void
+zaurus_power_info(struct pxa2x0_apm_softc *sc,
+ struct apm_power_info *power)
+{
+
+ if (zaurus_power_state == PS_CHARGING) {
+ power->ac_state = APM_AC_ON;
+ power->battery_state = APM_BATT_CHARGING;
+ power->battery_life = 100;
+ } else {
+ power->ac_state = zaurus_ac_present() ? APM_AC_ON :
+ APM_AC_OFF;
+ power->battery_state = zaurus_battery_state();
+ power->battery_life = zaurus_battery_life();
+ }
+}