aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power/apm_power.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/power/apm_power.c')
-rw-r--r--drivers/power/apm_power.c141
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;
26static void find_main_battery(void) 26static 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
53static int calculate_time(int status) 90static 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
90static int calculate_capacity(int using_charge) 149static 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