omap: Split i2c platform init for mach-omap1 and mach-omap2
[safe/jmp/linux-2.6] / arch / arm / plat-s3c / pm.c
index e320b0f..7674706 100644 (file)
@@ -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 <ben@simtec.co.uk>
  *     http://armlinux.simtec.co.uk/
  *
 
 #include <asm/cacheflush.h>
 #include <mach/hardware.h>
+#include <mach/map.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 <asm/irq.h>
 
@@ -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,
 };