USB: Implement PM FREEZE and PRETHAW
[linux-2.6/mini2440.git] / drivers / power / apm_power.c
blob042bd950d036109f0a9cb44ad25b661d0f1896f0
1 /*
2 * Copyright © 2007 Anton Vorontsov <cbou@mail.ru>
3 * Copyright © 2007 Eugeny Boger <eugenyboger@dgap.mipt.ru>
5 * Author: Eugeny Boger <eugenyboger@dgap.mipt.ru>
7 * Use consistent with the GNU GPL is permitted,
8 * provided that this copyright notice is
9 * preserved in its entirety in all copies and derived works.
12 #include <linux/module.h>
13 #include <linux/power_supply.h>
14 #include <linux/apm-emulation.h>
16 #define PSY_PROP(psy, prop, val) psy->get_property(psy, \
17 POWER_SUPPLY_PROP_##prop, val)
19 #define _MPSY_PROP(prop, val) main_battery->get_property(main_battery, \
20 prop, val)
22 #define MPSY_PROP(prop, val) _MPSY_PROP(POWER_SUPPLY_PROP_##prop, val)
24 static struct power_supply *main_battery;
26 static void find_main_battery(void)
28 struct device *dev;
29 struct power_supply *bat, *batm;
30 union power_supply_propval full;
31 int max_charge = 0;
33 main_battery = NULL;
34 batm = NULL;
35 list_for_each_entry(dev, &power_supply_class->devices, node) {
36 bat = dev_get_drvdata(dev);
37 /* If none of battery devices cantains 'use_for_apm' flag,
38 choice one with maximum design charge */
39 if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full)) {
40 if (full.intval > max_charge) {
41 batm = bat;
42 max_charge = full.intval;
46 if (bat->use_for_apm)
47 main_battery = bat;
49 if (!main_battery)
50 main_battery = batm;
52 return;
55 static int calculate_time(int status)
57 union power_supply_propval charge_full, charge_empty;
58 union power_supply_propval charge, I;
60 if (MPSY_PROP(CHARGE_FULL, &charge_full)) {
61 /* if battery can't report this property, use design value */
62 if (MPSY_PROP(CHARGE_FULL_DESIGN, &charge_full))
63 return -1;
66 if (MPSY_PROP(CHARGE_EMPTY, &charge_empty)) {
67 /* if battery can't report this property, use design value */
68 if (MPSY_PROP(CHARGE_EMPTY_DESIGN, &charge_empty))
69 charge_empty.intval = 0;
72 if (MPSY_PROP(CHARGE_AVG, &charge)) {
73 /* if battery can't report average value, use momentary */
74 if (MPSY_PROP(CHARGE_NOW, &charge))
75 return -1;
78 if (MPSY_PROP(CURRENT_AVG, &I)) {
79 /* if battery can't report average value, use momentary */
80 if (MPSY_PROP(CURRENT_NOW, &I))
81 return -1;
84 if (status == POWER_SUPPLY_STATUS_CHARGING)
85 return ((charge.intval - charge_full.intval) * 60L) /
86 I.intval;
87 else
88 return -((charge.intval - charge_empty.intval) * 60L) /
89 I.intval;
92 static int calculate_capacity(int using_charge)
94 enum power_supply_property full_prop, empty_prop;
95 enum power_supply_property full_design_prop, empty_design_prop;
96 enum power_supply_property now_prop, avg_prop;
97 union power_supply_propval empty, full, cur;
98 int ret;
100 if (using_charge) {
101 full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
102 empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
103 full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
104 empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN;
105 now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
106 avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
107 } else {
108 full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
109 empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
110 full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
111 empty_design_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN;
112 now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
113 avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
116 if (_MPSY_PROP(full_prop, &full)) {
117 /* if battery can't report this property, use design value */
118 if (_MPSY_PROP(full_design_prop, &full))
119 return -1;
122 if (_MPSY_PROP(avg_prop, &cur)) {
123 /* if battery can't report average value, use momentary */
124 if (_MPSY_PROP(now_prop, &cur))
125 return -1;
128 if (_MPSY_PROP(empty_prop, &empty)) {
129 /* if battery can't report this property, use design value */
130 if (_MPSY_PROP(empty_design_prop, &empty))
131 empty.intval = 0;
134 if (full.intval - empty.intval)
135 ret = ((cur.intval - empty.intval) * 100L) /
136 (full.intval - empty.intval);
137 else
138 return -1;
140 if (ret > 100)
141 return 100;
142 else if (ret < 0)
143 return 0;
145 return ret;
148 static void apm_battery_apm_get_power_status(struct apm_power_info *info)
150 union power_supply_propval status;
151 union power_supply_propval capacity, time_to_full, time_to_empty;
153 down(&power_supply_class->sem);
154 find_main_battery();
155 if (!main_battery) {
156 up(&power_supply_class->sem);
157 return;
160 /* status */
162 if (MPSY_PROP(STATUS, &status))
163 status.intval = POWER_SUPPLY_STATUS_UNKNOWN;
165 /* ac line status */
167 if ((status.intval == POWER_SUPPLY_STATUS_CHARGING) ||
168 (status.intval == POWER_SUPPLY_STATUS_NOT_CHARGING) ||
169 (status.intval == POWER_SUPPLY_STATUS_FULL))
170 info->ac_line_status = APM_AC_ONLINE;
171 else
172 info->ac_line_status = APM_AC_OFFLINE;
174 /* battery life (i.e. capacity, in percents) */
176 if (MPSY_PROP(CAPACITY, &capacity) == 0) {
177 info->battery_life = capacity.intval;
178 } else {
179 /* try calculate using energy */
180 info->battery_life = calculate_capacity(0);
181 /* if failed try calculate using charge instead */
182 if (info->battery_life == -1)
183 info->battery_life = calculate_capacity(1);
186 /* charging status */
188 if (status.intval == POWER_SUPPLY_STATUS_CHARGING) {
189 info->battery_status = APM_BATTERY_STATUS_CHARGING;
190 } else {
191 if (info->battery_life > 50)
192 info->battery_status = APM_BATTERY_STATUS_HIGH;
193 else if (info->battery_life > 5)
194 info->battery_status = APM_BATTERY_STATUS_LOW;
195 else
196 info->battery_status = APM_BATTERY_STATUS_CRITICAL;
198 info->battery_flag = info->battery_status;
200 /* time */
202 info->units = APM_UNITS_MINS;
204 if (status.intval == POWER_SUPPLY_STATUS_CHARGING) {
205 if (MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full)) {
206 if (MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full))
207 info->time = calculate_time(status.intval);
208 else
209 info->time = time_to_full.intval / 60;
211 } else {
212 if (MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty)) {
213 if (MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty))
214 info->time = calculate_time(status.intval);
215 else
216 info->time = time_to_empty.intval / 60;
220 up(&power_supply_class->sem);
221 return;
224 static int __init apm_battery_init(void)
226 printk(KERN_INFO "APM Battery Driver\n");
228 apm_get_power_status = apm_battery_apm_get_power_status;
229 return 0;
232 static void __exit apm_battery_exit(void)
234 apm_get_power_status = NULL;
235 return;
238 module_init(apm_battery_init);
239 module_exit(apm_battery_exit);
241 MODULE_AUTHOR("Eugeny Boger <eugenyboger@dgap.mipt.ru>");
242 MODULE_DESCRIPTION("APM emulation driver for battery monitoring class");
243 MODULE_LICENSE("GPL");