Merge git://git.infradead.org/battery-2.6

* git://git.infradead.org/battery-2.6:
  apm_power: calculate to_full/to_empty time using energy
  apm_power: improve battery finding algorithm
  apm_power: fix obviously wrong logic for time reporting
diff --git a/drivers/power/apm_power.c b/drivers/power/apm_power.c
index 39a90a6..bbf3ee1 100644
--- a/drivers/power/apm_power.c
+++ b/drivers/power/apm_power.c
@@ -26,52 +26,79 @@
 static void find_main_battery(void)
 {
 	struct device *dev;
-	struct power_supply *bat, *batm;
+	struct power_supply *bat = NULL;
+	struct power_supply *max_charge_bat = NULL;
+	struct power_supply *max_energy_bat = NULL;
 	union power_supply_propval full;
 	int max_charge = 0;
+	int max_energy = 0;
 
 	main_battery = NULL;
-	batm = NULL;
+
 	list_for_each_entry(dev, &power_supply_class->devices, node) {
 		bat = dev_get_drvdata(dev);
-		/* If none of battery devices cantains 'use_for_apm' flag,
-		   choice one with maximum design charge */
-		if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full)) {
-			if (full.intval > max_charge) {
-				batm = bat;
-				max_charge = full.intval;
-			}
+
+		if (bat->use_for_apm) {
+			/* nice, we explicitly asked to report this battery. */
+			main_battery = bat;
+			return;
 		}
 
-		if (bat->use_for_apm)
-			main_battery = bat;
+		if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full) ||
+				!PSY_PROP(bat, CHARGE_FULL, &full)) {
+			if (full.intval > max_charge) {
+				max_charge_bat = bat;
+				max_charge = full.intval;
+			}
+		} else if (!PSY_PROP(bat, ENERGY_FULL_DESIGN, &full) ||
+				!PSY_PROP(bat, ENERGY_FULL, &full)) {
+			if (full.intval > max_energy) {
+				max_energy_bat = bat;
+				max_energy = full.intval;
+			}
+		}
 	}
-	if (!main_battery)
-		main_battery = batm;
+
+	if ((max_energy_bat && max_charge_bat) &&
+			(max_energy_bat != max_charge_bat)) {
+		/* try guess battery with more capacity */
+		if (!PSY_PROP(max_charge_bat, VOLTAGE_MAX_DESIGN, &full)) {
+			if (max_energy > max_charge * full.intval)
+				main_battery = max_energy_bat;
+			else
+				main_battery = max_charge_bat;
+		} else if (!PSY_PROP(max_energy_bat, VOLTAGE_MAX_DESIGN,
+								  &full)) {
+			if (max_charge > max_energy / full.intval)
+				main_battery = max_charge_bat;
+			else
+				main_battery = max_energy_bat;
+		} else {
+			/* give up, choice any */
+			main_battery = max_energy_bat;
+		}
+	} else if (max_charge_bat) {
+		main_battery = max_charge_bat;
+	} else if (max_energy_bat) {
+		main_battery = max_energy_bat;
+	} else {
+		/* give up, try the last if any */
+		main_battery = bat;
+	}
 }
 
-static int calculate_time(int status)
+static int calculate_time(int status, int using_charge)
 {
-	union power_supply_propval charge_full, charge_empty;
-	union power_supply_propval charge, I;
-
-	if (MPSY_PROP(CHARGE_FULL, &charge_full)) {
-		/* if battery can't report this property, use design value */
-		if (MPSY_PROP(CHARGE_FULL_DESIGN, &charge_full))
-			return -1;
-	}
-
-	if (MPSY_PROP(CHARGE_EMPTY, &charge_empty)) {
-		/* if battery can't report this property, use design value */
-		if (MPSY_PROP(CHARGE_EMPTY_DESIGN, &charge_empty))
-			charge_empty.intval = 0;
-	}
-
-	if (MPSY_PROP(CHARGE_AVG, &charge)) {
-		/* if battery can't report average value, use momentary */
-		if (MPSY_PROP(CHARGE_NOW, &charge))
-			return -1;
-	}
+	union power_supply_propval full;
+	union power_supply_propval empty;
+	union power_supply_propval cur;
+	union power_supply_propval I;
+	enum power_supply_property full_prop;
+	enum power_supply_property full_design_prop;
+	enum power_supply_property empty_prop;
+	enum power_supply_property empty_design_prop;
+	enum power_supply_property cur_avg_prop;
+	enum power_supply_property cur_now_prop;
 
 	if (MPSY_PROP(CURRENT_AVG, &I)) {
 		/* if battery can't report average value, use momentary */
@@ -79,12 +106,44 @@
 			return -1;
 	}
 
+	if (using_charge) {
+		full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
+		full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
+		empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
+		empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
+		cur_avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
+		cur_now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
+	} else {
+		full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
+		full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
+		empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
+		empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
+		cur_avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
+		cur_now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
+	}
+
+	if (_MPSY_PROP(full_prop, &full)) {
+		/* if battery can't report this property, use design value */
+		if (_MPSY_PROP(full_design_prop, &full))
+			return -1;
+	}
+
+	if (_MPSY_PROP(empty_prop, &empty)) {
+		/* if battery can't report this property, use design value */
+		if (_MPSY_PROP(empty_design_prop, &empty))
+			empty.intval = 0;
+	}
+
+	if (_MPSY_PROP(cur_avg_prop, &cur)) {
+		/* if battery can't report average value, use momentary */
+		if (_MPSY_PROP(cur_now_prop, &cur))
+			return -1;
+	}
+
 	if (status == POWER_SUPPLY_STATUS_CHARGING)
-		return ((charge.intval - charge_full.intval) * 60L) /
-		       I.intval;
+		return ((cur.intval - full.intval) * 60L) / I.intval;
 	else
-		return -((charge.intval - charge_empty.intval) * 60L) /
-			I.intval;
+		return -((cur.intval - empty.intval) * 60L) / I.intval;
 }
 
 static int calculate_capacity(int using_charge)
@@ -200,18 +259,22 @@
 	info->units = APM_UNITS_MINS;
 
 	if (status.intval == POWER_SUPPLY_STATUS_CHARGING) {
-		if (MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full)) {
-			if (MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full))
-				info->time = calculate_time(status.intval);
-			else
-				info->time = time_to_full.intval / 60;
+		if (!MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full) ||
+				!MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full)) {
+			info->time = time_to_full.intval / 60;
+		} else {
+			info->time = calculate_time(status.intval, 0);
+			if (info->time == -1)
+				info->time = calculate_time(status.intval, 1);
 		}
 	} else {
-		if (MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty)) {
-			if (MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty))
-				info->time = calculate_time(status.intval);
-			else
-				info->time = time_to_empty.intval / 60;
+		if (!MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty) ||
+			      !MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty)) {
+			info->time = time_to_empty.intval / 60;
+		} else {
+			info->time = calculate_time(status.intval, 0);
+			if (info->time == -1)
+				info->time = calculate_time(status.intval, 1);
 		}
 	}