Loading arch/arm/plat-s3c/include/plat/pm.h +27 −0 Original line number Diff line number Diff line Loading @@ -113,3 +113,30 @@ extern void s3c_pm_check_store(void); #define s3c_pm_check_restore() do { } while(0) #define s3c_pm_check_store() do { } while(0) #endif /** * s3c_pm_configure_extint() - ensure pins are correctly set for IRQ * * Setup all the necessary GPIO pins for waking the system on external * interrupt. */ extern void s3c_pm_configure_extint(void); /** * s3c_pm_restore_gpios() - restore the state of the gpios after sleep. * * Restore the state of the GPIO pins after sleep, which may involve ensuring * that we do not glitch the state of the pins from that the bootloader's * resume code has done. */ extern void s3c_pm_restore_gpios(void); /** * s3c_pm_save_gpios() - save the state of the GPIOs for restoring after sleep. * * Save the GPIO states for resotration on resume. See s3c_pm_restore_gpios(). */ extern void s3c_pm_save_gpios(void); extern void s3c_pm_save_core(void); extern void s3c_pm_restore_core(void); arch/arm/plat-s3c/pm.c +211 −0 Original line number Diff line number Diff line Loading @@ -15,14 +15,32 @@ #include <linux/init.h> #include <linux/suspend.h> #include <linux/errno.h> #include <linux/delay.h> #include <linux/serial_core.h> #include <linux/io.h> #include <asm/cacheflush.h> #include <mach/hardware.h> #include <plat/regs-serial.h> #include <mach/regs-clock.h> #include <mach/regs-gpio.h> #include <mach/regs-mem.h> #include <mach/regs-irq.h> #include <plat/pm.h> #include <plat/pm-core.h> /* for external use */ unsigned long s3c_pm_flags; /* Debug code: * * This code supports debug output to the low level UARTs for use on * resume before the console layer is available. */ #ifdef CONFIG_S3C2410_PM_DEBUG extern void printascii(const char *); Loading @@ -37,8 +55,51 @@ void s3c_pm_dbg(const char *fmt, ...) printascii(buff); } static inline void s3c_pm_debug_init(void) { /* restart uart clocks so we can use them to output */ s3c_pm_debug_init_uart(); } #else #define s3c_pm_debug_init() do { } while(0) #endif /* CONFIG_S3C2410_PM_DEBUG */ /* Save the UART configurations if we are configured for debug. */ #ifdef CONFIG_S3C2410_PM_DEBUG #define SAVE_UART(va) \ SAVE_ITEM((va) + S3C2410_ULCON), \ SAVE_ITEM((va) + S3C2410_UCON), \ SAVE_ITEM((va) + S3C2410_UFCON), \ SAVE_ITEM((va) + S3C2410_UMCON), \ SAVE_ITEM((va) + S3C2410_UBRDIV) static struct sleep_save uart_save[] = { SAVE_UART(S3C_VA_UART0), SAVE_UART(S3C_VA_UART1), #ifndef CONFIG_CPU_S3C2400 SAVE_UART(S3C_VA_UART2), #endif }; static void s3c_pm_save_uart(void) { s3c_pm_do_save(uart_save, ARRAY_SIZE(uart_save)); } static void s3c_pm_restore_uart(void) { s3c_pm_do_restore(uart_save, ARRAY_SIZE(uart_save)); } #else static void s3c_pm_save_uart(void) { } static void s3c_pm_restore_uart(void) { } #endif /* helper functions to save and restore register state */ Loading Loading @@ -95,3 +156,153 @@ void s3c_pm_do_restore_core(struct sleep_save *ptr, int count) for (; count > 0; count--, ptr++) __raw_writel(ptr->val, ptr->reg); } /* s3c2410_pm_show_resume_irqs * * print any IRQs asserted at resume time (ie, we woke from) */ static void s3c_pm_show_resume_irqs(int start, unsigned long which, unsigned long mask) { int i; which &= ~mask; for (i = 0; i <= 31; i++) { if (which & (1L<<i)) { S3C_PMDBG("IRQ %d asserted at resume\n", start+i); } } } void (*pm_cpu_prep)(void); void (*pm_cpu_sleep)(void); #define any_allowed(mask, allow) (((mask) & (allow)) != (allow)) /* s3c_pm_enter * * central control for sleep/resume process */ static int s3c_pm_enter(suspend_state_t state) { unsigned long regs_save[16]; /* ensure the debug is initialised (if enabled) */ s3c_pm_debug_init(); S3C_PMDBG("%s(%d)\n", __func__, state); if (pm_cpu_prep == NULL || pm_cpu_sleep == NULL) { printk(KERN_ERR "%s: error: no cpu sleep function\n", __func__); return -EINVAL; } /* check if we have anything to wake-up with... bad things seem * to happen if you suspend with no wakeup (system will often * require a full power-cycle) */ if (!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) && !any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) { printk(KERN_ERR "%s: No wake-up sources!\n", __func__); printk(KERN_ERR "%s: Aborting sleep\n", __func__); return -EINVAL; } /* prepare check area if configured */ s3c_pm_check_prepare(); /* store the physical address of the register recovery block */ s3c_sleep_save_phys = virt_to_phys(regs_save); S3C_PMDBG("s3c_sleep_save_phys=0x%08lx\n", s3c_sleep_save_phys); /* save all necessary core registers not covered by the drivers */ s3c_pm_save_gpios(); s3c_pm_save_uart(); s3c_pm_save_core(); /* set the irq configuration for wake */ s3c_pm_configure_extint(); S3C_PMDBG("sleep: irq wakeup masks: %08lx,%08lx\n", s3c_irqwake_intmask, s3c_irqwake_eintmask); s3c_pm_arch_prepare_irqs(); /* call cpu specific preparation */ pm_cpu_prep(); /* flush cache back to ram */ flush_cache_all(); s3c_pm_check_store(); /* send the cpu to sleep... */ s3c_pm_arch_stop_clocks(); /* s3c2410_cpu_save will also act as our return point from when * we resume as it saves its own register state, so use the return * code to differentiate return from save and return from sleep */ if (s3c2410_cpu_save(regs_save) == 0) { flush_cache_all(); pm_cpu_sleep(); } /* restore the cpu state using the kernel's cpu init code. */ cpu_init(); /* restore the system state */ s3c_pm_restore_core(); s3c_pm_restore_uart(); s3c_pm_restore_gpios(); s3c_pm_debug_init(); /* check what irq (if any) restored the system */ s3c_pm_arch_show_resume_irqs(); S3C_PMDBG("%s: post sleep, preparing to return\n", __func__); s3c_pm_check_restore(); /* ok, let's return from sleep */ S3C_PMDBG("S3C PM Resume (post-restore)\n"); return 0; } static struct platform_suspend_ops s3c_pm_ops = { .enter = s3c_pm_enter, .valid = suspend_valid_only_mem, }; /* s3c2410_pm_init * * Attach the power management functions. This should be called * from the board specific initialisation if the board supports * it. */ int __init s3c2410_pm_init(void) { printk("S3C Power Management, Copyright 2004 Simtec Electronics\n"); suspend_set_ops(&s3c_pm_ops); return 0; } arch/arm/plat-s3c24xx/include/plat/pm-core.h 0 → 100644 +59 −0 Original line number Diff line number Diff line /* linux/arch/arm/plat-s3c24xx/include/plat/pll.h * * Copyright 2008 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> * http://armlinux.simtec.co.uk/ * * S3C24xx - PM core support for arch/arm/plat-s3c/pm.c * * 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. */ static inline void s3c_pm_debug_init_uart(void) { unsigned long tmp = __raw_readl(S3C2410_CLKCON); /* re-start uart clocks */ tmp |= S3C2410_CLKCON_UART0; tmp |= S3C2410_CLKCON_UART1; tmp |= S3C2410_CLKCON_UART2; __raw_writel(tmp, S3C2410_CLKCON); udelay(10); } static inline void s3c_pm_arch_prepare_irqs(void) { __raw_writel(s3c_irqwake_intmask, S3C2410_INTMSK); __raw_writel(s3c_irqwake_eintmask, S3C2410_EINTMASK); /* ack any outstanding external interrupts before we go to sleep */ __raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND); __raw_writel(__raw_readl(S3C2410_INTPND), S3C2410_INTPND); __raw_writel(__raw_readl(S3C2410_SRCPND), S3C2410_SRCPND); } static inline void s3c_pm_arch_stop_clocks(void) { __raw_writel(0x00, S3C2410_CLKCON); /* turn off clocks over sleep */ } static void s3c_pm_show_resume_irqs(int start, unsigned long which, unsigned long mask); static inline void s3c_pm_arch_show_resume_irqs(void) { S3C_PMDBG("post sleep: IRQs 0x%08x, 0x%08x\n", __raw_readl(S3C2410_SRCPND), __raw_readl(S3C2410_EINTPEND)); s3c_pm_show_resume_irqs(IRQ_EINT0, __raw_readl(S3C2410_SRCPND), s3c_irqwake_intmask); s3c_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND), s3c_irqwake_eintmask); } arch/arm/plat-s3c24xx/pm.c +14 −210 Original line number Diff line number Diff line Loading @@ -34,9 +34,6 @@ #include <linux/serial_core.h> #include <linux/io.h> #include <asm/cacheflush.h> #include <mach/hardware.h> #include <plat/regs-serial.h> #include <mach/regs-clock.h> #include <mach/regs-gpio.h> Loading @@ -47,7 +44,6 @@ #include <plat/pm.h> #define PFX "s3c24xx-pm: " static struct sleep_save core_save[] = { Loading Loading @@ -115,66 +111,6 @@ static struct sleep_save misc_save[] = { SAVE_ITEM(S3C2410_DCLKCON), }; #ifdef CONFIG_S3C2410_PM_DEBUG #define SAVE_UART(va) \ SAVE_ITEM((va) + S3C2410_ULCON), \ SAVE_ITEM((va) + S3C2410_UCON), \ SAVE_ITEM((va) + S3C2410_UFCON), \ SAVE_ITEM((va) + S3C2410_UMCON), \ SAVE_ITEM((va) + S3C2410_UBRDIV) static struct sleep_save uart_save[] = { SAVE_UART(S3C24XX_VA_UART0), SAVE_UART(S3C24XX_VA_UART1), #ifndef CONFIG_CPU_S3C2400 SAVE_UART(S3C24XX_VA_UART2), #endif }; /* debug * * we send the debug to printascii() to allow it to be seen if the * system never wakes up from the sleep */ static void s3c2410_pm_debug_init(void) { unsigned long tmp = __raw_readl(S3C2410_CLKCON); /* re-start uart clocks */ tmp |= S3C2410_CLKCON_UART0; tmp |= S3C2410_CLKCON_UART1; tmp |= S3C2410_CLKCON_UART2; __raw_writel(tmp, S3C2410_CLKCON); udelay(10); } #else #define s3c2410_pm_debug_init() do { } while(0) static struct sleep_save uart_save[] = {}; #endif /* s3c2410_pm_show_resume_irqs * * print any IRQs asserted at resume time (ie, we woke from) */ static void s3c2410_pm_show_resume_irqs(int start, unsigned long which, unsigned long mask) { int i; which &= ~mask; for (i = 0; i <= 31; i++) { if ((which) & (1L<<i)) { S3C_PMDBG("IRQ %d asserted at resume\n", start+i); } } } /* s3c_pm_check_resume_pin * Loading Loading @@ -206,12 +142,12 @@ static void s3c_pm_check_resume_pin(unsigned int pin, unsigned int irqoffs) } } /* s3c2410_pm_configure_extint /* s3c_pm_configure_extint * * configure all external interrupt pins */ static void s3c2410_pm_configure_extint(void) void s3c_pm_configure_extint(void) { int pin; Loading @@ -235,12 +171,12 @@ static void s3c2410_pm_configure_extint(void) #define OFFS_DAT (S3C2410_GPADAT - S3C2410_GPACON) #define OFFS_UP (S3C2410_GPBUP - S3C2410_GPBCON) /* s3c2410_pm_save_gpios() /* s3c_pm_save_gpios() * * Save the state of the GPIOs */ static void s3c2410_pm_save_gpios(void) void s3c_pm_save_gpios(void) { struct gpio_sleep *gps = gpio_save; unsigned int gpio; Loading Loading @@ -279,7 +215,10 @@ static inline int is_out(unsigned long con) return con == 1; } /* s3c2410_pm_restore_gpio() /** * s3c2410_pm_restore_gpio() - restore the given GPIO bank * @index: The number of the GPIO bank being resumed. * @gps: The sleep confgiuration for the bank. * * Restore one of the GPIO banks that was saved during suspend. This is * not as simple as once thought, due to the possibility of glitches Loading Loading @@ -397,7 +336,7 @@ static void s3c2410_pm_restore_gpio(int index, struct gpio_sleep *gps) * Restore the state of the GPIOs */ static void s3c2410_pm_restore_gpios(void) void s3c_pm_restore_gpios(void) { struct gpio_sleep *gps = gpio_save; int gpio; Loading @@ -407,150 +346,15 @@ static void s3c2410_pm_restore_gpios(void) } } void (*pm_cpu_prep)(void); void (*pm_cpu_sleep)(void); #define any_allowed(mask, allow) (((mask) & (allow)) != (allow)) /* s3c2410_pm_enter * * central control for sleep/resume process */ static int s3c2410_pm_enter(suspend_state_t state) void s3c_pm_restore_core(void) { unsigned long regs_save[16]; /* ensure the debug is initialised (if enabled) */ s3c2410_pm_debug_init(); S3C_PMDBG("s3c2410_pm_enter(%d)\n", state); if (pm_cpu_prep == NULL || pm_cpu_sleep == NULL) { printk(KERN_ERR PFX "error: no cpu sleep functions set\n"); return -EINVAL; } /* check if we have anything to wake-up with... bad things seem * to happen if you suspend with no wakeup (system will often * require a full power-cycle) */ if (!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) && !any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) { printk(KERN_ERR PFX "No sources enabled for wake-up!\n"); printk(KERN_ERR PFX "Aborting sleep\n"); return -EINVAL; } /* prepare check area if configured */ s3c_pm_check_prepare(); /* store the physical address of the register recovery block */ s3c_sleep_save_phys = virt_to_phys(regs_save); S3C_PMDBG("s3c_sleep_save_phys=0x%08lx\n", s3c_sleep_save_phys); /* save all necessary core registers not covered by the drivers */ s3c2410_pm_save_gpios(); s3c_pm_do_save(misc_save, ARRAY_SIZE(misc_save)); s3c_pm_do_save(core_save, ARRAY_SIZE(core_save)); s3c_pm_do_save(uart_save, ARRAY_SIZE(uart_save)); /* set the irq configuration for wake */ s3c2410_pm_configure_extint(); S3C_PMDBG("sleep: irq wakeup masks: %08lx,%08lx\n", s3c_irqwake_intmask, s3c_irqwake_eintmask); __raw_writel(s3c_irqwake_intmask, S3C2410_INTMSK); __raw_writel(s3c_irqwake_eintmask, S3C2410_EINTMASK); /* ack any outstanding external interrupts before we go to sleep */ __raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND); __raw_writel(__raw_readl(S3C2410_INTPND), S3C2410_INTPND); __raw_writel(__raw_readl(S3C2410_SRCPND), S3C2410_SRCPND); /* call cpu specific preparation */ pm_cpu_prep(); /* flush cache back to ram */ flush_cache_all(); s3c_pm_check_store(); /* send the cpu to sleep... */ __raw_writel(0x00, S3C2410_CLKCON); /* turn off clocks over sleep */ /* s3c2410_cpu_save will also act as our return point from when * we resume as it saves its own register state, so use the return * code to differentiate return from save and return from sleep */ if (s3c2410_cpu_save(regs_save) == 0) { flush_cache_all(); pm_cpu_sleep(); } /* restore the cpu state */ cpu_init(); /* restore the system state */ s3c_pm_do_restore_core(core_save, ARRAY_SIZE(core_save)); s3c_pm_do_restore(misc_save, ARRAY_SIZE(misc_save)); s3c_pm_do_restore(uart_save, ARRAY_SIZE(uart_save)); s3c2410_pm_restore_gpios(); s3c2410_pm_debug_init(); /* check what irq (if any) restored the system */ S3C_PMDBG("post sleep: IRQs 0x%08x, 0x%08x\n", __raw_readl(S3C2410_SRCPND), __raw_readl(S3C2410_EINTPEND)); s3c2410_pm_show_resume_irqs(IRQ_EINT0, __raw_readl(S3C2410_SRCPND), s3c_irqwake_intmask); s3c2410_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND), s3c_irqwake_eintmask); S3C_PMDBG("post sleep, preparing to return\n"); s3c_pm_check_restore(); /* ok, let's return from sleep */ S3C_PMDBG("S3C2410 PM Resume (post-restore)\n"); return 0; } static struct platform_suspend_ops s3c2410_pm_ops = { .enter = s3c2410_pm_enter, .valid = suspend_valid_only_mem, }; /* s3c2410_pm_init * * Attach the power management functions. This should be called * from the board specific initialisation if the board supports * it. */ int __init s3c2410_pm_init(void) void s3c_pm_save_core(void) { printk("S3C2410 Power Management, (c) 2004 Simtec Electronics\n"); suspend_set_ops(&s3c2410_pm_ops); return 0; s3c_pm_do_save(misc_save, ARRAY_SIZE(misc_save)); s3c_pm_do_save(core_save, ARRAY_SIZE(core_save)); } Loading
arch/arm/plat-s3c/include/plat/pm.h +27 −0 Original line number Diff line number Diff line Loading @@ -113,3 +113,30 @@ extern void s3c_pm_check_store(void); #define s3c_pm_check_restore() do { } while(0) #define s3c_pm_check_store() do { } while(0) #endif /** * s3c_pm_configure_extint() - ensure pins are correctly set for IRQ * * Setup all the necessary GPIO pins for waking the system on external * interrupt. */ extern void s3c_pm_configure_extint(void); /** * s3c_pm_restore_gpios() - restore the state of the gpios after sleep. * * Restore the state of the GPIO pins after sleep, which may involve ensuring * that we do not glitch the state of the pins from that the bootloader's * resume code has done. */ extern void s3c_pm_restore_gpios(void); /** * s3c_pm_save_gpios() - save the state of the GPIOs for restoring after sleep. * * Save the GPIO states for resotration on resume. See s3c_pm_restore_gpios(). */ extern void s3c_pm_save_gpios(void); extern void s3c_pm_save_core(void); extern void s3c_pm_restore_core(void);
arch/arm/plat-s3c/pm.c +211 −0 Original line number Diff line number Diff line Loading @@ -15,14 +15,32 @@ #include <linux/init.h> #include <linux/suspend.h> #include <linux/errno.h> #include <linux/delay.h> #include <linux/serial_core.h> #include <linux/io.h> #include <asm/cacheflush.h> #include <mach/hardware.h> #include <plat/regs-serial.h> #include <mach/regs-clock.h> #include <mach/regs-gpio.h> #include <mach/regs-mem.h> #include <mach/regs-irq.h> #include <plat/pm.h> #include <plat/pm-core.h> /* for external use */ unsigned long s3c_pm_flags; /* Debug code: * * This code supports debug output to the low level UARTs for use on * resume before the console layer is available. */ #ifdef CONFIG_S3C2410_PM_DEBUG extern void printascii(const char *); Loading @@ -37,8 +55,51 @@ void s3c_pm_dbg(const char *fmt, ...) printascii(buff); } static inline void s3c_pm_debug_init(void) { /* restart uart clocks so we can use them to output */ s3c_pm_debug_init_uart(); } #else #define s3c_pm_debug_init() do { } while(0) #endif /* CONFIG_S3C2410_PM_DEBUG */ /* Save the UART configurations if we are configured for debug. */ #ifdef CONFIG_S3C2410_PM_DEBUG #define SAVE_UART(va) \ SAVE_ITEM((va) + S3C2410_ULCON), \ SAVE_ITEM((va) + S3C2410_UCON), \ SAVE_ITEM((va) + S3C2410_UFCON), \ SAVE_ITEM((va) + S3C2410_UMCON), \ SAVE_ITEM((va) + S3C2410_UBRDIV) static struct sleep_save uart_save[] = { SAVE_UART(S3C_VA_UART0), SAVE_UART(S3C_VA_UART1), #ifndef CONFIG_CPU_S3C2400 SAVE_UART(S3C_VA_UART2), #endif }; static void s3c_pm_save_uart(void) { s3c_pm_do_save(uart_save, ARRAY_SIZE(uart_save)); } static void s3c_pm_restore_uart(void) { s3c_pm_do_restore(uart_save, ARRAY_SIZE(uart_save)); } #else static void s3c_pm_save_uart(void) { } static void s3c_pm_restore_uart(void) { } #endif /* helper functions to save and restore register state */ Loading Loading @@ -95,3 +156,153 @@ void s3c_pm_do_restore_core(struct sleep_save *ptr, int count) for (; count > 0; count--, ptr++) __raw_writel(ptr->val, ptr->reg); } /* s3c2410_pm_show_resume_irqs * * print any IRQs asserted at resume time (ie, we woke from) */ static void s3c_pm_show_resume_irqs(int start, unsigned long which, unsigned long mask) { int i; which &= ~mask; for (i = 0; i <= 31; i++) { if (which & (1L<<i)) { S3C_PMDBG("IRQ %d asserted at resume\n", start+i); } } } void (*pm_cpu_prep)(void); void (*pm_cpu_sleep)(void); #define any_allowed(mask, allow) (((mask) & (allow)) != (allow)) /* s3c_pm_enter * * central control for sleep/resume process */ static int s3c_pm_enter(suspend_state_t state) { unsigned long regs_save[16]; /* ensure the debug is initialised (if enabled) */ s3c_pm_debug_init(); S3C_PMDBG("%s(%d)\n", __func__, state); if (pm_cpu_prep == NULL || pm_cpu_sleep == NULL) { printk(KERN_ERR "%s: error: no cpu sleep function\n", __func__); return -EINVAL; } /* check if we have anything to wake-up with... bad things seem * to happen if you suspend with no wakeup (system will often * require a full power-cycle) */ if (!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) && !any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) { printk(KERN_ERR "%s: No wake-up sources!\n", __func__); printk(KERN_ERR "%s: Aborting sleep\n", __func__); return -EINVAL; } /* prepare check area if configured */ s3c_pm_check_prepare(); /* store the physical address of the register recovery block */ s3c_sleep_save_phys = virt_to_phys(regs_save); S3C_PMDBG("s3c_sleep_save_phys=0x%08lx\n", s3c_sleep_save_phys); /* save all necessary core registers not covered by the drivers */ s3c_pm_save_gpios(); s3c_pm_save_uart(); s3c_pm_save_core(); /* set the irq configuration for wake */ s3c_pm_configure_extint(); S3C_PMDBG("sleep: irq wakeup masks: %08lx,%08lx\n", s3c_irqwake_intmask, s3c_irqwake_eintmask); s3c_pm_arch_prepare_irqs(); /* call cpu specific preparation */ pm_cpu_prep(); /* flush cache back to ram */ flush_cache_all(); s3c_pm_check_store(); /* send the cpu to sleep... */ s3c_pm_arch_stop_clocks(); /* s3c2410_cpu_save will also act as our return point from when * we resume as it saves its own register state, so use the return * code to differentiate return from save and return from sleep */ if (s3c2410_cpu_save(regs_save) == 0) { flush_cache_all(); pm_cpu_sleep(); } /* restore the cpu state using the kernel's cpu init code. */ cpu_init(); /* restore the system state */ s3c_pm_restore_core(); s3c_pm_restore_uart(); s3c_pm_restore_gpios(); s3c_pm_debug_init(); /* check what irq (if any) restored the system */ s3c_pm_arch_show_resume_irqs(); S3C_PMDBG("%s: post sleep, preparing to return\n", __func__); s3c_pm_check_restore(); /* ok, let's return from sleep */ S3C_PMDBG("S3C PM Resume (post-restore)\n"); return 0; } static struct platform_suspend_ops s3c_pm_ops = { .enter = s3c_pm_enter, .valid = suspend_valid_only_mem, }; /* s3c2410_pm_init * * Attach the power management functions. This should be called * from the board specific initialisation if the board supports * it. */ int __init s3c2410_pm_init(void) { printk("S3C Power Management, Copyright 2004 Simtec Electronics\n"); suspend_set_ops(&s3c_pm_ops); return 0; }
arch/arm/plat-s3c24xx/include/plat/pm-core.h 0 → 100644 +59 −0 Original line number Diff line number Diff line /* linux/arch/arm/plat-s3c24xx/include/plat/pll.h * * Copyright 2008 Simtec Electronics * Ben Dooks <ben@simtec.co.uk> * http://armlinux.simtec.co.uk/ * * S3C24xx - PM core support for arch/arm/plat-s3c/pm.c * * 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. */ static inline void s3c_pm_debug_init_uart(void) { unsigned long tmp = __raw_readl(S3C2410_CLKCON); /* re-start uart clocks */ tmp |= S3C2410_CLKCON_UART0; tmp |= S3C2410_CLKCON_UART1; tmp |= S3C2410_CLKCON_UART2; __raw_writel(tmp, S3C2410_CLKCON); udelay(10); } static inline void s3c_pm_arch_prepare_irqs(void) { __raw_writel(s3c_irqwake_intmask, S3C2410_INTMSK); __raw_writel(s3c_irqwake_eintmask, S3C2410_EINTMASK); /* ack any outstanding external interrupts before we go to sleep */ __raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND); __raw_writel(__raw_readl(S3C2410_INTPND), S3C2410_INTPND); __raw_writel(__raw_readl(S3C2410_SRCPND), S3C2410_SRCPND); } static inline void s3c_pm_arch_stop_clocks(void) { __raw_writel(0x00, S3C2410_CLKCON); /* turn off clocks over sleep */ } static void s3c_pm_show_resume_irqs(int start, unsigned long which, unsigned long mask); static inline void s3c_pm_arch_show_resume_irqs(void) { S3C_PMDBG("post sleep: IRQs 0x%08x, 0x%08x\n", __raw_readl(S3C2410_SRCPND), __raw_readl(S3C2410_EINTPEND)); s3c_pm_show_resume_irqs(IRQ_EINT0, __raw_readl(S3C2410_SRCPND), s3c_irqwake_intmask); s3c_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND), s3c_irqwake_eintmask); }
arch/arm/plat-s3c24xx/pm.c +14 −210 Original line number Diff line number Diff line Loading @@ -34,9 +34,6 @@ #include <linux/serial_core.h> #include <linux/io.h> #include <asm/cacheflush.h> #include <mach/hardware.h> #include <plat/regs-serial.h> #include <mach/regs-clock.h> #include <mach/regs-gpio.h> Loading @@ -47,7 +44,6 @@ #include <plat/pm.h> #define PFX "s3c24xx-pm: " static struct sleep_save core_save[] = { Loading Loading @@ -115,66 +111,6 @@ static struct sleep_save misc_save[] = { SAVE_ITEM(S3C2410_DCLKCON), }; #ifdef CONFIG_S3C2410_PM_DEBUG #define SAVE_UART(va) \ SAVE_ITEM((va) + S3C2410_ULCON), \ SAVE_ITEM((va) + S3C2410_UCON), \ SAVE_ITEM((va) + S3C2410_UFCON), \ SAVE_ITEM((va) + S3C2410_UMCON), \ SAVE_ITEM((va) + S3C2410_UBRDIV) static struct sleep_save uart_save[] = { SAVE_UART(S3C24XX_VA_UART0), SAVE_UART(S3C24XX_VA_UART1), #ifndef CONFIG_CPU_S3C2400 SAVE_UART(S3C24XX_VA_UART2), #endif }; /* debug * * we send the debug to printascii() to allow it to be seen if the * system never wakes up from the sleep */ static void s3c2410_pm_debug_init(void) { unsigned long tmp = __raw_readl(S3C2410_CLKCON); /* re-start uart clocks */ tmp |= S3C2410_CLKCON_UART0; tmp |= S3C2410_CLKCON_UART1; tmp |= S3C2410_CLKCON_UART2; __raw_writel(tmp, S3C2410_CLKCON); udelay(10); } #else #define s3c2410_pm_debug_init() do { } while(0) static struct sleep_save uart_save[] = {}; #endif /* s3c2410_pm_show_resume_irqs * * print any IRQs asserted at resume time (ie, we woke from) */ static void s3c2410_pm_show_resume_irqs(int start, unsigned long which, unsigned long mask) { int i; which &= ~mask; for (i = 0; i <= 31; i++) { if ((which) & (1L<<i)) { S3C_PMDBG("IRQ %d asserted at resume\n", start+i); } } } /* s3c_pm_check_resume_pin * Loading Loading @@ -206,12 +142,12 @@ static void s3c_pm_check_resume_pin(unsigned int pin, unsigned int irqoffs) } } /* s3c2410_pm_configure_extint /* s3c_pm_configure_extint * * configure all external interrupt pins */ static void s3c2410_pm_configure_extint(void) void s3c_pm_configure_extint(void) { int pin; Loading @@ -235,12 +171,12 @@ static void s3c2410_pm_configure_extint(void) #define OFFS_DAT (S3C2410_GPADAT - S3C2410_GPACON) #define OFFS_UP (S3C2410_GPBUP - S3C2410_GPBCON) /* s3c2410_pm_save_gpios() /* s3c_pm_save_gpios() * * Save the state of the GPIOs */ static void s3c2410_pm_save_gpios(void) void s3c_pm_save_gpios(void) { struct gpio_sleep *gps = gpio_save; unsigned int gpio; Loading Loading @@ -279,7 +215,10 @@ static inline int is_out(unsigned long con) return con == 1; } /* s3c2410_pm_restore_gpio() /** * s3c2410_pm_restore_gpio() - restore the given GPIO bank * @index: The number of the GPIO bank being resumed. * @gps: The sleep confgiuration for the bank. * * Restore one of the GPIO banks that was saved during suspend. This is * not as simple as once thought, due to the possibility of glitches Loading Loading @@ -397,7 +336,7 @@ static void s3c2410_pm_restore_gpio(int index, struct gpio_sleep *gps) * Restore the state of the GPIOs */ static void s3c2410_pm_restore_gpios(void) void s3c_pm_restore_gpios(void) { struct gpio_sleep *gps = gpio_save; int gpio; Loading @@ -407,150 +346,15 @@ static void s3c2410_pm_restore_gpios(void) } } void (*pm_cpu_prep)(void); void (*pm_cpu_sleep)(void); #define any_allowed(mask, allow) (((mask) & (allow)) != (allow)) /* s3c2410_pm_enter * * central control for sleep/resume process */ static int s3c2410_pm_enter(suspend_state_t state) void s3c_pm_restore_core(void) { unsigned long regs_save[16]; /* ensure the debug is initialised (if enabled) */ s3c2410_pm_debug_init(); S3C_PMDBG("s3c2410_pm_enter(%d)\n", state); if (pm_cpu_prep == NULL || pm_cpu_sleep == NULL) { printk(KERN_ERR PFX "error: no cpu sleep functions set\n"); return -EINVAL; } /* check if we have anything to wake-up with... bad things seem * to happen if you suspend with no wakeup (system will often * require a full power-cycle) */ if (!any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) && !any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) { printk(KERN_ERR PFX "No sources enabled for wake-up!\n"); printk(KERN_ERR PFX "Aborting sleep\n"); return -EINVAL; } /* prepare check area if configured */ s3c_pm_check_prepare(); /* store the physical address of the register recovery block */ s3c_sleep_save_phys = virt_to_phys(regs_save); S3C_PMDBG("s3c_sleep_save_phys=0x%08lx\n", s3c_sleep_save_phys); /* save all necessary core registers not covered by the drivers */ s3c2410_pm_save_gpios(); s3c_pm_do_save(misc_save, ARRAY_SIZE(misc_save)); s3c_pm_do_save(core_save, ARRAY_SIZE(core_save)); s3c_pm_do_save(uart_save, ARRAY_SIZE(uart_save)); /* set the irq configuration for wake */ s3c2410_pm_configure_extint(); S3C_PMDBG("sleep: irq wakeup masks: %08lx,%08lx\n", s3c_irqwake_intmask, s3c_irqwake_eintmask); __raw_writel(s3c_irqwake_intmask, S3C2410_INTMSK); __raw_writel(s3c_irqwake_eintmask, S3C2410_EINTMASK); /* ack any outstanding external interrupts before we go to sleep */ __raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND); __raw_writel(__raw_readl(S3C2410_INTPND), S3C2410_INTPND); __raw_writel(__raw_readl(S3C2410_SRCPND), S3C2410_SRCPND); /* call cpu specific preparation */ pm_cpu_prep(); /* flush cache back to ram */ flush_cache_all(); s3c_pm_check_store(); /* send the cpu to sleep... */ __raw_writel(0x00, S3C2410_CLKCON); /* turn off clocks over sleep */ /* s3c2410_cpu_save will also act as our return point from when * we resume as it saves its own register state, so use the return * code to differentiate return from save and return from sleep */ if (s3c2410_cpu_save(regs_save) == 0) { flush_cache_all(); pm_cpu_sleep(); } /* restore the cpu state */ cpu_init(); /* restore the system state */ s3c_pm_do_restore_core(core_save, ARRAY_SIZE(core_save)); s3c_pm_do_restore(misc_save, ARRAY_SIZE(misc_save)); s3c_pm_do_restore(uart_save, ARRAY_SIZE(uart_save)); s3c2410_pm_restore_gpios(); s3c2410_pm_debug_init(); /* check what irq (if any) restored the system */ S3C_PMDBG("post sleep: IRQs 0x%08x, 0x%08x\n", __raw_readl(S3C2410_SRCPND), __raw_readl(S3C2410_EINTPEND)); s3c2410_pm_show_resume_irqs(IRQ_EINT0, __raw_readl(S3C2410_SRCPND), s3c_irqwake_intmask); s3c2410_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND), s3c_irqwake_eintmask); S3C_PMDBG("post sleep, preparing to return\n"); s3c_pm_check_restore(); /* ok, let's return from sleep */ S3C_PMDBG("S3C2410 PM Resume (post-restore)\n"); return 0; } static struct platform_suspend_ops s3c2410_pm_ops = { .enter = s3c2410_pm_enter, .valid = suspend_valid_only_mem, }; /* s3c2410_pm_init * * Attach the power management functions. This should be called * from the board specific initialisation if the board supports * it. */ int __init s3c2410_pm_init(void) void s3c_pm_save_core(void) { printk("S3C2410 Power Management, (c) 2004 Simtec Electronics\n"); suspend_set_ops(&s3c2410_pm_ops); return 0; s3c_pm_do_save(misc_save, ARRAY_SIZE(misc_save)); s3c_pm_do_save(core_save, ARRAY_SIZE(core_save)); }