msm: pil-q6v5: Migrate to clock APIs

Rather than writing to clock controller registers directly, utilize
the clock driver and its recently-added support for LPASS and MSS
clocks needed by PIL.

Since clock hardware differences are hidden under the clock APIs,
clock control can be moved from pil-q6v5-lpass into the pil-q6v5
library and shared with other PIL drivers that will eventually use
it.

Signed-off-by: Matt Wagantall <mattw@codeaurora.org>
Change-Id: I70d67d6abded93bcc5119e5bcec4c0211f157ac0
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
index 002431a..308f992 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
@@ -7,17 +7,15 @@
 
 Required properties:
 - compatible:	      Must be "qcom,pil-q6v5-lpass"
-- reg:		      Three pairs of physical base addresses and region sizes
+- reg:		      Two pairs of physical base addresses and region sizes
 		      of memory mapped registers. The first region corresponds
-		      to QDSP6SS_PUB, the second corresponds to LPASS_CC, and
-		      the third to LPASS_HALTREQ.
+		      to QDSP6SS_PUB, and the second to LPASS_HALTREQ.
 - qcom,firmware-name: Base name of the firmware image. Ex. "lpass"
 
 Example:
 	qcom,lpass@fe200000 {
 	        compatible = "qcom,pil-q6v5-lpass";
 	        reg = <0xfe200000 0x00100>,
-	              <0xfe000000 0x40000>,
 	              <0xfd485100 0x00010>;
 
 	        qcom,firmware-name = "lpass";
diff --git a/arch/arm/boot/dts/msmcopper.dtsi b/arch/arm/boot/dts/msmcopper.dtsi
index 69aff33..66f5fa1 100644
--- a/arch/arm/boot/dts/msmcopper.dtsi
+++ b/arch/arm/boot/dts/msmcopper.dtsi
@@ -276,7 +276,6 @@
 	qcom,lpass@fe200000 {
 		compatible = "qcom,pil-q6v5-lpass";
 		reg = <0xfe200000 0x00100>,
-		      <0xfe000000 0x40000>,
 		      <0xfd485100 0x00010>;
 
 		qcom,firmware-name = "lpass";
diff --git a/arch/arm/mach-msm/clock-copper.c b/arch/arm/mach-msm/clock-copper.c
index 03667d7..80403f8 100644
--- a/arch/arm/mach-msm/clock-copper.c
+++ b/arch/arm/mach-msm/clock-copper.c
@@ -4906,8 +4906,8 @@
 
 	CLK_LOOKUP("core_clk",       mss_xo_q6_clk.c, ""),
 	CLK_LOOKUP("bus_clk",       mss_bus_q6_clk.c, ""),
-	CLK_LOOKUP("core_clk",         q6ss_xo_clk.c, ""),
-	CLK_LOOKUP("bus_clk",  q6ss_ahb_lfabif_clk.c, ""),
+	CLK_LOOKUP("core_clk",         q6ss_xo_clk.c, "pil-q6v5-lpass"),
+	CLK_LOOKUP("bus_clk",  q6ss_ahb_lfabif_clk.c, "pil-q6v5-lpass"),
 	CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c, ""),
 	CLK_LOOKUP("bus_clk",  gcc_mss_cfg_ahb_clk.c, ""),
 
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index 5eac539..8691ac7 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -18,37 +18,19 @@
 #include <linux/iopoll.h>
 #include <linux/err.h>
 #include <linux/of.h>
+#include <linux/clk.h>
 
 #include "peripheral-loader.h"
 #include "pil-q6v5.h"
 
 /* Register Offsets */
 #define QDSP6SS_RST_EVB			0x010
-#define LPASS_Q6SS_BCR			0x06000
-#define LPASS_Q6SS_AHB_LFABIF_CBCR	0x22000
-#define LPASS_Q6SS_XO_CBCR		0x26000
 #define AXI_HALTREQ			0x0
 #define AXI_HALTACK			0x4
 #define AXI_IDLE			0x8
 
 #define HALT_ACK_TIMEOUT_US		100000
 
-static void clk_reg_enable(void __iomem *reg)
-{
-	u32 val;
-	val = readl_relaxed(reg);
-	val |= BIT(0);
-	writel_relaxed(val, reg);
-}
-
-static void clk_reg_disable(void __iomem *reg)
-{
-	u32 val;
-	val = readl_relaxed(reg);
-	val &= ~BIT(0);
-	writel_relaxed(val, reg);
-}
-
 static int pil_lpass_shutdown(struct pil_desc *pil)
 {
 	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
@@ -64,17 +46,18 @@
 		dev_err(pil->dev, "Port halt failed\n");
 	writel_relaxed(0, drv->axi_halt_base + AXI_HALTREQ);
 
-	/* Make sure Q6 registers are accessible */
-	writel_relaxed(0, drv->clk_base + LPASS_Q6SS_BCR);
-	clk_reg_enable(drv->clk_base + LPASS_Q6SS_AHB_LFABIF_CBCR);
-	mb();
+	/*
+	 * If the shutdown function is called before the reset function, clocks
+	 * will not be enabled yet. Enable them here so that register writes
+	 * performed during the shutdown succeed.
+	 */
+	if (drv->is_booted == false)
+		pil_q6v5_enable_clks(pil);
 
 	pil_q6v5_shutdown(pil);
+	pil_q6v5_disable_clks(pil);
 
-	/* Disable clocks and assert subsystem resets. */
-	clk_reg_disable(drv->clk_base + LPASS_Q6SS_AHB_LFABIF_CBCR);
-	clk_reg_disable(drv->clk_base + LPASS_Q6SS_XO_CBCR);
-	writel_relaxed(1, drv->clk_base + LPASS_Q6SS_BCR);
+	drv->is_booted = false;
 
 	return 0;
 }
@@ -82,21 +65,25 @@
 static int pil_lpass_reset(struct pil_desc *pil)
 {
 	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+	int ret;
 
-	/*
-	 * Bring subsystem out of reset and enable required
-	 * regulators and clocks.
-	 */
-	writel_relaxed(0, drv->clk_base + LPASS_Q6SS_BCR);
-	clk_reg_enable(drv->clk_base + LPASS_Q6SS_XO_CBCR);
-	clk_reg_enable(drv->clk_base + LPASS_Q6SS_AHB_LFABIF_CBCR);
-	mb();
+	ret = pil_q6v5_enable_clks(pil);
+	if (ret)
+		return ret;
 
 	/* Program Image Address */
 	writel_relaxed(((drv->start_addr >> 4) & 0x0FFFFFF0),
 				drv->reg_base + QDSP6SS_RST_EVB);
 
-	return pil_q6v5_reset(pil);
+	ret = pil_q6v5_reset(pil);
+	if (ret) {
+		pil_q6v5_disable_clks(pil);
+		return ret;
+	}
+
+	drv->is_booted = true;
+
+	return 0;
 }
 
 static struct pil_reset_ops pil_lpass_ops = {
@@ -124,7 +111,7 @@
 	desc->ops = &pil_lpass_ops;
 	desc->owner = THIS_MODULE;
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 	drv->axi_halt_base = devm_ioremap(&pdev->dev, res->start,
 					  resource_size(res));
 	if (!drv->axi_halt_base)
diff --git a/arch/arm/mach-msm/pil-q6v5.c b/arch/arm/mach-msm/pil-q6v5.c
index cd58a4c..3b9d542 100644
--- a/arch/arm/mach-msm/pil-q6v5.c
+++ b/arch/arm/mach-msm/pil-q6v5.c
@@ -20,6 +20,8 @@
 #include <linux/of.h>
 #include <linux/clk.h>
 
+#include <mach/clk.h>
+
 #include "peripheral-loader.h"
 #include "pil-q6v5.h"
 
@@ -76,6 +78,42 @@
 }
 EXPORT_SYMBOL(pil_q6v5_init_image);
 
+int pil_q6v5_enable_clks(struct pil_desc *pil)
+{
+	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+	int ret;
+
+	ret = clk_reset(drv->core_clk, CLK_RESET_DEASSERT);
+	if (ret)
+		goto err_reset;
+	ret = clk_prepare_enable(drv->core_clk);
+	if (ret)
+		goto err_core_clk;
+	ret = clk_prepare_enable(drv->bus_clk);
+	if (ret)
+		goto err_bus_clk;
+
+	return 0;
+
+err_bus_clk:
+	clk_disable_unprepare(drv->core_clk);
+err_core_clk:
+	clk_reset(drv->core_clk, CLK_RESET_ASSERT);
+err_reset:
+	return ret;
+}
+EXPORT_SYMBOL(pil_q6v5_enable_clks);
+
+void pil_q6v5_disable_clks(struct pil_desc *pil)
+{
+	struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+
+	clk_disable_unprepare(drv->bus_clk);
+	clk_disable_unprepare(drv->core_clk);
+	clk_reset(drv->core_clk, CLK_RESET_ASSERT);
+}
+EXPORT_SYMBOL(pil_q6v5_disable_clks);
+
 void pil_q6v5_shutdown(struct pil_desc *pil)
 {
 	u32 val;
@@ -173,12 +211,6 @@
 	if (!drv->reg_base)
 		return ERR_PTR(-ENOMEM);
 
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	drv->clk_base = devm_ioremap(&pdev->dev, res->start,
-				     resource_size(res));
-	if (!drv->clk_base)
-		return ERR_PTR(-ENOMEM);
-
 	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
 	if (!desc)
 		return ERR_PTR(-ENOMEM);
@@ -192,6 +224,14 @@
 	if (IS_ERR(drv->xo))
 		return ERR_CAST(drv->xo);
 
+	drv->bus_clk = devm_clk_get(&pdev->dev, "bus_clk");
+	if (IS_ERR(drv->bus_clk))
+		return ERR_CAST(drv->bus_clk);
+
+	drv->core_clk = devm_clk_get(&pdev->dev, "core_clk");
+	if (IS_ERR(drv->core_clk))
+		return ERR_CAST(drv->core_clk);
+
 	desc->dev = &pdev->dev;
 
 	return desc;
diff --git a/arch/arm/mach-msm/pil-q6v5.h b/arch/arm/mach-msm/pil-q6v5.h
index b17d4e7..5f283da 100644
--- a/arch/arm/mach-msm/pil-q6v5.h
+++ b/arch/arm/mach-msm/pil-q6v5.h
@@ -21,14 +21,15 @@
 
 struct q6v5_data {
 	void __iomem *reg_base;
-	void __iomem *clk_base;
+	struct clk *xo;
+	struct clk *bus_clk;
+	struct clk *core_clk;
 	void __iomem *axi_halt_base;
 	void __iomem *rmb_base;
 	unsigned long start_addr;
 	struct regulator *vreg;
-	bool vreg_enabled;
+	bool is_booted;
 	int self_auth;
-	struct clk *xo;
 	struct pil_device *pil;
 };
 
@@ -38,6 +39,8 @@
 			size_t size);
 void pil_q6v5_shutdown(struct pil_desc *pil);
 int pil_q6v5_reset(struct pil_desc *pil);
+int pil_q6v5_enable_clks(struct pil_desc *pil);
+void pil_q6v5_disable_clks(struct pil_desc *pil);
 struct pil_desc *pil_q6v5_init(struct platform_device *pdev);
 
 #endif