clk: msm: mdss: Add support for DSI PLL 1 clock registration

Setup DSI 1 PLL clock heirarchy. This is needed for instances
where we need to turn off the second pll in case of current
leak issue.

Change-Id: I694af1fa9591b2345709687c9e7b1d69f15b56a9
Signed-off-by: Siddhartha Agrawal <agrawals@codeaurora.org>
Signed-off-by: Veera Sundaram Sankaran <veeras@codeaurora.org>
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-20nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-20nm.c
index c5ef107..f6fada26 100644
--- a/drivers/clk/qcom/mdss/mdss-dsi-pll-20nm.c
+++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-20nm.c
@@ -56,6 +56,20 @@
 	return rc;
 }
 
+static int pll1_vco_set_rate_20nm(struct clk *c, unsigned long rate)
+{
+	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+	struct mdss_pll_resources *pll_res = vco->priv;
+
+	mdss_pll_resource_enable(pll_res, true);
+	__dsi_pll_disable(pll_res->pll_base);
+	mdss_pll_resource_enable(pll_res, false);
+
+	pr_debug("Configuring PLL1 registers.\n");
+
+	return 0;
+}
+
 static int shadow_vco_set_rate_20nm(struct clk *c, unsigned long rate)
 {
 	int rc;
@@ -111,6 +125,11 @@
 }
 
 /* Op structures */
+
+static const struct clk_ops pll1_clk_ops_dsi_vco = {
+	.set_rate = pll1_vco_set_rate_20nm,
+};
+
 static const struct clk_ops clk_ops_dsi_vco = {
 	.set_rate = vco_set_rate_20nm,
 	.round_rate = pll_20nm_vco_round_rate,
@@ -175,6 +194,15 @@
 	.get_mux_sel = get_mdss_pixel_mux_sel,
 };
 
+static struct dsi_pll_vco_clk mdss_dsi1_vco_clk_src = {
+	.c = {
+		.dbg_name = "mdss_dsi1_vco_clk_src",
+		.ops = &pll1_clk_ops_dsi_vco,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(mdss_dsi1_vco_clk_src.c),
+	},
+};
+
 static struct dsi_pll_vco_clk dsi_vco_clk_8994 = {
 	.ref_clk_rate = 19200000,
 	.min_rate = 1000000000,
@@ -435,6 +463,10 @@
 	}
 };
 
+static struct clk_lookup mdss_dsi_pll_1_cc_8994[] = {
+	CLK_LIST(mdss_dsi1_vco_clk_src),
+};
+
 static struct clk_lookup mdss_dsi_pllcc_8994[] = {
 	CLK_LIST(mdss_pixel_clk_mux),
 	CLK_LIST(mdss_byte_clk_mux),
@@ -519,68 +551,88 @@
 		return -EPROBE_DEFER;
 	}
 
-	/* Set client data to mux, div and vco clocks */
-	byte_clk_src.priv = pll_res;
-	pixel_clk_src.priv = pll_res;
-	bypass_lp_div_mux_8994.priv = pll_res;
-	indirect_path_div2_clk_8994.priv = pll_res;
-	ndiv_clk_8994.priv = pll_res;
-	fixed_hr_oclk2_div_clk_8994.priv = pll_res;
-	hr_oclk3_div_clk_8994.priv = pll_res;
-	dsi_vco_clk_8994.priv = pll_res;
+	/*
+	 * Set client data to mux, div and vco clocks.
+	 * This needs to be done only for PLL0 since, that is the one in
+	 * use.
+	 **/
+	if (!pll_res->index) {
+		byte_clk_src.priv = pll_res;
+		pixel_clk_src.priv = pll_res;
+		bypass_lp_div_mux_8994.priv = pll_res;
+		indirect_path_div2_clk_8994.priv = pll_res;
+		ndiv_clk_8994.priv = pll_res;
+		fixed_hr_oclk2_div_clk_8994.priv = pll_res;
+		hr_oclk3_div_clk_8994.priv = pll_res;
+		dsi_vco_clk_8994.priv = pll_res;
 
-	shadow_byte_clk_src.priv = pll_res;
-	shadow_pixel_clk_src.priv = pll_res;
-	shadow_bypass_lp_div_mux_8994.priv = pll_res;
-	shadow_indirect_path_div2_clk_8994.priv = pll_res;
-	shadow_ndiv_clk_8994.priv = pll_res;
-	shadow_fixed_hr_oclk2_div_clk_8994.priv = pll_res;
-	shadow_hr_oclk3_div_clk_8994.priv = pll_res;
-	shadow_dsi_vco_clk_8994.priv = pll_res;
+		shadow_byte_clk_src.priv = pll_res;
+		shadow_pixel_clk_src.priv = pll_res;
+		shadow_bypass_lp_div_mux_8994.priv = pll_res;
+		shadow_indirect_path_div2_clk_8994.priv = pll_res;
+		shadow_ndiv_clk_8994.priv = pll_res;
+		shadow_fixed_hr_oclk2_div_clk_8994.priv = pll_res;
+		shadow_hr_oclk3_div_clk_8994.priv = pll_res;
+		shadow_dsi_vco_clk_8994.priv = pll_res;
 
-	pll_res->vco_delay = VCO_DELAY_USEC;
+		pll_res->vco_delay = VCO_DELAY_USEC;
 
-	/* Set clock source operations */
-	pixel_clk_src_ops = clk_ops_slave_div;
-	pixel_clk_src_ops.prepare = dsi_pll_div_prepare;
+		/* Set clock source operations */
+		pixel_clk_src_ops = clk_ops_slave_div;
+		pixel_clk_src_ops.prepare = dsi_pll_div_prepare;
 
-	ndiv_clk_ops = clk_ops_div;
-	ndiv_clk_ops.prepare = dsi_pll_div_prepare;
+		ndiv_clk_ops = clk_ops_div;
+		ndiv_clk_ops.prepare = dsi_pll_div_prepare;
 
-	byte_clk_src_ops = clk_ops_div;
-	byte_clk_src_ops.prepare = dsi_pll_div_prepare;
+		byte_clk_src_ops = clk_ops_div;
+		byte_clk_src_ops.prepare = dsi_pll_div_prepare;
 
-	bypass_lp_div_mux_clk_ops = clk_ops_gen_mux;
-	bypass_lp_div_mux_clk_ops.prepare = dsi_pll_mux_prepare;
+		bypass_lp_div_mux_clk_ops = clk_ops_gen_mux;
+		bypass_lp_div_mux_clk_ops.prepare = dsi_pll_mux_prepare;
 
-	clk_ops_gen_mux_dsi = clk_ops_gen_mux;
-	clk_ops_gen_mux_dsi.round_rate = parent_round_rate;
-	clk_ops_gen_mux_dsi.set_rate = parent_set_rate;
+		clk_ops_gen_mux_dsi = clk_ops_gen_mux;
+		clk_ops_gen_mux_dsi.round_rate = parent_round_rate;
+		clk_ops_gen_mux_dsi.set_rate = parent_set_rate;
 
-	shadow_pixel_clk_src_ops = clk_ops_slave_div;
-	shadow_pixel_clk_src_ops.prepare = dsi_pll_div_prepare;
+		shadow_pixel_clk_src_ops = clk_ops_slave_div;
+		shadow_pixel_clk_src_ops.prepare = dsi_pll_div_prepare;
 
-	shadow_byte_clk_src_ops = clk_ops_div;
-	shadow_byte_clk_src_ops.prepare = dsi_pll_div_prepare;
+		shadow_byte_clk_src_ops = clk_ops_div;
+		shadow_byte_clk_src_ops.prepare = dsi_pll_div_prepare;
+	} else {
+		mdss_dsi1_vco_clk_src.priv = pll_res;
+	}
 
 	if (pll_res->target_id == MDSS_PLL_TARGET_8994) {
-		pll_res->gdsc_cb.notifier_call =
-			dsi_pll_regulator_notifier_call;
-		INIT_WORK(&pll_res->pll_off, dsi_pll_off_work);
+		if (pll_res->index) {
+			rc = of_msm_clock_register(pdev->dev.of_node,
+					mdss_dsi_pll_1_cc_8994,
+					ARRAY_SIZE(mdss_dsi_pll_1_cc_8994));
+			if (rc) {
+				pr_err("Clock register failed\n");
+				rc = -EPROBE_DEFER;
+			}
+		} else {
+			rc = of_msm_clock_register(pdev->dev.of_node,
+				mdss_dsi_pllcc_8994,
+				ARRAY_SIZE(mdss_dsi_pllcc_8994));
+			if (rc) {
+				pr_err("Clock register failed\n");
+				rc = -EPROBE_DEFER;
+			}
+			pll_res->gdsc_cb.notifier_call =
+				dsi_pll_regulator_notifier_call;
+			INIT_WORK(&pll_res->pll_off, dsi_pll_off_work);
 
-		rc = of_msm_clock_register(pdev->dev.of_node,
-			mdss_dsi_pllcc_8994, ARRAY_SIZE(mdss_dsi_pllcc_8994));
-		if (rc) {
-			pr_err("Clock register failed\n");
-			rc = -EPROBE_DEFER;
+			pll_reg = mdss_pll_get_mp_by_reg_name(pll_res, "gdsc");
+			if (pll_reg) {
+				pr_debug("Registering for gdsc regulator events\n");
+				if (regulator_register_notifier(pll_reg->vreg,
+							&(pll_res->gdsc_cb)))
+					pr_err("Regulator notification registration failed!\n");
+			}
 		}
-		pll_reg = mdss_pll_get_mp_by_reg_name(pll_res, "gdsc");
-		if (pll_reg) {
-			pr_debug("Registering for gdsc regulator events\n");
-			if (regulator_register_notifier(pll_reg->vreg,
-						&(pll_res->gdsc_cb)))
-				pr_err("Regulator notification registration failed!\n");
-		}
+
 	} else {
 		pr_err("Invalid target ID\n");
 		rc = -EINVAL;
diff --git a/drivers/clk/qcom/mdss/mdss-pll.c b/drivers/clk/qcom/mdss/mdss-pll.c
index 115878a..8e2acac 100644
--- a/drivers/clk/qcom/mdss/mdss-pll.c
+++ b/drivers/clk/qcom/mdss/mdss-pll.c
@@ -227,6 +227,13 @@
 	}
 	platform_set_drvdata(pdev, pll_res);
 
+	rc = of_property_read_u32(pdev->dev.of_node, "cell-index",
+			&pll_res->index);
+	if (rc) {
+		pr_err("Unable to get the cell-index rc=%d\n", rc);
+		pll_res->index = 0;
+	}
+
 	pll_base_reg = platform_get_resource_byname(pdev,
 						IORESOURCE_MEM, "pll_base");
 	if (!pll_base_reg) {
diff --git a/drivers/clk/qcom/mdss/mdss-pll.h b/drivers/clk/qcom/mdss/mdss-pll.h
index e90394a..20642a9 100644
--- a/drivers/clk/qcom/mdss/mdss-pll.h
+++ b/drivers/clk/qcom/mdss/mdss-pll.h
@@ -119,6 +119,12 @@
 	 */
 	struct work_struct pll_off;
 
+	/*
+	 * PLL index if multiple index are available. Eg. in case of
+	 * DSI we have 2 plls.
+	 */
+	uint32_t index;
+
 };
 
 struct mdss_pll_vco_calc {