Merge branches 'timers/clocksource', 'timers/hrtimers', 'timers/nohz', 'timers/ntp...
[linux-2.6] / drivers / macintosh / apm_emu.c
1 /*
2  * APM emulation for PMU-based machines
3  *
4  * Copyright 2001 Benjamin Herrenschmidt (benh@kernel.crashing.org)
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the
8  * Free Software Foundation; either version 2, or (at your option) any
9  * later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  *
17  */
18
19 #include <linux/kernel.h>
20 #include <linux/module.h>
21 #include <linux/apm-emulation.h>
22 #include <linux/adb.h>
23 #include <linux/pmu.h>
24
25 #define APM_CRITICAL            10
26 #define APM_LOW                 30
27
28 static void pmu_apm_get_power_status(struct apm_power_info *info)
29 {
30         int percentage = -1;
31         int batteries = 0;
32         int time_units = -1;
33         int real_count = 0;
34         int i;
35         char charging = 0;
36         long charge = -1;
37         long amperage = 0;
38         unsigned long btype = 0;
39
40         info->battery_status = APM_BATTERY_STATUS_UNKNOWN;
41         info->battery_flag = APM_BATTERY_FLAG_UNKNOWN;
42         info->units = APM_UNITS_MINS;
43
44         if (pmu_power_flags & PMU_PWR_AC_PRESENT)
45                 info->ac_line_status = APM_AC_ONLINE;
46         else
47                 info->ac_line_status = APM_AC_OFFLINE;
48
49         for (i=0; i<pmu_battery_count; i++) {
50                 if (pmu_batteries[i].flags & PMU_BATT_PRESENT) {
51                         batteries++;
52                         if (percentage < 0)
53                                 percentage = 0;
54                         if (charge < 0)
55                                 charge = 0;
56                         percentage += (pmu_batteries[i].charge * 100) /
57                                 pmu_batteries[i].max_charge;
58                         charge += pmu_batteries[i].charge;
59                         amperage += pmu_batteries[i].amperage;
60                         if (btype == 0)
61                                 btype = (pmu_batteries[i].flags & PMU_BATT_TYPE_MASK);
62                         real_count++;
63                         if ((pmu_batteries[i].flags & PMU_BATT_CHARGING))
64                                 charging++;
65                 }
66         }
67         if (batteries == 0)
68                 info->ac_line_status = APM_AC_ONLINE;
69
70         if (real_count) {
71                 if (amperage < 0) {
72                         if (btype == PMU_BATT_TYPE_SMART)
73                                 time_units = (charge * 59) / (amperage * -1);
74                         else
75                                 time_units = (charge * 16440) / (amperage * -60);
76                 }
77                 percentage /= real_count;
78                 if (charging > 0) {
79                         info->battery_status = APM_BATTERY_STATUS_CHARGING;
80                         info->battery_flag = APM_BATTERY_FLAG_CHARGING;
81                 } else if (percentage <= APM_CRITICAL) {
82                         info->battery_status = APM_BATTERY_STATUS_CRITICAL;
83                         info->battery_flag = APM_BATTERY_FLAG_CRITICAL;
84                 } else if (percentage <= APM_LOW) {
85                         info->battery_status = APM_BATTERY_STATUS_LOW;
86                         info->battery_flag = APM_BATTERY_FLAG_LOW;
87                 } else {
88                         info->battery_status = APM_BATTERY_STATUS_HIGH;
89                         info->battery_flag = APM_BATTERY_FLAG_HIGH;
90                 }
91         }
92
93         info->battery_life = percentage;
94         info->time = time_units;
95 }
96
97 static int __init apm_emu_init(void)
98 {
99         apm_get_power_status = pmu_apm_get_power_status;
100
101         printk(KERN_INFO "apm_emu: PMU APM Emulation initialized.\n");
102
103         return 0;
104 }
105
106 static void __exit apm_emu_exit(void)
107 {
108         if (apm_get_power_status == pmu_apm_get_power_status)
109                 apm_get_power_status = NULL;
110
111         printk(KERN_INFO "apm_emu: PMU APM Emulation removed.\n");
112 }
113
114 module_init(apm_emu_init);
115 module_exit(apm_emu_exit);
116
117 MODULE_AUTHOR("Benjamin Herrenschmidt");
118 MODULE_DESCRIPTION("APM emulation for PowerMac");
119 MODULE_LICENSE("GPL");