If OFF-mode is enabled, each enabled UART will save its
context whenever clocks are disabled and restore it when
clocks are re-enabled.
Signed-off-by: Kevin Hilman <[EMAIL PROTECTED]>
---
arch/arm/mach-omap2/serial.c | 77 ++++++++++++++++++++++++++++++++++++++++++
include/linux/serial_reg.h | 1 +
2 files changed, 78 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index f93dc52..dd32047 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -50,6 +50,18 @@ struct omap_uart_state {
struct plat_serial8250_port *p;
struct list_head node;
+
+#ifdef CONFIG_ARCH_OMAP3
+ int context_valid;
+
+ /* Registers to be saved/restored for OFF-mode */
+ u16 dll;
+ u16 dlh;
+ u16 ier;
+ u16 sysc;
+ u16 scr;
+ u16 wer;
+#endif
};
static struct omap_uart_state omap_uart[OMAP_MAX_NR_PORTS];
@@ -114,6 +126,69 @@ static inline void __init omap_uart_reset(struct
omap_uart_state *uart)
serial_write_reg(p, UART_OMAP_SYSC, (0x02 << 3) | (1 << 2) | (1 << 0));
}
+#ifdef CONFIG_ARCH_OMAP3
+/* to be replaced by global with forthcoming OFF-mode patches */
+static int enable_off_mode;
+
+static void omap_uart_save_context(struct omap_uart_state *uart)
+{
+ u16 lcr = 0;
+ struct plat_serial8250_port *p = uart->p;
+
+ if (!enable_off_mode)
+ return;
+
+ lcr = serial_read_reg(p, UART_LCR);
+ serial_write_reg(p, UART_LCR, 0xBF);
+ uart->dll = serial_read_reg(p, UART_DLL);
+ uart->dlh = serial_read_reg(p, UART_DLM);
+ serial_write_reg(p, UART_LCR, lcr);
+ uart->ier = serial_read_reg(p, UART_IER);
+ uart->sysc = serial_read_reg(p, UART_OMAP_SYSC);
+ uart->scr = serial_read_reg(p, UART_OMAP_SCR);
+ uart->wer = serial_read_reg(p, UART_OMAP_WER);
+
+ uart->context_valid = 1;
+}
+
+static void omap_uart_restore_context(struct omap_uart_state *uart)
+{
+ u16 efr = 0;
+ struct plat_serial8250_port *p = uart->p;
+
+ if (!enable_off_mode)
+ return;
+
+ if (!uart->context_valid)
+ return;
+
+ uart->context_valid = 0;
+
+ serial_write_reg(p, UART_OMAP_MDR1, 0x7);
+ serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
+ efr = serial_read_reg(p, UART_EFR);
+ serial_write_reg(p, UART_EFR, UART_EFR_ECB);
+ serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */
+ serial_write_reg(p, UART_IER, 0x0);
+ serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
+ serial_write_reg(p, UART_DLL, uart->dll);
+ serial_write_reg(p, UART_DLM, uart->dlh);
+ serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */
+ serial_write_reg(p, UART_IER, uart->ier);
+ serial_write_reg(p, UART_FCR, 0xA1);
+ serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
+ serial_write_reg(p, UART_EFR, efr);
+ serial_write_reg(p, UART_LCR, UART_LCR_WLEN8);
+ serial_write_reg(p, UART_OMAP_SCR, uart->scr);
+ serial_write_reg(p, UART_OMAP_WER, uart->wer);
+ serial_write_reg(p, UART_OMAP_SYSC, uart->sysc);
+ serial_write_reg(p, UART_OMAP_MDR1, 0x00); /* UART 16x mode */
+}
+#else
+static inline void omap_uart_save_context(struct omap_uart_state *uart) {}
+static inline void omap_uart_restore_context(struct omap_uart_state *uart) {}
+#endif /* CONFIG_ARCH_OMAP3 */
+
static void omap_uart_smart_idle_enable(struct omap_uart_state *uart,
int enable)
{
@@ -137,6 +212,7 @@ static inline void omap_uart_enable_clocks(struct
omap_uart_state *uart)
clk_enable(uart->ick);
clk_enable(uart->fck);
uart->clocked = 1;
+ omap_uart_restore_context(uart);
}
static inline void omap_uart_disable_clocks(struct omap_uart_state *uart)
@@ -144,6 +220,7 @@ static inline void omap_uart_disable_clocks(struct
omap_uart_state *uart)
if (!uart->clocked)
return;
+ omap_uart_save_context(uart);
uart->clocked = 0;
clk_disable(uart->ick);
clk_disable(uart->fck);
diff --git a/include/linux/serial_reg.h b/include/linux/serial_reg.h
index 96c0d93..850db2e 100644
--- a/include/linux/serial_reg.h
+++ b/include/linux/serial_reg.h
@@ -323,6 +323,7 @@
#define UART_OMAP_MVER 0x14 /* Module version register */
#define UART_OMAP_SYSC 0x15 /* System configuration register */
#define UART_OMAP_SYSS 0x16 /* System status register */
+#define UART_OMAP_WER 0x17 /* Wake-up enable register */
#endif /* _LINUX_SERIAL_REG_H */
--
1.6.0.3
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html