Merge "msm: adsp-loader: Add support for adsp state in adsp loader"
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 1e647a7..213da90 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -474,3 +474,22 @@
 			"MIC BIAS4 External", "Digital Mic6";
 			qcom,taiko-mclk-clk-freq = <12288000>;
 };
+
+* msm-adsp-loader
+
+Required properties:
+ - compatible : "msm-adsp-loader"
+ - qcom,adsp-state:
+	It is possible that some MSM use PIL to load the ADSP image. While
+	other MSM may use SBL to load the ADSP image at boot. Audio APR needs
+	state of ADSP to register and enable APR to be used for sending commands
+	to ADSP. so adsp-state represents the state of ADSP to ADSP loader. Value
+	of 0 indicates ADSP loader needs to use PIL and value of 2 means ADSP
+	image is already loaded by SBL.
+
+Example:
+
+qcom,msm-adsp-loader {
+	compatible = "qcom,adsp-loader";
+	qcom,adsp-state = <2>;
+};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 4618ca2..1bad657 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -809,6 +809,7 @@
 
 	qcom,msm-adsp-loader {
 		compatible = "qcom,adsp-loader";
+		qcom,adsp-state = <0>;
 	};
 
 	qcom,msm-pcm {
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index 6e4d9e6..09c388f 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -393,6 +393,7 @@
 
 	qcom,msm-adsp-loader {
 		compatible = "qcom,adsp-loader";
+		qcom,adsp-state = <2>;
 	};
 
 	qcom,msm-pcm {
diff --git a/arch/arm/mach-msm/qdsp6v2/adsp-loader.c b/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
index c28e403..02dbece 100644
--- a/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
+++ b/arch/arm/mach-msm/qdsp6v2/adsp-loader.c
@@ -19,6 +19,7 @@
 #include <linux/platform_device.h>
 #include <mach/subsystem_restart.h>
 #include <mach/qdsp6v2/apr.h>
+#include <linux/of_device.h>
 
 #define Q6_PIL_GET_DELAY_MS 100
 
@@ -30,25 +31,41 @@
 {
 	struct adsp_loader_private *priv;
 	int rc = 0;
+	const char *adsp_dt = "qcom,adsp-state";
+	u32 adsp_state;
 
-	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
-	platform_set_drvdata(pdev, priv);
-
-	priv->pil_h = subsystem_get("adsp");
-	if (IS_ERR(priv->pil_h)) {
-		pr_err("%s: pil get adsp failed, error:%d\n", __func__, rc);
-		devm_kfree(&pdev->dev, priv);
-		goto fail;
+	rc = of_property_read_u32(pdev->dev.of_node, adsp_dt, &adsp_state);
+	if (rc) {
+		dev_err(&pdev->dev,
+			"%s: ADSP state = %x\n", __func__, adsp_state);
+		return rc;
 	}
 
-	/* Query the DSP to check if resources are available */
-	msleep(Q6_PIL_GET_DELAY_MS);
+	if (adsp_state == APR_SUBSYS_DOWN) {
+		priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+		if (!priv)
+			return -ENOMEM;
 
-	/* Set the state of the ADSP in APR driver */
-	apr_set_q6_state(APR_SUBSYS_LOADED);
+		platform_set_drvdata(pdev, priv);
+
+		priv->pil_h = subsystem_get("adsp");
+		if (IS_ERR(priv->pil_h)) {
+			pr_err("%s: pil get adsp failed, error:%d\n",
+				__func__, rc);
+			devm_kfree(&pdev->dev, priv);
+			goto fail;
+		}
+
+		/* Query the DSP to check if resources are available */
+		msleep(Q6_PIL_GET_DELAY_MS);
+
+		/* Set the state of the ADSP in APR driver */
+		apr_set_q6_state(APR_SUBSYS_LOADED);
+	} else if (adsp_state == APR_SUBSYS_LOADED) {
+		dev_dbg(&pdev->dev,
+			"%s:MDM9x25 ADSP state = %x\n", __func__, adsp_state);
+		apr_set_q6_state(APR_SUBSYS_LOADED);
+	}
 
 	/* Query for MMPM API */
 
@@ -62,7 +79,8 @@
 	struct adsp_loader_private *priv;
 
 	priv = platform_get_drvdata(pdev);
-	subsystem_put(priv->pil_h);
+	if (priv != NULL)
+		subsystem_put(priv->pil_h);
 	pr_info("%s: Q6/ADSP image is unloaded\n", __func__);
 
 	return 0;