Annotation of sys/arch/zaurus/dev/zaurus_apm.c, Revision 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