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