pmu.c (185727) | pmu.c (185754) |
---|---|
1/*- 2 * Copyright (c) 2006 Michael Lorenz 3 * Copyright 2008 by Nathan Whitehorn 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: --- 15 unchanged lines hidden (view full) --- 24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 */ 30 31#include <sys/cdefs.h> | 1/*- 2 * Copyright (c) 2006 Michael Lorenz 3 * Copyright 2008 by Nathan Whitehorn 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: --- 15 unchanged lines hidden (view full) --- 24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 */ 30 31#include <sys/cdefs.h> |
32__FBSDID("$FreeBSD: head/sys/powerpc/powermac/pmu.c 185727 2008-12-07 00:42:15Z nwhitehorn $"); | 32__FBSDID("$FreeBSD: head/sys/powerpc/powermac/pmu.c 185754 2008-12-08 02:37:08Z nwhitehorn $"); |
33 34#include <sys/param.h> 35#include <sys/systm.h> 36#include <sys/module.h> 37#include <sys/bus.h> 38#include <sys/conf.h> 39#include <sys/kernel.h> 40#include <sys/sysctl.h> --- 21 unchanged lines hidden (view full) --- 62/* 63 * MacIO interface 64 */ 65static int pmu_probe(device_t); 66static int pmu_attach(device_t); 67static int pmu_detach(device_t); 68 69static u_int pmu_adb_send(device_t dev, u_char command_byte, int len, | 33 34#include <sys/param.h> 35#include <sys/systm.h> 36#include <sys/module.h> 37#include <sys/bus.h> 38#include <sys/conf.h> 39#include <sys/kernel.h> 40#include <sys/sysctl.h> --- 21 unchanged lines hidden (view full) --- 62/* 63 * MacIO interface 64 */ 65static int pmu_probe(device_t); 66static int pmu_attach(device_t); 67static int pmu_detach(device_t); 68 69static u_int pmu_adb_send(device_t dev, u_char command_byte, int len, |
70 u_char *data, u_char poll); | 70 u_char *data, u_char poll); |
71static u_int pmu_adb_autopoll(device_t dev, uint16_t mask); 72static void pmu_poll(device_t dev); | 71static u_int pmu_adb_autopoll(device_t dev, uint16_t mask); 72static void pmu_poll(device_t dev); |
73 |
|
73static int pmu_server_mode(SYSCTL_HANDLER_ARGS); | 74static int pmu_server_mode(SYSCTL_HANDLER_ARGS); |
75static int pmu_query_battery(struct pmu_softc *sc, int batt, 76 struct pmu_battstate *info); 77static int pmu_battquery_sysctl(SYSCTL_HANDLER_ARGS); |
|
74 | 78 |
79/* 80 * List of battery-related sysctls we might ask for 81 */ 82 83enum { 84 PMU_BATSYSCTL_PRESENT = 1 << 8, 85 PMU_BATSYSCTL_CHARGING = 2 << 8, 86 PMU_BATSYSCTL_CHARGE = 3 << 8, 87 PMU_BATSYSCTL_MAXCHARGE = 4 << 8, 88 PMU_BATSYSCTL_CURRENT = 5 << 8, 89 PMU_BATSYSCTL_VOLTAGE = 6 << 8, 90 PMU_BATSYSCTL_TIME = 7 << 8, 91 PMU_BATSYSCTL_LIFE = 8 << 8 92}; 93 |
|
75static device_method_t pmu_methods[] = { 76 /* Device interface */ 77 DEVMETHOD(device_probe, pmu_probe), 78 DEVMETHOD(device_attach, pmu_attach), 79 DEVMETHOD(device_detach, pmu_detach), 80 DEVMETHOD(device_shutdown, bus_generic_shutdown), 81 DEVMETHOD(device_suspend, bus_generic_suspend), 82 DEVMETHOD(device_resume, bus_generic_resume), --- 192 unchanged lines hidden (view full) --- 275 return (0); 276} 277 278static int 279pmu_attach(device_t dev) 280{ 281 struct pmu_softc *sc; 282 | 94static device_method_t pmu_methods[] = { 95 /* Device interface */ 96 DEVMETHOD(device_probe, pmu_probe), 97 DEVMETHOD(device_attach, pmu_attach), 98 DEVMETHOD(device_detach, pmu_detach), 99 DEVMETHOD(device_shutdown, bus_generic_shutdown), 100 DEVMETHOD(device_suspend, bus_generic_suspend), 101 DEVMETHOD(device_resume, bus_generic_resume), --- 192 unchanged lines hidden (view full) --- 294 return (0); 295} 296 297static int 298pmu_attach(device_t dev) 299{ 300 struct pmu_softc *sc; 301 |
302 int i; |
|
283 uint8_t reg; 284 uint8_t cmd[2] = {2, 0}; 285 uint8_t resp[16]; 286 phandle_t node,child; 287 struct sysctl_ctx_list *ctx; 288 struct sysctl_oid *tree; 289 290 sc = device_get_softc(dev); --- 16 unchanged lines hidden (view full) --- 307 * attach our interrupt then. 308 */ 309 pmu = dev; 310 if (pmu_extint != NULL) { 311 if (setup_pmu_intr(dev,pmu_extint) != 0) 312 return (ENXIO); 313 } 314 | 303 uint8_t reg; 304 uint8_t cmd[2] = {2, 0}; 305 uint8_t resp[16]; 306 phandle_t node,child; 307 struct sysctl_ctx_list *ctx; 308 struct sysctl_oid *tree; 309 310 sc = device_get_softc(dev); --- 16 unchanged lines hidden (view full) --- 327 * attach our interrupt then. 328 */ 329 pmu = dev; 330 if (pmu_extint != NULL) { 331 if (setup_pmu_intr(dev,pmu_extint) != 0) 332 return (ENXIO); 333 } 334 |
315 sc->sc_error = 0; 316 sc->sc_polling = 0; | |
317 sc->sc_autopoll = 0; 318 319 /* Init PMU */ 320 321 reg = PMU_INT_TICK | PMU_INT_ADB | PMU_INT_PCEJECT | PMU_INT_SNDBRT; 322 reg |= PMU_INT_BATTERY; 323 reg |= PMU_INT_ENVIRONMENT; 324 pmu_send(sc, PMU_SET_IMASK, 1, ®, 16, resp); --- 13 unchanged lines hidden (view full) --- 338 OF_getprop(child, "name", name, sizeof(name)); 339 340 if (bootverbose) 341 device_printf(dev, "PMU child <%s>\n",name); 342 343 if (strncmp(name, "adb", 4) == 0) { 344 sc->adb_bus = device_add_child(dev,"adb",-1); 345 } | 335 sc->sc_autopoll = 0; 336 337 /* Init PMU */ 338 339 reg = PMU_INT_TICK | PMU_INT_ADB | PMU_INT_PCEJECT | PMU_INT_SNDBRT; 340 reg |= PMU_INT_BATTERY; 341 reg |= PMU_INT_ENVIRONMENT; 342 pmu_send(sc, PMU_SET_IMASK, 1, ®, 16, resp); --- 13 unchanged lines hidden (view full) --- 356 OF_getprop(child, "name", name, sizeof(name)); 357 358 if (bootverbose) 359 device_printf(dev, "PMU child <%s>\n",name); 360 361 if (strncmp(name, "adb", 4) == 0) { 362 sc->adb_bus = device_add_child(dev,"adb",-1); 363 } |
364 365 if (strncmp(name, "power-mgt", 9) == 0) { 366 uint32_t prim_info[9]; 367 368 if (OF_getprop(child, "prim-info", prim_info, 369 sizeof(prim_info)) >= 7) 370 sc->sc_batteries = (prim_info[6] >> 16) & 0xff; 371 372 if (bootverbose && sc->sc_batteries > 0) 373 device_printf(dev, "%d batteries detected\n", 374 sc->sc_batteries); 375 } |
|
346 } 347 348 /* 349 * Set up sysctls 350 */ 351 352 ctx = device_get_sysctl_ctx(dev); 353 tree = device_get_sysctl_tree(dev); 354 355 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, | 376 } 377 378 /* 379 * Set up sysctls 380 */ 381 382 ctx = device_get_sysctl_ctx(dev); 383 tree = device_get_sysctl_tree(dev); 384 385 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, |
356 "server_mode", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 357 pmu_server_mode, "I", "Enable reboot after power failure"); | 386 "server_mode", CTLTYPE_INT | CTLFLAG_RW, sc, 0, 387 pmu_server_mode, "I", "Enable reboot after power failure"); |
358 | 388 |
389 if (sc->sc_batteries > 0) { 390 struct sysctl_oid *oid, *battroot; 391 char battnum[2]; 392 393 battroot = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 394 "batteries", CTLFLAG_RD, 0, "Battery Information"); 395 396 for (i = 0; i < sc->sc_batteries; i++) { 397 battnum[0] = i + '0'; 398 battnum[1] = '\0'; 399 400 oid = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(battroot), 401 OID_AUTO, battnum, CTLFLAG_RD, 0, 402 "Battery Information"); 403 404 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 405 "present", CTLTYPE_INT | CTLFLAG_RD, sc, 406 PMU_BATSYSCTL_PRESENT | i, pmu_battquery_sysctl, 407 "I", "Battery present"); 408 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 409 "charging", CTLTYPE_INT | CTLFLAG_RD, sc, 410 PMU_BATSYSCTL_CHARGING | i, pmu_battquery_sysctl, 411 "I", "Battery charging"); 412 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 413 "charge", CTLTYPE_INT | CTLFLAG_RD, sc, 414 PMU_BATSYSCTL_CHARGE | i, pmu_battquery_sysctl, 415 "I", "Battery charge (mAh)"); 416 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 417 "maxcharge", CTLTYPE_INT | CTLFLAG_RD, sc, 418 PMU_BATSYSCTL_MAXCHARGE | i, pmu_battquery_sysctl, 419 "I", "Maximum battery capacity (mAh)"); 420 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 421 "rate", CTLTYPE_INT | CTLFLAG_RD, sc, 422 PMU_BATSYSCTL_CURRENT | i, pmu_battquery_sysctl, 423 "I", "Battery discharge rate (mA)"); 424 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 425 "voltage", CTLTYPE_INT | CTLFLAG_RD, sc, 426 PMU_BATSYSCTL_VOLTAGE | i, pmu_battquery_sysctl, 427 "I", "Battery voltage (mV)"); 428 429 /* Knobs for mental compatibility with ACPI */ 430 431 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 432 "time", CTLTYPE_INT | CTLFLAG_RD, sc, 433 PMU_BATSYSCTL_TIME | i, pmu_battquery_sysctl, 434 "I", "Time Remaining (minutes)"); 435 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 436 "life", CTLTYPE_INT | CTLFLAG_RD, sc, 437 PMU_BATSYSCTL_LIFE | i, pmu_battquery_sysctl, 438 "I", "Capacity remaining (percent)"); 439 } 440 } 441 |
|
359 return (bus_generic_attach(dev)); 360} 361 362static int 363pmu_detach(device_t dev) 364{ 365 struct pmu_softc *sc; 366 --- 65 unchanged lines hidden (view full) --- 432 uint8_t out_len, intreg; 433 434 intreg = pmu_read_reg(sc, vIER); 435 intreg &= 0x10; 436 pmu_write_reg(sc, vIER, intreg); 437 438 /* wait idle */ 439 do {} while (pmu_intr_state(sc)); | 442 return (bus_generic_attach(dev)); 443} 444 445static int 446pmu_detach(device_t dev) 447{ 448 struct pmu_softc *sc; 449 --- 65 unchanged lines hidden (view full) --- 515 uint8_t out_len, intreg; 516 517 intreg = pmu_read_reg(sc, vIER); 518 intreg &= 0x10; 519 pmu_write_reg(sc, vIER, intreg); 520 521 /* wait idle */ 522 do {} while (pmu_intr_state(sc)); |
440 sc->sc_error = 0; | |
441 442 /* send command */ 443 pmu_send_byte(sc, cmd); 444 445 /* send length if necessary */ 446 if (pm_send_cmd_type[cmd] < 0) { 447 pmu_send_byte(sc, length); 448 } --- 217 unchanged lines hidden (view full) --- 666 667 mtx_lock(&sc->sc_mutex); 668 pmu_send(sc, PMU_POWER_EVENTS, 3, setcmd, 2, resp); 669 mtx_unlock(&sc->sc_mutex); 670 671 return (0); 672} 673 | 523 524 /* send command */ 525 pmu_send_byte(sc, cmd); 526 527 /* send length if necessary */ 528 if (pm_send_cmd_type[cmd] < 0) { 529 pmu_send_byte(sc, length); 530 } --- 217 unchanged lines hidden (view full) --- 748 749 mtx_lock(&sc->sc_mutex); 750 pmu_send(sc, PMU_POWER_EVENTS, 3, setcmd, 2, resp); 751 mtx_unlock(&sc->sc_mutex); 752 753 return (0); 754} 755 |
756static int 757pmu_query_battery(struct pmu_softc *sc, int batt, struct pmu_battstate *info) 758{ 759 uint8_t reg; 760 uint8_t resp[16]; 761 int len; 762 763 reg = batt + 1; 764 765 mtx_lock(&sc->sc_mutex); 766 len = pmu_send(sc, PMU_SMART_BATTERY_STATE, 1, ®, 16, resp); 767 mtx_unlock(&sc->sc_mutex); 768 769 if (len < 3) 770 return (-1); 771 772 /* All PMU battery info replies share a common header: 773 * Byte 1 Payload Format 774 * Byte 2 Battery Flags 775 */ 776 777 info->state = resp[2]; 778 779 switch (resp[1]) { 780 case 3: 781 case 4: 782 /* 783 * Formats 3 and 4 appear to be the same: 784 * Byte 3 Charge 785 * Byte 4 Max Charge 786 * Byte 5 Current 787 * Byte 6 Voltage 788 */ 789 790 info->charge = resp[3]; 791 info->maxcharge = resp[4]; 792 /* Current can be positive or negative */ 793 info->current = (int8_t)resp[5]; 794 info->voltage = resp[6]; 795 break; 796 case 5: 797 /* 798 * Formats 5 is a wider version of formats 3 and 4 799 * Byte 3-4 Charge 800 * Byte 5-6 Max Charge 801 * Byte 7-8 Current 802 * Byte 9-10 Voltage 803 */ 804 805 info->charge = (resp[3] << 8) | resp[4]; 806 info->maxcharge = (resp[5] << 8) | resp[6]; 807 /* Current can be positive or negative */ 808 info->current = (int16_t)((resp[7] << 8) | resp[8]); 809 info->voltage = (resp[9] << 8) | resp[10]; 810 break; 811 default: 812 device_printf(sc->sc_dev, "Unknown battery info format (%d)!\n", 813 resp[1]); 814 return (-1); 815 } 816 817 return (0); 818} 819 820static int 821pmu_battquery_sysctl(SYSCTL_HANDLER_ARGS) 822{ 823 struct pmu_softc *sc; 824 struct pmu_battstate batt; 825 int error, result; 826 827 sc = arg1; 828 829 error = pmu_query_battery(sc, arg2 & 0x00ff, &batt); 830 831 if (error != 0) 832 return (error); 833 834 switch (arg2 & 0xff00) { 835 case PMU_BATSYSCTL_PRESENT: 836 result = (batt.state & PMU_PWR_BATT_PRESENT) ? 1 : 0; 837 break; 838 case PMU_BATSYSCTL_CHARGING: 839 result = (batt.state & PMU_PWR_BATT_CHARGING) ? 1 : 0; 840 break; 841 case PMU_BATSYSCTL_CHARGE: 842 result = batt.charge; 843 break; 844 case PMU_BATSYSCTL_MAXCHARGE: 845 result = batt.maxcharge; 846 break; 847 case PMU_BATSYSCTL_CURRENT: 848 result = batt.current; 849 break; 850 case PMU_BATSYSCTL_VOLTAGE: 851 result = batt.voltage; 852 break; 853 case PMU_BATSYSCTL_TIME: 854 /* Time remaining until full charge/discharge, in minutes */ 855 856 if (batt.current >= 0) 857 result = (batt.maxcharge - batt.charge) /* mAh */ * 60 858 / batt.current /* mA */; 859 else 860 result = (batt.charge /* mAh */ * 60) 861 / (-batt.current /* mA */); 862 break; 863 case PMU_BATSYSCTL_LIFE: 864 /* Battery charge fraction, in percent */ 865 result = (batt.charge * 100) / batt.maxcharge; 866 break; 867 default: 868 /* This should never happen */ 869 result = -1; 870 }; 871 872 error = sysctl_handle_int(oidp, &result, 0, req); 873 874 return (error); 875} 876 |
|