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