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