]> git.karo-electronics.de Git - linux-beck.git/commitdiff
[ARM] S3C64XX: Add IRQ PM code
authorBen Dooks <ben-linux@fluff.org>
Fri, 12 Dec 2008 00:24:32 +0000 (00:24 +0000)
committerBen Dooks <ben-linux@fluff.org>
Thu, 7 May 2009 10:04:56 +0000 (11:04 +0100)
Add support for saving the state of the IRQ registers over suspend.

This requires moving the S3C64XX UART registers into <plat/regs-serial.h>
and adding irq-pm.c which saves the state of all the IRQ registers.

The irq-pm.c saves all the IRQ registers, including the IRQ_EINT and
IRQ_EINT_GROUP registers as it was easier than adding three different
files. Also ensuring that all the registers are restored to the same
state as before suspend is considered to be the best thing to do.

Note, we do not suspend the VIC here, this is done by the VIC driver
itself.

Signed-off-by: Ben Dooks <ben-linux@fluff.org>
arch/arm/plat-s3c/include/plat/regs-serial.h
arch/arm/plat-s3c64xx/Makefile
arch/arm/plat-s3c64xx/irq-pm.c [new file with mode: 0644]
arch/arm/plat-s3c64xx/irq.c

index 487d7d2a7e1d1a315fdd7f3f8f6687882203833a..66af75a5cdd1f54cc564f660b0da23611481793f 100644 (file)
 
 #define S3C2443_DIVSLOT                  (0x2C)
 
+/* S3C64XX interrupt registers. */
+#define S3C64XX_UINTP          0x30
+#define S3C64XX_UINTSP         0x34
+#define S3C64XX_UINTM          0x38
+
 #ifndef __ASSEMBLY__
 
 /* struct s3c24xx_uart_clksrc
index b2bc2a9ed46b618faafcb5a65a27dfd595f83a2a..12ac7a50ab748b13200276d693d89ebf61a3c53c 100644 (file)
@@ -28,6 +28,7 @@ obj-$(CONFIG_CPU_S3C6400_CLOCK)       += s3c6400-clock.o
 
 obj-$(CONFIG_PM)               += pm.o
 obj-$(CONFIG_PM)               += sleep.o
+obj-$(CONFIG_PM)               += irq-pm.o
 
 # Device setup
 
diff --git a/arch/arm/plat-s3c64xx/irq-pm.c b/arch/arm/plat-s3c64xx/irq-pm.c
new file mode 100644 (file)
index 0000000..ca523b5
--- /dev/null
@@ -0,0 +1,111 @@
+/* arch/arm/plat-s3c64xx/irq-pm.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C64XX - Interrupt handling Power Management
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sysdev.h>
+#include <linux/interrupt.h>
+#include <linux/serial_core.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <mach/map.h>
+
+#include <plat/regs-serial.h>
+#include <plat/regs-timer.h>
+#include <plat/regs-gpio.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
+
+/* We handled all the IRQ types in this code, to save having to make several
+ * small files to handle each different type separately. Having the EINT_GRP
+ * code here shouldn't be as much bloat as the IRQ table space needed when
+ * they are enabled. The added benefit is we ensure that these registers are
+ * in the same state as we suspended.
+ */
+
+static struct sleep_save irq_save[] = {
+       SAVE_ITEM(S3C64XX_PRIORITY),
+       SAVE_ITEM(S3C64XX_EINT0CON0),
+       SAVE_ITEM(S3C64XX_EINT0CON1),
+       SAVE_ITEM(S3C64XX_EINT0FLTCON0),
+       SAVE_ITEM(S3C64XX_EINT0FLTCON1),
+       SAVE_ITEM(S3C64XX_EINT0FLTCON2),
+       SAVE_ITEM(S3C64XX_EINT0FLTCON3),
+       SAVE_ITEM(S3C64XX_EINT0MASK),
+       SAVE_ITEM(S3C64XX_TINT_CSTAT),
+};
+
+static struct irq_grp_save {
+       u32     fltcon;
+       u32     con;
+       u32     mask;
+} eint_grp_save[5];
+
+static u32 irq_uart_mask[CONFIG_SERIAL_SAMSUNG_UARTS];
+
+static int s3c64xx_irq_pm_suspend(struct sys_device *dev, pm_message_t state)
+{
+       struct irq_grp_save *grp = eint_grp_save;
+       int i;
+
+       S3C_PMDBG("%s: suspending IRQs\n", __func__);
+
+       s3c_pm_do_save(irq_save, ARRAY_SIZE(irq_save));
+
+       for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++)
+               irq_uart_mask[i] = __raw_readl(S3C_VA_UARTx(i) + S3C64XX_UINTM);
+
+       for (i = 0; i < ARRAY_SIZE(eint_grp_save); i++, grp++) {
+               grp->con = __raw_readl(S3C64XX_EINT12CON + (i * 4));
+               grp->mask = __raw_readl(S3C64XX_EINT12MASK + (i * 4));
+               grp->fltcon = __raw_readl(S3C64XX_EINT12FLTCON + (i * 4));
+       }
+
+       return 0;
+}
+
+static int s3c64xx_irq_pm_resume(struct sys_device *dev)
+{
+       struct irq_grp_save *grp = eint_grp_save;
+       int i;
+
+       S3C_PMDBG("%s: resuming IRQs\n", __func__);
+
+       s3c_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
+
+       for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++)
+               __raw_writel(irq_uart_mask[i], S3C_VA_UARTx(i) + S3C64XX_UINTM);
+
+       for (i = 0; i < ARRAY_SIZE(eint_grp_save); i++, grp++) {
+               __raw_writel(grp->con, S3C64XX_EINT12CON + (i * 4));
+               __raw_writel(grp->mask, S3C64XX_EINT12MASK + (i * 4));
+               __raw_writel(grp->fltcon, S3C64XX_EINT12FLTCON + (i * 4));
+       }
+
+       S3C_PMDBG("%s: IRQ configuration restored\n", __func__);
+       return 0;
+}
+
+static struct sysdev_driver s3c64xx_irq_driver = {
+       .suspend = s3c64xx_irq_pm_suspend,
+       .resume  = s3c64xx_irq_pm_resume,
+};
+
+static int __init s3c64xx_irq_pm_init(void)
+{
+       return sysdev_driver_register(&s3c64xx_sysclass, &s3c64xx_irq_driver);
+}
+
+arch_initcall(s3c64xx_irq_pm_init);
+
index f22edf7c2d2de65b8fee6ba955468d8b9feb7bcf..f4c4844f9fdbcfff2cb89b62b4c243f968a16d3c 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
+#include <linux/serial_core.h>
 #include <linux/irq.h>
 #include <linux/io.h>
 
 #include <asm/hardware/vic.h>
 
 #include <mach/map.h>
+#include <plat/regs-serial.h>
 #include <plat/regs-timer.h>
 #include <plat/cpu.h>
 
@@ -135,9 +137,6 @@ static inline unsigned int s3c_irq_uart_bit(unsigned int irq)
 }
 
 /* UART interrupt registers, not worth adding to seperate include header */
-#define S3C64XX_UINTP  0x30
-#define S3C64XX_UINTSP 0x34
-#define S3C64XX_UINTM  0x38
 
 static void s3c_irq_uart_mask(unsigned int irq)
 {