[ARM] pxa: introduce sysdev for IRQ register saving/restoring

Signed-off-by: eric miao <eric.miao@marvell.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h
index b30f240..367b679 100644
--- a/arch/arm/mach-pxa/generic.h
+++ b/arch/arm/mach-pxa/generic.h
@@ -52,3 +52,5 @@
 #define pxa3xx_get_clk_frequency_khz(x)		(0)
 #define pxa3xx_get_memclk_frequency_10khz()	(0)
 #endif
+
+extern struct sysdev_class pxa_irq_sysclass;
diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
index 07acb45..5a1d5ee 100644
--- a/arch/arm/mach-pxa/irq.c
+++ b/arch/arm/mach-pxa/irq.c
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/sysdev.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
@@ -321,3 +322,64 @@
 	pxa_low_gpio_chip.set_wake = set_wake;
 	pxa_muxed_gpio_chip.set_wake = set_wake;
 }
+
+#ifdef CONFIG_PM
+static unsigned long saved_icmr[2];
+
+static int pxa_irq_suspend(struct sys_device *dev, pm_message_t state)
+{
+	switch (dev->id) {
+	case 0:
+		saved_icmr[0] = ICMR;
+		ICMR = 0;
+		break;
+#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
+	case 1:
+		saved_icmr[1] = ICMR2;
+		ICMR2 = 0;
+		break;
+#endif
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int pxa_irq_resume(struct sys_device *dev)
+{
+	switch (dev->id) {
+	case 0:
+		ICMR = saved_icmr[0];
+		ICLR = 0;
+		ICCR = 1;
+		break;
+#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
+	case 1:
+		ICMR2 = saved_icmr[1];
+		ICLR2 = 0;
+		break;
+#endif
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+#else
+#define pxa_irq_suspend		NULL
+#define pxa_irq_resume		NULL
+#endif
+
+struct sysdev_class pxa_irq_sysclass = {
+	.name		= "irq",
+	.suspend	= pxa_irq_suspend,
+	.resume		= pxa_irq_resume,
+};
+
+static int __init pxa_irq_init(void)
+{
+	return sysdev_class_register(&pxa_irq_sysclass);
+}
+
+core_initcall(pxa_irq_init);
diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
index ddd05bf..797635e 100644
--- a/arch/arm/mach-pxa/pxa25x.c
+++ b/arch/arm/mach-pxa/pxa25x.c
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/suspend.h>
+#include <linux/sysdev.h>
 
 #include <asm/hardware.h>
 #include <asm/arch/irqs.h>
@@ -165,7 +166,6 @@
 
 	SLEEP_SAVE_PSTR,
 
-	SLEEP_SAVE_ICMR,
 	SLEEP_SAVE_CKEN,
 
 	SLEEP_SAVE_SIZE
@@ -184,7 +184,6 @@
 	SAVE(GAFR1_L); SAVE(GAFR1_U);
 	SAVE(GAFR2_L); SAVE(GAFR2_U);
 
-	SAVE(ICMR); ICMR = 0;
 	SAVE(CKEN);
 	SAVE(PSTR);
 
@@ -210,10 +209,6 @@
 	PSSR = PSSR_RDH | PSSR_PH;
 
 	RESTORE(CKEN);
-
-	ICLR = 0;
-	ICCR = 1;
-	RESTORE(ICMR);
 	RESTORE(PSTR);
 }
 
@@ -304,9 +299,15 @@
 	&pxa25x_device_assp,
 };
 
+static struct sys_device pxa25x_sysdev[] = {
+	{
+		.cls	= &pxa_irq_sysclass,
+	},
+};
+
 static int __init pxa25x_init(void)
 {
-	int ret = 0;
+	int i, ret = 0;
 
 	/* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */
 	if (cpu_is_pxa25x())
@@ -320,9 +321,18 @@
 
 		pxa25x_init_pm();
 
+		for (i = 0; i < ARRAY_SIZE(pxa25x_sysdev); i++) {
+			ret = sysdev_register(&pxa25x_sysdev[i]);
+			if (ret)
+				pr_err("failed to register sysdev[%d]\n", i);
+		}
+
 		ret = platform_add_devices(pxa25x_devices,
 					   ARRAY_SIZE(pxa25x_devices));
+		if (ret)
+			return ret;
 	}
+
 	/* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */
 	if (cpu_is_pxa25x())
 		ret = platform_device_register(&pxa_device_hwuart);
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index 96cf274..343296a 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/suspend.h>
 #include <linux/platform_device.h>
+#include <linux/sysdev.h>
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
@@ -196,7 +197,6 @@
 
 	SLEEP_SAVE_PSTR,
 
-	SLEEP_SAVE_ICMR,
 	SLEEP_SAVE_CKEN,
 
 	SLEEP_SAVE_MDREFR,
@@ -223,7 +223,6 @@
 	SAVE(PWER); SAVE(PCFR); SAVE(PRER);
 	SAVE(PFER); SAVE(PKWR);
 
-	SAVE(ICMR); ICMR = 0;
 	SAVE(CKEN);
 	SAVE(PSTR);
 
@@ -256,9 +255,6 @@
 
 	RESTORE(CKEN);
 
-	ICLR = 0;
-	ICCR = 1;
-	RESTORE(ICMR);
 	RESTORE(PSTR);
 }
 
@@ -409,9 +405,20 @@
 	&pxa27x_device_ssp3,
 };
 
+static struct sys_device pxa27x_sysdev[] = {
+	{
+		.id	= 0,
+		.cls	= &pxa_irq_sysclass,
+	}, {
+		.id	= 1,
+		.cls	= &pxa_irq_sysclass,
+	},
+};
+
 static int __init pxa27x_init(void)
 {
-	int ret = 0;
+	int i, ret = 0;
+
 	if (cpu_is_pxa27x()) {
 		clks_register(pxa27x_clks, ARRAY_SIZE(pxa27x_clks));
 
@@ -420,8 +427,15 @@
 
 		pxa27x_init_pm();
 
+		for (i = 0; i < ARRAY_SIZE(pxa27x_sysdev); i++) {
+			ret = sysdev_register(&pxa27x_sysdev[i]);
+			if (ret)
+				pr_err("failed to register sysdev[%d]\n", i);
+		}
+
 		ret = platform_add_devices(devices, ARRAY_SIZE(devices));
 	}
+
 	return ret;
 }
 
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index 5cbf057..3a7e8cc 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -20,6 +20,7 @@
 #include <linux/platform_device.h>
 #include <linux/irq.h>
 #include <linux/io.h>
+#include <linux/sysdev.h>
 
 #include <asm/hardware.h>
 #include <asm/arch/pxa3xx-regs.h>
@@ -452,9 +453,19 @@
 	&pxa3xx_device_ssp4,
 };
 
+static struct sys_device pxa3xx_sysdev[] = {
+	{
+		.id	= 0,
+		.cls	= &pxa_irq_sysclass,
+	}, {
+		.id	= 1,
+		.cls	= &pxa_irq_sysclass,
+	},
+};
+
 static int __init pxa3xx_init(void)
 {
-	int ret = 0;
+	int i, ret = 0;
 
 	if (cpu_is_pxa3xx()) {
 		clks_register(pxa3xx_clks, ARRAY_SIZE(pxa3xx_clks));
@@ -464,9 +475,16 @@
 
 		pxa3xx_init_pm();
 
-		return platform_add_devices(devices, ARRAY_SIZE(devices));
+		for (i = 0; i < ARRAY_SIZE(pxa3xx_sysdev); i++) {
+			ret = sysdev_register(&pxa3xx_sysdev[i]);
+			if (ret)
+				pr_err("failed to register sysdev[%d]\n", i);
+		}
+
+		ret = platform_add_devices(devices, ARRAY_SIZE(devices));
 	}
-	return 0;
+
+	return ret;
 }
 
 subsys_initcall(pxa3xx_init);