diff options
Diffstat (limited to 'drivers/power/apm_power.c')
-rw-r--r-- | drivers/power/apm_power.c | 116 |
1 files changed, 68 insertions, 48 deletions
diff --git a/drivers/power/apm_power.c b/drivers/power/apm_power.c index bbf3ee10da04..7e29b90a4f63 100644 --- a/drivers/power/apm_power.c +++ b/drivers/power/apm_power.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/power_supply.h> | 13 | #include <linux/power_supply.h> |
14 | #include <linux/apm-emulation.h> | 14 | #include <linux/apm-emulation.h> |
15 | 15 | ||
16 | static DEFINE_MUTEX(apm_mutex); | ||
16 | #define PSY_PROP(psy, prop, val) psy->get_property(psy, \ | 17 | #define PSY_PROP(psy, prop, val) psy->get_property(psy, \ |
17 | POWER_SUPPLY_PROP_##prop, val) | 18 | POWER_SUPPLY_PROP_##prop, val) |
18 | 19 | ||
@@ -23,67 +24,86 @@ | |||
23 | 24 | ||
24 | static struct power_supply *main_battery; | 25 | static struct power_supply *main_battery; |
25 | 26 | ||
26 | static void find_main_battery(void) | 27 | struct find_bat_param { |
27 | { | 28 | struct power_supply *main; |
28 | struct device *dev; | 29 | struct power_supply *bat; |
29 | struct power_supply *bat = NULL; | 30 | struct power_supply *max_charge_bat; |
30 | struct power_supply *max_charge_bat = NULL; | 31 | struct power_supply *max_energy_bat; |
31 | struct power_supply *max_energy_bat = NULL; | ||
32 | union power_supply_propval full; | 32 | union power_supply_propval full; |
33 | int max_charge = 0; | 33 | int max_charge; |
34 | int max_energy = 0; | 34 | int max_energy; |
35 | }; | ||
35 | 36 | ||
36 | main_battery = NULL; | 37 | static int __find_main_battery(struct device *dev, void *data) |
38 | { | ||
39 | struct find_bat_param *bp = (struct find_bat_param *)data; | ||
37 | 40 | ||
38 | list_for_each_entry(dev, &power_supply_class->devices, node) { | 41 | bp->bat = dev_get_drvdata(dev); |
39 | bat = dev_get_drvdata(dev); | ||
40 | 42 | ||
41 | if (bat->use_for_apm) { | 43 | if (bp->bat->use_for_apm) { |
42 | /* nice, we explicitly asked to report this battery. */ | 44 | /* nice, we explicitly asked to report this battery. */ |
43 | main_battery = bat; | 45 | bp->main = bp->bat; |
44 | return; | 46 | return 1; |
45 | } | 47 | } |
46 | 48 | ||
47 | if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full) || | 49 | if (!PSY_PROP(bp->bat, CHARGE_FULL_DESIGN, &bp->full) || |
48 | !PSY_PROP(bat, CHARGE_FULL, &full)) { | 50 | !PSY_PROP(bp->bat, CHARGE_FULL, &bp->full)) { |
49 | if (full.intval > max_charge) { | 51 | if (bp->full.intval > bp->max_charge) { |
50 | max_charge_bat = bat; | 52 | bp->max_charge_bat = bp->bat; |
51 | max_charge = full.intval; | 53 | bp->max_charge = bp->full.intval; |
52 | } | 54 | } |
53 | } else if (!PSY_PROP(bat, ENERGY_FULL_DESIGN, &full) || | 55 | } else if (!PSY_PROP(bp->bat, ENERGY_FULL_DESIGN, &bp->full) || |
54 | !PSY_PROP(bat, ENERGY_FULL, &full)) { | 56 | !PSY_PROP(bp->bat, ENERGY_FULL, &bp->full)) { |
55 | if (full.intval > max_energy) { | 57 | if (bp->full.intval > bp->max_energy) { |
56 | max_energy_bat = bat; | 58 | bp->max_energy_bat = bp->bat; |
57 | max_energy = full.intval; | 59 | bp->max_energy = bp->full.intval; |
58 | } | ||
59 | } | 60 | } |
60 | } | 61 | } |
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static void find_main_battery(void) | ||
66 | { | ||
67 | struct find_bat_param bp; | ||
68 | int error; | ||
69 | |||
70 | memset(&bp, 0, sizeof(struct find_bat_param)); | ||
71 | main_battery = NULL; | ||
72 | bp.main = main_battery; | ||
73 | |||
74 | error = class_for_each_device(power_supply_class, &bp, | ||
75 | __find_main_battery); | ||
76 | if (error) { | ||
77 | main_battery = bp.main; | ||
78 | return; | ||
79 | } | ||
61 | 80 | ||
62 | if ((max_energy_bat && max_charge_bat) && | 81 | if ((bp.max_energy_bat && bp.max_charge_bat) && |
63 | (max_energy_bat != max_charge_bat)) { | 82 | (bp.max_energy_bat != bp.max_charge_bat)) { |
64 | /* try guess battery with more capacity */ | 83 | /* try guess battery with more capacity */ |
65 | if (!PSY_PROP(max_charge_bat, VOLTAGE_MAX_DESIGN, &full)) { | 84 | if (!PSY_PROP(bp.max_charge_bat, VOLTAGE_MAX_DESIGN, |
66 | if (max_energy > max_charge * full.intval) | 85 | &bp.full)) { |
67 | main_battery = max_energy_bat; | 86 | if (bp.max_energy > bp.max_charge * bp.full.intval) |
87 | main_battery = bp.max_energy_bat; | ||
68 | else | 88 | else |
69 | main_battery = max_charge_bat; | 89 | main_battery = bp.max_charge_bat; |
70 | } else if (!PSY_PROP(max_energy_bat, VOLTAGE_MAX_DESIGN, | 90 | } else if (!PSY_PROP(bp.max_energy_bat, VOLTAGE_MAX_DESIGN, |
71 | &full)) { | 91 | &bp.full)) { |
72 | if (max_charge > max_energy / full.intval) | 92 | if (bp.max_charge > bp.max_energy / bp.full.intval) |
73 | main_battery = max_charge_bat; | 93 | main_battery = bp.max_charge_bat; |
74 | else | 94 | else |
75 | main_battery = max_energy_bat; | 95 | main_battery = bp.max_energy_bat; |
76 | } else { | 96 | } else { |
77 | /* give up, choice any */ | 97 | /* give up, choice any */ |
78 | main_battery = max_energy_bat; | 98 | main_battery = bp.max_energy_bat; |
79 | } | 99 | } |
80 | } else if (max_charge_bat) { | 100 | } else if (bp.max_charge_bat) { |
81 | main_battery = max_charge_bat; | 101 | main_battery = bp.max_charge_bat; |
82 | } else if (max_energy_bat) { | 102 | } else if (bp.max_energy_bat) { |
83 | main_battery = max_energy_bat; | 103 | main_battery = bp.max_energy_bat; |
84 | } else { | 104 | } else { |
85 | /* give up, try the last if any */ | 105 | /* give up, try the last if any */ |
86 | main_battery = bat; | 106 | main_battery = bp.bat; |
87 | } | 107 | } |
88 | } | 108 | } |
89 | 109 | ||
@@ -207,10 +227,10 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info) | |||
207 | union power_supply_propval status; | 227 | union power_supply_propval status; |
208 | union power_supply_propval capacity, time_to_full, time_to_empty; | 228 | union power_supply_propval capacity, time_to_full, time_to_empty; |
209 | 229 | ||
210 | down(&power_supply_class->sem); | 230 | mutex_lock(&apm_mutex); |
211 | find_main_battery(); | 231 | find_main_battery(); |
212 | if (!main_battery) { | 232 | if (!main_battery) { |
213 | up(&power_supply_class->sem); | 233 | mutex_unlock(&apm_mutex); |
214 | return; | 234 | return; |
215 | } | 235 | } |
216 | 236 | ||
@@ -278,7 +298,7 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info) | |||
278 | } | 298 | } |
279 | } | 299 | } |
280 | 300 | ||
281 | up(&power_supply_class->sem); | 301 | mutex_unlock(&apm_mutex); |
282 | } | 302 | } |
283 | 303 | ||
284 | static int __init apm_battery_init(void) | 304 | static int __init apm_battery_init(void) |