Merge "msm: mdss: cleanup dsi clock handling"
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index d51bef1..7c55702 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -151,7 +151,6 @@
 #define DSI_CMD_TERM    BIT(0)
 
 extern struct device dsi_dev;
-extern int mdss_dsi_clk_on;
 extern u32 dsi_irq;
 extern struct mdss_dsi_ctrl_pdata *ctrl_list[];
 
@@ -246,7 +245,6 @@
 	struct dss_io_data phy_io;
 	int reg_size;
 	u32 clk_cnt;
-	int clk_cnt_sub;
 	u32 flags;
 	struct clk *mdp_core_clk;
 	struct clk *ahb_clk;
@@ -258,7 +256,6 @@
 	u8 ctrl_state;
 	int panel_mode;
 	int irq_cnt;
-	int mdss_dsi_clk_on;
 	int rst_gpio;
 	int disp_en_gpio;
 	int disp_te_gpio;
@@ -317,7 +314,7 @@
 void mdss_dsi_cmd_mdp_start(struct mdss_dsi_ctrl_pdata *ctrl);
 void mdss_dsi_cmd_bta_sw_trigger(struct mdss_panel_data *pdata);
 void mdss_dsi_ack_err_status(struct mdss_dsi_ctrl_pdata *ctrl);
-void mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable);
+int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable);
 int mdss_dsi_link_clk_start(struct mdss_dsi_ctrl_pdata *ctrl);
 void mdss_dsi_link_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl);
 int mdss_dsi_bus_clk_start(struct mdss_dsi_ctrl_pdata *ctrl);
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 73e0ebe..b16ad0d 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -408,11 +408,6 @@
 
 	pr_debug("%s: ndx=%d\n", __func__, ctrl_pdata->ndx);
 
-	if (ctrl_pdata->mdss_dsi_clk_on) {
-		pr_info("%s: mdss_dsi_clks already ON\n", __func__);
-		return 0;
-	}
-
 	rc = clk_enable(ctrl_pdata->esc_clk);
 	if (rc) {
 		pr_err("%s: Failed to enable dsi esc clk\n", __func__);
@@ -431,8 +426,6 @@
 		goto pixel_clk_err;
 	}
 
-	ctrl_pdata->mdss_dsi_clk_on = 1;
-
 	return rc;
 
 pixel_clk_err:
@@ -452,16 +445,9 @@
 
 	pr_debug("%s: ndx=%d\n", __func__, ctrl_pdata->ndx);
 
-	if (ctrl_pdata->mdss_dsi_clk_on == 0) {
-		pr_info("%s: mdss_dsi_clks already OFF\n", __func__);
-		return;
-	}
-
 	clk_disable(ctrl_pdata->esc_clk);
 	clk_disable(ctrl_pdata->pixel_clk);
 	clk_disable(ctrl_pdata->byte_clk);
-
-	ctrl_pdata->mdss_dsi_clk_on = 0;
 }
 
 int mdss_dsi_link_clk_start(struct mdss_dsi_ctrl_pdata *ctrl)
@@ -500,35 +486,52 @@
 	mdss_dsi_link_clk_unprepare(ctrl);
 }
 
-static void mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
+static int __mdss_dsi_update_clk_cnt(u32 *clk_cnt, int enable)
 {
 	int changed = 0;
 
 	if (enable) {
-		if (ctrl->clk_cnt_sub == 0)
+		if (*clk_cnt == 0)
 			changed++;
-		ctrl->clk_cnt_sub++;
+		(*clk_cnt)++;
 	} else {
-		if (ctrl->clk_cnt_sub) {
-			ctrl->clk_cnt_sub--;
-			if (ctrl->clk_cnt_sub == 0)
+		if (*clk_cnt != 0) {
+			(*clk_cnt)--;
+			if (*clk_cnt == 0)
 				changed++;
 		} else {
-			pr_debug("%s: Can not be turned off\n", __func__);
+			pr_debug("%s: clk cnt already zero\n", __func__);
 		}
 	}
 
-	pr_debug("%s: ndx=%d clk_cnt_sub=%d changed=%d enable=%d\n",
-		__func__, ctrl->ndx, ctrl->clk_cnt_sub, changed, enable);
-	if (changed) {
-		if (enable) {
-			if (mdss_dsi_bus_clk_start(ctrl) == 0)
-				mdss_dsi_link_clk_start(ctrl);
-		} else {
-			mdss_dsi_link_clk_stop(ctrl);
-			mdss_dsi_bus_clk_stop(ctrl);
+	return changed;
+}
+
+static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
+{
+	int rc = 0;
+
+	pr_debug("%s: ndx=%d enable=%d\n", __func__, ctrl->ndx, enable);
+
+	if (enable) {
+		rc = mdss_dsi_bus_clk_start(ctrl);
+		if (rc) {
+			pr_err("Failed to start bus clocks. rc=%d\n", rc);
+			goto error;
 		}
+		rc = mdss_dsi_link_clk_start(ctrl);
+		if (rc) {
+			pr_err("Failed to start link clocks. rc=%d\n", rc);
+			mdss_dsi_bus_clk_stop(ctrl);
+			goto error;
+		}
+	} else {
+		mdss_dsi_link_clk_stop(ctrl);
+		mdss_dsi_bus_clk_stop(ctrl);
 	}
+
+error:
+	return rc;
 }
 
 static DEFINE_MUTEX(dsi_clk_lock); /* per system */
@@ -543,11 +546,17 @@
 	return enabled;
 }
 
-void mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
+int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
 {
-	int changed = 0;
+	int rc = 0;
+	int changed = 0, m_changed = 0;
 	struct mdss_dsi_ctrl_pdata *mctrl = NULL;
 
+	if (!ctrl) {
+		pr_err("%s: Invalid arg\n", __func__);
+		return -EINVAL;
+	}
+
 	/*
 	 * In broadcast mode, we need to enable clocks for the
 	 * master controller as well when enabling clocks for the
@@ -559,34 +568,61 @@
 			pr_warn("%s: Unable to get master control\n", __func__);
 	}
 
+	pr_debug("%s++: ndx=%d clk_cnt=%d mctrl=%s m_clk_cnt=%d\n, enable=%d\n",
+		__func__, ctrl->ndx, ctrl->clk_cnt,
+		mctrl ? "yes" : "no", mctrl ? mctrl->clk_cnt : -1, enable);
+
 	mutex_lock(&dsi_clk_lock);
-	if (enable) {
-		if (ctrl->clk_cnt == 0)
-			changed++;
-		ctrl->clk_cnt++;
-	} else {
-		if (ctrl->clk_cnt) {
-			ctrl->clk_cnt--;
-			if (ctrl->clk_cnt == 0)
-				changed++;
-		} else {
-			pr_debug("%s: Can not be turned off\n", __func__);
+	changed = __mdss_dsi_update_clk_cnt(&ctrl->clk_cnt, enable);
+	if (changed && mctrl)
+		m_changed = __mdss_dsi_update_clk_cnt(&mctrl->clk_cnt, enable);
+
+	if (changed) {
+		if (enable && m_changed) {
+			rc = mdss_dsi_clk_ctrl_sub(mctrl, enable);
+			if (rc) {
+				pr_err("Failed to start mctrl clocks. rc=%d\n",
+					rc);
+				goto error_mctrl_start;
+			}
+		}
+
+		rc = mdss_dsi_clk_ctrl_sub(ctrl, enable);
+		if (rc) {
+			pr_err("Failed to %s ctrl clocks. rc=%d\n",
+				(enable ? "start" : "stop"), rc);
+			goto error_ctrl;
+		}
+
+		if (!enable && m_changed) {
+			rc = mdss_dsi_clk_ctrl_sub(mctrl, enable);
+			if (rc) {
+				pr_err("Failed to stop mctrl clocks. rc=%d\n",
+					rc);
+				goto error_mctrl_stop;
+			}
 		}
 	}
 
-	pr_debug("%s: ndx=%d clk_cnt=%d changed=%d enable=%d\n",
-		__func__, ctrl->ndx, ctrl->clk_cnt, changed, enable);
+	goto no_error;
 
-	if (changed) {
-		if (enable && mctrl)
-			mdss_dsi_clk_ctrl_sub(mctrl, enable);
+error_mctrl_stop:
+	mdss_dsi_clk_ctrl_sub(ctrl, enable ? 0 : 1);
+error_ctrl:
+	mdss_dsi_clk_ctrl_sub(mctrl, 0);
+error_mctrl_start:
+	__mdss_dsi_update_clk_cnt(&mctrl->clk_cnt, enable ? 0 : 1);
+	__mdss_dsi_update_clk_cnt(&ctrl->clk_cnt, enable ? 0 : 1);
 
-		mdss_dsi_clk_ctrl_sub(ctrl, enable);
-
-		if (!enable && mctrl)
-			mdss_dsi_clk_ctrl_sub(mctrl, enable);
-	}
+no_error:
 	mutex_unlock(&dsi_clk_lock);
+	pr_debug("%s--: ndx=%d clk_cnt=%d changed=%d mctrl=%s m_clk_cnt=%d\n",
+		__func__, ctrl->ndx, ctrl->clk_cnt, changed,
+		mctrl ? "yes" : "no", mctrl ? mctrl->clk_cnt : -1);
+	pr_debug("%s--: m_changed=%d enable=%d\n", __func__,
+		mctrl ? m_changed : -1, enable);
+
+	return rc;
 }
 
 void mdss_dsi_phy_sw_reset(unsigned char *ctrl_base)