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