power: msm_charger: control system power

Some chargers can control their current supply for the system. Provide
facility in the msm_charger to choose which charger supplies system
current. It is guaranteed that start charging will always be called
on a charger that has been previously been asked to provide system
current.

Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
diff --git a/drivers/power/msm_charger.c b/drivers/power/msm_charger.c
index f82df2a..2dbc629 100644
--- a/drivers/power/msm_charger.c
+++ b/drivers/power/msm_charger.c
@@ -480,6 +480,19 @@
 	return ret;
 }
 
+static void msm_enable_system_current(struct msm_hardware_charger_priv *priv)
+{
+	if (priv->hw_chg->start_system_current)
+		priv->hw_chg->start_system_current(priv->hw_chg,
+					 priv->max_source_current);
+}
+
+static void msm_disable_system_current(struct msm_hardware_charger_priv *priv)
+{
+	if (priv->hw_chg->stop_system_current)
+		priv->hw_chg->stop_system_current(priv->hw_chg);
+}
+
 /* the best charger has been selected -start charging from current_chg_priv */
 static int msm_start_charging(void)
 {
@@ -630,11 +643,17 @@
 /* set the charger state to READY before calling this */
 static void handle_charger_ready(struct msm_hardware_charger_priv *hw_chg_priv)
 {
+	struct msm_hardware_charger_priv *old_chg_priv = NULL;
+
 	debug_print(__func__, hw_chg_priv);
 
 	if (msm_chg.current_chg_priv != NULL
 	    && hw_chg_priv->hw_chg->rating >
 	    msm_chg.current_chg_priv->hw_chg->rating) {
+		/*
+		 * a better charger was found, ask the current charger
+		 * to stop charging if it was charging
+		 */
 		if (msm_chg.current_chg_priv->hw_chg_state ==
 		    CHG_CHARGING_STATE) {
 			if (msm_stop_charging(msm_chg.current_chg_priv)) {
@@ -649,6 +668,7 @@
 			}
 		}
 		msm_chg.current_chg_priv->hw_chg_state = CHG_READY_STATE;
+		old_chg_priv = msm_chg.current_chg_priv;
 		msm_chg.current_chg_priv = NULL;
 	}
 
@@ -658,6 +678,14 @@
 			 "%s: best charger = %s\n", __func__,
 			 msm_chg.current_chg_priv->hw_chg->name);
 
+		msm_enable_system_current(msm_chg.current_chg_priv);
+		/*
+		 * since a better charger was chosen, ask the old
+		 * charger to stop providing system current
+		 */
+		if (old_chg_priv != NULL)
+			msm_disable_system_current(old_chg_priv);
+
 		if (!is_batt_status_capable_of_charging())
 			return;
 
@@ -693,6 +721,7 @@
 	debug_print(__func__, hw_chg_removed);
 
 	if (msm_chg.current_chg_priv == hw_chg_removed) {
+		msm_disable_system_current(hw_chg_removed);
 		if (msm_chg.current_chg_priv->hw_chg_state
 						== CHG_CHARGING_STATE) {
 			if (msm_stop_charging(hw_chg_removed)) {
@@ -717,6 +746,7 @@
 				msm_chg.batt_status = BATT_STATUS_DISCHARGING;
 		} else {
 			msm_chg.current_chg_priv = hw_chg_priv;
+			msm_enable_system_current(hw_chg_priv);
 			dev_info(msm_chg.dev,
 				 "%s: best charger = %s\n", __func__,
 				 msm_chg.current_chg_priv->hw_chg->name);