Annotation of sys/arch/zaurus/dev/zaurus_apm.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: zaurus_apm.c,v 1.13 2006/12/12 23:14:28 dim Exp $ */
2:
3: /*
4: * Copyright (c) 2005 Uwe Stuehler <uwe@bsdx.de>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: #include <sys/param.h>
20: #include <sys/systm.h>
21: #include <sys/kernel.h>
22: #include <sys/timeout.h>
23: #include <sys/conf.h>
24: #include <sys/sysctl.h>
25:
26: #include <arm/xscale/pxa2x0reg.h>
27: #include <arm/xscale/pxa2x0var.h>
28: #include <arm/xscale/pxa2x0_apm.h>
29: #include <arm/xscale/pxa2x0_gpio.h>
30:
31: #include <zaurus/dev/zaurus_scoopvar.h>
32: #include <zaurus/dev/zaurus_sspvar.h>
33: void zssp_init(void); /* XXX */
34:
35: #include <zaurus/dev/zaurus_apm.h>
36:
37: #if defined(APMDEBUG)
38: #define DPRINTF(x) printf x
39: #else
40: #define DPRINTF(x) /**/
41: #endif
42:
43: struct zapm_softc {
44: struct pxa2x0_apm_softc sc;
45: struct timeout sc_poll;
46: struct timeval sc_lastbattchk;
47: int sc_suspended;
48: int sc_ac_on;
49: int sc_charging;
50: int sc_discharging;
51: int sc_batt_full;
52: int sc_batt_volt;
53: u_int sc_event;
54: };
55:
56: int apm_match(struct device *, void *, void *);
57: void apm_attach(struct device *, struct device *, void *);
58:
59: struct cfattach apm_pxaip_ca = {
60: sizeof (struct zapm_softc), apm_match, apm_attach
61: };
62: extern struct cfdriver apm_cd;
63:
64: /* MAX1111 command word */
65: #define MAXCTRL_PD0 (1<<0)
66: #define MAXCTRL_PD1 (1<<1)
67: #define MAXCTRL_SGL (1<<2)
68: #define MAXCTRL_UNI (1<<3)
69: #define MAXCTRL_SEL_SHIFT 4
70: #define MAXCTRL_STR (1<<7)
71:
72: /* MAX1111 ADC channels */
73: #define BATT_THM 2
74: #define BATT_AD 4
75: #define JK_VAD 6
76:
77: /* battery-related GPIO pins */
78: #define GPIO_AC_IN_C3000 115 /* 0=AC connected */
79: #define GPIO_CHRG_CO_C3000 101 /* 1=battery full */
80: #define GPIO_BATT_COVER_C3000 90 /* 0=unlocked */
81:
82: /*
83: * Battery-specific information
84: */
85:
86: struct battery_threshold {
87: int bt_volt;
88: int bt_life;
89: int bt_state;
90: };
91:
92: struct battery_info {
93: int bi_minutes; /* 100% life time */
94: const struct battery_threshold *bi_thres;
95: };
96:
97: const struct battery_threshold zaurus_battery_life_c3000[] = {
98: #if 0
99: {224, 125, APM_BATT_HIGH}, /* XXX unverified */
100: #endif
101: {194, 100, APM_BATT_HIGH},
102: {188, 75, APM_BATT_HIGH},
103: {184, 50, APM_BATT_HIGH},
104: {180, 25, APM_BATT_LOW},
105: {178, 5, APM_BATT_LOW},
106: {0, 0, APM_BATT_CRITICAL},
107: };
108:
109: const struct battery_info zaurus_battery_c3000 = {
110: 180 /* minutes; pessimistic estimate */,
111: zaurus_battery_life_c3000
112: };
113:
114: const struct battery_info *zaurus_main_battery = &zaurus_battery_c3000;
115:
116: /* Restart charging this many times before accepting BATT_FULL. */
117: #define MIN_BATT_FULL 2
118:
119: /* Discharge 100 ms before reading the voltage if AC is connected. */
120: #define DISCHARGE_TIMEOUT (hz / 10)
121:
122: /* Check battery voltage and "kick charging" every minute. */
123: const struct timeval zapm_battchkrate = { 60, 0 };
124:
125: /* Prototypes */
126:
127: #if 0
128: void zapm_shutdown(void *);
129: #endif
130: int zapm_acintr(void *);
131: int zapm_bcintr(void *);
132: int zapm_ac_on(void);
133: int max1111_adc_value(int);
134: int max1111_adc_value_avg(int, int);
135: #if 0
136: int zapm_jkvad_voltage(void);
137: int zapm_batt_temp(void);
138: #endif
139: int zapm_batt_volt(void);
140: int zapm_batt_state(int);
141: int zapm_batt_life(int);
142: int zapm_batt_minutes(int);
143: void zapm_enable_charging(struct zapm_softc *, int);
144: int zapm_charge_complete(struct zapm_softc *);
145: void zapm_poll(void *);
146: int zapm_get_event(struct pxa2x0_apm_softc *, u_int *);
147: void zapm_power_info(struct pxa2x0_apm_softc *, struct apm_power_info *);
148: void zapm_suspend(struct pxa2x0_apm_softc *);
149: int zapm_resume(struct pxa2x0_apm_softc *);
150: void pxa2x0_setperf(int);
151: int pxa2x0_cpuspeed(int *);
152:
153:
154: int
155: apm_match(struct device *parent, void *match, void *aux)
156: {
157: return (1);
158: }
159:
160: void
161: apm_attach(struct device *parent, struct device *self, void *aux)
162: {
163: struct zapm_softc *sc = (struct zapm_softc *)self;
164:
165: pxa2x0_gpio_set_function(GPIO_AC_IN_C3000, GPIO_IN);
166: pxa2x0_gpio_set_function(GPIO_CHRG_CO_C3000, GPIO_IN);
167: pxa2x0_gpio_set_function(GPIO_BATT_COVER_C3000, GPIO_IN);
168:
169: (void)pxa2x0_gpio_intr_establish(GPIO_AC_IN_C3000,
170: IST_EDGE_BOTH, IPL_BIO, zapm_acintr, sc, "apm_ac");
171: (void)pxa2x0_gpio_intr_establish(GPIO_BATT_COVER_C3000,
172: IST_EDGE_BOTH, IPL_BIO, zapm_bcintr, sc, "apm_bc");
173:
174: sc->sc_event = APM_NOEVENT;
175: sc->sc.sc_get_event = zapm_get_event;
176: sc->sc.sc_power_info = zapm_power_info;
177: sc->sc.sc_suspend = zapm_suspend;
178: sc->sc.sc_resume = zapm_resume;
179:
180: timeout_set(&sc->sc_poll, &zapm_poll, sc);
181:
182: /* Get initial battery voltage. */
183: zapm_enable_charging(sc, 0);
184: if (zapm_ac_on()) {
185: /* C3000: discharge 100 ms when AC is on. */
186: scoop_discharge_battery(1);
187: delay(100000);
188: }
189: sc->sc_batt_volt = zapm_batt_volt();
190: scoop_discharge_battery(0);
191:
192: pxa2x0_apm_attach_sub(&sc->sc);
193:
194: #if 0
195: (void)shutdownhook_establish(zapm_shutdown, NULL);
196: #endif
197:
198: cpu_setperf = pxa2x0_setperf;
199: cpu_cpuspeed = pxa2x0_cpuspeed;
200: }
201:
202: #if 0
203: void
204: zapm_shutdown(void *v)
205: {
206: struct zapm_softc *sc = v;
207:
208: zapm_enable_charging(sc, 0);
209: }
210: #endif
211:
212: int
213: zapm_acintr(void *v)
214: {
215: zapm_poll(v);
216: return (1);
217: }
218:
219: int
220: zapm_bcintr(void *v)
221: {
222: zapm_poll(v);
223: return (1);
224: }
225:
226: int
227: zapm_ac_on(void)
228: {
229: return (!pxa2x0_gpio_get_bit(GPIO_AC_IN_C3000));
230: }
231:
232: int
233: max1111_adc_value(int chan)
234: {
235:
236: return ((int)zssp_ic_send(ZSSP_IC_MAX1111, MAXCTRL_PD0 |
237: MAXCTRL_PD1 | MAXCTRL_SGL | MAXCTRL_UNI |
238: (chan << MAXCTRL_SEL_SHIFT) | MAXCTRL_STR));
239: }
240:
241: /* XXX simplify */
242: int
243: max1111_adc_value_avg(int chan, int pause)
244: {
245: int val[5];
246: int i, j, k, x;
247: int sum = 0;
248:
249: for (i = 0; i < 5; i++) {
250: val[i] = max1111_adc_value(chan);
251: if (i != 4)
252: delay(pause * 1000);
253: }
254:
255: x = val[0];
256: j = 0;
257: for (i = 1; i < 5; i++) {
258: if (x < val[i]) {
259: x = val[i];
260: j = i;
261: }
262: }
263:
264: x = val[4];
265: k = 4;
266: for (i = 3; i >= 0; i--) {
267: if (x > val[i]) {
268: x = val[i];
269: k = i;
270: }
271: }
272:
273: for (i = 0; i < 5; i++) {
274: if (i == j || i == k)
275: continue;
276: sum += val[i];
277: }
278:
279: return (sum / 3);
280: }
281:
282: #if 0
283: /*
284: * Return the voltage available for charging. This will be zero,
285: * unless A/C power is connected.
286: */
287: int
288: zapm_jkvad_voltage(void)
289: {
290:
291: return (max1111_adc_value_avg(JK_VAD, 10));
292: }
293:
294: int
295: zapm_batt_temp(void)
296: {
297: int temp;
298:
299: scoop_battery_temp_adc(1);
300: delay(10000);
301: temp = max1111_adc_value_avg(BATT_THM, 1);
302: scoop_battery_temp_adc(0);
303:
304: return (temp);
305: }
306: #endif
307:
308: int
309: zapm_batt_volt(void)
310: {
311:
312: return (max1111_adc_value_avg(BATT_AD, 10));
313: }
314:
315: int
316: zapm_batt_state(int volt)
317: {
318: const struct battery_threshold *bthr;
319: int i;
320:
321: bthr = zaurus_main_battery->bi_thres;
322:
323: for (i = 0; bthr[i].bt_volt > 0; i++)
324: if (bthr[i].bt_volt <= volt)
325: break;
326:
327: return (bthr[i].bt_state);
328: }
329:
330: int
331: zapm_batt_life(int volt)
332: {
333: const struct battery_threshold *bthr;
334: int i;
335:
336: bthr = zaurus_main_battery->bi_thres;
337:
338: for (i = 0; bthr[i].bt_volt > 0; i++)
339: if (bthr[i].bt_volt <= volt)
340: break;
341:
342: if (i == 0)
343: return (bthr[i].bt_life);
344:
345: return (bthr[i].bt_life +
346: ((volt - bthr[i].bt_volt) * 100) /
347: (bthr[i-1].bt_volt - bthr[i].bt_volt) *
348: (bthr[i-1].bt_life - bthr[i].bt_life) / 100);
349: }
350:
351: int
352: zapm_batt_minutes(int life)
353: {
354:
355: return (zaurus_main_battery->bi_minutes * life / 100);
356: }
357:
358: void
359: zapm_enable_charging(struct zapm_softc *sc, int enable)
360: {
361:
362: scoop_discharge_battery(0);
363: scoop_charge_battery(enable, 0);
364: scoop_led_set(SCOOP_LED_ORANGE, enable);
365: }
366:
367: /*
368: * Return non-zero if the charge complete signal indicates that the
369: * battery is fully charged. Restart charging to clear this signal.
370: */
371: int
372: zapm_charge_complete(struct zapm_softc *sc)
373: {
374:
375: if (sc->sc_charging && sc->sc_batt_full < MIN_BATT_FULL) {
376: if (pxa2x0_gpio_get_bit(GPIO_CHRG_CO_C3000) != 0) {
377: if (++sc->sc_batt_full < MIN_BATT_FULL) {
378: DPRINTF(("battery almost full\n"));
379: zapm_enable_charging(sc, 0);
380: delay(15000);
381: zapm_enable_charging(sc, 1);
382: }
383: } else if (sc->sc_batt_full > 0) {
384: /* false alarm */
385: sc->sc_batt_full = 0;
386: zapm_enable_charging(sc, 0);
387: delay(15000);
388: zapm_enable_charging(sc, 1);
389: }
390: }
391:
392: return (sc->sc_batt_full >= MIN_BATT_FULL);
393: }
394:
395: /*
396: * Poll power-management related GPIO inputs, update battery life
397: * in softc, and/or control battery charging.
398: */
399: void
400: zapm_poll(void *v)
401: {
402: struct zapm_softc *sc = v;
403: int ac_on;
404: int bc_lock;
405: int charging;
406: int volt;
407: int s;
408:
409: s = splhigh();
410:
411: /* Check positition of battery compartment lock switch. */
412: bc_lock = pxa2x0_gpio_get_bit(GPIO_BATT_COVER_C3000) ? 1 : 0;
413:
414: /* Stop discharging. */
415: if (sc->sc_discharging) {
416: sc->sc_discharging = 0;
417: volt = zapm_batt_volt();
418: ac_on = zapm_ac_on();
419: charging = 0;
420: DPRINTF(("zapm_poll: discharge off volt %d\n", volt));
421: } else {
422: ac_on = zapm_ac_on();
423: charging = sc->sc_charging;
424: volt = sc->sc_batt_volt;
425: }
426:
427: /* Start or stop charging as necessary. */
428: if (ac_on && bc_lock) {
429: if (charging) {
430: if (zapm_charge_complete(sc)) {
431: DPRINTF(("zapm_poll: batt full\n"));
432: charging = 0;
433: zapm_enable_charging(sc, 0);
434: }
435: } else if (!zapm_charge_complete(sc)) {
436: charging = 1;
437: volt = zapm_batt_volt();
438: zapm_enable_charging(sc, 1);
439: DPRINTF(("zapm_poll: start charging volt %d\n", volt));
440: }
441: } else {
442: if (charging) {
443: charging = 0;
444: zapm_enable_charging(sc, 0);
445: timerclear(&sc->sc_lastbattchk);
446: DPRINTF(("zapm_poll: stop charging\n"));
447: }
448: sc->sc_batt_full = 0;
449: }
450:
451: /*
452: * Restart charging once in a while. Discharge a few milliseconds
453: * before updating the voltage in our softc if A/C is connected.
454: */
455: if (bc_lock && ratecheck(&sc->sc_lastbattchk, &zapm_battchkrate)) {
456: if (sc->sc_suspended) {
457: DPRINTF(("zapm_poll: suspended %lu %lu\n",
458: sc->sc_lastbattchk.tv_sec,
459: pxa2x0_rtc_getsecs()));
460: if (charging) {
461: zapm_enable_charging(sc, 0);
462: delay(15000);
463: zapm_enable_charging(sc, 1);
464: pxa2x0_rtc_setalarm(pxa2x0_rtc_getsecs() +
465: zapm_battchkrate.tv_sec + 1);
466: }
467: } else if (ac_on && sc->sc_batt_full == 0) {
468: DPRINTF(("zapm_poll: discharge on\n"));
469: if (charging)
470: zapm_enable_charging(sc, 0);
471: sc->sc_discharging = 1;
472: scoop_discharge_battery(1);
473: timeout_add(&sc->sc_poll, DISCHARGE_TIMEOUT);
474: } else if (!ac_on) {
475: volt = zapm_batt_volt();
476: DPRINTF(("zapm_poll: volt %d\n", volt));
477: }
478: }
479:
480: /* Update the cached power state in our softc. */
481: if (ac_on != sc->sc_ac_on || charging != sc->sc_charging ||
482: volt != sc->sc_batt_volt) {
483: sc->sc_ac_on = ac_on;
484: sc->sc_charging = charging;
485: sc->sc_batt_volt = volt;
486: if (sc->sc_event == APM_NOEVENT)
487: sc->sc_event = APM_POWER_CHANGE;
488: }
489:
490: /* Detect battery low conditions. */
491: if (!ac_on) {
492: if (zapm_batt_life(volt) < 5)
493: sc->sc_event = APM_BATTERY_LOW;
494: if (zapm_batt_state(volt) == APM_BATT_CRITICAL)
495: sc->sc_event = APM_CRIT_SUSPEND_REQ;
496: }
497:
498: #ifdef APMDEBUG
499: if (sc->sc_event != APM_NOEVENT)
500: DPRINTF(("zapm_poll: power event %d\n", sc->sc_event));
501: #endif
502: splx(s);
503: }
504:
505: /*
506: * apm_thread() calls this routine approximately once per second.
507: */
508: int
509: zapm_get_event(struct pxa2x0_apm_softc *pxa_sc, u_int *typep)
510: {
511: struct zapm_softc *sc = (struct zapm_softc *)pxa_sc;
512: int s;
513:
514: s = splsoftclock();
515:
516: /* Don't interfere with discharging. */
517: if (sc->sc_discharging)
518: *typep = sc->sc_event;
519: else if (sc->sc_event == APM_NOEVENT) {
520: zapm_poll(sc);
521: *typep = sc->sc_event;
522: }
523: sc->sc_event = APM_NOEVENT;
524:
525: splx(s);
526: return (*typep == APM_NOEVENT);
527: }
528:
529: /*
530: * Return power status to the generic APM driver.
531: */
532: void
533: zapm_power_info(struct pxa2x0_apm_softc *pxa_sc, struct apm_power_info *power)
534: {
535: struct zapm_softc *sc = (struct zapm_softc *)pxa_sc;
536: int s;
537: int ac_on;
538: int volt;
539: int charging;
540:
541: s = splsoftclock();
542: ac_on = sc->sc_ac_on;
543: volt = sc->sc_batt_volt;
544: charging = sc->sc_charging;
545: splx(s);
546:
547: power->ac_state = ac_on ? APM_AC_ON : APM_AC_OFF;
548: if (charging)
549: power->battery_state = APM_BATT_CHARGING;
550: else
551: power->battery_state = zapm_batt_state(volt);
552:
553: power->battery_life = zapm_batt_life(volt);
554: power->minutes_left = zapm_batt_minutes(power->battery_life);
555: }
556:
557: /*
558: * Called before suspending when all powerhooks are done.
559: */
560: void
561: zapm_suspend(struct pxa2x0_apm_softc *pxa_sc)
562: {
563: struct zapm_softc *sc = (struct zapm_softc *)pxa_sc;
564:
565: /* Poll in suspended mode and forget the discharge timeout. */
566: sc->sc_suspended = 1;
567: timeout_del(&sc->sc_poll);
568:
569: /* Make sure charging is enabled and RTC alarm is set. */
570: timerclear(&sc->sc_lastbattchk);
571:
572: zapm_poll(sc);
573:
574: #if 0
575: pxa2x0_rtc_setalarm(pxa2x0_rtc_getsecs() + 5);
576: #endif
577: pxa2x0_wakeup_config(PXA2X0_WAKEUP_ALL, 1);
578: }
579:
580: /*
581: * Called after wake-up from suspend with interrupts still disabled,
582: * before any powerhooks are done.
583: */
584: int
585: zapm_resume(struct pxa2x0_apm_softc *pxa_sc)
586: {
587: struct zapm_softc *sc = (struct zapm_softc *)pxa_sc;
588: int a, b;
589: u_int wsrc;
590: int wakeup = 0;
591:
592: /* C3000 */
593: a = pxa2x0_gpio_get_bit(97) ? 1 : 0;
594: b = pxa2x0_gpio_get_bit(96) ? 2 : 0;
595:
596: wsrc = pxa2x0_wakeup_status();
597:
598: /* Resume only if the lid is not closed. */
599: if ((a | b) != 3 && (wsrc & PXA2X0_WAKEUP_POWERON) != 0) {
600: int timeout = 100; /* 10 ms */
601: /* C3000 */
602: while (timeout-- > 0 && pxa2x0_gpio_get_bit(95) != 0) {
603: if (timeout == 0) {
604: wakeup = 1;
605: break;
606: }
607: delay(100);
608: }
609: }
610:
611: /* Initialize the SSP unit before using the MAX1111 again. */
612: zssp_init();
613:
614: zapm_poll(sc);
615:
616: if (wakeup) {
617: /* Resume normal polling. */
618: sc->sc_suspended = 0;
619:
620: pxa2x0_rtc_setalarm(0);
621: } else {
622: #if 0
623: DPRINTF(("zapm_resume: suspended %lu %lu\n",
624: sc->sc_lastbattchk.tv_sec, pxa2x0_rtc_getsecs()));
625: pxa2x0_rtc_setalarm(pxa2x0_rtc_getsecs() + 5);
626: #endif
627: }
628:
629: return (wakeup);
630: }
631:
632: void
633: zapm_poweroff(void)
634: {
635: struct pxa2x0_apm_softc *sc;
636:
637: KASSERT(apm_cd.cd_ndevs > 0 && apm_cd.cd_devs[0] != NULL);
638: sc = apm_cd.cd_devs[0];
639:
640: dopowerhooks(PWR_SUSPEND);
641:
642: /* XXX enable charging during suspend */
643:
644: /* XXX keep power LED state during suspend */
645:
646: /* XXX do the same thing for GPIO 43 (BTTXD) */
647:
648: /* XXX scoop power down */
649:
650: /* XXX set PGSRn and GPDRn */
651:
652: pxa2x0_wakeup_config(PXA2X0_WAKEUP_ALL, 1);
653:
654: do {
655: pxa2x0_apm_sleep(sc);
656: }
657: while (!zapm_resume(sc));
658:
659: zapm_restart();
660:
661: /* NOTREACHED */
662: dopowerhooks(PWR_RESUME);
663: }
664:
665: /*
666: * Do a GPIO reset, immediately causing the processor to begin the normal
667: * boot sequence. See 2.7 Reset in the PXA27x Developer's Manual for the
668: * summary of effects of this kind of reset.
669: */
670: void
671: zapm_restart(void)
672: {
673: if (apm_cd.cd_ndevs > 0 && apm_cd.cd_devs[0] != NULL) {
674: struct pxa2x0_apm_softc *sc = apm_cd.cd_devs[0];
675: int rv;
676:
677: /*
678: * Reduce the ROM Delay Next Access and ROM Delay First
679: * Access times for synchronous flash connected to nCS1.
680: */
681: rv = bus_space_read_4(sc->sc_iot, sc->sc_memctl_ioh,
682: MEMCTL_MSC0);
683: if ((rv & 0xffff0000) == 0x7ff00000)
684: bus_space_write_4(sc->sc_iot, sc->sc_memctl_ioh,
685: MEMCTL_MSC0, (rv & 0xffff) | 0x7ee00000);
686: }
687:
688: /* External reset circuit presumably asserts nRESET_GPIO. */
689: pxa2x0_gpio_set_function(89, GPIO_OUT | GPIO_SET);
690: delay(1000000);
691: }
CVSweb