msm: SSR: Make a registration/unregistration API

Add a struct subsys_device for the internal stuff we don't want
to expose. Propagate that struct throughout the code. Add a new
restart API, subsystem_restart_dev() that takes the subsys_device
pointer to restart the processor. This saves having to iterate
through the list of devices to find the subsystem (saving a
spinlock for callers in atomic context). Since we still have some
callers of the old string based API, leave subsystem_restart() in
place.

While we're here, remove code that isn't doing anything. We always
know to use the current subsystem if we only have one so the
single_restart_list is useless. Plus, if someone is passing a
NULL descriptor or not initializing the fields of the descriptor
when they register with SSR, they will soon realize that their
code doesn't work. Remove these checks as they'll impede future
patches that don't want to supply all possible ops.

Change-Id: Ia53ffd530982390d1871bd62bfe31e3a0a512fbe
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
diff --git a/arch/arm/mach-msm/gss-8064.c b/arch/arm/mach-msm/gss-8064.c
index b9b877a..e528650 100644
--- a/arch/arm/mach-msm/gss-8064.c
+++ b/arch/arm/mach-msm/gss-8064.c
@@ -43,6 +43,8 @@
 
 static int crash_shutdown;
 
+static struct subsys_device *gss_8064_dev;
+
 #define MAX_SSR_REASON_LEN 81U
 
 static void log_gss_sfr(void)
@@ -72,7 +74,7 @@
 static void restart_gss(void)
 {
 	log_gss_sfr();
-	subsystem_restart("gss");
+	subsystem_restart_dev(gss_8064_dev);
 }
 
 static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
@@ -91,7 +93,7 @@
 
 #define Q6_FW_WDOG_ENABLE		0x08882024
 #define Q6_SW_WDOG_ENABLE		0x08982024
-static int gss_shutdown(const struct subsys_data *subsys)
+static int gss_shutdown(const struct subsys_desc *desc)
 {
 	pil_force_shutdown("gss");
 	disable_irq_nosync(GSS_A5_WDOG_EXPIRED);
@@ -99,14 +101,14 @@
 	return 0;
 }
 
-static int gss_powerup(const struct subsys_data *subsys)
+static int gss_powerup(const struct subsys_desc *desc)
 {
 	pil_force_boot("gss");
 	enable_irq(GSS_A5_WDOG_EXPIRED);
 	return 0;
 }
 
-void gss_crash_shutdown(const struct subsys_data *subsys)
+void gss_crash_shutdown(const struct subsys_desc *desc)
 {
 	crash_shutdown = 1;
 	smsm_reset_modem(SMSM_RESET);
@@ -122,7 +124,7 @@
 };
 
 static int gss_ramdump(int enable,
-				const struct subsys_data *crashed_subsys)
+				const struct subsys_desc *crashed_subsys)
 {
 	int ret = 0;
 
@@ -157,7 +159,7 @@
 	return IRQ_HANDLED;
 }
 
-static struct subsys_data gss_8064 = {
+static struct subsys_desc gss_8064 = {
 	.name = "gss",
 	.shutdown = gss_shutdown,
 	.powerup = gss_powerup,
@@ -167,7 +169,10 @@
 
 static int gss_subsystem_restart_init(void)
 {
-	return ssr_register_subsystem(&gss_8064);
+	gss_8064_dev = subsys_register(&gss_8064);
+	if (IS_ERR(gss_8064_dev))
+		return PTR_ERR(gss_8064_dev);
+	return 0;
 }
 
 static int gss_open(struct inode *inode, struct file *filep)
diff --git a/arch/arm/mach-msm/include/mach/subsystem_restart.h b/arch/arm/mach-msm/include/mach/subsystem_restart.h
index 51ace96..6d15f47 100644
--- a/arch/arm/mach-msm/include/mach/subsystem_restart.h
+++ b/arch/arm/mach-msm/include/mach/subsystem_restart.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* 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
@@ -18,6 +18,8 @@
 
 #define SUBSYS_NAME_MAX_LENGTH 40
 
+struct subsys_device;
+
 enum {
 	RESET_SOC = 1,
 	RESET_SUBSYS_COUPLED,
@@ -25,29 +27,23 @@
 	RESET_LEVEL_MAX
 };
 
-struct subsys_data {
+struct subsys_desc {
 	const char *name;
-	int (*shutdown) (const struct subsys_data *);
-	int (*powerup) (const struct subsys_data *);
-	void (*crash_shutdown) (const struct subsys_data *);
-	int (*ramdump) (int, const struct subsys_data *);
 
-	/* Internal use only */
-	struct list_head list;
-	void *notif_handle;
-
-	struct mutex shutdown_lock;
-	struct mutex powerup_lock;
-
-	void *restart_order;
-	struct subsys_data *single_restart_list[1];
+	int (*shutdown)(const struct subsys_desc *desc);
+	int (*powerup)(const struct subsys_desc *desc);
+	void (*crash_shutdown)(const struct subsys_desc *desc);
+	int (*ramdump)(int, const struct subsys_desc *desc);
 };
 
 #if defined(CONFIG_MSM_SUBSYSTEM_RESTART)
 
-int get_restart_level(void);
-int subsystem_restart(const char *subsys_name);
-int ssr_register_subsystem(struct subsys_data *subsys);
+extern int get_restart_level(void);
+extern int subsystem_restart_dev(struct subsys_device *dev);
+extern int subsystem_restart(const char *name);
+
+extern struct subsys_device *subsys_register(struct subsys_desc *desc);
+extern void subsys_unregister(struct subsys_device *dev);
 
 #else
 
@@ -56,16 +52,24 @@
 	return 0;
 }
 
-static inline int subsystem_restart(const char *subsystem_name)
+static inline int subsystem_restart_dev(struct subsys_device *dev)
 {
 	return 0;
 }
 
-static inline int ssr_register_subsystem(struct subsys_data *subsys)
+static inline int subsystem_restart(const char *name)
 {
 	return 0;
 }
 
+static inline
+struct subsys_device *subsys_register(struct subsys_desc *desc)
+{
+	return NULL;
+}
+
+static inline void subsys_unregister(struct subsys_device *dev) { }
+
 #endif /* CONFIG_MSM_SUBSYSTEM_RESTART */
 
 #endif
diff --git a/arch/arm/mach-msm/lpass-8660.c b/arch/arm/mach-msm/lpass-8660.c
index 1018360..be18b68 100644
--- a/arch/arm/mach-msm/lpass-8660.c
+++ b/arch/arm/mach-msm/lpass-8660.c
@@ -19,6 +19,7 @@
 #include <linux/stringify.h>
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/err.h>
 
 #include <mach/irqs.h>
 #include <mach/scm.h>
@@ -35,6 +36,8 @@
 #define MODULE_NAME			"lpass_8x60"
 #define SCM_Q6_NMI_CMD			0x1
 
+static struct subsys_device *subsys_8x60_q6_dev;
+
 /* Subsystem restart: QDSP6 data, functions */
 static void *q6_ramdump_dev;
 static void q6_fatal_fn(struct work_struct *);
@@ -44,7 +47,7 @@
 static void q6_fatal_fn(struct work_struct *work)
 {
 	pr_err("%s: Watchdog bite received from Q6!\n", MODULE_NAME);
-	subsystem_restart("lpass");
+	subsystem_restart_dev(subsys_8x60_q6_dev);
 	enable_irq(LPASS_Q6SS_WDOG_EXPIRED);
 }
 
@@ -65,7 +68,7 @@
 	pr_info("subsystem-fatal-8x60: Q6 NMI was sent.\n");
 }
 
-int subsys_q6_shutdown(const struct subsys_data *crashed_subsys)
+int subsys_q6_shutdown(const struct subsys_desc *crashed_subsys)
 {
 	void __iomem *q6_wdog_addr =
 		ioremap_nocache(Q6SS_WDOG_ENABLE, 8);
@@ -82,7 +85,7 @@
 	return 0;
 }
 
-int subsys_q6_powerup(const struct subsys_data *crashed_subsys)
+int subsys_q6_powerup(const struct subsys_desc *crashed_subsys)
 {
 	int ret = pil_force_boot("q6");
 	enable_irq(LPASS_Q6SS_WDOG_EXPIRED);
@@ -93,7 +96,7 @@
 static struct ramdump_segment q6_segments[] = { {0x46700000, 0x47F00000 -
 					0x46700000}, {0x28400000, 0x12800} };
 static int subsys_q6_ramdump(int enable,
-				const struct subsys_data *crashed_subsys)
+				const struct subsys_desc *crashed_subsys)
 {
 	if (enable)
 		return do_ramdump(q6_ramdump_dev, q6_segments,
@@ -102,7 +105,7 @@
 		return 0;
 }
 
-void subsys_q6_crash_shutdown(const struct subsys_data *crashed_subsys)
+void subsys_q6_crash_shutdown(const struct subsys_desc *crashed_subsys)
 {
 	send_q6_nmi();
 }
@@ -117,7 +120,7 @@
 	return IRQ_HANDLED;
 }
 
-static struct subsys_data subsys_8x60_q6 = {
+static struct subsys_desc subsys_8x60_q6 = {
 	.name = "lpass",
 	.shutdown = subsys_q6_shutdown,
 	.powerup = subsys_q6_powerup,
@@ -127,6 +130,7 @@
 
 static void __exit lpass_fatal_exit(void)
 {
+	subsys_unregister(subsys_8x60_q6_dev);
 	iounmap(q6_wakeup_intr);
 	free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
 }
@@ -156,7 +160,9 @@
 	if (!q6_wakeup_intr)
 		pr_warn("lpass-8660: Unable to ioremap q6 wakeup address.");
 
-	ret = ssr_register_subsystem(&subsys_8x60_q6);
+	subsys_8x60_q6_dev = subsys_register(&subsys_8x60_q6);
+	if (IS_ERR(subsys_8x60_q6_dev))
+		ret = PTR_ERR(subsys_8x60_q6_dev);
 out:
 	return ret;
 }
diff --git a/arch/arm/mach-msm/lpass-8960.c b/arch/arm/mach-msm/lpass-8960.c
index c58b0e1..b714a7f 100644
--- a/arch/arm/mach-msm/lpass-8960.c
+++ b/arch/arm/mach-msm/lpass-8960.c
@@ -152,7 +152,7 @@
 	pr_debug("%s: Q6 NMI was sent.\n", __func__);
 }
 
-static int lpass_shutdown(const struct subsys_data *subsys)
+static int lpass_shutdown(const struct subsys_desc *subsys)
 {
 	send_q6_nmi();
 	pil_force_shutdown("q6");
@@ -161,7 +161,7 @@
 	return 0;
 }
 
-static int lpass_powerup(const struct subsys_data *subsys)
+static int lpass_powerup(const struct subsys_desc *subsys)
 {
 	int ret = pil_force_boot("q6");
 	enable_irq(LPASS_Q6SS_WDOG_EXPIRED);
@@ -170,7 +170,7 @@
 /* RAM segments - address and size for 8960 */
 static struct ramdump_segment q6_segments[] = { {0x8da00000, 0x8f200000 -
 					0x8da00000}, {0x28400000, 0x20000} };
-static int lpass_ramdump(int enable, const struct subsys_data *subsys)
+static int lpass_ramdump(int enable, const struct subsys_desc *subsys)
 {
 	pr_debug("%s: enable[%d]\n", __func__, enable);
 	if (enable)
@@ -181,7 +181,7 @@
 		return 0;
 }
 
-static void lpass_crash_shutdown(const struct subsys_data *subsys)
+static void lpass_crash_shutdown(const struct subsys_desc *subsys)
 {
 	q6_crash_shutdown = 1;
 	send_q6_nmi();
@@ -198,7 +198,9 @@
 	return IRQ_HANDLED;
 }
 
-static struct subsys_data lpass_8960 = {
+static struct subsys_device *lpass_8960_dev;
+
+static struct subsys_desc lpass_8960 = {
 	.name = "lpass",
 	.shutdown = lpass_shutdown,
 	.powerup = lpass_powerup,
@@ -208,7 +210,10 @@
 
 static int __init lpass_restart_init(void)
 {
-	return ssr_register_subsystem(&lpass_8960);
+	lpass_8960_dev = subsys_register(&lpass_8960);
+	if (IS_ERR(lpass_8960_dev))
+		return PTR_ERR(lpass_8960_dev);
+	return 0;
 }
 
 static int __init lpass_fatal_init(void)
@@ -275,6 +280,7 @@
 {
 	subsys_notif_unregister_notifier(ssr_notif_hdle, &rnb);
 	subsys_notif_unregister_notifier(ssr_modem_notif_hdle, &mnb);
+	subsys_unregister(lpass_8960_dev);
 	free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
 }
 
diff --git a/arch/arm/mach-msm/mdm.c b/arch/arm/mach-msm/mdm.c
index cbdc92a..4280fb4 100644
--- a/arch/arm/mach-msm/mdm.c
+++ b/arch/arm/mach-msm/mdm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-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
@@ -73,14 +73,14 @@
 
 }
 
-static int charm_subsys_shutdown(const struct subsys_data *crashed_subsys)
+static int charm_subsys_shutdown(const struct subsys_desc *crashed_subsys)
 {
 	charm_ready = 0;
 	power_down_charm();
 	return 0;
 }
 
-static int charm_subsys_powerup(const struct subsys_data *crashed_subsys)
+static int charm_subsys_powerup(const struct subsys_desc *crashed_subsys)
 {
 	power_on_charm();
 	boot_type = CHARM_NORMAL_BOOT;
@@ -92,7 +92,7 @@
 }
 
 static int charm_subsys_ramdumps(int want_dumps,
-				const struct subsys_data *crashed_subsys)
+				const struct subsys_desc *crashed_subsys)
 {
 	charm_ram_dump_status = 0;
 	if (want_dumps) {
@@ -105,7 +105,9 @@
 	return charm_ram_dump_status;
 }
 
-static struct subsys_data charm_subsystem = {
+static struct subsys_device *charm_subsys;
+
+static struct subsys_desc charm_subsystem = {
 	.shutdown = charm_subsys_shutdown,
 	.ramdump = charm_subsys_ramdumps,
 	.powerup = charm_subsys_powerup,
@@ -229,7 +231,7 @@
 static void charm_status_fn(struct work_struct *work)
 {
 	pr_info("Reseting the charm because status changed\n");
-	subsystem_restart("external_modem");
+	subsystem_restart_dev(charm_subsys);
 }
 
 static DECLARE_WORK(charm_status_work, charm_status_fn);
@@ -239,7 +241,7 @@
 	pr_info("Reseting the charm due to an errfatal\n");
 	if (get_restart_level() == RESET_SOC)
 		pm8xxx_stay_on();
-	subsystem_restart("external_modem");
+	subsystem_restart_dev(charm_subsys);
 }
 
 static DECLARE_WORK(charm_fatal_work, charm_fatal_fn);
@@ -349,7 +351,11 @@
 	atomic_notifier_chain_register(&panic_notifier_list, &charm_panic_blk);
 	charm_debugfs_init();
 
-	ssr_register_subsystem(&charm_subsystem);
+	charm_subsys = subsys_register(&charm_subsystem);
+	if (IS_ERR(charm_subsys)) {
+		ret = PTR_ERR(charm_subsys);
+		goto fatal_err;
+	}
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index 5b181e1..ac9da2e 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -56,6 +56,7 @@
 #define EXTERNAL_MODEM "external_modem"
 
 static struct mdm_modem_drv *mdm_drv;
+static struct subsys_device *mdm_subsys_dev;
 
 DECLARE_COMPLETION(mdm_needs_reload);
 DECLARE_COMPLETION(mdm_boot);
@@ -154,7 +155,7 @@
 		pr_err("%s: MDM2AP_STATUS gpio did not go high\n",
 			   __func__);
 		mdm_drv->mdm_ready = 0;
-		subsystem_restart(EXTERNAL_MODEM);
+		subsystem_restart_dev(mdm_subsys_dev);
 	}
 }
 
@@ -271,7 +272,7 @@
 		(gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 1)) {
 		pr_info("%s: Reseting the mdm due to an errfatal\n", __func__);
 		mdm_drv->mdm_ready = 0;
-		subsystem_restart(EXTERNAL_MODEM);
+		subsystem_restart_dev(mdm_subsys_dev);
 	}
 	return IRQ_HANDLED;
 }
@@ -332,7 +333,7 @@
 		pr_info("%s: unexpected reset external modem\n", __func__);
 		mdm_drv->mdm_unexpected_reset_occurred = 1;
 		mdm_drv->mdm_ready = 0;
-		subsystem_restart(EXTERNAL_MODEM);
+		subsystem_restart_dev(mdm_subsys_dev);
 	} else if (value == 1) {
 		cancel_delayed_work(&mdm2ap_status_check_work);
 		pr_info("%s: status = 1: mdm is now ready\n", __func__);
@@ -349,7 +350,7 @@
 	return IRQ_HANDLED;
 }
 
-static int mdm_subsys_shutdown(const struct subsys_data *crashed_subsys)
+static int mdm_subsys_shutdown(const struct subsys_desc *crashed_subsys)
 {
 	mdm_drv->mdm_ready = 0;
 	gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 1);
@@ -367,7 +368,7 @@
 	return 0;
 }
 
-static int mdm_subsys_powerup(const struct subsys_data *crashed_subsys)
+static int mdm_subsys_powerup(const struct subsys_desc *crashed_subsys)
 {
 	gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 0);
 	gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
@@ -390,7 +391,7 @@
 }
 
 static int mdm_subsys_ramdumps(int want_dumps,
-				const struct subsys_data *crashed_subsys)
+				const struct subsys_desc *crashed_subsys)
 {
 	mdm_drv->mdm_ram_dump_status = 0;
 	if (want_dumps) {
@@ -411,7 +412,7 @@
 	return mdm_drv->mdm_ram_dump_status;
 }
 
-static struct subsys_data mdm_subsystem = {
+static struct subsys_desc mdm_subsystem = {
 	.shutdown = mdm_subsys_shutdown,
 	.ramdump = mdm_subsys_ramdumps,
 	.powerup = mdm_subsys_powerup,
@@ -588,7 +589,11 @@
 	mdm_debugfs_init();
 
 	/* Register subsystem handlers */
-	ssr_register_subsystem(&mdm_subsystem);
+	mdm_subsys_dev = subsys_register(&mdm_subsystem);
+	if (IS_ERR(mdm_subsys_dev)) {
+		ret = PTR_ERR(mdm_subsys_dev);
+		goto fatal_err;
+	}
 
 	/* ERR_FATAL irq. */
 	irq = MSM_GPIO_TO_INT(mdm_drv->mdm2ap_errfatal_gpio);
diff --git a/arch/arm/mach-msm/modem-8660.c b/arch/arm/mach-msm/modem-8660.c
index 9c558e4..096ed9c 100644
--- a/arch/arm/mach-msm/modem-8660.c
+++ b/arch/arm/mach-msm/modem-8660.c
@@ -19,6 +19,7 @@
 #include <linux/stringify.h>
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/err.h>
 
 #include <mach/irqs.h>
 #include <mach/scm.h>
@@ -48,6 +49,8 @@
 module_param(reset_modem, int, 0644);
 #endif
 
+static struct subsys_device *modem_8660_dev;
+
 /* Subsystem restart: Modem data, functions */
 static void *modem_ramdump_dev;
 static void modem_fatal_fn(struct work_struct *);
@@ -75,7 +78,7 @@
 	mb();
 	iounmap(hwio_modem_reset_addr);
 
-	subsystem_restart("modem");
+	subsystem_restart_dev(modem_8660_dev);
 	enable_irq(MARM_WDOG_EXPIRED);
 }
 
@@ -93,7 +96,7 @@
 
 	if (modem_state == 0 || modem_state & panic_smsm_states) {
 
-		subsystem_restart("modem");
+		subsystem_restart_dev(modem_8660_dev);
 		enable_irq(MARM_WDOG_EXPIRED);
 
 	} else if (modem_state & reset_smsm_states) {
@@ -135,13 +138,13 @@
 			goto out;
 		}
 		pr_err("%s: Modem error fatal'ed.", MODULE_NAME);
-		subsystem_restart("modem");
+		subsystem_restart_dev(modem_8660_dev);
 	}
 out:
 	return NOTIFY_DONE;
 }
 
-static int modem_shutdown(const struct subsys_data *crashed_subsys)
+static int modem_shutdown(const struct subsys_desc *crashed_subsys)
 {
 	void __iomem *modem_wdog_addr;
 
@@ -178,7 +181,7 @@
 	return 0;
 }
 
-static int modem_powerup(const struct subsys_data *crashed_subsys)
+static int modem_powerup(const struct subsys_desc *crashed_subsys)
 {
 	int ret;
 
@@ -192,8 +195,7 @@
 static struct ramdump_segment modem_segments[] = {
 	{0x42F00000, 0x46000000 - 0x42F00000} };
 
-static int modem_ramdump(int enable,
-				const struct subsys_data *crashed_subsys)
+static int modem_ramdump(int enable, const struct subsys_desc *crashed_subsys)
 {
 	if (enable)
 		return do_ramdump(modem_ramdump_dev, modem_segments,
@@ -202,8 +204,7 @@
 		return 0;
 }
 
-static void modem_crash_shutdown(
-				const struct subsys_data *crashed_subsys)
+static void modem_crash_shutdown(const struct subsys_desc *crashed_subsys)
 {
 	/* If modem hasn't already crashed, send SMSM_RESET. */
 	if (!(smsm_get_state(SMSM_MODEM_STATE) & SMSM_RESET)) {
@@ -225,7 +226,7 @@
 	return IRQ_HANDLED;
 }
 
-static struct subsys_data subsys_8660_modem = {
+static struct subsys_desc subsys_8660_modem = {
 	.name = "modem",
 	.shutdown = modem_shutdown,
 	.powerup = modem_powerup,
@@ -260,13 +261,16 @@
 		goto out;
 	}
 
-	ret = ssr_register_subsystem(&subsys_8660_modem);
+	modem_8660_dev = subsys_register(&subsys_8660_modem);
+	if (IS_ERR(modem_8660_dev))
+		ret = PTR_ERR(modem_8660_dev);
 out:
 	return ret;
 }
 
 static void __exit modem_8660_exit(void)
 {
+	subsys_unregister(modem_8660_dev);
 	free_irq(MARM_WDOG_EXPIRED, NULL);
 }
 
diff --git a/arch/arm/mach-msm/modem-8960.c b/arch/arm/mach-msm/modem-8960.c
index fd7b7b5..73b9b1f 100644
--- a/arch/arm/mach-msm/modem-8960.c
+++ b/arch/arm/mach-msm/modem-8960.c
@@ -35,6 +35,8 @@
 
 static int crash_shutdown;
 
+static struct subsys_device *modem_8960_dev;
+
 #define MAX_SSR_REASON_LEN 81U
 #define Q6_FW_WDOG_ENABLE		0x08882024
 #define Q6_SW_WDOG_ENABLE		0x08982024
@@ -66,7 +68,7 @@
 static void restart_modem(void)
 {
 	log_modem_sfr();
-	subsystem_restart("modem");
+	subsystem_restart_dev(modem_8960_dev);
 }
 
 static void modem_wdog_check(struct work_struct *work)
@@ -101,7 +103,7 @@
 	}
 }
 
-static int modem_shutdown(const struct subsys_data *subsys)
+static int modem_shutdown(const struct subsys_desc *subsys)
 {
 	void __iomem *q6_fw_wdog_addr;
 	void __iomem *q6_sw_wdog_addr;
@@ -142,7 +144,7 @@
 
 #define MODEM_WDOG_CHECK_TIMEOUT_MS 10000
 
-static int modem_powerup(const struct subsys_data *subsys)
+static int modem_powerup(const struct subsys_desc *subsys)
 {
 	pil_force_boot("modem_fw");
 	pil_force_boot("modem");
@@ -153,7 +155,7 @@
 	return 0;
 }
 
-void modem_crash_shutdown(const struct subsys_data *subsys)
+void modem_crash_shutdown(const struct subsys_desc *subsys)
 {
 	crash_shutdown = 1;
 	smsm_reset_modem(SMSM_RESET);
@@ -176,8 +178,7 @@
 static void *modemsw_ramdump_dev;
 static void *smem_ramdump_dev;
 
-static int modem_ramdump(int enable,
-				const struct subsys_data *crashed_subsys)
+static int modem_ramdump(int enable, const struct subsys_desc *crashed_subsys)
 {
 	int ret = 0;
 
@@ -234,7 +235,7 @@
 	return IRQ_HANDLED;
 }
 
-static struct subsys_data modem_8960 = {
+static struct subsys_desc modem_8960 = {
 	.name = "modem",
 	.shutdown = modem_shutdown,
 	.powerup = modem_powerup,
@@ -244,13 +245,16 @@
 
 static int modem_subsystem_restart_init(void)
 {
-	return ssr_register_subsystem(&modem_8960);
+	modem_8960_dev = subsys_register(&modem_8960);
+	if (IS_ERR(modem_8960_dev))
+		return PTR_ERR(modem_8960_dev);
+	return 0;
 }
 
 static int modem_debug_set(void *data, u64 val)
 {
 	if (val == 1)
-		subsystem_restart("modem");
+		subsystem_restart_dev(modem_8960_dev);
 
 	return 0;
 }
diff --git a/arch/arm/mach-msm/msm_dsps.c b/arch/arm/mach-msm/msm_dsps.c
index 200d717..6dde576 100644
--- a/arch/arm/mach-msm/msm_dsps.c
+++ b/arch/arm/mach-msm/msm_dsps.c
@@ -722,6 +722,8 @@
 	.unlocked_ioctl = dsps_ioctl,
 };
 
+static struct subsys_device *dsps_dev;
+
 /**
  *  Fatal error handler
  *  Resets DSPS.
@@ -735,7 +737,7 @@
 		pr_err("%s: DSPS already resetting. Count %d\n", __func__,
 		       atomic_read(&drv->crash_in_progress));
 	} else {
-		subsystem_restart("dsps");
+		subsystem_restart_dev(dsps_dev);
 	}
 }
 
@@ -765,7 +767,7 @@
  * called by the restart notifier
  *
  */
-static int dsps_shutdown(const struct subsys_data *subsys)
+static int dsps_shutdown(const struct subsys_desc *subsys)
 {
 	pr_debug("%s\n", __func__);
 	disable_irq_nosync(drv->wdog_irq);
@@ -779,7 +781,7 @@
  * called by the restart notifier
  *
  */
-static int dsps_powerup(const struct subsys_data *subsys)
+static int dsps_powerup(const struct subsys_desc *subsys)
 {
 	pr_debug("%s\n", __func__);
 	dsps_power_on_handler();
@@ -794,7 +796,7 @@
  * called by the restart notifier
  *
  */
-static void dsps_crash_shutdown(const struct subsys_data *subsys)
+static void dsps_crash_shutdown(const struct subsys_desc *subsys)
 {
 	pr_debug("%s\n", __func__);
 	dsps_crash_shutdown_g = 1;
@@ -806,7 +808,7 @@
  * called by the restart notifier
  *
  */
-static int dsps_ramdump(int enable, const struct subsys_data *subsys)
+static int dsps_ramdump(int enable, const struct subsys_desc *subsys)
 {
 	int ret = 0;
 	pr_debug("%s\n", __func__);
@@ -838,7 +840,7 @@
 	return ret;
 }
 
-static struct subsys_data dsps_ssrops = {
+static struct subsys_desc dsps_ssrops = {
 	.name = "dsps",
 	.shutdown = dsps_shutdown,
 	.powerup = dsps_powerup,
@@ -919,9 +921,10 @@
 		goto smsm_register_err;
 	}
 
-	ret = ssr_register_subsystem(&dsps_ssrops);
-	if (ret) {
-		pr_err("%s: ssr_register_subsystem fail %d\n", __func__,
+	dsps_dev = subsys_register(&dsps_ssrops);
+	if (IS_ERR(dsps_dev)) {
+		ret = PTR_ERR(dsps_dev);
+		pr_err("%s: subsys_register fail %d\n", __func__,
 		       ret);
 		goto ssr_register_err;
 	}
@@ -953,6 +956,7 @@
 {
 	pr_debug("%s.\n", __func__);
 
+	subsys_unregister(dsps_dev);
 	dsps_power_off_handler();
 	dsps_free_resources();
 
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index 0b6f225..cc76fb4 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -25,6 +25,7 @@
 #include <linux/time.h>
 #include <linux/wakelock.h>
 #include <linux/suspend.h>
+#include <linux/mutex.h>
 
 #include <asm/current.h>
 
@@ -42,11 +43,11 @@
 
 	struct mutex shutdown_lock;
 	struct mutex powerup_lock;
-	struct subsys_data *subsys_ptrs[];
+	struct subsys_device *subsys_ptrs[];
 };
 
 struct restart_wq_data {
-	struct subsys_data *subsys;
+	struct subsys_device *dev;
 	struct wake_lock ssr_wake_lock;
 	char wlname[64];
 	int use_restart_order;
@@ -55,17 +56,29 @@
 
 struct restart_log {
 	struct timeval time;
-	struct subsys_data *subsys;
+	struct subsys_device *dev;
 	struct list_head list;
 };
 
+struct subsys_device {
+	struct subsys_desc *desc;
+	struct list_head list;
+
+	void *notify;
+
+	struct mutex shutdown_lock;
+	struct mutex powerup_lock;
+
+	void *restart_order;
+};
+
 static int restart_level;
 static int enable_ramdumps;
 struct workqueue_struct *ssr_wq;
 
 static LIST_HEAD(restart_log_list);
 static LIST_HEAD(subsystem_list);
-static DEFINE_SPINLOCK(subsystem_list_lock);
+static DEFINE_MUTEX(subsystem_list_lock);
 static DEFINE_MUTEX(soc_order_reg_lock);
 static DEFINE_MUTEX(restart_log_mutex);
 
@@ -124,9 +137,6 @@
 
 module_param(enable_ramdumps, int, S_IRUGO | S_IWUSR);
 
-static struct subsys_soc_restart_order *_update_restart_order(
-		struct subsys_data *subsys);
-
 int get_restart_level()
 {
 	return restart_level;
@@ -167,62 +177,40 @@
 module_param_call(restart_level, restart_level_set, param_get_int,
 			&restart_level, 0644);
 
-static struct subsys_data *_find_subsystem(const char *subsys_name)
-{
-	struct subsys_data *subsys;
-	unsigned long flags;
-
-	spin_lock_irqsave(&subsystem_list_lock, flags);
-	list_for_each_entry(subsys, &subsystem_list, list)
-		if (!strncmp(subsys->name, subsys_name,
-				SUBSYS_NAME_MAX_LENGTH)) {
-			spin_unlock_irqrestore(&subsystem_list_lock, flags);
-			return subsys;
-		}
-	spin_unlock_irqrestore(&subsystem_list_lock, flags);
-
-	return NULL;
-}
-
-static struct subsys_soc_restart_order *_update_restart_order(
-		struct subsys_data *subsys)
+static struct subsys_soc_restart_order *
+update_restart_order(struct subsys_device *dev)
 {
 	int i, j;
-
-	if (!subsys)
-		return NULL;
-
-	if (!subsys->name)
-		return NULL;
+	struct subsys_soc_restart_order *order;
+	const char *name = dev->desc->name;
+	int len = SUBSYS_NAME_MAX_LENGTH;
 
 	mutex_lock(&soc_order_reg_lock);
 	for (j = 0; j < n_restart_orders; j++) {
-		for (i = 0; i < restart_orders[j]->count; i++)
-			if (!strncmp(restart_orders[j]->subsystem_list[i],
-				subsys->name, SUBSYS_NAME_MAX_LENGTH)) {
-
-					restart_orders[j]->subsys_ptrs[i] =
-						subsys;
-					mutex_unlock(&soc_order_reg_lock);
-					return restart_orders[j];
+		order = restart_orders[j];
+		for (i = 0; i < order->count; i++) {
+			if (!strncmp(order->subsystem_list[i], name, len)) {
+				order->subsys_ptrs[i] = dev;
+				goto found;
 			}
+		}
 	}
-
+	order = NULL;
+found:
 	mutex_unlock(&soc_order_reg_lock);
 
-	return NULL;
+	return order;
 }
 
-static void _send_notification_to_order(struct subsys_data
-			**restart_list, int count,
-			enum subsys_notif_type notif_type)
+static void _send_notification_to_order(struct subsys_device **restart_list,
+					int count, enum subsys_notif_type type)
 {
 	int i;
+	struct subsys_device **dev;
 
-	for (i = 0; i < count; i++)
-		if (restart_list[i])
-			subsys_notif_queue_notification(
-				restart_list[i]->notif_handle, notif_type);
+	for (i = 0, dev = restart_list; i < count; i++, dev++)
+		if (*dev)
+			subsys_notif_queue_notification((*dev)->notify, type);
 }
 
 static int max_restarts;
@@ -231,7 +219,7 @@
 static long max_history_time = 3600;
 module_param(max_history_time, long, 0644);
 
-static void do_epoch_check(struct subsys_data *subsys)
+static void do_epoch_check(struct subsys_device *dev)
 {
 	int n = 0;
 	struct timeval *time_first = NULL, *curr_time;
@@ -251,7 +239,7 @@
 	r_log = kmalloc(sizeof(struct restart_log), GFP_KERNEL);
 	if (!r_log)
 		goto out;
-	r_log->subsys = subsys;
+	r_log->dev = dev;
 	do_gettimeofday(&r_log->time);
 	curr_time = &r_log->time;
 	INIT_LIST_HEAD(&r_log->list);
@@ -293,8 +281,9 @@
 {
 	struct restart_wq_data *r_work = container_of(work,
 						struct restart_wq_data, work);
-	struct subsys_data **restart_list;
-	struct subsys_data *subsys = r_work->subsys;
+	struct subsys_device **restart_list;
+	struct subsys_device *dev = r_work->dev;
+	struct subsys_desc *desc = dev->desc;
 	struct subsys_soc_restart_order *soc_restart_order = NULL;
 
 	struct mutex *powerup_lock;
@@ -304,17 +293,17 @@
 	int restart_list_count = 0;
 
 	if (r_work->use_restart_order)
-		soc_restart_order = subsys->restart_order;
+		soc_restart_order = dev->restart_order;
 
 	/* It's OK to not take the registration lock at this point.
 	 * This is because the subsystem list inside the relevant
 	 * restart order is not being traversed.
 	 */
 	if (!soc_restart_order) {
-		restart_list = subsys->single_restart_list;
+		restart_list = &dev;
 		restart_list_count = 1;
-		powerup_lock = &subsys->powerup_lock;
-		shutdown_lock = &subsys->shutdown_lock;
+		powerup_lock = &dev->powerup_lock;
+		shutdown_lock = &dev->shutdown_lock;
 	} else {
 		restart_list = soc_restart_order->subsys_ptrs;
 		restart_list_count = soc_restart_order->count;
@@ -341,7 +330,7 @@
 		panic("%s[%p]: Subsystem died during powerup!",
 						__func__, current);
 
-	do_epoch_check(subsys);
+	do_epoch_check(dev);
 
 	/* Now it is necessary to take the registration lock. This is because
 	 * the subsystem list in the SoC restart order will be traversed
@@ -350,23 +339,25 @@
 	mutex_lock(&soc_order_reg_lock);
 
 	pr_debug("[%p]: Starting restart sequence for %s\n", current,
-			r_work->subsys->name);
+			desc->name);
 
 	_send_notification_to_order(restart_list,
 				restart_list_count,
 				SUBSYS_BEFORE_SHUTDOWN);
 
 	for (i = 0; i < restart_list_count; i++) {
+		const struct subsys_device *dev = restart_list[i];
+		const char *name;
 
-		if (!restart_list[i])
+		if (!dev)
 			continue;
+		name = dev->desc->name;
 
-		pr_info("[%p]: Shutting down %s\n", current,
-			restart_list[i]->name);
+		pr_info("[%p]: Shutting down %s\n", current, name);
 
-		if (restart_list[i]->shutdown(subsys) < 0)
+		if (dev->desc->shutdown(dev->desc) < 0)
 			panic("subsys-restart: %s[%p]: Failed to shutdown %s!",
-				__func__, current, restart_list[i]->name);
+				__func__, current, name);
 	}
 
 	_send_notification_to_order(restart_list, restart_list_count,
@@ -381,14 +372,17 @@
 
 	/* Collect ram dumps for all subsystems in order here */
 	for (i = 0; i < restart_list_count; i++) {
-		if (!restart_list[i])
-			continue;
+		const struct subsys_device *dev = restart_list[i];
+		const char *name;
 
-		if (restart_list[i]->ramdump)
-			if (restart_list[i]->ramdump(enable_ramdumps,
-							subsys) < 0)
-				pr_warn("%s[%p]: Ramdump failed.\n",
-						restart_list[i]->name, current);
+		if (!dev)
+			continue;
+		name = dev->desc->name;
+
+		if (dev->desc->ramdump)
+			if (dev->desc->ramdump(enable_ramdumps, dev->desc) < 0)
+				pr_warn("%s[%p]: Ramdump failed.\n", name,
+						current);
 	}
 
 	_send_notification_to_order(restart_list,
@@ -396,16 +390,18 @@
 			SUBSYS_BEFORE_POWERUP);
 
 	for (i = restart_list_count - 1; i >= 0; i--) {
+		const struct subsys_device *dev = restart_list[i];
+		const char *name;
 
-		if (!restart_list[i])
+		if (!dev)
 			continue;
+		name = dev->desc->name;
 
-		pr_info("[%p]: Powering up %s\n", current,
-					restart_list[i]->name);
+		pr_info("[%p]: Powering up %s\n", current, name);
 
-		if (restart_list[i]->powerup(subsys) < 0)
+		if (dev->desc->powerup(dev->desc) < 0)
 			panic("%s[%p]: Failed to powerup %s!", __func__,
-				current, restart_list[i]->name);
+				current, name);
 	}
 
 	_send_notification_to_order(restart_list,
@@ -413,7 +409,7 @@
 				SUBSYS_AFTER_POWERUP);
 
 	pr_info("[%p]: Restart sequence for %s completed.\n",
-			current, r_work->subsys->name);
+			current, desc->name);
 
 	mutex_unlock(powerup_lock);
 
@@ -427,25 +423,25 @@
 	kfree(r_work);
 }
 
-static void __subsystem_restart(struct subsys_data *subsys)
+static void __subsystem_restart_dev(struct subsys_device *dev)
 {
 	struct restart_wq_data *data = NULL;
 	int rc;
+	struct subsys_desc *desc = dev->desc;
 
-	pr_debug("Restarting %s [level=%d]!\n", subsys->name,
-				restart_level);
+	pr_debug("Restarting %s [level=%d]!\n", desc->name, restart_level);
 
 	data = kzalloc(sizeof(struct restart_wq_data), GFP_ATOMIC);
 	if (!data)
 		panic("%s: Unable to allocate memory to restart %s.",
-		      __func__, subsys->name);
+		      __func__, desc->name);
 
-	data->subsys = subsys;
+	data->dev = dev;
 
 	if (restart_level != RESET_SUBSYS_INDEPENDENT)
 		data->use_restart_order = 1;
 
-	snprintf(data->wlname, sizeof(data->wlname), "ssr(%s)", subsys->name);
+	snprintf(data->wlname, sizeof(data->wlname), "ssr(%s)", desc->name);
 	wake_lock_init(&data->ssr_wake_lock, WAKE_LOCK_SUSPEND, data->wlname);
 	wake_lock(&data->ssr_wake_lock);
 
@@ -453,41 +449,25 @@
 	rc = queue_work(ssr_wq, &data->work);
 	if (rc < 0)
 		panic("%s: Unable to schedule work to restart %s (%d).",
-		     __func__, subsys->name, rc);
+		     __func__, desc->name, rc);
 }
 
-int subsystem_restart(const char *subsys_name)
+int subsystem_restart_dev(struct subsys_device *dev)
 {
-	struct subsys_data *subsys;
-
-	if (!subsys_name) {
-		pr_err("Invalid subsystem name.\n");
-		return -EINVAL;
-	}
+	const char *name = dev->desc->name;
 
 	pr_info("Restart sequence requested for %s, restart_level = %d.\n",
-		subsys_name, restart_level);
-
-	/* List of subsystems is protected by a lock. New subsystems can
-	 * still come in.
-	 */
-	subsys = _find_subsystem(subsys_name);
-
-	if (!subsys) {
-		pr_warn("Unregistered subsystem %s!\n", subsys_name);
-		return -EINVAL;
-	}
+		name, restart_level);
 
 	switch (restart_level) {
 
 	case RESET_SUBSYS_COUPLED:
 	case RESET_SUBSYS_INDEPENDENT:
-		__subsystem_restart(subsys);
+		__subsystem_restart_dev(dev);
 		break;
 
 	case RESET_SOC:
-		panic("subsys-restart: Resetting the SoC - %s crashed.",
-			subsys->name);
+		panic("subsys-restart: Resetting the SoC - %s crashed.", name);
 		break;
 
 	default:
@@ -498,47 +478,67 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(subsystem_restart_dev);
+
+int subsystem_restart(const char *name)
+{
+	struct subsys_device *dev;
+
+	mutex_lock(&subsystem_list_lock);
+	list_for_each_entry(dev, &subsystem_list, list)
+		if (!strncmp(dev->desc->name, name, SUBSYS_NAME_MAX_LENGTH))
+			goto found;
+	dev = NULL;
+found:
+	mutex_unlock(&subsystem_list_lock);
+	if (dev)
+		return subsystem_restart_dev(dev);
+	return -ENODEV;
+}
 EXPORT_SYMBOL(subsystem_restart);
 
-int ssr_register_subsystem(struct subsys_data *subsys)
+struct subsys_device *subsys_register(struct subsys_desc *desc)
 {
-	unsigned long flags;
+	struct subsys_device *dev;
 
-	if (!subsys)
-		goto err;
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return ERR_PTR(-ENOMEM);
 
-	if (!subsys->name)
-		goto err;
+	dev->desc = desc;
+	dev->notify = subsys_notif_add_subsys(desc->name);
+	dev->restart_order = update_restart_order(dev);
 
-	if (!subsys->powerup || !subsys->shutdown)
-		goto err;
+	mutex_init(&dev->shutdown_lock);
+	mutex_init(&dev->powerup_lock);
 
-	subsys->notif_handle = subsys_notif_add_subsys(subsys->name);
-	subsys->restart_order = _update_restart_order(subsys);
-	subsys->single_restart_list[0] = subsys;
+	mutex_lock(&subsystem_list_lock);
+	list_add(&dev->list, &subsystem_list);
+	mutex_unlock(&subsystem_list_lock);
 
-	mutex_init(&subsys->shutdown_lock);
-	mutex_init(&subsys->powerup_lock);
-
-	spin_lock_irqsave(&subsystem_list_lock, flags);
-	list_add(&subsys->list, &subsystem_list);
-	spin_unlock_irqrestore(&subsystem_list_lock, flags);
-
-	return 0;
-
-err:
-	return -EINVAL;
+	return dev;
 }
-EXPORT_SYMBOL(ssr_register_subsystem);
+EXPORT_SYMBOL(subsys_register);
+
+void subsys_unregister(struct subsys_device *dev)
+{
+	if (IS_ERR_OR_NULL(dev))
+		return;
+	mutex_lock(&subsystem_list_lock);
+	list_del(&dev->list);
+	mutex_unlock(&subsystem_list_lock);
+	kfree(dev);
+}
+EXPORT_SYMBOL(subsys_unregister);
 
 static int ssr_panic_handler(struct notifier_block *this,
 				unsigned long event, void *ptr)
 {
-	struct subsys_data *subsys;
+	struct subsys_device *dev;
 
-	list_for_each_entry(subsys, &subsystem_list, list)
-		if (subsys->crash_shutdown)
-			subsys->crash_shutdown(subsys);
+	list_for_each_entry(dev, &subsystem_list, list)
+		if (dev->desc->crash_shutdown)
+			dev->desc->crash_shutdown(dev->desc);
 	return NOTIFY_DONE;
 }
 
diff --git a/arch/arm/mach-msm/wcnss-ssr-8960.c b/arch/arm/mach-msm/wcnss-ssr-8960.c
index 6e8d57c..4295d9b 100644
--- a/arch/arm/mach-msm/wcnss-ssr-8960.c
+++ b/arch/arm/mach-msm/wcnss-ssr-8960.c
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/wcnss_wlan.h>
+#include <linux/err.h>
 #include <mach/irqs.h>
 #include <mach/scm.h>
 #include <mach/subsystem_restart.h>
@@ -37,6 +38,7 @@
 static int riva_crash;
 static int ss_restart_inprogress;
 static int enable_riva_ssr;
+static struct subsys_device *riva_8960_dev;
 
 static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
 					uint32_t new_state)
@@ -83,7 +85,7 @@
 	}
 
 	ss_restart_inprogress = true;
-	subsystem_restart("riva");
+	subsystem_restart_dev(riva_8960_dev);
 }
 
 static irqreturn_t riva_wdog_bite_irq_hdlr(int irq, void *dev_id)
@@ -100,7 +102,7 @@
 		panic(MODULE_NAME ": Watchdog bite received from Riva");
 
 	ss_restart_inprogress = true;
-	subsystem_restart("riva");
+	subsystem_restart_dev(riva_8960_dev);
 
 	return IRQ_HANDLED;
 }
@@ -126,7 +128,7 @@
 }
 
 /* Subsystem handlers */
-static int riva_shutdown(const struct subsys_data *subsys)
+static int riva_shutdown(const struct subsys_desc *subsys)
 {
 	pil_force_shutdown("wcnss");
 	flush_delayed_work(&cancel_vote_work);
@@ -135,7 +137,7 @@
 	return 0;
 }
 
-static int riva_powerup(const struct subsys_data *subsys)
+static int riva_powerup(const struct subsys_desc *subsys)
 {
 	struct platform_device *pdev = wcnss_get_platform_device();
 	struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
@@ -162,7 +164,7 @@
 static struct ramdump_segment riva_segments[] = {{0x8f200000,
 						0x8f700000 - 0x8f200000} };
 
-static int riva_ramdump(int enable, const struct subsys_data *subsys)
+static int riva_ramdump(int enable, const struct subsys_desc *subsys)
 {
 	pr_debug("%s: enable[%d]\n", MODULE_NAME, enable);
 	if (enable)
@@ -174,14 +176,14 @@
 }
 
 /* Riva crash handler */
-static void riva_crash_shutdown(const struct subsys_data *subsys)
+static void riva_crash_shutdown(const struct subsys_desc *subsys)
 {
 	pr_err("%s: crash shutdown : %d\n", MODULE_NAME, riva_crash);
 	if (riva_crash != true)
 		smsm_riva_reset();
 }
 
-static struct subsys_data riva_8960 = {
+static struct subsys_desc riva_8960 = {
 	.name = "riva",
 	.shutdown = riva_shutdown,
 	.powerup = riva_powerup,
@@ -208,7 +210,10 @@
 
 static int __init riva_restart_init(void)
 {
-	return ssr_register_subsystem(&riva_8960);
+	riva_8960_dev = subsys_register(&riva_8960);
+	if (IS_ERR(riva_8960_dev))
+		return PTR_ERR(riva_8960_dev);
+	return 0;
 }
 
 static int __init riva_ssr_module_init(void)
@@ -253,6 +258,7 @@
 
 static void __exit riva_ssr_module_exit(void)
 {
+	subsys_unregister(riva_8960_dev);
 	free_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ, NULL);
 }