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/* 16 * NOTE: Code in this file is not used when booting with Device Tree support. 17 */ 18 19#include <linux/kernel.h> 20#include <linux/syscore_ops.h> 21#include <linux/interrupt.h> 22#include <linux/serial_core.h> 23#include <linux/serial_s3c.h> 24#include <linux/irq.h> 25#include <linux/io.h> 26#include <linux/of.h> 27 28#include <mach/map.h> 29 30#include <mach/regs-gpio.h> 31#include <plat/cpu.h> 32#include <plat/pm.h> 33 34/* We handled all the IRQ types in this code, to save having to make several 35 * small files to handle each different type separately. Having the EINT_GRP 36 * code here shouldn't be as much bloat as the IRQ table space needed when 37 * they are enabled. The added benefit is we ensure that these registers are 38 * in the same state as we suspended. 39 */ 40 41static struct sleep_save irq_save[] = { 42 SAVE_ITEM(S3C64XX_PRIORITY), 43 SAVE_ITEM(S3C64XX_EINT0CON0), 44 SAVE_ITEM(S3C64XX_EINT0CON1), 45 SAVE_ITEM(S3C64XX_EINT0FLTCON0), 46 SAVE_ITEM(S3C64XX_EINT0FLTCON1), 47 SAVE_ITEM(S3C64XX_EINT0FLTCON2), 48 SAVE_ITEM(S3C64XX_EINT0FLTCON3), 49 SAVE_ITEM(S3C64XX_EINT0MASK), 50}; 51 52static struct irq_grp_save { 53 u32 fltcon; 54 u32 con; 55 u32 mask; 56} eint_grp_save[5]; 57 58#ifndef CONFIG_SERIAL_SAMSUNG_UARTS 59#define SERIAL_SAMSUNG_UARTS 0 60#else 61#define SERIAL_SAMSUNG_UARTS CONFIG_SERIAL_SAMSUNG_UARTS 62#endif 63 64static u32 irq_uart_mask[SERIAL_SAMSUNG_UARTS]; 65 66static int s3c64xx_irq_pm_suspend(void) 67{ 68 struct irq_grp_save *grp = eint_grp_save; 69 int i; 70 71 S3C_PMDBG("%s: suspending IRQs\n", __func__); 72 73 s3c_pm_do_save(irq_save, ARRAY_SIZE(irq_save)); 74 75 for (i = 0; i < SERIAL_SAMSUNG_UARTS; i++) 76 irq_uart_mask[i] = __raw_readl(S3C_VA_UARTx(i) + S3C64XX_UINTM); 77 78 for (i = 0; i < ARRAY_SIZE(eint_grp_save); i++, grp++) { 79 grp->con = __raw_readl(S3C64XX_EINT12CON + (i * 4)); 80 grp->mask = __raw_readl(S3C64XX_EINT12MASK + (i * 4)); 81 grp->fltcon = __raw_readl(S3C64XX_EINT12FLTCON + (i * 4)); 82 } 83 84 return 0; 85} 86 87static void s3c64xx_irq_pm_resume(void) 88{ 89 struct irq_grp_save *grp = eint_grp_save; 90 int i; 91 92 S3C_PMDBG("%s: resuming IRQs\n", __func__); 93 94 s3c_pm_do_restore(irq_save, ARRAY_SIZE(irq_save)); 95 96 for (i = 0; i < SERIAL_SAMSUNG_UARTS; i++) 97 __raw_writel(irq_uart_mask[i], S3C_VA_UARTx(i) + S3C64XX_UINTM); 98 99 for (i = 0; i < ARRAY_SIZE(eint_grp_save); i++, grp++) { 100 __raw_writel(grp->con, S3C64XX_EINT12CON + (i * 4)); 101 __raw_writel(grp->mask, S3C64XX_EINT12MASK + (i * 4)); 102 __raw_writel(grp->fltcon, S3C64XX_EINT12FLTCON + (i * 4)); 103 } 104 105 S3C_PMDBG("%s: IRQ configuration restored\n", __func__); 106} 107 108static struct syscore_ops s3c64xx_irq_syscore_ops = { 109 .suspend = s3c64xx_irq_pm_suspend, 110 .resume = s3c64xx_irq_pm_resume, 111}; 112 113static __init int s3c64xx_syscore_init(void) 114{ 115 /* Appropriate drivers (pinctrl, uart) handle this when using DT. */ 116 if (of_have_populated_dt()) 117 return 0; 118 119 register_syscore_ops(&s3c64xx_irq_syscore_ops); 120 121 return 0; 122} 123 124core_initcall(s3c64xx_syscore_init); 125