msm: pil-q6v5-lpass: Combine SSR and PIL drivers

Combine both drivers into one so that we can merge the PIL and
SSR frameworks.

Change-Id: I81621ca07794f81ec9e7f5567b27b6aa02a6c138
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
index d39c98c..ac9600d 100644
--- a/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-lpass.txt
@@ -11,6 +11,7 @@
 		      memory mapped registers.
 - reg-names:	      Names of the bases for the above registers. "qdsp6_base"
 		      and "halt_base" are expected.
+- interrupts:         The lpass watchdog interrupt
 - qcom,firmware-name: Base name of the firmware image. Ex. "lpass"
 
 Example:
@@ -19,6 +20,7 @@
 	        reg = <0xfe200000 0x00100>,
 	              <0xfd485100 0x00010>;
 		reg-names = "qdsp6_base", "halt_base";
+		interrupts = <0 194 1>;
 
 	        qcom,firmware-name = "lpass";
 	};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 172d094..e147b6e 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -659,6 +659,7 @@
 		reg = <0xfe200000 0x00100>,
 		      <0xfd485100 0x00010>;
 		reg-names = "qdsp6_base", "halt_base";
+		interrupts = <0 194 1>;
 
 		qcom,firmware-name = "adsp";
 	};
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 08127d2..904dcba 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -1958,11 +1958,13 @@
 	  If unsure, say N.
 
 config MSM_PIL_LPASS_QDSP6V5
-       tristate "LPASS QDSP6v5 (Hexagon) Boot Support"
-       depends on MSM_PIL
-       help
-         Support for booting and shutting down QDSP6v5 (Hexagon) processors
-	 in low power audio subsystems.
+	tristate "LPASS QDSP6v5 (Hexagon) Boot Support"
+	depends on MSM_PIL && MSM_SUBSYSTEM_RESTART
+	help
+	  Support for booting and shutting down QDSP6v5 (Hexagon) processors
+	  in low power audio subsystems. This driver also monitors the ADSP
+	  SMSM status bits and the ADSP's watchdog interrupt and restarts the
+	  ADSP if the processor encounters a fatal error.
 
 config MSM_PIL_MSS_QDSP6V5
        tristate "MSS QDSP6v5 (Hexagon) Boot Support"
@@ -2037,15 +2039,6 @@
 	bool "Secure Channel Manager (SCM) support"
 	default n
 
-config MSM_ADSP_SSR_8974
-	bool "MSM 8974 adsp restart driver"
-	depends on (ARCH_MSM8974)
-	help
-	 This option enables the adsp restart driver for the MSM8974.
-	 It monitors the adsp SMSM status bits and the adsp watchdog line and
-	 restarts the adsp or the 8974 when the adsp encounters a fatal error,
-	 depending on the restart level selected in the subsystem restart driver.
-
 config MSM_WCNSS_SSR_8974
 	tristate "MSM 8974 WCNSS restart module"
 	depends on (ARCH_MSM8974)
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 29d74ef..d5de523 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -200,7 +200,6 @@
 	obj-y += ramdump.o
 endif
 obj-$(CONFIG_MSM_SYSMON_COMM) += sysmon.o
-obj-$(CONFIG_MSM_ADSP_SSR_8974) += adsp-8974.o
 obj-$(CONFIG_MSM_WCNSS_SSR_8974) += wcnss-ssr-8974.o
 
 ifdef CONFIG_CPU_IDLE
diff --git a/arch/arm/mach-msm/adsp-8974.c b/arch/arm/mach-msm/adsp-8974.c
deleted file mode 100644
index fa7d9d4..0000000
--- a/arch/arm/mach-msm/adsp-8974.c
+++ /dev/null
@@ -1,301 +0,0 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/workqueue.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/err.h>
-
-#include <mach/irqs.h>
-#include <mach/scm.h>
-#include <mach/peripheral-loader.h>
-#include <mach/subsystem_restart.h>
-#include <mach/subsystem_notif.h>
-
-#include "smd_private.h"
-#include "ramdump.h"
-#include "sysmon.h"
-
-#define SCM_Q6_NMI_CMD			0x1
-#define MODULE_NAME			"adsp_8974"
-#define MAX_BUF_SIZE			0x51
-
-/* Interrupt line for WDOG bite*/
-#define ADSP_Q6SS_WDOG_EXPIRED		194
-
-/* Subsystem restart: QDSP6 data, functions */
-static void adsp_fatal_fn(struct work_struct *);
-static DECLARE_WORK(adsp_fatal_work, adsp_fatal_fn);
-
-struct adsp_ssr {
-	void *adsp_ramdump_dev;
-} adsp_ssr;
-
-static struct adsp_ssr adsp_ssr_8974;
-static int q6_crash_shutdown;
-
-static int riva_notifier_cb(struct notifier_block *this, unsigned long code,
-								void *ss_handle)
-{
-	int ret;
-	switch (code) {
-	case SUBSYS_BEFORE_SHUTDOWN:
-		pr_debug("%s: R-Notify: Shutdown started\n", __func__);
-		ret = sysmon_send_event(SYSMON_SS_LPASS, "wcnss",
-				SUBSYS_BEFORE_SHUTDOWN);
-		if (ret < 0)
-			pr_err("%s: sysmon_send_event error %d", __func__,
-				ret);
-		break;
-	}
-	return NOTIFY_DONE;
-}
-
-static void *ssr_notif_hdle;
-static struct notifier_block rnb = {
-	.notifier_call = riva_notifier_cb,
-};
-
-static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
-								void *ss_handle)
-{
-	int ret;
-	switch (code) {
-	case SUBSYS_BEFORE_SHUTDOWN:
-		pr_debug("%s: M-Notify: Shutdown started\n", __func__);
-		ret = sysmon_send_event(SYSMON_SS_LPASS, "modem",
-				SUBSYS_BEFORE_SHUTDOWN);
-		if (ret < 0)
-			pr_err("%s: sysmon_send_event error %d", __func__,
-				ret);
-		break;
-	}
-	return NOTIFY_DONE;
-}
-
-static void *ssr_modem_notif_hdle;
-static struct notifier_block mnb = {
-	.notifier_call = modem_notifier_cb,
-};
-
-static void adsp_log_failure_reason(void)
-{
-	char *reason;
-	char buffer[MAX_BUF_SIZE];
-	unsigned size;
-
-	reason = smem_get_entry(SMEM_SSR_REASON_LPASS0, &size);
-
-	if (!reason) {
-		pr_err("%s: subsystem failure reason: (unknown, smem_get_entry failed).",
-			 MODULE_NAME);
-		return;
-	}
-
-	if (reason[0] == '\0') {
-		pr_err("%s: subsystem failure reason: (unknown, init value found)",
-			 MODULE_NAME);
-		return;
-	}
-
-	size = size < MAX_BUF_SIZE ? size : (MAX_BUF_SIZE-1);
-	memcpy(buffer, reason, size);
-	buffer[size] = '\0';
-	pr_err("%s: subsystem failure reason: %s", MODULE_NAME, buffer);
-	memset((void *)reason, 0x0, size);
-	wmb();
-}
-
-static void restart_adsp(void)
-{
-	adsp_log_failure_reason();
-	subsystem_restart("adsp");
-}
-
-static void adsp_fatal_fn(struct work_struct *work)
-{
-	pr_err("%s %s: Watchdog bite received from Q6!\n", MODULE_NAME,
-		__func__);
-	restart_adsp();
-}
-
-static void adsp_smsm_state_cb(void *data, uint32_t old_state,
-				uint32_t new_state)
-{
-	/* Ignore if we're the one that set SMSM_RESET */
-	if (q6_crash_shutdown)
-		return;
-
-	if (new_state & SMSM_RESET) {
-		pr_debug("%s: ADSP SMSM state changed to SMSM_RESET, new_state= 0x%x, old_state = 0x%x\n",
-			 __func__, new_state, old_state);
-		restart_adsp();
-	}
-}
-
-static void send_q6_nmi(void)
-{
-	/* Send NMI to QDSP6 via an SCM call. */
-	scm_call_atomic1(SCM_SVC_UTIL, SCM_Q6_NMI_CMD, 0x1);
-	pr_debug("%s: Q6 NMI was sent.\n", __func__);
-}
-
-static int adsp_shutdown(const struct subsys_desc *subsys)
-{
-	send_q6_nmi();
-
-	/* The write needs to go through before the q6 is shutdown. */
-	mb();
-
-	pil_force_shutdown("adsp");
-	disable_irq_nosync(ADSP_Q6SS_WDOG_EXPIRED);
-
-	return 0;
-}
-
-static int adsp_powerup(const struct subsys_desc *subsys)
-{
-	int ret;
-
-	if (get_restart_level() == RESET_SUBSYS_INDEPENDENT) {
-		pr_debug("%s: Wait for ADSP power up!", __func__);
-		msleep(10000);
-	}
-
-	ret = pil_force_boot("adsp");
-	enable_irq(ADSP_Q6SS_WDOG_EXPIRED);
-	return ret;
-}
-/* RAM segments - address and size for 8974 */
-static struct ramdump_segment q6_segment = {0xdc00000, 0x1800000};
-
-static int adsp_ramdump(int enable, const struct subsys_desc *subsys)
-{
-	pr_debug("%s: enable[%d]\n", __func__, enable);
-	if (enable)
-		return do_ramdump(adsp_ssr_8974.adsp_ramdump_dev,
-				&q6_segment, 1);
-	else
-		return 0;
-}
-
-static void adsp_crash_shutdown(const struct subsys_desc *subsys)
-{
-	q6_crash_shutdown = 1;
-	send_q6_nmi();
-}
-
-static irqreturn_t adsp_wdog_bite_irq(int irq, void *dev_id)
-{
-	int ret;
-
-	pr_debug("%s: rxed irq[0x%x]", __func__, irq);
-	disable_irq_nosync(ADSP_Q6SS_WDOG_EXPIRED);
-	ret = schedule_work(&adsp_fatal_work);
-
-	return IRQ_HANDLED;
-}
-
-static struct subsys_device *adsp_8974_dev;
-
-static struct subsys_desc adsp_8974 = {
-	.name = "adsp",
-	.shutdown = adsp_shutdown,
-	.powerup = adsp_powerup,
-	.ramdump = adsp_ramdump,
-	.crash_shutdown = adsp_crash_shutdown
-};
-
-static int __init adsp_restart_init(void)
-{
-	adsp_8974_dev = subsys_register(&adsp_8974);
-	if (IS_ERR(adsp_8974_dev))
-		return PTR_ERR(adsp_8974_dev);
-	return 0;
-}
-
-static int __init adsp_fatal_init(void)
-{
-	int ret;
-
-	ret = smsm_state_cb_register(SMSM_Q6_STATE, SMSM_RESET,
-		adsp_smsm_state_cb, 0);
-
-	if (ret < 0)
-		pr_err("%s: Unable to register SMSM callback! (%d)\n",
-				__func__, ret);
-
-	ret = request_irq(ADSP_Q6SS_WDOG_EXPIRED, adsp_wdog_bite_irq,
-			IRQF_TRIGGER_RISING, "q6_wdog", NULL);
-
-	if (ret < 0) {
-		pr_err("%s: Unable to request ADSP_Q6SS_WDOG_EXPIRED irq.",
-			__func__);
-		goto out;
-	}
-	ret = adsp_restart_init();
-	if (ret < 0) {
-		pr_err("%s: Unable to reg with adsp ssr. (%d)\n",
-				__func__, ret);
-		goto out;
-	}
-
-	adsp_ssr_8974.adsp_ramdump_dev = create_ramdump_device("adsp");
-
-	if (!adsp_ssr_8974.adsp_ramdump_dev) {
-		pr_err("%s: Unable to create ramdump device.\n",
-				__func__);
-		ret = -ENOMEM;
-		goto out;
-	}
-	ssr_notif_hdle = subsys_notif_register_notifier("riva",
-							&rnb);
-	if (IS_ERR(ssr_notif_hdle) < 0) {
-		ret = PTR_ERR(ssr_notif_hdle);
-		pr_err("%s: subsys_register_notifier for Riva: err = %d\n",
-			__func__, ret);
-		free_irq(ADSP_Q6SS_WDOG_EXPIRED, NULL);
-		goto out;
-	}
-
-	ssr_modem_notif_hdle = subsys_notif_register_notifier("modem",
-							&mnb);
-	if (IS_ERR(ssr_modem_notif_hdle) < 0) {
-		ret = PTR_ERR(ssr_modem_notif_hdle);
-		pr_err("%s: subsys_register_notifier for Modem: err = %d\n",
-			__func__, ret);
-		subsys_notif_unregister_notifier(ssr_notif_hdle, &rnb);
-		free_irq(ADSP_Q6SS_WDOG_EXPIRED, NULL);
-		goto out;
-	}
-
-	pr_info("%s: adsp ssr driver init'ed.\n", __func__);
-out:
-	return ret;
-}
-
-static void __exit adsp_fatal_exit(void)
-{
-	subsys_notif_unregister_notifier(ssr_notif_hdle, &rnb);
-	subsys_notif_unregister_notifier(ssr_modem_notif_hdle, &mnb);
-	subsys_unregister(adsp_8974_dev);
-	free_irq(ADSP_Q6SS_WDOG_EXPIRED, NULL);
-}
-
-module_init(adsp_fatal_init);
-module_exit(adsp_fatal_exit);
-
-MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-q6v5-lpass.c b/arch/arm/mach-msm/pil-q6v5-lpass.c
index ad17c9b..c48ea02 100644
--- a/arch/arm/mach-msm/pil-q6v5-lpass.c
+++ b/arch/arm/mach-msm/pil-q6v5-lpass.c
@@ -18,14 +18,39 @@
 #include <linux/err.h>
 #include <linux/of.h>
 #include <linux/clk.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
 #include <mach/clk.h>
+#include <mach/subsystem_restart.h>
+#include <mach/subsystem_notif.h>
+#include <mach/scm.h>
+#include <mach/peripheral-loader.h>
+
 #include "peripheral-loader.h"
 #include "pil-q6v5.h"
 #include "scm-pas.h"
+#include "ramdump.h"
+#include "sysmon.h"
 
 #define QDSP6SS_RST_EVB			0x010
 #define PROXY_TIMEOUT_MS		10000
 
+struct lpass_data {
+	struct q6v5_data *q6;
+	struct subsys_device *subsys;
+	struct subsys_desc subsys_desc;
+	void *ramdump_dev;
+	int wdog_irq;
+	struct work_struct work;
+	void *riva_notif_hdle;
+	void *modem_notif_hdle;
+	int crash_shutdown;
+};
+
+#define subsys_to_drv(d) container_of(d, struct lpass_data, subsys_desc)
+
 static int pil_lpass_enable_clks(struct q6v5_data *drv)
 {
 	int ret;
@@ -147,36 +172,211 @@
 	.shutdown = pil_lpass_shutdown_trusted,
 };
 
+static int riva_notifier_cb(struct notifier_block *this, unsigned long code,
+								void *ss_handle)
+{
+	int ret;
+	switch (code) {
+	case SUBSYS_BEFORE_SHUTDOWN:
+		pr_debug("%s: R-Notify: Shutdown started\n", __func__);
+		ret = sysmon_send_event(SYSMON_SS_LPASS, "wcnss",
+				SUBSYS_BEFORE_SHUTDOWN);
+		if (ret < 0)
+			pr_err("%s: sysmon_send_event error %d", __func__, ret);
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block rnb = {
+	.notifier_call = riva_notifier_cb,
+};
+
+static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
+								void *ss_handle)
+{
+	int ret;
+	switch (code) {
+	case SUBSYS_BEFORE_SHUTDOWN:
+		pr_debug("%s: M-Notify: Shutdown started\n", __func__);
+		ret = sysmon_send_event(SYSMON_SS_LPASS, "modem",
+				SUBSYS_BEFORE_SHUTDOWN);
+		if (ret < 0)
+			pr_err("%s: sysmon_send_event error %d", __func__, ret);
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block mnb = {
+	.notifier_call = modem_notifier_cb,
+};
+
+static void adsp_log_failure_reason(void)
+{
+	char *reason;
+	char buffer[81];
+	unsigned size;
+
+	reason = smem_get_entry(SMEM_SSR_REASON_LPASS0, &size);
+
+	if (!reason) {
+		pr_err("ADSP subsystem failure reason: (unknown, smem_get_entry failed).");
+		return;
+	}
+
+	if (reason[0] == '\0') {
+		pr_err("ADSP subsystem failure reason: (unknown, init value found)");
+		return;
+	}
+
+	size = min(size, sizeof(buffer) - 1);
+	memcpy(buffer, reason, size);
+	buffer[size] = '\0';
+	pr_err("ADSP subsystem failure reason: %s", buffer);
+	memset((void *)reason, 0x0, size);
+	wmb();
+}
+
+static void restart_adsp(struct lpass_data *drv)
+{
+	adsp_log_failure_reason();
+	subsystem_restart_dev(drv->subsys);
+}
+
+static void adsp_fatal_fn(struct work_struct *work)
+{
+	struct lpass_data *drv = container_of(work, struct lpass_data, work);
+
+	pr_err("Watchdog bite received from ADSP!\n");
+	restart_adsp(drv);
+}
+
+static void adsp_smsm_state_cb(void *data, uint32_t old_state,
+				uint32_t new_state)
+{
+	struct lpass_data *drv = data;
+
+	/* Ignore if we're the one that set SMSM_RESET */
+	if (drv->crash_shutdown)
+		return;
+
+	if (new_state & SMSM_RESET) {
+		pr_err("%s: ADSP SMSM state changed to SMSM_RESET, new_state = %#x, old_state = %#x\n",
+				__func__, new_state, old_state);
+		restart_adsp(drv);
+	}
+}
+
+#define SCM_Q6_NMI_CMD 0x1
+
+static void send_q6_nmi(void)
+{
+	/* Send NMI to QDSP6 via an SCM call. */
+	scm_call_atomic1(SCM_SVC_UTIL, SCM_Q6_NMI_CMD, 0x1);
+	pr_debug("%s: Q6 NMI was sent.\n", __func__);
+}
+
+#define subsys_to_lpass(d) container_of(d, struct lpass_data, subsys_desc)
+
+static int adsp_shutdown(const struct subsys_desc *subsys)
+{
+	struct lpass_data *drv = subsys_to_lpass(subsys);
+
+	send_q6_nmi();
+	/* The write needs to go through before the q6 is shutdown. */
+	mb();
+	pil_force_shutdown("adsp");
+	disable_irq_nosync(drv->wdog_irq);
+
+	return 0;
+}
+
+static int adsp_powerup(const struct subsys_desc *subsys)
+{
+	struct lpass_data *drv = subsys_to_lpass(subsys);
+	int ret = 0;
+
+	if (get_restart_level() == RESET_SUBSYS_INDEPENDENT) {
+		pr_debug("%s: Wait for ADSP power up!", __func__);
+		msleep(10000);
+	}
+
+	ret = pil_force_boot("adsp");
+	enable_irq(drv->wdog_irq);
+
+	return ret;
+}
+
+static struct ramdump_segment segments = { 0xdc00000, 0x1800000 };
+
+static int adsp_ramdump(int enable, const struct subsys_desc *subsys)
+{
+	struct lpass_data *drv = subsys_to_lpass(subsys);
+
+	if (!enable)
+		return 0;
+	return do_ramdump(drv->ramdump_dev, &segments, 1);
+}
+
+static void adsp_crash_shutdown(const struct subsys_desc *subsys)
+{
+	struct lpass_data *drv = subsys_to_lpass(subsys);
+
+	drv->crash_shutdown = 1;
+	send_q6_nmi();
+}
+
+static irqreturn_t adsp_wdog_bite_irq(int irq, void *dev_id)
+{
+	struct lpass_data *drv = dev_id;
+
+	disable_irq_nosync(drv->wdog_irq);
+	schedule_work(&drv->work);
+
+	return IRQ_HANDLED;
+}
+
 static int __devinit pil_lpass_driver_probe(struct platform_device *pdev)
 {
-	struct q6v5_data *drv;
+	struct lpass_data *drv;
+	struct q6v5_data *q6;
 	struct pil_desc *desc;
+	int ret;
 
-	drv = pil_q6v5_init(pdev);
-	if (IS_ERR(drv))
-		return PTR_ERR(drv);
+	drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+	if (!drv)
+		return -ENOMEM;
 	platform_set_drvdata(pdev, drv);
 
-	desc = &drv->desc;
-	desc->ops = &pil_lpass_ops;
+	drv->wdog_irq = platform_get_irq(pdev, 0);
+	if (drv->wdog_irq < 0)
+		return drv->wdog_irq;
+
+	q6 = pil_q6v5_init(pdev);
+	if (IS_ERR(q6))
+		return PTR_ERR(q6);
+	drv->q6 = q6;
+
+	desc = &q6->desc;
 	desc->owner = THIS_MODULE;
 	desc->proxy_timeout = PROXY_TIMEOUT_MS;
 
-	drv->core_clk = devm_clk_get(&pdev->dev, "core_clk");
-	if (IS_ERR(drv->core_clk))
-		return PTR_ERR(drv->core_clk);
+	q6->core_clk = devm_clk_get(&pdev->dev, "core_clk");
+	if (IS_ERR(q6->core_clk))
+		return PTR_ERR(q6->core_clk);
 
-	drv->ahb_clk = devm_clk_get(&pdev->dev, "iface_clk");
-	if (IS_ERR(drv->ahb_clk))
-		return PTR_ERR(drv->ahb_clk);
+	q6->ahb_clk = devm_clk_get(&pdev->dev, "iface_clk");
+	if (IS_ERR(q6->ahb_clk))
+		return PTR_ERR(q6->ahb_clk);
 
-	drv->axi_clk = devm_clk_get(&pdev->dev, "bus_clk");
-	if (IS_ERR(drv->axi_clk))
-		return PTR_ERR(drv->axi_clk);
+	q6->axi_clk = devm_clk_get(&pdev->dev, "bus_clk");
+	if (IS_ERR(q6->axi_clk))
+		return PTR_ERR(q6->axi_clk);
 
-	drv->reg_clk = devm_clk_get(&pdev->dev, "reg_clk");
-	if (IS_ERR(drv->reg_clk))
-		return PTR_ERR(drv->reg_clk);
+	q6->reg_clk = devm_clk_get(&pdev->dev, "reg_clk");
+	if (IS_ERR(q6->reg_clk))
+		return PTR_ERR(q6->reg_clk);
 
 	if (pas_supported(PAS_Q6) > 0) {
 		desc->ops = &pil_lpass_ops_trusted;
@@ -186,17 +386,79 @@
 		dev_info(&pdev->dev, "using non-secure boot\n");
 	}
 
-	drv->pil = msm_pil_register(desc);
-	if (IS_ERR(drv->pil))
-		return PTR_ERR(drv->pil);
+	drv->q6->pil = msm_pil_register(desc);
+	if (IS_ERR(drv->q6->pil))
+		return PTR_ERR(drv->q6->pil);
 
+	drv->subsys_desc.name = desc->name;
+	drv->subsys_desc.owner = THIS_MODULE;
+	drv->subsys_desc.dev = &pdev->dev;
+	drv->subsys_desc.shutdown = adsp_shutdown;
+	drv->subsys_desc.powerup = adsp_powerup;
+	drv->subsys_desc.ramdump = adsp_ramdump;
+	drv->subsys_desc.crash_shutdown = adsp_crash_shutdown;
+
+	INIT_WORK(&drv->work, adsp_fatal_fn);
+
+	drv->ramdump_dev = create_ramdump_device("adsp");
+	if (!drv->ramdump_dev) {
+		ret = -ENOMEM;
+		goto err_ramdump;
+	}
+
+	drv->subsys = subsys_register(&drv->subsys_desc);
+	if (IS_ERR(drv->subsys)) {
+		ret = PTR_ERR(drv->subsys);
+		goto err_subsys;
+	}
+
+	ret = devm_request_irq(&pdev->dev, drv->wdog_irq, adsp_wdog_bite_irq,
+			IRQF_TRIGGER_RISING, dev_name(&pdev->dev), drv);
+	if (ret)
+		goto err_irq;
+
+	ret = smsm_state_cb_register(SMSM_Q6_STATE, SMSM_RESET,
+			adsp_smsm_state_cb, drv);
+	if (ret < 0)
+		goto err_smsm;
+
+	drv->riva_notif_hdle = subsys_notif_register_notifier("riva", &rnb);
+	if (IS_ERR(drv->riva_notif_hdle)) {
+		ret = PTR_ERR(drv->riva_notif_hdle);
+		goto err_notif_riva;
+	}
+
+	drv->modem_notif_hdle = subsys_notif_register_notifier("modem", &mnb);
+	if (IS_ERR(drv->modem_notif_hdle)) {
+		ret = PTR_ERR(drv->modem_notif_hdle);
+		goto err_notif_modem;
+	}
+	return 0;
+err_notif_modem:
+	subsys_notif_unregister_notifier(drv->riva_notif_hdle, &rnb);
+err_notif_riva:
+	smsm_state_cb_deregister(SMSM_Q6_STATE, SMSM_RESET,
+			adsp_smsm_state_cb, drv);
+err_smsm:
+err_irq:
+	subsys_unregister(drv->subsys);
+err_subsys:
+	destroy_ramdump_device(drv->ramdump_dev);
+err_ramdump:
+	msm_pil_unregister(drv->q6->pil);
 	return 0;
 }
 
 static int __devexit pil_lpass_driver_exit(struct platform_device *pdev)
 {
-	struct q6v5_data *drv = platform_get_drvdata(pdev);
-	msm_pil_unregister(drv->pil);
+	struct lpass_data *drv = platform_get_drvdata(pdev);
+	subsys_notif_unregister_notifier(drv->riva_notif_hdle, &rnb);
+	subsys_notif_unregister_notifier(drv->modem_notif_hdle, &mnb);
+	smsm_state_cb_deregister(SMSM_Q6_STATE, SMSM_RESET,
+			adsp_smsm_state_cb, drv);
+	subsys_unregister(drv->subsys);
+	destroy_ramdump_device(drv->ramdump_dev);
+	msm_pil_unregister(drv->q6->pil);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/pil-q6v5.c b/arch/arm/mach-msm/pil-q6v5.c
index 43d7a2c..70a12de 100644
--- a/arch/arm/mach-msm/pil-q6v5.c
+++ b/arch/arm/mach-msm/pil-q6v5.c
@@ -217,10 +217,7 @@
 	if (!drv->axi_halt_base)
 		return ERR_PTR(-ENOMEM);
 
-	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
-	if (!desc)
-		return ERR_PTR(-ENOMEM);
-
+	desc = &drv->desc;
 	ret = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
 				      &desc->name);
 	if (ret)