Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[ARM] S3C64XX: Add IRQ PM code

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>

Ben Dooks 966bcc14 1deb507d

+119 -3
+5
arch/arm/plat-s3c/include/plat/regs-serial.h
··· 189 189 190 190 #define S3C2443_DIVSLOT (0x2C) 191 191 192 + /* S3C64XX interrupt registers. */ 193 + #define S3C64XX_UINTP 0x30 194 + #define S3C64XX_UINTSP 0x34 195 + #define S3C64XX_UINTM 0x38 196 + 192 197 #ifndef __ASSEMBLY__ 193 198 194 199 /* struct s3c24xx_uart_clksrc
+1
arch/arm/plat-s3c64xx/Makefile
··· 28 28 29 29 obj-$(CONFIG_PM) += pm.o 30 30 obj-$(CONFIG_PM) += sleep.o 31 + obj-$(CONFIG_PM) += irq-pm.o 31 32 32 33 # Device setup 33 34
+111
arch/arm/plat-s3c64xx/irq-pm.c
··· 1 + /* arch/arm/plat-s3c64xx/irq-pm.c 2 + * 3 + * Copyright 2008 Openmoko, Inc. 4 + * Copyright 2008 Simtec Electronics 5 + * Ben Dooks <ben@simtec.co.uk> 6 + * http://armlinux.simtec.co.uk/ 7 + * 8 + * S3C64XX - Interrupt handling Power Management 9 + * 10 + * This program is free software; you can redistribute it and/or modify 11 + * it under the terms of the GNU General Public License version 2 as 12 + * published by the Free Software Foundation. 13 + */ 14 + 15 + #include <linux/kernel.h> 16 + #include <linux/sysdev.h> 17 + #include <linux/interrupt.h> 18 + #include <linux/serial_core.h> 19 + #include <linux/irq.h> 20 + #include <linux/io.h> 21 + 22 + #include <mach/map.h> 23 + 24 + #include <plat/regs-serial.h> 25 + #include <plat/regs-timer.h> 26 + #include <plat/regs-gpio.h> 27 + #include <plat/cpu.h> 28 + #include <plat/pm.h> 29 + 30 + /* We handled all the IRQ types in this code, to save having to make several 31 + * small files to handle each different type separately. Having the EINT_GRP 32 + * code here shouldn't be as much bloat as the IRQ table space needed when 33 + * they are enabled. The added benefit is we ensure that these registers are 34 + * in the same state as we suspended. 35 + */ 36 + 37 + static struct sleep_save irq_save[] = { 38 + SAVE_ITEM(S3C64XX_PRIORITY), 39 + SAVE_ITEM(S3C64XX_EINT0CON0), 40 + SAVE_ITEM(S3C64XX_EINT0CON1), 41 + SAVE_ITEM(S3C64XX_EINT0FLTCON0), 42 + SAVE_ITEM(S3C64XX_EINT0FLTCON1), 43 + SAVE_ITEM(S3C64XX_EINT0FLTCON2), 44 + SAVE_ITEM(S3C64XX_EINT0FLTCON3), 45 + SAVE_ITEM(S3C64XX_EINT0MASK), 46 + SAVE_ITEM(S3C64XX_TINT_CSTAT), 47 + }; 48 + 49 + static struct irq_grp_save { 50 + u32 fltcon; 51 + u32 con; 52 + u32 mask; 53 + } eint_grp_save[5]; 54 + 55 + static u32 irq_uart_mask[CONFIG_SERIAL_SAMSUNG_UARTS]; 56 + 57 + static int s3c64xx_irq_pm_suspend(struct sys_device *dev, pm_message_t state) 58 + { 59 + struct irq_grp_save *grp = eint_grp_save; 60 + int i; 61 + 62 + S3C_PMDBG("%s: suspending IRQs\n", __func__); 63 + 64 + s3c_pm_do_save(irq_save, ARRAY_SIZE(irq_save)); 65 + 66 + for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++) 67 + irq_uart_mask[i] = __raw_readl(S3C_VA_UARTx(i) + S3C64XX_UINTM); 68 + 69 + for (i = 0; i < ARRAY_SIZE(eint_grp_save); i++, grp++) { 70 + grp->con = __raw_readl(S3C64XX_EINT12CON + (i * 4)); 71 + grp->mask = __raw_readl(S3C64XX_EINT12MASK + (i * 4)); 72 + grp->fltcon = __raw_readl(S3C64XX_EINT12FLTCON + (i * 4)); 73 + } 74 + 75 + return 0; 76 + } 77 + 78 + static int s3c64xx_irq_pm_resume(struct sys_device *dev) 79 + { 80 + struct irq_grp_save *grp = eint_grp_save; 81 + int i; 82 + 83 + S3C_PMDBG("%s: resuming IRQs\n", __func__); 84 + 85 + s3c_pm_do_restore(irq_save, ARRAY_SIZE(irq_save)); 86 + 87 + for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++) 88 + __raw_writel(irq_uart_mask[i], S3C_VA_UARTx(i) + S3C64XX_UINTM); 89 + 90 + for (i = 0; i < ARRAY_SIZE(eint_grp_save); i++, grp++) { 91 + __raw_writel(grp->con, S3C64XX_EINT12CON + (i * 4)); 92 + __raw_writel(grp->mask, S3C64XX_EINT12MASK + (i * 4)); 93 + __raw_writel(grp->fltcon, S3C64XX_EINT12FLTCON + (i * 4)); 94 + } 95 + 96 + S3C_PMDBG("%s: IRQ configuration restored\n", __func__); 97 + return 0; 98 + } 99 + 100 + static struct sysdev_driver s3c64xx_irq_driver = { 101 + .suspend = s3c64xx_irq_pm_suspend, 102 + .resume = s3c64xx_irq_pm_resume, 103 + }; 104 + 105 + static int __init s3c64xx_irq_pm_init(void) 106 + { 107 + return sysdev_driver_register(&s3c64xx_sysclass, &s3c64xx_irq_driver); 108 + } 109 + 110 + arch_initcall(s3c64xx_irq_pm_init); 111 +
+2 -3
arch/arm/plat-s3c64xx/irq.c
··· 14 14 15 15 #include <linux/kernel.h> 16 16 #include <linux/interrupt.h> 17 + #include <linux/serial_core.h> 17 18 #include <linux/irq.h> 18 19 #include <linux/io.h> 19 20 20 21 #include <asm/hardware/vic.h> 21 22 22 23 #include <mach/map.h> 24 + #include <plat/regs-serial.h> 23 25 #include <plat/regs-timer.h> 24 26 #include <plat/cpu.h> 25 27 ··· 137 135 } 138 136 139 137 /* UART interrupt registers, not worth adding to seperate include header */ 140 - #define S3C64XX_UINTP 0x30 141 - #define S3C64XX_UINTSP 0x34 142 - #define S3C64XX_UINTM 0x38 143 138 144 139 static void s3c_irq_uart_mask(unsigned int irq) 145 140 {