Deleted Added
full compact
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, &reg, 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, &reg, 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, &reg, 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