diff options
Diffstat (limited to 'drivers/power/apm_power.c')
-rw-r--r-- | drivers/power/apm_power.c | 141 |
1 files changed, 102 insertions, 39 deletions
diff --git a/drivers/power/apm_power.c b/drivers/power/apm_power.c index 39a90a6f0f80..bbf3ee10da04 100644 --- a/drivers/power/apm_power.c +++ b/drivers/power/apm_power.c | |||
@@ -26,65 +26,124 @@ static struct power_supply *main_battery; | |||
26 | static void find_main_battery(void) | 26 | static void find_main_battery(void) |
27 | { | 27 | { |
28 | struct device *dev; | 28 | struct device *dev; |
29 | struct power_supply *bat, *batm; | 29 | struct power_supply *bat = NULL; |
30 | struct power_supply *max_charge_bat = NULL; | ||
31 | struct power_supply *max_energy_bat = NULL; | ||
30 | union power_supply_propval full; | 32 | union power_supply_propval full; |
31 | int max_charge = 0; | 33 | int max_charge = 0; |
34 | int max_energy = 0; | ||
32 | 35 | ||
33 | main_battery = NULL; | 36 | main_battery = NULL; |
34 | batm = NULL; | 37 | |
35 | list_for_each_entry(dev, &power_supply_class->devices, node) { | 38 | list_for_each_entry(dev, &power_supply_class->devices, node) { |
36 | bat = dev_get_drvdata(dev); | 39 | bat = dev_get_drvdata(dev); |
37 | /* If none of battery devices cantains 'use_for_apm' flag, | 40 | |
38 | choice one with maximum design charge */ | 41 | if (bat->use_for_apm) { |
39 | if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full)) { | 42 | /* nice, we explicitly asked to report this battery. */ |
43 | main_battery = bat; | ||
44 | return; | ||
45 | } | ||
46 | |||
47 | if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full) || | ||
48 | !PSY_PROP(bat, CHARGE_FULL, &full)) { | ||
40 | if (full.intval > max_charge) { | 49 | if (full.intval > max_charge) { |
41 | batm = bat; | 50 | max_charge_bat = bat; |
42 | max_charge = full.intval; | 51 | max_charge = full.intval; |
43 | } | 52 | } |
53 | } else if (!PSY_PROP(bat, ENERGY_FULL_DESIGN, &full) || | ||
54 | !PSY_PROP(bat, ENERGY_FULL, &full)) { | ||
55 | if (full.intval > max_energy) { | ||
56 | max_energy_bat = bat; | ||
57 | max_energy = full.intval; | ||
58 | } | ||
44 | } | 59 | } |
60 | } | ||
45 | 61 | ||
46 | if (bat->use_for_apm) | 62 | if ((max_energy_bat && max_charge_bat) && |
47 | main_battery = bat; | 63 | (max_energy_bat != max_charge_bat)) { |
64 | /* try guess battery with more capacity */ | ||
65 | if (!PSY_PROP(max_charge_bat, VOLTAGE_MAX_DESIGN, &full)) { | ||
66 | if (max_energy > max_charge * full.intval) | ||
67 | main_battery = max_energy_bat; | ||
68 | else | ||
69 | main_battery = max_charge_bat; | ||
70 | } else if (!PSY_PROP(max_energy_bat, VOLTAGE_MAX_DESIGN, | ||
71 | &full)) { | ||
72 | if (max_charge > max_energy / full.intval) | ||
73 | main_battery = max_charge_bat; | ||
74 | else | ||
75 | main_battery = max_energy_bat; | ||
76 | } else { | ||
77 | /* give up, choice any */ | ||
78 | main_battery = max_energy_bat; | ||
79 | } | ||
80 | } else if (max_charge_bat) { | ||
81 | main_battery = max_charge_bat; | ||
82 | } else if (max_energy_bat) { | ||
83 | main_battery = max_energy_bat; | ||
84 | } else { | ||
85 | /* give up, try the last if any */ | ||
86 | main_battery = bat; | ||
48 | } | 87 | } |
49 | if (!main_battery) | ||
50 | main_battery = batm; | ||
51 | } | 88 | } |
52 | 89 | ||
53 | static int calculate_time(int status) | 90 | static int calculate_time(int status, int using_charge) |
54 | { | 91 | { |
55 | union power_supply_propval charge_full, charge_empty; | 92 | union power_supply_propval full; |
56 | union power_supply_propval charge, I; | 93 | union power_supply_propval empty; |
94 | union power_supply_propval cur; | ||
95 | union power_supply_propval I; | ||
96 | enum power_supply_property full_prop; | ||
97 | enum power_supply_property full_design_prop; | ||
98 | enum power_supply_property empty_prop; | ||
99 | enum power_supply_property empty_design_prop; | ||
100 | enum power_supply_property cur_avg_prop; | ||
101 | enum power_supply_property cur_now_prop; | ||
57 | 102 | ||
58 | if (MPSY_PROP(CHARGE_FULL, &charge_full)) { | 103 | if (MPSY_PROP(CURRENT_AVG, &I)) { |
59 | /* if battery can't report this property, use design value */ | 104 | /* if battery can't report average value, use momentary */ |
60 | if (MPSY_PROP(CHARGE_FULL_DESIGN, &charge_full)) | 105 | if (MPSY_PROP(CURRENT_NOW, &I)) |
61 | return -1; | 106 | return -1; |
62 | } | 107 | } |
63 | 108 | ||
64 | if (MPSY_PROP(CHARGE_EMPTY, &charge_empty)) { | 109 | if (using_charge) { |
65 | /* if battery can't report this property, use design value */ | 110 | full_prop = POWER_SUPPLY_PROP_CHARGE_FULL; |
66 | if (MPSY_PROP(CHARGE_EMPTY_DESIGN, &charge_empty)) | 111 | full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN; |
67 | charge_empty.intval = 0; | 112 | empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY; |
113 | empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY; | ||
114 | cur_avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG; | ||
115 | cur_now_prop = POWER_SUPPLY_PROP_CHARGE_NOW; | ||
116 | } else { | ||
117 | full_prop = POWER_SUPPLY_PROP_ENERGY_FULL; | ||
118 | full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN; | ||
119 | empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY; | ||
120 | empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY; | ||
121 | cur_avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG; | ||
122 | cur_now_prop = POWER_SUPPLY_PROP_ENERGY_NOW; | ||
68 | } | 123 | } |
69 | 124 | ||
70 | if (MPSY_PROP(CHARGE_AVG, &charge)) { | 125 | if (_MPSY_PROP(full_prop, &full)) { |
71 | /* if battery can't report average value, use momentary */ | 126 | /* if battery can't report this property, use design value */ |
72 | if (MPSY_PROP(CHARGE_NOW, &charge)) | 127 | if (_MPSY_PROP(full_design_prop, &full)) |
73 | return -1; | 128 | return -1; |
74 | } | 129 | } |
75 | 130 | ||
76 | if (MPSY_PROP(CURRENT_AVG, &I)) { | 131 | if (_MPSY_PROP(empty_prop, &empty)) { |
132 | /* if battery can't report this property, use design value */ | ||
133 | if (_MPSY_PROP(empty_design_prop, &empty)) | ||
134 | empty.intval = 0; | ||
135 | } | ||
136 | |||
137 | if (_MPSY_PROP(cur_avg_prop, &cur)) { | ||
77 | /* if battery can't report average value, use momentary */ | 138 | /* if battery can't report average value, use momentary */ |
78 | if (MPSY_PROP(CURRENT_NOW, &I)) | 139 | if (_MPSY_PROP(cur_now_prop, &cur)) |
79 | return -1; | 140 | return -1; |
80 | } | 141 | } |
81 | 142 | ||
82 | if (status == POWER_SUPPLY_STATUS_CHARGING) | 143 | if (status == POWER_SUPPLY_STATUS_CHARGING) |
83 | return ((charge.intval - charge_full.intval) * 60L) / | 144 | return ((cur.intval - full.intval) * 60L) / I.intval; |
84 | I.intval; | ||
85 | else | 145 | else |
86 | return -((charge.intval - charge_empty.intval) * 60L) / | 146 | return -((cur.intval - empty.intval) * 60L) / I.intval; |
87 | I.intval; | ||
88 | } | 147 | } |
89 | 148 | ||
90 | static int calculate_capacity(int using_charge) | 149 | static int calculate_capacity(int using_charge) |
@@ -200,18 +259,22 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info) | |||
200 | info->units = APM_UNITS_MINS; | 259 | info->units = APM_UNITS_MINS; |
201 | 260 | ||
202 | if (status.intval == POWER_SUPPLY_STATUS_CHARGING) { | 261 | if (status.intval == POWER_SUPPLY_STATUS_CHARGING) { |
203 | if (MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full)) { | 262 | if (!MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full) || |
204 | if (MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full)) | 263 | !MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full)) { |
205 | info->time = calculate_time(status.intval); | 264 | info->time = time_to_full.intval / 60; |
206 | else | 265 | } else { |
207 | info->time = time_to_full.intval / 60; | 266 | info->time = calculate_time(status.intval, 0); |
267 | if (info->time == -1) | ||
268 | info->time = calculate_time(status.intval, 1); | ||
208 | } | 269 | } |
209 | } else { | 270 | } else { |
210 | if (MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty)) { | 271 | if (!MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty) || |
211 | if (MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty)) | 272 | !MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty)) { |
212 | info->time = calculate_time(status.intval); | 273 | info->time = time_to_empty.intval / 60; |
213 | else | 274 | } else { |
214 | info->time = time_to_empty.intval / 60; | 275 | info->time = calculate_time(status.intval, 0); |
276 | if (info->time == -1) | ||
277 | info->time = calculate_time(status.intval, 1); | ||
215 | } | 278 | } |
216 | } | 279 | } |
217 | 280 | ||