X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=arch%2Farm%2Fplat-s3c%2Fpm.c;h=767470601e5c392481d25ceb88e501661f212482;hb=b63128e81214cc2db2995d690438055c26d213a5;hp=e320b0ff385225cafacb4a8786163fb26c832e61;hpb=ef30e14420df546bc6576b00f9caf3379b6699d1;p=safe%2Fjmp%2Flinux-2.6 diff --git a/arch/arm/plat-s3c/pm.c b/arch/arm/plat-s3c/pm.c index e320b0f..7674706 100644 --- a/arch/arm/plat-s3c/pm.c +++ b/arch/arm/plat-s3c/pm.c @@ -1,7 +1,7 @@ /* linux/arch/arm/plat-s3c/pm.c * * Copyright 2008 Openmoko, Inc. - * Copyright 2004,2006,2008 Simtec Electronics + * Copyright 2004-2008 Simtec Electronics * Ben Dooks * http://armlinux.simtec.co.uk/ * @@ -21,11 +21,10 @@ #include #include +#include #include #include -#include -#include #include #include @@ -70,35 +69,65 @@ static inline void s3c_pm_debug_init(void) /* Save the UART configurations if we are configured for debug. */ +unsigned char pm_uart_udivslot; + #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 -}; +struct pm_uart_save uart_save[CONFIG_SERIAL_SAMSUNG_UARTS]; -static void s3c_pm_save_uart(void) +static void s3c_pm_save_uart(unsigned int uart, struct pm_uart_save *save) { - s3c_pm_do_save(uart_save, ARRAY_SIZE(uart_save)); + void __iomem *regs = S3C_VA_UARTx(uart); + + save->ulcon = __raw_readl(regs + S3C2410_ULCON); + save->ucon = __raw_readl(regs + S3C2410_UCON); + save->ufcon = __raw_readl(regs + S3C2410_UFCON); + save->umcon = __raw_readl(regs + S3C2410_UMCON); + save->ubrdiv = __raw_readl(regs + S3C2410_UBRDIV); + + if (pm_uart_udivslot) + save->udivslot = __raw_readl(regs + S3C2443_DIVSLOT); + + S3C_PMDBG("UART[%d]: ULCON=%04x, UCON=%04x, UFCON=%04x, UBRDIV=%04x\n", + uart, save->ulcon, save->ucon, save->ufcon, save->ubrdiv); } -static void s3c_pm_restore_uart(void) +static void s3c_pm_save_uarts(void) { - s3c_pm_do_restore(uart_save, ARRAY_SIZE(uart_save)); + struct pm_uart_save *save = uart_save; + unsigned int uart; + + for (uart = 0; uart < CONFIG_SERIAL_SAMSUNG_UARTS; uart++, save++) + s3c_pm_save_uart(uart, save); +} + +static void s3c_pm_restore_uart(unsigned int uart, struct pm_uart_save *save) +{ + void __iomem *regs = S3C_VA_UARTx(uart); + + s3c_pm_arch_update_uart(regs, save); + + __raw_writel(save->ulcon, regs + S3C2410_ULCON); + __raw_writel(save->ucon, regs + S3C2410_UCON); + __raw_writel(save->ufcon, regs + S3C2410_UFCON); + __raw_writel(save->umcon, regs + S3C2410_UMCON); + __raw_writel(save->ubrdiv, regs + S3C2410_UBRDIV); + + if (pm_uart_udivslot) + __raw_writel(save->udivslot, regs + S3C2443_DIVSLOT); +} + +static void s3c_pm_restore_uarts(void) +{ + struct pm_uart_save *save = uart_save; + unsigned int uart; + + for (uart = 0; uart < CONFIG_SERIAL_SAMSUNG_UARTS; uart++, save++) + s3c_pm_restore_uart(uart, save); } #else -static void s3c_pm_save_uart(void) { } -static void s3c_pm_restore_uart(void) { } +static void s3c_pm_save_uarts(void) { } +static void s3c_pm_restore_uarts(void) { } #endif /* The IRQ ext-int code goes here, it is too small to currently bother @@ -212,7 +241,7 @@ void (*pm_cpu_sleep)(void); static int s3c_pm_enter(suspend_state_t state) { - unsigned long regs_save[16]; + static unsigned long regs_save[16]; /* ensure the debug is initialised (if enabled) */ @@ -237,10 +266,6 @@ static int s3c_pm_enter(suspend_state_t state) 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); @@ -250,7 +275,7 @@ static int s3c_pm_enter(suspend_state_t state) /* save all necessary core registers not covered by the drivers */ s3c_pm_save_gpios(); - s3c_pm_save_uart(); + s3c_pm_save_uarts(); s3c_pm_save_core(); /* set the irq configuration for wake */ @@ -276,15 +301,11 @@ static int s3c_pm_enter(suspend_state_t state) 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 */ + /* s3c_cpu_save will also act as our return point from when + * we resume as it saves its own register state and restores it + * during the resume. */ - if (s3c_cpu_save(regs_save) == 0) { - flush_cache_all(); - S3C_PMDBG("preparing to sleep\n"); - pm_cpu_sleep(); - } + s3c_cpu_save(regs_save); /* restore the cpu state using the kernel's cpu init code. */ @@ -293,7 +314,7 @@ static int s3c_pm_enter(suspend_state_t state) /* restore the system state */ s3c_pm_restore_core(); - s3c_pm_restore_uart(); + s3c_pm_restore_uarts(); s3c_pm_restore_gpios(); s3c_pm_debug_init(); @@ -304,6 +325,9 @@ static int s3c_pm_enter(suspend_state_t state) S3C_PMDBG("%s: post sleep, preparing to return\n", __func__); + /* LEDs should now be 1110 */ + s3c_pm_debug_smdkled(1 << 1, 0); + s3c_pm_check_restore(); /* ok, let's return from sleep */ @@ -312,8 +336,29 @@ static int s3c_pm_enter(suspend_state_t state) return 0; } +/* callback from assembly code */ +void s3c_pm_cb_flushcache(void) +{ + flush_cache_all(); +} + +static int s3c_pm_prepare(void) +{ + /* prepare check area if configured */ + + s3c_pm_check_prepare(); + return 0; +} + +static void s3c_pm_finish(void) +{ + s3c_pm_check_cleanup(); +} + static struct platform_suspend_ops s3c_pm_ops = { .enter = s3c_pm_enter, + .prepare = s3c_pm_prepare, + .finish = s3c_pm_finish, .valid = suspend_valid_only_mem, };