[ARM] S3C: Update UART save over PM suspend/resume
authorBen Dooks <ben-linux@fluff.org>
Fri, 12 Dec 2008 00:24:20 +0000 (00:24 +0000)
committerBen Dooks <ben-linux@fluff.org>
Sun, 8 Mar 2009 12:37:10 +0000 (12:37 +0000)
Change the way the UART state is saved over suspend to allow the s3c64xx
code to modify the settings on resume to avoid any illegal state changes
to the UART clocks. This will also allow us to save the UDIVSLOT register
on newer SoCs.

Move to using a structure for the UART use the extant Kconfig configuration
specifying the number of UARTs.

Signed-off-by: Ben Dooks <ben-linux@fluff.org>
arch/arm/plat-s3c/include/plat/pm.h
arch/arm/plat-s3c/pm.c
arch/arm/plat-s3c24xx/include/plat/map.h

index f121a5a..c27b8cf 100644 (file)
@@ -71,6 +71,25 @@ struct sleep_save {
 #define SAVE_ITEM(x) \
        { .reg = (x) }
 
+/**
+ * struct pm_uart_save - save block for core UART
+ * @ulcon: Save value for S3C2410_ULCON
+ * @ucon: Save value for S3C2410_UCON
+ * @ufcon: Save value for S3C2410_UFCON
+ * @umcon: Save value for S3C2410_UMCON
+ * @ubrdiv: Save value for S3C2410_UBRDIV
+ *
+ * Save block for UART registers to be held over sleep and restored if they
+ * are needed (say by debug).
+*/
+struct pm_uart_save {
+       u32     ulcon;
+       u32     ucon;
+       u32     ufcon;
+       u32     umcon;
+       u32     ubrdiv;
+};
+
 /* helper functions to save/restore lists of registers. */
 
 extern void s3c_pm_do_save(struct sleep_save *ptr, int count);
index e320b0f..78bf50a 100644 (file)
@@ -72,33 +72,50 @@ static inline void s3c_pm_debug_init(void)
 
 #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(unsigned int uart, struct pm_uart_save *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);
+}
 
-static void s3c_pm_save_uart(void)
+static void s3c_pm_save_uarts(void)
 {
-       s3c_pm_do_save(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);
+
+       __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);
 }
 
-static void s3c_pm_restore_uart(void)
+static void s3c_pm_restore_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_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
@@ -250,7 +267,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 */
@@ -293,7 +310,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();
index fef8ea8..eed8f78 100644 (file)
@@ -31,6 +31,8 @@
 #define S3C24XX_SZ_UART           SZ_1M
 #define S3C_UART_OFFSET           (0x4000)
 
+#define S3C_VA_UARTx(uart) (S3C_VA_UART + ((uart * S3C_UART_OFFSET)))
+
 /* Timers */
 #define S3C24XX_VA_TIMER   S3C_VA_TIMER
 #define S3C2410_PA_TIMER   (0x51000000)