Commit 14ea37b2 authored by Kevin Hilman's avatar Kevin Hilman

OMAP3: PM: UART save/restore support for OFF-mode

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: default avatarKevin Hilman <khilman@deeprootsystems.com>
parent 77d8bc05
...@@ -49,6 +49,18 @@ struct omap_uart_state { ...@@ -49,6 +49,18 @@ struct omap_uart_state {
struct plat_serial8250_port *p; struct plat_serial8250_port *p;
struct list_head node; struct list_head node;
#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
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]; 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) ...@@ -114,6 +126,69 @@ static inline void __init omap_uart_reset(struct omap_uart_state *uart)
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
#ifdef CONFIG_ARCH_OMAP3
static int enable_off_mode; /* to be removed by full off-mode patches */
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, static void omap_uart_smart_idle_enable(struct omap_uart_state *uart,
int enable) int enable)
{ {
...@@ -137,6 +212,7 @@ static inline void omap_uart_enable_clocks(struct omap_uart_state *uart) ...@@ -137,6 +212,7 @@ static inline void omap_uart_enable_clocks(struct omap_uart_state *uart)
clk_enable(uart->ick); clk_enable(uart->ick);
clk_enable(uart->fck); clk_enable(uart->fck);
uart->clocked = 1; uart->clocked = 1;
omap_uart_restore_context(uart);
} }
static inline void omap_uart_disable_clocks(struct omap_uart_state *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) ...@@ -144,6 +220,7 @@ static inline void omap_uart_disable_clocks(struct omap_uart_state *uart)
if (!uart->clocked) if (!uart->clocked)
return; return;
omap_uart_save_context(uart);
uart->clocked = 0; uart->clocked = 0;
clk_disable(uart->ick); clk_disable(uart->ick);
clk_disable(uart->fck); clk_disable(uart->fck);
......
...@@ -323,6 +323,7 @@ ...@@ -323,6 +323,7 @@
#define UART_OMAP_MVER 0x14 /* Module version register */ #define UART_OMAP_MVER 0x14 /* Module version register */
#define UART_OMAP_SYSC 0x15 /* System configuration register */ #define UART_OMAP_SYSC 0x15 /* System configuration register */
#define UART_OMAP_SYSS 0x16 /* System status register */ #define UART_OMAP_SYSS 0x16 /* System status register */
#define UART_OMAP_WER 0x17 /* Wake-up enable register */
#endif /* _LINUX_SERIAL_REG_H */ #endif /* _LINUX_SERIAL_REG_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment