/* * arch/arm/mach-omap2/serial.c * * OMAP2 serial support. * * 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 * * Copyright (C) 2009 Texas Instruments * Added OMAP4 support - Santosh Shilimkar #include #include #include #include #include #include #include #include #include #include "prm.h" #include "pm.h" #include "prm-regbits-34xx.h" #define UART_OMAP_WER 0x17 /* Wake-up enable register */ #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; struct platform_device pdev; #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 LIST_HEAD(uart_list); static struct plat_serial8250_port serial_platform_data0[] = { { .membase = OMAP2_IO_ADDRESS(OMAP_UART1_BASE), .mapbase = OMAP_UART1_BASE, .irq = 72, .flags = UPF_BOOT_AUTOCONF, .iotype = UPIO_MEM, .regshift = 2, .uartclk = OMAP24XX_BASE_BAUD * 16, }, { .flags = 0 } }; static struct plat_serial8250_port serial_platform_data1[] = { { .membase = OMAP2_IO_ADDRESS(OMAP_UART2_BASE), .mapbase = OMAP_UART2_BASE, .irq = 73, .flags = UPF_BOOT_AUTOCONF, .iotype = UPIO_MEM, .regshift = 2, .uartclk = OMAP24XX_BASE_BAUD * 16, }, { .flags = 0 } }; static struct plat_serial8250_port serial_platform_data2[] = { { .membase = OMAP2_IO_ADDRESS(OMAP_UART3_BASE), .mapbase = OMAP_UART3_BASE, .irq = 74, .flags = UPF_BOOT_AUTOCONF, .iotype = UPIO_MEM, .regshift = 2, .uartclk = OMAP24XX_BASE_BAUD * 16, }, { .flags = 0 } }; static inline unsigned int serial_read_reg(struct plat_serial8250_port *up, int offset) { offset <<= up->regshift; return (unsigned int)__raw_readb(up->membase + offset); } static inline void serial_write_reg(struct plat_serial8250_port *p, int offset, int value) { offset <<= p->regshift; __raw_writeb(value, p->membase + offset); } /* * Internal UARTs need to be initialized for the 8250 autoconfig to work * 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) { 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)); } #if defined(CONFIG_PM) && defined(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_PM && CONFIG_ARCH_OMAP3 */ 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; omap_uart_restore_context(uart); } #ifdef CONFIG_PM 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_enable_wakeup(struct omap_uart_state *uart) { /* Set wake-enable bit */ if (uart->wk_en && uart->wk_mask) { u32 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 = omap_ctrl_readw(uart->padconf); v |= OMAP3_PADCONF_WAKEUPENABLE0; omap_ctrl_writew(v, uart->padconf); } } static void omap_uart_disable_wakeup(struct omap_uart_state *uart) { /* Clear wake-enable bit */ if (uart->wk_en && uart->wk_mask) { u32 v = __raw_readl(uart->wk_en); v &= ~uart->wk_mask; __raw_writel(v, uart->wk_en); } /* Ensure IOPAD wake-enables are cleared */ if (cpu_is_omap34xx() && uart->padconf) { u16 v = omap_ctrl_readw(uart->padconf); v &= ~OMAP3_PADCONF_WAKEUPENABLE0; omap_ctrl_writew(v, uart->padconf); } } static void omap_uart_smart_idle_enable(struct omap_uart_state *uart, 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 void omap_uart_block_sleep(struct omap_uart_state *uart) { omap_uart_enable_clocks(uart); omap_uart_smart_idle_enable(uart, 0); uart->can_sleep = 0; if (uart->timeout) mod_timer(&uart->timer, jiffies + uart->timeout); else del_timer(&uart->timer); } static void omap_uart_allow_sleep(struct omap_uart_state *uart) { if (device_may_wakeup(&uart->pdev.dev)) omap_uart_enable_wakeup(uart); else omap_uart_disable_wakeup(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 (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_enable_clocks(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); } /* 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 void omap_uart_idle_init(struct omap_uart_state *uart) { struct plat_serial8250_port *p = uart->p; int ret; uart->can_sleep = 0; uart->timeout = DEFAULT_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; } p->flags |= UPF_SHARE_IRQ; ret = request_irq(p->irq, omap_uart_interrupt, IRQF_SHARED, "serial idle", (void *)uart); WARN_ON(ret); } void omap_uart_enable_irqs(int enable) { int ret; struct omap_uart_state *uart; list_for_each_entry(uart, &uart_list, node) { if (enable) ret = request_irq(uart->p->irq, omap_uart_interrupt, IRQF_SHARED, "serial idle", (void *)uart); else free_irq(uart->p->irq, (void *)uart); } } static ssize_t sleep_timeout_show(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = container_of(dev, struct platform_device, dev); struct omap_uart_state *uart = container_of(pdev, struct omap_uart_state, pdev); return sprintf(buf, "%u\n", uart->timeout / HZ); } static ssize_t sleep_timeout_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) { struct platform_device *pdev = container_of(dev, struct platform_device, dev); struct omap_uart_state *uart = container_of(pdev, struct omap_uart_state, pdev); unsigned int value; if (sscanf(buf, "%u", &value) != 1) { printk(KERN_ERR "sleep_timeout_store: Invalid value\n"); return -EINVAL; } uart->timeout = value * HZ; if (uart->timeout) mod_timer(&uart->timer, jiffies + uart->timeout); else /* A zero value means disable timeout feature */ omap_uart_block_sleep(uart); return n; } DEVICE_ATTR(sleep_timeout, 0644, sleep_timeout_show, sleep_timeout_store); #define DEV_CREATE_FILE(dev, attr) WARN_ON(device_create_file(dev, attr)) #else static inline void omap_uart_idle_init(struct omap_uart_state *uart) {} #define DEV_CREATE_FILE(dev, attr) #endif /* CONFIG_PM */ static struct omap_uart_state omap_uart[OMAP_MAX_NR_PORTS] = { { .pdev = { .name = "serial8250", .id = PLAT8250_DEV_PLATFORM, .dev = { .platform_data = serial_platform_data0, }, }, }, { .pdev = { .name = "serial8250", .id = PLAT8250_DEV_PLATFORM1, .dev = { .platform_data = serial_platform_data1, }, }, }, { .pdev = { .name = "serial8250", .id = PLAT8250_DEV_PLATFORM2, .dev = { .platform_data = serial_platform_data2, }, }, }, }; void __init omap_serial_init(void) { int i; char name[16]; /* * Make sure the serial ports are muxed on at this point. * You have to mux them off in device drivers later on * if not needed. */ for (i = 0; i < OMAP_MAX_NR_PORTS; i++) { struct omap_uart_state *uart = &omap_uart[i]; struct platform_device *pdev = &uart->pdev; struct device *dev = &pdev->dev; struct plat_serial8250_port *p = dev->platform_data; sprintf(name, "uart%d_ick", i+1); uart->ick = clk_get(NULL, name); if (IS_ERR(uart->ick)) { printk(KERN_ERR "Could not get uart%d_ick\n", i+1); uart->ick = NULL; } sprintf(name, "uart%d_fck", i+1); uart->fck = clk_get(NULL, name); if (IS_ERR(uart->fck)) { 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_tail(&uart->node, &uart_list); if (cpu_is_omap44xx()) p->irq += 32; omap_uart_enable_clocks(uart); omap_uart_reset(uart); omap_uart_idle_init(uart); if (WARN_ON(platform_device_register(pdev))) continue; if ((cpu_is_omap34xx() && uart->padconf) || (uart->wk_en && uart->wk_mask)) { device_init_wakeup(dev, true); DEV_CREATE_FILE(dev, &dev_attr_sleep_timeout); } } }