X-Git-Url: http://www.pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=arch%2Farm%2Fmach-omap2%2Fserial.c;h=4dcf39c285b94bac5e1e6292469299c633fcd0bf;hb=eba05254cb561dc27d5664503f91f7c21954e648;hp=fd5b9f83e0bc51ad361c2eaaf11a7b016ee65f7c;hpb=ed99db8e5c53acced1a7c02aa9a94d50bea48409;p=linux-2.6-omap-h63xx.git diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c index fd5b9f83e0b..4dcf39c285b 100644 --- a/arch/arm/mach-omap2/serial.c +++ b/arch/arm/mach-omap2/serial.c @@ -6,8 +6,6 @@ * Copyright (C) 2005-2008 Nokia Corporation * Author: Paul Mundt * - * Major rework for PM support by Kevin Hilman - * * Based off of arch/arm/mach-omap/omap1/serial.c * * This file is subject to the terms and conditions of the GNU General Public @@ -23,48 +21,9 @@ #include #include -#include -#include - -#include "prm.h" -#include "pm.h" -#include "prm-regbits-34xx.h" - -#define DEFAULT_TIMEOUT (5 * HZ) - -struct omap_uart_state { - int num; - int can_sleep; - struct timer_list timer; - u32 timeout; - - void __iomem *wk_st; - void __iomem *wk_en; - u32 wk_mask; - u32 padconf; - struct clk *ick; - struct clk *fck; - int clocked; - - struct plat_serial8250_port *p; - 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 LIST_HEAD(uart_list); +static struct clk *uart_ick[OMAP_MAX_NR_PORTS]; +static struct clk *uart_fck[OMAP_MAX_NR_PORTS]; static struct plat_serial8250_port serial_platform_data[] = { { @@ -115,356 +74,30 @@ static inline void serial_write_reg(struct plat_serial8250_port *p, int offset, * properly. Note that the TX watermark initialization may not be needed * once the 8250.c watermark handling code is merged. */ -static inline void __init omap_uart_reset(struct omap_uart_state *uart) +static inline void __init omap_serial_reset(struct plat_serial8250_port *p) { - struct plat_serial8250_port *p = uart->p; - serial_write_reg(p, UART_OMAP_MDR1, 0x07); serial_write_reg(p, UART_OMAP_SCR, 0x08); serial_write_reg(p, UART_OMAP_MDR1, 0x00); serial_write_reg(p, UART_OMAP_SYSC, (0x02 << 3) | (1 << 2) | (1 << 0)); } -static inline void omap_uart_enable_clocks(struct omap_uart_state *uart) -{ - if (uart->clocked) - return; - - clk_enable(uart->ick); - clk_enable(uart->fck); - uart->clocked = 1; -} - -#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, - int enable) +void omap_serial_enable_clocks(int enable) { - struct plat_serial8250_port *p = uart->p; - u16 sysc; - - sysc = serial_read_reg(p, UART_OMAP_SYSC) & 0x7; - if (enable) - sysc |= 0x2 << 3; - else - sysc |= 0x1 << 3; - - serial_write_reg(p, UART_OMAP_SYSC, sysc); -} - -static inline void omap_uart_restore(struct omap_uart_state *uart) -{ - omap_uart_enable_clocks(uart); - omap_uart_restore_context(uart); -} - -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); -} - -static void omap_uart_block_sleep(struct omap_uart_state *uart) -{ - omap_uart_restore(uart); - - omap_uart_smart_idle_enable(uart, 0); - uart->can_sleep = 0; - mod_timer(&uart->timer, jiffies + uart->timeout); -} - -static void omap_uart_allow_sleep(struct omap_uart_state *uart) -{ - if (!uart->clocked) - return; - - omap_uart_smart_idle_enable(uart, 1); - uart->can_sleep = 1; - del_timer(&uart->timer); -} - -static void omap_uart_idle_timer(unsigned long data) -{ - struct omap_uart_state *uart = (struct omap_uart_state *)data; - - omap_uart_allow_sleep(uart); -} - -void omap_uart_prepare_idle(int num) -{ - struct omap_uart_state *uart; - - list_for_each_entry(uart, &uart_list, node) { - if (!clocks_off_while_idle) - continue; - - if (num == uart->num && uart->can_sleep) { - omap_uart_disable_clocks(uart); - return; - } - } -} - -void omap_uart_resume_idle(int num) -{ - struct omap_uart_state *uart; - - list_for_each_entry(uart, &uart_list, node) { - if (num == uart->num) { - omap_uart_restore(uart); - - /* Check for IO pad wakeup */ - if (cpu_is_omap34xx() && uart->padconf) { - u16 p = omap_ctrl_readw(uart->padconf); - - if (p & OMAP3_PADCONF_WAKEUPEVENT0) - omap_uart_block_sleep(uart); + int i; + for (i = 0; i < OMAP_MAX_NR_PORTS; i++) { + if (uart_ick[i] && uart_fck[i]) { + if (enable) { + clk_enable(uart_ick[i]); + clk_enable(uart_fck[i]); + } else { + clk_disable(uart_ick[i]); + clk_disable(uart_fck[i]); } - - /* Check for normal UART wakeup */ - if (__raw_readl(uart->wk_st) & uart->wk_mask) - omap_uart_block_sleep(uart); - - return; - } - } -} - -void omap_uart_prepare_suspend(void) -{ - struct omap_uart_state *uart; - - list_for_each_entry(uart, &uart_list, node) { - omap_uart_allow_sleep(uart); - } -} - -int omap_uart_can_sleep(void) -{ - struct omap_uart_state *uart; - int can_sleep = 1; - - list_for_each_entry(uart, &uart_list, node) { - if (!uart->clocked) - continue; - - if (!uart->can_sleep) { - can_sleep = 0; - continue; - } - - /* This UART can now safely sleep. */ - omap_uart_allow_sleep(uart); - } - - return can_sleep; -} - -/** - * omap_uart_interrupt() - * - * This handler is used only to detect that *any* UART interrupt has - * occurred. It does _nothing_ to handle the interrupt. Rather, - * any UART interrupt will trigger the inactivity timer so the - * UART will not idle or sleep for its timeout period. - * - **/ -static irqreturn_t omap_uart_interrupt(int irq, void *dev_id) -{ - struct omap_uart_state *uart = dev_id; - - omap_uart_block_sleep(uart); - - return IRQ_NONE; -} - -static u32 sleep_timeout = DEFAULT_TIMEOUT; - -static void omap_uart_idle_init(struct omap_uart_state *uart) -{ - u32 v; - struct plat_serial8250_port *p = uart->p; - int ret; - - uart->can_sleep = 0; - uart->timeout = sleep_timeout; - setup_timer(&uart->timer, omap_uart_idle_timer, - (unsigned long) uart); - mod_timer(&uart->timer, jiffies + uart->timeout); - omap_uart_smart_idle_enable(uart, 0); - - if (cpu_is_omap34xx()) { - u32 mod = (uart->num == 2) ? OMAP3430_PER_MOD : CORE_MOD; - u32 wk_mask = 0; - u32 padconf = 0; - - uart->wk_en = OMAP34XX_PRM_REGADDR(mod, PM_WKEN1); - uart->wk_st = OMAP34XX_PRM_REGADDR(mod, PM_WKST1); - switch (uart->num) { - case 0: - wk_mask = OMAP3430_ST_UART1_MASK; - padconf = 0x182; - break; - case 1: - wk_mask = OMAP3430_ST_UART2_MASK; - padconf = 0x17a; - break; - case 2: - wk_mask = OMAP3430_ST_UART3_MASK; - padconf = 0x19e; - break; - } - uart->wk_mask = wk_mask; - uart->padconf = padconf; - } else if (cpu_is_omap24xx()) { - u32 wk_mask = 0; - - if (cpu_is_omap2430()) { - uart->wk_en = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKEN1); - uart->wk_st = OMAP2430_PRM_REGADDR(CORE_MOD, PM_WKST1); - } else if (cpu_is_omap2420()) { - uart->wk_en = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKEN1); - uart->wk_st = OMAP2420_PRM_REGADDR(CORE_MOD, PM_WKST1); } - switch (uart->num) { - case 0: - wk_mask = OMAP24XX_ST_UART1_MASK; - break; - case 1: - wk_mask = OMAP24XX_ST_UART2_MASK; - break; - case 2: - wk_mask = OMAP24XX_ST_UART3_MASK; - break; - } - uart->wk_mask = wk_mask; - } else { - uart->wk_en = 0; - uart->wk_st = 0; - uart->wk_mask = 0; - uart->padconf = 0; - } - - /* Set wake-enable bit */ - if (uart->wk_en && uart->wk_mask) { - v = __raw_readl(uart->wk_en); - v |= uart->wk_mask; - __raw_writel(v, uart->wk_en); - } - - /* Ensure IOPAD wake-enables are set */ - if (cpu_is_omap34xx() && uart->padconf) { - u16 v; - - v = omap_ctrl_readw(uart->padconf); - v |= OMAP3_PADCONF_WAKEUPENABLE0; - omap_ctrl_writew(v, uart->padconf); } - - p->flags |= UPF_SHARE_IRQ; - ret = request_irq(p->irq, omap_uart_interrupt, IRQF_SHARED, - "serial idle", (void *)uart); - WARN_ON(ret); } -static ssize_t sleep_timeout_show(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) -{ - return sprintf(buf, "%u\n", sleep_timeout / HZ); -} - -static ssize_t sleep_timeout_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t n) -{ - struct omap_uart_state *uart; - unsigned int value; - - if (sscanf(buf, "%u", &value) != 1) { - printk(KERN_ERR "sleep_timeout_store: Invalid value\n"); - return -EINVAL; - } - sleep_timeout = value * HZ; - list_for_each_entry(uart, &uart_list, node) - uart->timeout = sleep_timeout; - return n; -} - -static struct kobj_attribute sleep_timeout_attr = - __ATTR(sleep_timeout, 0644, sleep_timeout_show, sleep_timeout_store); - -#else -static inline void omap_uart_idle_init(struct omap_uart_state *uart) {} -#endif /* CONFIG_PM */ - void __init omap_serial_init(void) { int i; @@ -484,7 +117,6 @@ void __init omap_serial_init(void) for (i = 0; i < OMAP_MAX_NR_PORTS; i++) { struct plat_serial8250_port *p = serial_platform_data + i; - struct omap_uart_state *uart = &omap_uart[i]; if (!(info->enabled_uarts & (1 << i))) { p->membase = NULL; @@ -493,30 +125,22 @@ void __init omap_serial_init(void) } sprintf(name, "uart%d_ick", i+1); - uart->ick = clk_get(NULL, name); - if (IS_ERR(uart->ick)) { + uart_ick[i] = clk_get(NULL, name); + if (IS_ERR(uart_ick[i])) { printk(KERN_ERR "Could not get uart%d_ick\n", i+1); - uart->ick = NULL; - } + uart_ick[i] = NULL; + } else + clk_enable(uart_ick[i]); sprintf(name, "uart%d_fck", i+1); - uart->fck = clk_get(NULL, name); - if (IS_ERR(uart->fck)) { + uart_fck[i] = clk_get(NULL, name); + if (IS_ERR(uart_fck[i])) { printk(KERN_ERR "Could not get uart%d_fck\n", i+1); - uart->fck = NULL; - } - - if (!uart->ick || !uart->fck) - continue; - - uart->num = i; - p->private_data = uart; - uart->p = p; - list_add(&uart->node, &uart_list); + uart_fck[i] = NULL; + } else + clk_enable(uart_fck[i]); - omap_uart_enable_clocks(uart); - omap_uart_reset(uart); - omap_uart_idle_init(uart); + omap_serial_reset(p); } } @@ -530,15 +154,6 @@ static struct platform_device serial_device = { static int __init omap_init(void) { - int ret; - - ret = platform_device_register(&serial_device); - -#ifdef CONFIG_PM - if (!ret) - ret = sysfs_create_file(&serial_device.dev.kobj, - &sleep_timeout_attr.attr); -#endif - return ret; + return platform_device_register(&serial_device); } arch_initcall(omap_init);