1*8c0984e5SSebastian Reichel /*
2*8c0984e5SSebastian Reichel * Copyright © 2007 Anton Vorontsov <cbou@mail.ru>
3*8c0984e5SSebastian Reichel * Copyright © 2007 Eugeny Boger <eugenyboger@dgap.mipt.ru>
4*8c0984e5SSebastian Reichel *
5*8c0984e5SSebastian Reichel * Author: Eugeny Boger <eugenyboger@dgap.mipt.ru>
6*8c0984e5SSebastian Reichel *
7*8c0984e5SSebastian Reichel * Use consistent with the GNU GPL is permitted,
8*8c0984e5SSebastian Reichel * provided that this copyright notice is
9*8c0984e5SSebastian Reichel * preserved in its entirety in all copies and derived works.
10*8c0984e5SSebastian Reichel */
11*8c0984e5SSebastian Reichel
12*8c0984e5SSebastian Reichel #include <linux/module.h>
13*8c0984e5SSebastian Reichel #include <linux/device.h>
14*8c0984e5SSebastian Reichel #include <linux/power_supply.h>
15*8c0984e5SSebastian Reichel #include <linux/apm-emulation.h>
16*8c0984e5SSebastian Reichel
17*8c0984e5SSebastian Reichel
18*8c0984e5SSebastian Reichel #define PSY_PROP(psy, prop, val) (power_supply_get_property(psy, \
19*8c0984e5SSebastian Reichel POWER_SUPPLY_PROP_##prop, val))
20*8c0984e5SSebastian Reichel
21*8c0984e5SSebastian Reichel #define _MPSY_PROP(prop, val) (power_supply_get_property(main_battery, \
22*8c0984e5SSebastian Reichel prop, val))
23*8c0984e5SSebastian Reichel
24*8c0984e5SSebastian Reichel #define MPSY_PROP(prop, val) _MPSY_PROP(POWER_SUPPLY_PROP_##prop, val)
25*8c0984e5SSebastian Reichel
26*8c0984e5SSebastian Reichel static DEFINE_MUTEX(apm_mutex);
27*8c0984e5SSebastian Reichel static struct power_supply *main_battery;
28*8c0984e5SSebastian Reichel
29*8c0984e5SSebastian Reichel enum apm_source {
30*8c0984e5SSebastian Reichel SOURCE_ENERGY,
31*8c0984e5SSebastian Reichel SOURCE_CHARGE,
32*8c0984e5SSebastian Reichel SOURCE_VOLTAGE,
33*8c0984e5SSebastian Reichel };
34*8c0984e5SSebastian Reichel
35*8c0984e5SSebastian Reichel struct find_bat_param {
36*8c0984e5SSebastian Reichel struct power_supply *main;
37*8c0984e5SSebastian Reichel struct power_supply *bat;
38*8c0984e5SSebastian Reichel struct power_supply *max_charge_bat;
39*8c0984e5SSebastian Reichel struct power_supply *max_energy_bat;
40*8c0984e5SSebastian Reichel union power_supply_propval full;
41*8c0984e5SSebastian Reichel int max_charge;
42*8c0984e5SSebastian Reichel int max_energy;
43*8c0984e5SSebastian Reichel };
44*8c0984e5SSebastian Reichel
__find_main_battery(struct device * dev,void * data)45*8c0984e5SSebastian Reichel static int __find_main_battery(struct device *dev, void *data)
46*8c0984e5SSebastian Reichel {
47*8c0984e5SSebastian Reichel struct find_bat_param *bp = (struct find_bat_param *)data;
48*8c0984e5SSebastian Reichel
49*8c0984e5SSebastian Reichel bp->bat = dev_get_drvdata(dev);
50*8c0984e5SSebastian Reichel
51*8c0984e5SSebastian Reichel if (bp->bat->desc->use_for_apm) {
52*8c0984e5SSebastian Reichel /* nice, we explicitly asked to report this battery. */
53*8c0984e5SSebastian Reichel bp->main = bp->bat;
54*8c0984e5SSebastian Reichel return 1;
55*8c0984e5SSebastian Reichel }
56*8c0984e5SSebastian Reichel
57*8c0984e5SSebastian Reichel if (!PSY_PROP(bp->bat, CHARGE_FULL_DESIGN, &bp->full) ||
58*8c0984e5SSebastian Reichel !PSY_PROP(bp->bat, CHARGE_FULL, &bp->full)) {
59*8c0984e5SSebastian Reichel if (bp->full.intval > bp->max_charge) {
60*8c0984e5SSebastian Reichel bp->max_charge_bat = bp->bat;
61*8c0984e5SSebastian Reichel bp->max_charge = bp->full.intval;
62*8c0984e5SSebastian Reichel }
63*8c0984e5SSebastian Reichel } else if (!PSY_PROP(bp->bat, ENERGY_FULL_DESIGN, &bp->full) ||
64*8c0984e5SSebastian Reichel !PSY_PROP(bp->bat, ENERGY_FULL, &bp->full)) {
65*8c0984e5SSebastian Reichel if (bp->full.intval > bp->max_energy) {
66*8c0984e5SSebastian Reichel bp->max_energy_bat = bp->bat;
67*8c0984e5SSebastian Reichel bp->max_energy = bp->full.intval;
68*8c0984e5SSebastian Reichel }
69*8c0984e5SSebastian Reichel }
70*8c0984e5SSebastian Reichel return 0;
71*8c0984e5SSebastian Reichel }
72*8c0984e5SSebastian Reichel
find_main_battery(void)73*8c0984e5SSebastian Reichel static void find_main_battery(void)
74*8c0984e5SSebastian Reichel {
75*8c0984e5SSebastian Reichel struct find_bat_param bp;
76*8c0984e5SSebastian Reichel int error;
77*8c0984e5SSebastian Reichel
78*8c0984e5SSebastian Reichel memset(&bp, 0, sizeof(struct find_bat_param));
79*8c0984e5SSebastian Reichel main_battery = NULL;
80*8c0984e5SSebastian Reichel bp.main = main_battery;
81*8c0984e5SSebastian Reichel
82*8c0984e5SSebastian Reichel error = class_for_each_device(power_supply_class, NULL, &bp,
83*8c0984e5SSebastian Reichel __find_main_battery);
84*8c0984e5SSebastian Reichel if (error) {
85*8c0984e5SSebastian Reichel main_battery = bp.main;
86*8c0984e5SSebastian Reichel return;
87*8c0984e5SSebastian Reichel }
88*8c0984e5SSebastian Reichel
89*8c0984e5SSebastian Reichel if ((bp.max_energy_bat && bp.max_charge_bat) &&
90*8c0984e5SSebastian Reichel (bp.max_energy_bat != bp.max_charge_bat)) {
91*8c0984e5SSebastian Reichel /* try guess battery with more capacity */
92*8c0984e5SSebastian Reichel if (!PSY_PROP(bp.max_charge_bat, VOLTAGE_MAX_DESIGN,
93*8c0984e5SSebastian Reichel &bp.full)) {
94*8c0984e5SSebastian Reichel if (bp.max_energy > bp.max_charge * bp.full.intval)
95*8c0984e5SSebastian Reichel main_battery = bp.max_energy_bat;
96*8c0984e5SSebastian Reichel else
97*8c0984e5SSebastian Reichel main_battery = bp.max_charge_bat;
98*8c0984e5SSebastian Reichel } else if (!PSY_PROP(bp.max_energy_bat, VOLTAGE_MAX_DESIGN,
99*8c0984e5SSebastian Reichel &bp.full)) {
100*8c0984e5SSebastian Reichel if (bp.max_charge > bp.max_energy / bp.full.intval)
101*8c0984e5SSebastian Reichel main_battery = bp.max_charge_bat;
102*8c0984e5SSebastian Reichel else
103*8c0984e5SSebastian Reichel main_battery = bp.max_energy_bat;
104*8c0984e5SSebastian Reichel } else {
105*8c0984e5SSebastian Reichel /* give up, choice any */
106*8c0984e5SSebastian Reichel main_battery = bp.max_energy_bat;
107*8c0984e5SSebastian Reichel }
108*8c0984e5SSebastian Reichel } else if (bp.max_charge_bat) {
109*8c0984e5SSebastian Reichel main_battery = bp.max_charge_bat;
110*8c0984e5SSebastian Reichel } else if (bp.max_energy_bat) {
111*8c0984e5SSebastian Reichel main_battery = bp.max_energy_bat;
112*8c0984e5SSebastian Reichel } else {
113*8c0984e5SSebastian Reichel /* give up, try the last if any */
114*8c0984e5SSebastian Reichel main_battery = bp.bat;
115*8c0984e5SSebastian Reichel }
116*8c0984e5SSebastian Reichel }
117*8c0984e5SSebastian Reichel
do_calculate_time(int status,enum apm_source source)118*8c0984e5SSebastian Reichel static int do_calculate_time(int status, enum apm_source source)
119*8c0984e5SSebastian Reichel {
120*8c0984e5SSebastian Reichel union power_supply_propval full;
121*8c0984e5SSebastian Reichel union power_supply_propval empty;
122*8c0984e5SSebastian Reichel union power_supply_propval cur;
123*8c0984e5SSebastian Reichel union power_supply_propval I;
124*8c0984e5SSebastian Reichel enum power_supply_property full_prop;
125*8c0984e5SSebastian Reichel enum power_supply_property full_design_prop;
126*8c0984e5SSebastian Reichel enum power_supply_property empty_prop;
127*8c0984e5SSebastian Reichel enum power_supply_property empty_design_prop;
128*8c0984e5SSebastian Reichel enum power_supply_property cur_avg_prop;
129*8c0984e5SSebastian Reichel enum power_supply_property cur_now_prop;
130*8c0984e5SSebastian Reichel
131*8c0984e5SSebastian Reichel if (MPSY_PROP(CURRENT_AVG, &I)) {
132*8c0984e5SSebastian Reichel /* if battery can't report average value, use momentary */
133*8c0984e5SSebastian Reichel if (MPSY_PROP(CURRENT_NOW, &I))
134*8c0984e5SSebastian Reichel return -1;
135*8c0984e5SSebastian Reichel }
136*8c0984e5SSebastian Reichel
137*8c0984e5SSebastian Reichel if (!I.intval)
138*8c0984e5SSebastian Reichel return 0;
139*8c0984e5SSebastian Reichel
140*8c0984e5SSebastian Reichel switch (source) {
141*8c0984e5SSebastian Reichel case SOURCE_CHARGE:
142*8c0984e5SSebastian Reichel full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
143*8c0984e5SSebastian Reichel full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
144*8c0984e5SSebastian Reichel empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
145*8c0984e5SSebastian Reichel empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
146*8c0984e5SSebastian Reichel cur_avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
147*8c0984e5SSebastian Reichel cur_now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
148*8c0984e5SSebastian Reichel break;
149*8c0984e5SSebastian Reichel case SOURCE_ENERGY:
150*8c0984e5SSebastian Reichel full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
151*8c0984e5SSebastian Reichel full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
152*8c0984e5SSebastian Reichel empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
153*8c0984e5SSebastian Reichel empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
154*8c0984e5SSebastian Reichel cur_avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
155*8c0984e5SSebastian Reichel cur_now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
156*8c0984e5SSebastian Reichel break;
157*8c0984e5SSebastian Reichel case SOURCE_VOLTAGE:
158*8c0984e5SSebastian Reichel full_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX;
159*8c0984e5SSebastian Reichel full_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN;
160*8c0984e5SSebastian Reichel empty_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN;
161*8c0984e5SSebastian Reichel empty_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN;
162*8c0984e5SSebastian Reichel cur_avg_prop = POWER_SUPPLY_PROP_VOLTAGE_AVG;
163*8c0984e5SSebastian Reichel cur_now_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW;
164*8c0984e5SSebastian Reichel break;
165*8c0984e5SSebastian Reichel default:
166*8c0984e5SSebastian Reichel printk(KERN_ERR "Unsupported source: %d\n", source);
167*8c0984e5SSebastian Reichel return -1;
168*8c0984e5SSebastian Reichel }
169*8c0984e5SSebastian Reichel
170*8c0984e5SSebastian Reichel if (_MPSY_PROP(full_prop, &full)) {
171*8c0984e5SSebastian Reichel /* if battery can't report this property, use design value */
172*8c0984e5SSebastian Reichel if (_MPSY_PROP(full_design_prop, &full))
173*8c0984e5SSebastian Reichel return -1;
174*8c0984e5SSebastian Reichel }
175*8c0984e5SSebastian Reichel
176*8c0984e5SSebastian Reichel if (_MPSY_PROP(empty_prop, &empty)) {
177*8c0984e5SSebastian Reichel /* if battery can't report this property, use design value */
178*8c0984e5SSebastian Reichel if (_MPSY_PROP(empty_design_prop, &empty))
179*8c0984e5SSebastian Reichel empty.intval = 0;
180*8c0984e5SSebastian Reichel }
181*8c0984e5SSebastian Reichel
182*8c0984e5SSebastian Reichel if (_MPSY_PROP(cur_avg_prop, &cur)) {
183*8c0984e5SSebastian Reichel /* if battery can't report average value, use momentary */
184*8c0984e5SSebastian Reichel if (_MPSY_PROP(cur_now_prop, &cur))
185*8c0984e5SSebastian Reichel return -1;
186*8c0984e5SSebastian Reichel }
187*8c0984e5SSebastian Reichel
188*8c0984e5SSebastian Reichel if (status == POWER_SUPPLY_STATUS_CHARGING)
189*8c0984e5SSebastian Reichel return ((cur.intval - full.intval) * 60L) / I.intval;
190*8c0984e5SSebastian Reichel else
191*8c0984e5SSebastian Reichel return -((cur.intval - empty.intval) * 60L) / I.intval;
192*8c0984e5SSebastian Reichel }
193*8c0984e5SSebastian Reichel
calculate_time(int status)194*8c0984e5SSebastian Reichel static int calculate_time(int status)
195*8c0984e5SSebastian Reichel {
196*8c0984e5SSebastian Reichel int time;
197*8c0984e5SSebastian Reichel
198*8c0984e5SSebastian Reichel time = do_calculate_time(status, SOURCE_ENERGY);
199*8c0984e5SSebastian Reichel if (time != -1)
200*8c0984e5SSebastian Reichel return time;
201*8c0984e5SSebastian Reichel
202*8c0984e5SSebastian Reichel time = do_calculate_time(status, SOURCE_CHARGE);
203*8c0984e5SSebastian Reichel if (time != -1)
204*8c0984e5SSebastian Reichel return time;
205*8c0984e5SSebastian Reichel
206*8c0984e5SSebastian Reichel time = do_calculate_time(status, SOURCE_VOLTAGE);
207*8c0984e5SSebastian Reichel if (time != -1)
208*8c0984e5SSebastian Reichel return time;
209*8c0984e5SSebastian Reichel
210*8c0984e5SSebastian Reichel return -1;
211*8c0984e5SSebastian Reichel }
212*8c0984e5SSebastian Reichel
calculate_capacity(enum apm_source source)213*8c0984e5SSebastian Reichel static int calculate_capacity(enum apm_source source)
214*8c0984e5SSebastian Reichel {
215*8c0984e5SSebastian Reichel enum power_supply_property full_prop, empty_prop;
216*8c0984e5SSebastian Reichel enum power_supply_property full_design_prop, empty_design_prop;
217*8c0984e5SSebastian Reichel enum power_supply_property now_prop, avg_prop;
218*8c0984e5SSebastian Reichel union power_supply_propval empty, full, cur;
219*8c0984e5SSebastian Reichel int ret;
220*8c0984e5SSebastian Reichel
221*8c0984e5SSebastian Reichel switch (source) {
222*8c0984e5SSebastian Reichel case SOURCE_CHARGE:
223*8c0984e5SSebastian Reichel full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
224*8c0984e5SSebastian Reichel empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
225*8c0984e5SSebastian Reichel full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
226*8c0984e5SSebastian Reichel empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN;
227*8c0984e5SSebastian Reichel now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
228*8c0984e5SSebastian Reichel avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
229*8c0984e5SSebastian Reichel break;
230*8c0984e5SSebastian Reichel case SOURCE_ENERGY:
231*8c0984e5SSebastian Reichel full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
232*8c0984e5SSebastian Reichel empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
233*8c0984e5SSebastian Reichel full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
234*8c0984e5SSebastian Reichel empty_design_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN;
235*8c0984e5SSebastian Reichel now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
236*8c0984e5SSebastian Reichel avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
237*8c0984e5SSebastian Reichel break;
238*8c0984e5SSebastian Reichel case SOURCE_VOLTAGE:
239*8c0984e5SSebastian Reichel full_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX;
240*8c0984e5SSebastian Reichel empty_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN;
241*8c0984e5SSebastian Reichel full_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN;
242*8c0984e5SSebastian Reichel empty_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN;
243*8c0984e5SSebastian Reichel now_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW;
244*8c0984e5SSebastian Reichel avg_prop = POWER_SUPPLY_PROP_VOLTAGE_AVG;
245*8c0984e5SSebastian Reichel break;
246*8c0984e5SSebastian Reichel default:
247*8c0984e5SSebastian Reichel printk(KERN_ERR "Unsupported source: %d\n", source);
248*8c0984e5SSebastian Reichel return -1;
249*8c0984e5SSebastian Reichel }
250*8c0984e5SSebastian Reichel
251*8c0984e5SSebastian Reichel if (_MPSY_PROP(full_prop, &full)) {
252*8c0984e5SSebastian Reichel /* if battery can't report this property, use design value */
253*8c0984e5SSebastian Reichel if (_MPSY_PROP(full_design_prop, &full))
254*8c0984e5SSebastian Reichel return -1;
255*8c0984e5SSebastian Reichel }
256*8c0984e5SSebastian Reichel
257*8c0984e5SSebastian Reichel if (_MPSY_PROP(avg_prop, &cur)) {
258*8c0984e5SSebastian Reichel /* if battery can't report average value, use momentary */
259*8c0984e5SSebastian Reichel if (_MPSY_PROP(now_prop, &cur))
260*8c0984e5SSebastian Reichel return -1;
261*8c0984e5SSebastian Reichel }
262*8c0984e5SSebastian Reichel
263*8c0984e5SSebastian Reichel if (_MPSY_PROP(empty_prop, &empty)) {
264*8c0984e5SSebastian Reichel /* if battery can't report this property, use design value */
265*8c0984e5SSebastian Reichel if (_MPSY_PROP(empty_design_prop, &empty))
266*8c0984e5SSebastian Reichel empty.intval = 0;
267*8c0984e5SSebastian Reichel }
268*8c0984e5SSebastian Reichel
269*8c0984e5SSebastian Reichel if (full.intval - empty.intval)
270*8c0984e5SSebastian Reichel ret = ((cur.intval - empty.intval) * 100L) /
271*8c0984e5SSebastian Reichel (full.intval - empty.intval);
272*8c0984e5SSebastian Reichel else
273*8c0984e5SSebastian Reichel return -1;
274*8c0984e5SSebastian Reichel
275*8c0984e5SSebastian Reichel if (ret > 100)
276*8c0984e5SSebastian Reichel return 100;
277*8c0984e5SSebastian Reichel else if (ret < 0)
278*8c0984e5SSebastian Reichel return 0;
279*8c0984e5SSebastian Reichel
280*8c0984e5SSebastian Reichel return ret;
281*8c0984e5SSebastian Reichel }
282*8c0984e5SSebastian Reichel
apm_battery_apm_get_power_status(struct apm_power_info * info)283*8c0984e5SSebastian Reichel static void apm_battery_apm_get_power_status(struct apm_power_info *info)
284*8c0984e5SSebastian Reichel {
285*8c0984e5SSebastian Reichel union power_supply_propval status;
286*8c0984e5SSebastian Reichel union power_supply_propval capacity, time_to_full, time_to_empty;
287*8c0984e5SSebastian Reichel
288*8c0984e5SSebastian Reichel mutex_lock(&apm_mutex);
289*8c0984e5SSebastian Reichel find_main_battery();
290*8c0984e5SSebastian Reichel if (!main_battery) {
291*8c0984e5SSebastian Reichel mutex_unlock(&apm_mutex);
292*8c0984e5SSebastian Reichel return;
293*8c0984e5SSebastian Reichel }
294*8c0984e5SSebastian Reichel
295*8c0984e5SSebastian Reichel /* status */
296*8c0984e5SSebastian Reichel
297*8c0984e5SSebastian Reichel if (MPSY_PROP(STATUS, &status))
298*8c0984e5SSebastian Reichel status.intval = POWER_SUPPLY_STATUS_UNKNOWN;
299*8c0984e5SSebastian Reichel
300*8c0984e5SSebastian Reichel /* ac line status */
301*8c0984e5SSebastian Reichel
302*8c0984e5SSebastian Reichel if ((status.intval == POWER_SUPPLY_STATUS_CHARGING) ||
303*8c0984e5SSebastian Reichel (status.intval == POWER_SUPPLY_STATUS_NOT_CHARGING) ||
304*8c0984e5SSebastian Reichel (status.intval == POWER_SUPPLY_STATUS_FULL))
305*8c0984e5SSebastian Reichel info->ac_line_status = APM_AC_ONLINE;
306*8c0984e5SSebastian Reichel else
307*8c0984e5SSebastian Reichel info->ac_line_status = APM_AC_OFFLINE;
308*8c0984e5SSebastian Reichel
309*8c0984e5SSebastian Reichel /* battery life (i.e. capacity, in percents) */
310*8c0984e5SSebastian Reichel
311*8c0984e5SSebastian Reichel if (MPSY_PROP(CAPACITY, &capacity) == 0) {
312*8c0984e5SSebastian Reichel info->battery_life = capacity.intval;
313*8c0984e5SSebastian Reichel } else {
314*8c0984e5SSebastian Reichel /* try calculate using energy */
315*8c0984e5SSebastian Reichel info->battery_life = calculate_capacity(SOURCE_ENERGY);
316*8c0984e5SSebastian Reichel /* if failed try calculate using charge instead */
317*8c0984e5SSebastian Reichel if (info->battery_life == -1)
318*8c0984e5SSebastian Reichel info->battery_life = calculate_capacity(SOURCE_CHARGE);
319*8c0984e5SSebastian Reichel if (info->battery_life == -1)
320*8c0984e5SSebastian Reichel info->battery_life = calculate_capacity(SOURCE_VOLTAGE);
321*8c0984e5SSebastian Reichel }
322*8c0984e5SSebastian Reichel
323*8c0984e5SSebastian Reichel /* charging status */
324*8c0984e5SSebastian Reichel
325*8c0984e5SSebastian Reichel if (status.intval == POWER_SUPPLY_STATUS_CHARGING) {
326*8c0984e5SSebastian Reichel info->battery_status = APM_BATTERY_STATUS_CHARGING;
327*8c0984e5SSebastian Reichel } else {
328*8c0984e5SSebastian Reichel if (info->battery_life > 50)
329*8c0984e5SSebastian Reichel info->battery_status = APM_BATTERY_STATUS_HIGH;
330*8c0984e5SSebastian Reichel else if (info->battery_life > 5)
331*8c0984e5SSebastian Reichel info->battery_status = APM_BATTERY_STATUS_LOW;
332*8c0984e5SSebastian Reichel else
333*8c0984e5SSebastian Reichel info->battery_status = APM_BATTERY_STATUS_CRITICAL;
334*8c0984e5SSebastian Reichel }
335*8c0984e5SSebastian Reichel info->battery_flag = info->battery_status;
336*8c0984e5SSebastian Reichel
337*8c0984e5SSebastian Reichel /* time */
338*8c0984e5SSebastian Reichel
339*8c0984e5SSebastian Reichel info->units = APM_UNITS_MINS;
340*8c0984e5SSebastian Reichel
341*8c0984e5SSebastian Reichel if (status.intval == POWER_SUPPLY_STATUS_CHARGING) {
342*8c0984e5SSebastian Reichel if (!MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full) ||
343*8c0984e5SSebastian Reichel !MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full))
344*8c0984e5SSebastian Reichel info->time = time_to_full.intval / 60;
345*8c0984e5SSebastian Reichel else
346*8c0984e5SSebastian Reichel info->time = calculate_time(status.intval);
347*8c0984e5SSebastian Reichel } else {
348*8c0984e5SSebastian Reichel if (!MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty) ||
349*8c0984e5SSebastian Reichel !MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty))
350*8c0984e5SSebastian Reichel info->time = time_to_empty.intval / 60;
351*8c0984e5SSebastian Reichel else
352*8c0984e5SSebastian Reichel info->time = calculate_time(status.intval);
353*8c0984e5SSebastian Reichel }
354*8c0984e5SSebastian Reichel
355*8c0984e5SSebastian Reichel mutex_unlock(&apm_mutex);
356*8c0984e5SSebastian Reichel }
357*8c0984e5SSebastian Reichel
apm_battery_init(void)358*8c0984e5SSebastian Reichel static int __init apm_battery_init(void)
359*8c0984e5SSebastian Reichel {
360*8c0984e5SSebastian Reichel printk(KERN_INFO "APM Battery Driver\n");
361*8c0984e5SSebastian Reichel
362*8c0984e5SSebastian Reichel apm_get_power_status = apm_battery_apm_get_power_status;
363*8c0984e5SSebastian Reichel return 0;
364*8c0984e5SSebastian Reichel }
365*8c0984e5SSebastian Reichel
apm_battery_exit(void)366*8c0984e5SSebastian Reichel static void __exit apm_battery_exit(void)
367*8c0984e5SSebastian Reichel {
368*8c0984e5SSebastian Reichel apm_get_power_status = NULL;
369*8c0984e5SSebastian Reichel }
370*8c0984e5SSebastian Reichel
371*8c0984e5SSebastian Reichel module_init(apm_battery_init);
372*8c0984e5SSebastian Reichel module_exit(apm_battery_exit);
373*8c0984e5SSebastian Reichel
374*8c0984e5SSebastian Reichel MODULE_AUTHOR("Eugeny Boger <eugenyboger@dgap.mipt.ru>");
375*8c0984e5SSebastian Reichel MODULE_DESCRIPTION("APM emulation driver for battery monitoring class");
376*8c0984e5SSebastian Reichel MODULE_LICENSE("GPL");
377