[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>
This commit is contained in:
parent
1deb507dc7
commit
966bcc1438
@ -189,6 +189,11 @@
|
||||
|
||||
#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
|
||||
|
@ -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
|
||||
|
||||
|
111
arch/arm/plat-s3c64xx/irq-pm.c
Normal file
111
arch/arm/plat-s3c64xx/irq-pm.c
Normal file
@ -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);
|
||||
|
@ -14,12 +14,14 @@
|
||||
|
||||
#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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user