1 /* $NetBSD: zapm.c,v 1.6 2009/04/03 04:13:17 uwe Exp $ */ 2 /* $OpenBSD: zaurus_apm.c,v 1.13 2006/12/12 23:14:28 dim Exp $ */ 3 4 /* 5 * Copyright (c) 2005 Uwe Stuehler <uwe@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/cdefs.h> 21 __KERNEL_RCSID(0, "$NetBSD: zapm.c,v 1.6 2009/04/03 04:13:17 uwe Exp $"); 22 23 #include <sys/param.h> 24 #include <sys/systm.h> 25 #include <sys/kernel.h> 26 #include <sys/callout.h> 27 #include <sys/selinfo.h> /* XXX: for apm_softc that is exposed here */ 28 29 #include <dev/hpc/apm/apmvar.h> 30 31 #include <arm/xscale/pxa2x0reg.h> 32 #include <arm/xscale/pxa2x0var.h> 33 #include <arm/xscale/pxa2x0cpu.h> 34 #include <arm/xscale/pxa2x0_gpio.h> 35 36 #include <machine/config_hook.h> 37 38 #include <zaurus/dev/scoopvar.h> 39 #include <zaurus/dev/zsspvar.h> 40 #include <zaurus/zaurus/zaurus_reg.h> 41 #include <zaurus/zaurus/zaurus_var.h> 42 43 #ifdef APMDEBUG 44 #define DPRINTF(x) printf x 45 #else 46 #define DPRINTF(x) do { } while (/*CONSTCOND*/0) 47 #endif 48 49 struct zapm_softc { 50 device_t sc_dev; 51 void *sc_apmdev; 52 53 struct callout sc_cyclic_poll; 54 struct callout sc_discharge_poll; 55 struct timeval sc_lastbattchk; 56 volatile int suspended; 57 volatile int charging; 58 volatile int discharging; 59 int battery_volt; 60 int battery_full_cnt; 61 62 /* GPIO pin */ 63 int sc_ac_detect_pin; 64 int sc_batt_cover_pin; 65 int sc_charge_comp_pin; 66 67 /* machine-independent part */ 68 volatile u_int events; 69 volatile int power_state; 70 volatile int battery_state; 71 volatile int ac_state; 72 config_hook_tag sc_standby_hook; 73 config_hook_tag sc_suspend_hook; 74 config_hook_tag sc_battery_hook; 75 config_hook_tag sc_ac_hook; 76 int battery_life; 77 int minutes_left; 78 }; 79 80 static int zapm_match(device_t, cfdata_t, void *); 81 static void zapm_attach(device_t, device_t, void *); 82 83 CFATTACH_DECL_NEW(zapm, sizeof(struct zapm_softc), 84 zapm_match, zapm_attach, NULL, NULL); 85 86 static int zapm_hook(void *, int, long, void *); 87 static void zapm_disconnect(void *); 88 static void zapm_enable(void *, int); 89 static int zapm_set_powstate(void *, u_int, u_int); 90 static int zapm_get_powstat(void *, u_int, struct apm_power_info *); 91 static int zapm_get_event(void *, u_int *, u_int *); 92 static void zapm_cpu_busy(void *); 93 static void zapm_cpu_idle(void *); 94 static void zapm_get_capabilities(void *, u_int *, u_int *); 95 96 static struct apm_accessops zapm_accessops = { 97 zapm_disconnect, 98 zapm_enable, 99 zapm_set_powstate, 100 zapm_get_powstat, 101 zapm_get_event, 102 zapm_cpu_busy, 103 zapm_cpu_idle, 104 zapm_get_capabilities, 105 }; 106 107 static int zapm_acintr(void *); 108 static int zapm_bcintr(void *); 109 static void zapm_cyclic(void *); 110 static void zapm_poll(void *); 111 static void zapm_poll1(void *, int); 112 113 /* battery-related GPIO pins */ 114 #define GPIO_AC_IN_C3000 115 /* 0=AC connected */ 115 #define GPIO_CHRG_CO_C3000 101 /* 1=battery full */ 116 #define GPIO_BATT_COVER_C3000 90 /* 0=unlocked */ 117 118 /* Cyclic timer value */ 119 #define CYCLIC_TIME (60 * hz) /* 60s */ 120 121 static int 122 zapm_match(device_t parent, cfdata_t cf, void *aux) 123 { 124 125 if (!ZAURUS_ISC3000) 126 return 0; 127 return 1; 128 } 129 130 static void 131 zapm_attach(device_t parent, device_t self, void *aux) 132 { 133 struct zapm_softc *sc = device_private(self); 134 struct apmdev_attach_args aaa; 135 136 sc->sc_dev = self; 137 138 aprint_normal(": pseudo power management module\n"); 139 aprint_naive("\n"); 140 141 /* machine-depent part */ 142 callout_init(&sc->sc_cyclic_poll, 0); 143 callout_setfunc(&sc->sc_cyclic_poll, zapm_cyclic, sc); 144 callout_init(&sc->sc_discharge_poll, 0); 145 callout_setfunc(&sc->sc_discharge_poll, zapm_poll, sc); 146 147 if (ZAURUS_ISC3000) { 148 sc->sc_ac_detect_pin = GPIO_AC_IN_C3000; 149 sc->sc_batt_cover_pin = GPIO_BATT_COVER_C3000; 150 sc->sc_charge_comp_pin = GPIO_CHRG_CO_C3000; 151 } else { 152 /* XXX */ 153 return; 154 } 155 156 pxa2x0_gpio_set_function(sc->sc_ac_detect_pin, GPIO_IN); 157 pxa2x0_gpio_set_function(sc->sc_charge_comp_pin, GPIO_IN); 158 pxa2x0_gpio_set_function(sc->sc_batt_cover_pin, GPIO_IN); 159 160 (void)pxa2x0_gpio_intr_establish(sc->sc_ac_detect_pin, 161 IST_EDGE_BOTH, IPL_BIO, zapm_acintr, sc); 162 (void)pxa2x0_gpio_intr_establish(sc->sc_charge_comp_pin, 163 IST_EDGE_BOTH, IPL_BIO, zapm_bcintr, sc); 164 165 /* machine-independent part */ 166 sc->events = 0; 167 sc->power_state = APM_SYS_READY; 168 sc->battery_state = APM_BATT_FLAG_UNKNOWN; 169 sc->ac_state = APM_AC_UNKNOWN; 170 sc->battery_life = APM_BATT_LIFE_UNKNOWN; 171 sc->minutes_left = 0; 172 sc->sc_standby_hook = config_hook(CONFIG_HOOK_PMEVENT, 173 CONFIG_HOOK_PMEVENT_STANDBYREQ, 174 CONFIG_HOOK_EXCLUSIVE, 175 zapm_hook, sc); 176 sc->sc_suspend_hook = config_hook(CONFIG_HOOK_PMEVENT, 177 CONFIG_HOOK_PMEVENT_SUSPENDREQ, 178 CONFIG_HOOK_EXCLUSIVE, 179 zapm_hook, sc); 180 181 sc->sc_battery_hook = config_hook(CONFIG_HOOK_PMEVENT, 182 CONFIG_HOOK_PMEVENT_BATTERY, 183 CONFIG_HOOK_SHARE, 184 zapm_hook, sc); 185 186 sc->sc_ac_hook = config_hook(CONFIG_HOOK_PMEVENT, 187 CONFIG_HOOK_PMEVENT_AC, 188 CONFIG_HOOK_SHARE, 189 zapm_hook, sc); 190 191 aaa.accessops = &zapm_accessops; 192 aaa.accesscookie = sc; 193 aaa.apm_detail = 0x0102; 194 195 sc->sc_apmdev = config_found_ia(self, "apmdevif", &aaa, apmprint); 196 if (sc->sc_apmdev != NULL) { 197 zapm_poll1(sc, 0); 198 callout_schedule(&sc->sc_cyclic_poll, CYCLIC_TIME); 199 } 200 } 201 202 static int 203 zapm_hook(void *v, int type, long id, void *msg) 204 { 205 struct zapm_softc *sc = (struct zapm_softc *)v; 206 int charge; 207 int message; 208 int s; 209 210 if (type != CONFIG_HOOK_PMEVENT) 211 return 1; 212 213 if (CONFIG_HOOK_VALUEP(msg)) 214 message = (int)msg; 215 else 216 message = *(int *)msg; 217 218 s = splhigh(); 219 220 switch (id) { 221 case CONFIG_HOOK_PMEVENT_STANDBYREQ: 222 if (sc->power_state != APM_SYS_STANDBY) { 223 sc->events |= (1 << APM_USER_STANDBY_REQ); 224 } else { 225 sc->events |= (1 << APM_NORMAL_RESUME); 226 } 227 break; 228 case CONFIG_HOOK_PMEVENT_SUSPENDREQ: 229 if (sc->power_state != APM_SYS_SUSPEND) { 230 DPRINTF(("zapm: suspend request\n")); 231 sc->events |= (1 << APM_USER_SUSPEND_REQ); 232 } else { 233 sc->events |= (1 << APM_NORMAL_RESUME); 234 } 235 break; 236 case CONFIG_HOOK_PMEVENT_BATTERY: 237 switch (message) { 238 case CONFIG_HOOK_BATT_CRITICAL: 239 DPRINTF(("zapm: battery state critical\n")); 240 charge = sc->battery_state & APM_BATT_FLAG_CHARGING; 241 sc->battery_state = APM_BATT_FLAG_CRITICAL; 242 sc->battery_state |= charge; 243 sc->battery_life = 0; 244 break; 245 case CONFIG_HOOK_BATT_LOW: 246 DPRINTF(("zapm: battery state low\n")); 247 charge = sc->battery_state & APM_BATT_FLAG_CHARGING; 248 sc->battery_state = APM_BATT_FLAG_LOW; 249 sc->battery_state |= charge; 250 break; 251 case CONFIG_HOOK_BATT_HIGH: 252 DPRINTF(("zapm: battery state high\n")); 253 charge = sc->battery_state & APM_BATT_FLAG_CHARGING; 254 sc->battery_state = APM_BATT_FLAG_HIGH; 255 sc->battery_state |= charge; 256 break; 257 case CONFIG_HOOK_BATT_10P: 258 DPRINTF(("zapm: battery life 10%%\n")); 259 sc->battery_life = 10; 260 break; 261 case CONFIG_HOOK_BATT_20P: 262 DPRINTF(("zapm: battery life 20%%\n")); 263 sc->battery_life = 20; 264 break; 265 case CONFIG_HOOK_BATT_30P: 266 DPRINTF(("zapm: battery life 30%%\n")); 267 sc->battery_life = 30; 268 break; 269 case CONFIG_HOOK_BATT_40P: 270 DPRINTF(("zapm: battery life 40%%\n")); 271 sc->battery_life = 40; 272 break; 273 case CONFIG_HOOK_BATT_50P: 274 DPRINTF(("zapm: battery life 50%%\n")); 275 sc->battery_life = 50; 276 break; 277 case CONFIG_HOOK_BATT_60P: 278 DPRINTF(("zapm: battery life 60%%\n")); 279 sc->battery_life = 60; 280 break; 281 case CONFIG_HOOK_BATT_70P: 282 DPRINTF(("zapm: battery life 70%%\n")); 283 sc->battery_life = 70; 284 break; 285 case CONFIG_HOOK_BATT_80P: 286 DPRINTF(("zapm: battery life 80%%\n")); 287 sc->battery_life = 80; 288 break; 289 case CONFIG_HOOK_BATT_90P: 290 DPRINTF(("zapm: battery life 90%%\n")); 291 sc->battery_life = 90; 292 break; 293 case CONFIG_HOOK_BATT_100P: 294 DPRINTF(("zapm: battery life 100%%\n")); 295 sc->battery_life = 100; 296 break; 297 case CONFIG_HOOK_BATT_UNKNOWN: 298 DPRINTF(("zapm: battery state unknown\n")); 299 sc->battery_state = APM_BATT_FLAG_UNKNOWN; 300 sc->battery_life = APM_BATT_LIFE_UNKNOWN; 301 break; 302 case CONFIG_HOOK_BATT_NO_SYSTEM_BATTERY: 303 DPRINTF(("zapm: battery state no system battery?\n")); 304 sc->battery_state = APM_BATT_FLAG_NO_SYSTEM_BATTERY; 305 sc->battery_life = APM_BATT_LIFE_UNKNOWN; 306 break; 307 } 308 break; 309 case CONFIG_HOOK_PMEVENT_AC: 310 switch (message) { 311 case CONFIG_HOOK_AC_OFF: 312 DPRINTF(("zapm: ac not connected\n")); 313 sc->battery_state &= ~APM_BATT_FLAG_CHARGING; 314 sc->ac_state = APM_AC_OFF; 315 break; 316 case CONFIG_HOOK_AC_ON_CHARGE: 317 DPRINTF(("zapm: charging\n")); 318 sc->battery_state |= APM_BATT_FLAG_CHARGING; 319 sc->ac_state = APM_AC_ON; 320 break; 321 case CONFIG_HOOK_AC_ON_NOCHARGE: 322 DPRINTF(("zapm: ac connected\n")); 323 sc->battery_state &= ~APM_BATT_FLAG_CHARGING; 324 sc->ac_state = APM_AC_ON; 325 break; 326 case CONFIG_HOOK_AC_UNKNOWN: 327 sc->ac_state = APM_AC_UNKNOWN; 328 break; 329 } 330 break; 331 } 332 333 splx(s); 334 335 return 0; 336 } 337 338 static void 339 zapm_disconnect(void *v) 340 { 341 #if 0 342 struct zapm_softc *sc = (struct zapm_softc *)v; 343 #endif 344 } 345 346 static void 347 zapm_enable(void *v, int onoff) 348 { 349 #if 0 350 struct zapm_softc *sc = (struct zapm_softc *)v; 351 #endif 352 } 353 354 static int 355 zapm_set_powstate(void *v, u_int devid, u_int powstat) 356 { 357 struct zapm_softc *sc = (struct zapm_softc *)v; 358 359 if (devid != APM_DEV_ALLDEVS) 360 return APM_ERR_UNRECOG_DEV; 361 362 switch (powstat) { 363 case APM_SYS_READY: 364 DPRINTF(("zapm: set power state READY\n")); 365 sc->power_state = APM_SYS_READY; 366 break; 367 case APM_SYS_STANDBY: 368 DPRINTF(("zapm: set power state STANDBY\n")); 369 /* XXX */ 370 DPRINTF(("zapm: resume\n")); 371 break; 372 case APM_SYS_SUSPEND: 373 DPRINTF(("zapm: set power state SUSPEND...\n")); 374 /* XXX */ 375 DPRINTF(("zapm: resume\n")); 376 break; 377 case APM_SYS_OFF: 378 DPRINTF(("zapm: set power state OFF\n")); 379 sc->power_state = APM_SYS_OFF; 380 break; 381 case APM_LASTREQ_INPROG: 382 /*DPRINTF(("zapm: set power state INPROG\n"));*/ 383 break; 384 case APM_LASTREQ_REJECTED: 385 DPRINTF(("zapm: set power state REJECTED\n")); 386 break; 387 } 388 389 return 0; 390 } 391 392 static int 393 zapm_get_powstat(void *v, u_int batteryid, struct apm_power_info *pinfo) 394 { 395 struct zapm_softc *sc = (struct zapm_softc *)v; 396 int val; 397 398 if (config_hook_call(CONFIG_HOOK_GET, 399 CONFIG_HOOK_ACADAPTER, &val) != -1) 400 pinfo->ac_state = val; 401 else 402 pinfo->ac_state = sc->ac_state; 403 if (config_hook_call(CONFIG_HOOK_GET, 404 CONFIG_HOOK_CHARGE, &val) != -1) 405 pinfo->battery_state = val; 406 else 407 pinfo->battery_state = sc->battery_state; 408 if (config_hook_call(CONFIG_HOOK_GET, 409 CONFIG_HOOK_BATTERYVAL, &val) != -1) 410 pinfo->battery_life = val; 411 else 412 pinfo->battery_life = sc->battery_life; 413 414 return 0; 415 } 416 417 static int 418 zapm_get_event(void *v, u_int *event_type, u_int *event_info) 419 { 420 struct zapm_softc *sc = (struct zapm_softc *)v; 421 u_int ev; 422 int s; 423 424 s = splhigh(); 425 for (ev = APM_STANDBY_REQ; ev <= APM_CAP_CHANGE; ev++) { 426 if (sc->events & (1 << ev)) { 427 sc->events &= ~(1 << ev); 428 *event_type = ev; 429 if (*event_type == APM_NORMAL_RESUME || 430 *event_type == APM_CRIT_RESUME) { 431 /* pccard power off in the suspend state */ 432 *event_info = 1; 433 sc->power_state = APM_SYS_READY; 434 } else { 435 *event_info = 0; 436 } 437 splx(s); 438 439 return 0; 440 } 441 } 442 splx(s); 443 444 return APM_ERR_NOEVENTS; 445 } 446 447 static void 448 zapm_cpu_busy(void *v) 449 { 450 #if 0 451 struct zapm_softc *sc = (struct zapm_softc *)v; 452 #endif 453 } 454 455 static void 456 zapm_cpu_idle(void *v) 457 { 458 #if 0 459 struct zapm_softc *sc = (struct zapm_softc *)v; 460 #endif 461 } 462 463 static void 464 zapm_get_capabilities(void *v, u_int *numbatts, u_int *capflags) 465 { 466 #if 0 467 struct zapm_softc *sc = (struct zapm_softc *)v; 468 #endif 469 470 *numbatts = 1; 471 *capflags = 0 /* | APM_GLOBAL_STANDBY | APM_GLOBAL_SUSPEND */; 472 } 473 474 /*----------------------------------------------------------------------------- 475 * zaurus depent part 476 */ 477 /* MAX1111 command word */ 478 #define MAXCTRL_PD0 (1<<0) 479 #define MAXCTRL_PD1 (1<<1) 480 #define MAXCTRL_SGL (1<<2) 481 #define MAXCTRL_UNI (1<<3) 482 #define MAXCTRL_SEL_SHIFT 4 483 #define MAXCTRL_STR (1<<7) 484 485 /* MAX1111 ADC channels */ 486 #define BATT_THM 2 487 #define BATT_AD 4 488 #define JK_VAD 6 489 490 /* 491 * Battery-specific information 492 */ 493 struct battery_threshold { 494 int percent; 495 int value; 496 int state; 497 }; 498 499 struct battery_info { 500 const struct battery_threshold *bi_thres; 501 }; 502 503 static const struct battery_threshold zaurus_battery_life_c3000[] = { 504 { 100, 212, CONFIG_HOOK_BATT_HIGH }, 505 { 98, 212, CONFIG_HOOK_BATT_HIGH }, 506 { 95, 211, CONFIG_HOOK_BATT_HIGH }, 507 { 93, 210, CONFIG_HOOK_BATT_HIGH }, 508 { 90, 209, CONFIG_HOOK_BATT_HIGH }, 509 { 88, 208, CONFIG_HOOK_BATT_HIGH }, 510 { 85, 207, CONFIG_HOOK_BATT_HIGH }, 511 { 83, 206, CONFIG_HOOK_BATT_HIGH }, 512 { 80, 205, CONFIG_HOOK_BATT_HIGH }, 513 { 78, 204, CONFIG_HOOK_BATT_HIGH }, 514 { 75, 203, CONFIG_HOOK_BATT_HIGH }, 515 { 73, 202, CONFIG_HOOK_BATT_HIGH }, 516 { 70, 201, CONFIG_HOOK_BATT_HIGH }, 517 { 68, 200, CONFIG_HOOK_BATT_HIGH }, 518 { 65, 199, CONFIG_HOOK_BATT_HIGH }, 519 { 63, 198, CONFIG_HOOK_BATT_HIGH }, 520 { 60, 197, CONFIG_HOOK_BATT_HIGH }, 521 { 58, 196, CONFIG_HOOK_BATT_HIGH }, 522 { 55, 195, CONFIG_HOOK_BATT_HIGH }, 523 { 53, 194, CONFIG_HOOK_BATT_HIGH }, 524 { 50, 193, CONFIG_HOOK_BATT_HIGH }, 525 { 48, 192, CONFIG_HOOK_BATT_HIGH }, 526 { 45, 192, CONFIG_HOOK_BATT_HIGH }, 527 { 43, 191, CONFIG_HOOK_BATT_HIGH }, 528 { 40, 191, CONFIG_HOOK_BATT_HIGH }, 529 { 38, 190, CONFIG_HOOK_BATT_HIGH }, 530 { 35, 190, CONFIG_HOOK_BATT_HIGH }, 531 { 33, 189, CONFIG_HOOK_BATT_HIGH }, 532 { 30, 188, CONFIG_HOOK_BATT_HIGH }, 533 { 28, 187, CONFIG_HOOK_BATT_LOW }, 534 { 25, 186, CONFIG_HOOK_BATT_LOW }, 535 { 23, 185, CONFIG_HOOK_BATT_LOW }, 536 { 20, 184, CONFIG_HOOK_BATT_LOW }, 537 { 18, 183, CONFIG_HOOK_BATT_LOW }, 538 { 15, 182, CONFIG_HOOK_BATT_LOW }, 539 { 13, 181, CONFIG_HOOK_BATT_LOW }, 540 { 10, 180, CONFIG_HOOK_BATT_LOW }, 541 { 8, 179, CONFIG_HOOK_BATT_LOW }, 542 { 5, 178, CONFIG_HOOK_BATT_LOW }, 543 { 0, 0, CONFIG_HOOK_BATT_CRITICAL } 544 }; 545 546 static const struct battery_info zaurus_battery_c3000 = { 547 zaurus_battery_life_c3000 548 }; 549 550 static const struct battery_info *zaurus_main_battery = &zaurus_battery_c3000; 551 552 /* Restart charging this many times before accepting BATT_FULL. */ 553 #define MIN_BATT_FULL 2 554 555 /* Discharge 100 ms before reading the voltage if AC is connected. */ 556 #define DISCHARGE_TIMEOUT (hz / 10) 557 558 /* Check battery voltage and "kick charging" every minute. */ 559 static const struct timeval zapm_battchkrate = { 60, 0 }; 560 561 static int zapm_get_ac_state(struct zapm_softc *); 562 static int zapm_get_battery_compartment_state(struct zapm_softc *); 563 static int zapm_get_charge_complete_state(struct zapm_softc *); 564 static void zapm_set_charging(struct zapm_softc *, int); 565 static int zapm_charge_complete(struct zapm_softc *); 566 static int max1111_adc_value_avg(int chan, int pause); 567 static int zapm_get_battery_volt(void); 568 static int zapm_battery_state(int volt); 569 static int zapm_battery_life(int volt); 570 571 static int 572 zapm_acintr(void *v) 573 { 574 575 zapm_poll1(v, 1); 576 577 return 1; 578 } 579 580 static int 581 zapm_bcintr(void *v) 582 { 583 584 zapm_poll1(v, 1); 585 586 return 1; 587 } 588 589 static void 590 zapm_cyclic(void *v) 591 { 592 struct zapm_softc *sc = (struct zapm_softc *)v; 593 594 zapm_poll1(sc, 1); 595 596 callout_schedule(&sc->sc_cyclic_poll, CYCLIC_TIME); 597 } 598 599 static void 600 zapm_poll(void *v) 601 { 602 603 zapm_poll1(v, 1); 604 } 605 606 static int 607 zapm_get_ac_state(struct zapm_softc *sc) 608 { 609 610 if (!pxa2x0_gpio_get_bit(sc->sc_ac_detect_pin)) 611 return APM_AC_ON; 612 return APM_AC_OFF; 613 } 614 615 static int 616 zapm_get_battery_compartment_state(struct zapm_softc *sc) 617 { 618 619 return pxa2x0_gpio_get_bit(sc->sc_batt_cover_pin); 620 } 621 622 static int 623 zapm_get_charge_complete_state(struct zapm_softc *sc) 624 { 625 626 return pxa2x0_gpio_get_bit(sc->sc_charge_comp_pin); 627 } 628 629 static void 630 zapm_set_charging(struct zapm_softc *sc, int enable) 631 { 632 633 scoop_discharge_battery(0); 634 scoop_charge_battery(enable, 0); 635 scoop_led_set(SCOOP_LED_ORANGE, enable); 636 } 637 638 /* 639 * Return non-zero if the charge complete signal indicates that the 640 * battery is fully charged. Restart charging to clear this signal. 641 */ 642 static int 643 zapm_charge_complete(struct zapm_softc *sc) 644 { 645 646 if (sc->charging && sc->battery_full_cnt < MIN_BATT_FULL) { 647 if (zapm_get_charge_complete_state(sc)) { 648 sc->battery_full_cnt++; 649 if (sc->battery_full_cnt < MIN_BATT_FULL) { 650 DPRINTF(("battery almost full\n")); 651 zapm_set_charging(sc, 0); 652 delay(15000); 653 zapm_set_charging(sc, 1); 654 } 655 } else if (sc->battery_full_cnt > 0) { 656 /* false alarm */ 657 sc->battery_full_cnt = 0; 658 zapm_set_charging(sc, 0); 659 delay(15000); 660 zapm_set_charging(sc, 1); 661 } 662 } 663 664 return (sc->battery_full_cnt >= MIN_BATT_FULL); 665 } 666 667 static int 668 max1111_adc_value(int chan) 669 { 670 671 return ((int)zssp_ic_send(ZSSP_IC_MAX1111, MAXCTRL_PD0 | 672 MAXCTRL_PD1 | MAXCTRL_SGL | MAXCTRL_UNI | 673 (chan << MAXCTRL_SEL_SHIFT) | MAXCTRL_STR)); 674 } 675 676 /* XXX simplify */ 677 static int 678 max1111_adc_value_avg(int chan, int pause) 679 { 680 int val[5]; 681 int sum; 682 int minv, maxv, v; 683 int i; 684 685 DPRINTF(("max1111_adc_value_avg: chan = %d, pause = %d\n", 686 chan, pause)); 687 688 for (i = 0; i < 5; i++) { 689 val[i] = max1111_adc_value(chan); 690 if (i != 4) 691 delay(pause * 1000); 692 DPRINTF(("max1111_adc_value_avg: chan[%d] = %d\n", i, val[i])); 693 } 694 695 /* get max value */ 696 v = val[0]; 697 minv = 0; 698 for (i = 1; i < 5; i++) { 699 if (v < val[i]) { 700 v = val[i]; 701 minv = i; 702 } 703 } 704 705 /* get min value */ 706 v = val[4]; 707 maxv = 4; 708 for (i = 3; i >= 0; i--) { 709 if (v > val[i]) { 710 v = val[i]; 711 maxv = i; 712 } 713 } 714 715 DPRINTF(("max1111_adc_value_avg: minv = %d, maxv = %d\n", minv, maxv)); 716 sum = 0; 717 for (i = 0; i < 5; i++) { 718 if (i == minv || i == maxv) 719 continue; 720 sum += val[i]; 721 } 722 723 DPRINTF(("max1111_adc_value_avg: sum = %d, sum / 3 = %d\n", 724 sum, sum / 3)); 725 726 return sum / 3; 727 } 728 729 static int 730 zapm_get_battery_volt(void) 731 { 732 733 return max1111_adc_value_avg(BATT_AD, 10); 734 } 735 736 static int 737 zapm_battery_state(int volt) 738 { 739 const struct battery_threshold *bthr; 740 int i; 741 742 bthr = zaurus_main_battery->bi_thres; 743 744 for (i = 0; bthr[i].value > 0; i++) 745 if (bthr[i].value <= volt) 746 break; 747 748 return bthr[i].state; 749 } 750 751 static int 752 zapm_battery_life(int volt) 753 { 754 const struct battery_threshold *bthr; 755 int i; 756 757 bthr = zaurus_main_battery->bi_thres; 758 759 for (i = 0; bthr[i].value > 0; i++) 760 if (bthr[i].value <= volt) 761 break; 762 763 if (i == 0) 764 return bthr[0].percent; 765 766 return (bthr[i].percent + 767 ((volt - bthr[i].value) * 100) / 768 (bthr[i-1].value - bthr[i].value) * 769 (bthr[i-1].percent - bthr[i].percent) / 100); 770 } 771 772 /* 773 * Poll power-management related GPIO inputs, update battery life 774 * in softc, and/or control battery charging. 775 */ 776 static void 777 zapm_poll1(void *v, int do_suspend) 778 { 779 struct zapm_softc *sc = (struct zapm_softc *)v; 780 int ac_state; 781 int bc_lock; 782 int charging; 783 int volt; 784 int s; 785 786 s = splhigh(); 787 788 ac_state = zapm_get_ac_state(sc); 789 bc_lock = zapm_get_battery_compartment_state(sc); 790 791 /* Stop discharging. */ 792 if (sc->discharging) { 793 sc->discharging = 0; 794 charging = 0; 795 volt = zapm_get_battery_volt(); 796 DPRINTF(("zapm_poll: discharge off volt %d\n", volt)); 797 } else { 798 charging = sc->battery_state & APM_BATT_FLAG_CHARGING; 799 volt = sc->battery_volt; 800 } 801 802 /* Start or stop charging as necessary. */ 803 if (ac_state && bc_lock) { 804 int charge_completed = zapm_charge_complete(sc); 805 if (charging) { 806 if (charge_completed) { 807 DPRINTF(("zapm_poll: battery is full\n")); 808 charging = 0; 809 zapm_set_charging(sc, 0); 810 } 811 } else if (!charge_completed) { 812 charging = 1; 813 volt = zapm_get_battery_volt(); 814 zapm_set_charging(sc, 1); 815 DPRINTF(("zapm_poll: start charging volt %d\n", volt)); 816 } 817 } else { 818 if (charging) { 819 charging = 0; 820 zapm_set_charging(sc, 0); 821 timerclear(&sc->sc_lastbattchk); 822 DPRINTF(("zapm_poll: stop charging\n")); 823 } 824 sc->battery_full_cnt = 0; 825 } 826 827 /* 828 * Restart charging once in a while. Discharge a few milliseconds 829 * before updating the voltage in our softc if A/C is connected. 830 */ 831 if (bc_lock && ratecheck(&sc->sc_lastbattchk, &zapm_battchkrate)) { 832 if (do_suspend && sc->suspended) { 833 /* XXX */ 834 #if 0 835 DPRINTF(("zapm_poll: suspended %lu %lu\n", 836 sc->lastbattchk.tv_sec, 837 pxa2x0_rtc_getsecs())); 838 if (charging) { 839 zapm_set_charging(sc, 0); 840 delay(15000); 841 zapm_set_charging(sc, 1); 842 pxa2x0_rtc_setalarm(pxa2x0_rtc_getsecs() + 843 zapm_battchkrate.tv_sec + 1); 844 } 845 #endif 846 } else if (ac_state && sc->battery_full_cnt == 0) { 847 DPRINTF(("zapm_poll: discharge on\n")); 848 if (charging) 849 zapm_set_charging(sc, 0); 850 sc->discharging = 1; 851 scoop_discharge_battery(1); 852 callout_schedule(&sc->sc_discharge_poll, 853 DISCHARGE_TIMEOUT); 854 } else if (!ac_state) { 855 volt = zapm_get_battery_volt(); 856 DPRINTF(("zapm_poll: volt %d\n", volt)); 857 } 858 } 859 860 /* Update the cached power state in our softc. */ 861 if ((ac_state != sc->ac_state) 862 || (charging != (sc->battery_state & APM_BATT_FLAG_CHARGING))) { 863 config_hook_call(CONFIG_HOOK_PMEVENT, 864 CONFIG_HOOK_PMEVENT_AC, 865 (void *)((ac_state == APM_AC_OFF) 866 ? CONFIG_HOOK_AC_OFF 867 : (charging ? CONFIG_HOOK_AC_ON_CHARGE 868 : CONFIG_HOOK_AC_ON_NOCHARGE))); 869 } 870 if (volt != sc->battery_volt) { 871 sc->battery_volt = volt; 872 sc->battery_life = zapm_battery_life(volt); 873 config_hook_call(CONFIG_HOOK_PMEVENT, 874 CONFIG_HOOK_PMEVENT_BATTERY, 875 (void *)zapm_battery_state(volt)); 876 } 877 878 splx(s); 879 } 880