diff options
author | Ian Wisbon <ian.wisbon@timesys.com> | 2011-02-10 17:15:15 -0500 |
---|---|---|
committer | Ian Wisbon <ian.wisbon@timesys.com> | 2011-02-10 17:15:15 -0500 |
commit | a9d2ba1444b0af6c2d8534f0b306660ffc045bc6 (patch) | |
tree | 79b396bf70ae3795e6ee9a3b645e64f7e29474e7 /drivers/serial/mxs-auart.c | |
parent | effff5718c380983788fe6c380671c18e15ac7c2 (diff) |
Linux 2.6.31 Release for Digi ConnectCore Wi-i.MX boards2.6.31-digi-201102101717
Diffstat (limited to 'drivers/serial/mxs-auart.c')
-rw-r--r-- | drivers/serial/mxs-auart.c | 193 |
1 files changed, 190 insertions, 3 deletions
diff --git a/drivers/serial/mxs-auart.c b/drivers/serial/mxs-auart.c index 0eea46d71979..63d7d9128efc 100644 --- a/drivers/serial/mxs-auart.c +++ b/drivers/serial/mxs-auart.c @@ -19,6 +19,7 @@ #include <linux/device.h> #include <linux/errno.h> #include <linux/init.h> +#include <linux/console.h> #include <linux/interrupt.h> #include <linux/module.h> #include <linux/slab.h> @@ -47,6 +48,8 @@ #define MXS_AUART_MAJOR 242 #define MXS_AUART_RX_THRESHOLD 16 +static struct uart_driver auart_driver; + struct mxs_auart_port { struct uart_port port; @@ -514,7 +517,7 @@ static void mxs_auart_settermios(struct uart_port *u, /* parity */ if (cflag & PARENB) { - ctrl |= BM_UARTAPP_LINECTRL_PEN | BM_UARTAPP_LINECTRL_SPS; + ctrl |= BM_UARTAPP_LINECTRL_PEN; if ((cflag & PARODD) == 0) ctrl |= BM_UARTAPP_LINECTRL_EPS; } @@ -565,9 +568,33 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context) mxs_auart_tx_chars(s); istat &= ~BM_UARTAPP_INTR_TXIS; } - if (istat & 0xFFFF) + /* modem status interrupt bits are undefined + after reset,and the hardware do not support + DSRMIS,DCDMIS and RIMIS bit,so we should ingore + them when they are pending. */ + if (istat & (BM_UARTAPP_INTR_ABDIS + | BM_UARTAPP_INTR_OEIS + | BM_UARTAPP_INTR_BEIS + | BM_UARTAPP_INTR_PEIS + | BM_UARTAPP_INTR_FEIS + | BM_UARTAPP_INTR_RTIS + | BM_UARTAPP_INTR_TXIS + | BM_UARTAPP_INTR_RXIS + | BM_UARTAPP_INTR_CTSMIS)) { dev_info(s->dev, "Unhandled status %x\n", istat); - __raw_writel(istatus & 0xFFFF, + } + __raw_writel(istatus & (BM_UARTAPP_INTR_ABDIS + | BM_UARTAPP_INTR_OEIS + | BM_UARTAPP_INTR_BEIS + | BM_UARTAPP_INTR_PEIS + | BM_UARTAPP_INTR_FEIS + | BM_UARTAPP_INTR_RTIS + | BM_UARTAPP_INTR_TXIS + | BM_UARTAPP_INTR_RXIS + | BM_UARTAPP_INTR_DSRMIS + | BM_UARTAPP_INTR_DCDMIS + | BM_UARTAPP_INTR_CTSMIS + | BM_UARTAPP_INTR_RIMIS), s->port.membase + HW_UARTAPP_INTR_CLR); return IRQ_HANDLED; @@ -761,7 +788,160 @@ static struct uart_ops mxs_auart_ops = { .config_port = mxs_auart_config_port, .verify_port = mxs_auart_verify_port, }; +#ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE +static struct mxs_auart_port auart_port[CONFIG_MXS_AUART_PORTS] = {}; + +static void +auart_console_write(struct console *co, const char *s, unsigned int count) +{ + struct uart_port *port; + unsigned int status, old_cr; + int i; + + if (co->index > CONFIG_MXS_AUART_PORTS || co->index < 0) + return; + + port = &auart_port[co->index].port; + + /* First save the CR then disable the interrupts */ + old_cr = __raw_readl(port->membase + HW_UARTAPP_CTRL2); + __raw_writel(BM_UARTAPP_CTRL2_UARTEN | BM_UARTAPP_CTRL2_TXE, + port->membase + HW_UARTAPP_CTRL2_SET); + + /* Now, do each character */ + for (i = 0; i < count; i++) { + do { + status = __raw_readl(port->membase + HW_UARTAPP_STAT); + } while (status & BM_UARTAPP_STAT_TXFF); + + __raw_writel(s[i], port->membase + HW_UARTAPP_DATA); + if (s[i] == '\n') { + do { + status = __raw_readl(port->membase + + HW_UARTAPP_STAT); + } while (status & BM_UARTAPP_STAT_TXFF); + __raw_writel('\r', port->membase + HW_UARTAPP_DATA); + } + } + + /* + * Finally, wait for transmitter to become empty + * and restore the TCR + */ + do { + status = __raw_readl(port->membase + HW_UARTAPP_STAT); + } while (status & BM_UARTAPP_STAT_BUSY); + __raw_writel(old_cr, port->membase + HW_UARTAPP_CTRL2); +} + +static void __init +auart_console_get_options(struct uart_port *port, int *baud, + int *parity, int *bits) +{ + if (__raw_readl(port->membase + HW_UARTAPP_CTRL2) + & BM_UARTAPP_CTRL2_UARTEN) { + unsigned int lcr_h, quot; + lcr_h = __raw_readl(port->membase + HW_UARTAPP_LINECTRL); + + *parity = 'n'; + if (lcr_h & BM_UARTAPP_LINECTRL_PEN) { + if (lcr_h & BM_UARTAPP_LINECTRL_EPS) + *parity = 'e'; + else + *parity = 'o'; + } + + if ((lcr_h & BM_UARTAPP_LINECTRL_WLEN) + == BF_UARTAPP_LINECTRL_WLEN(2)) + *bits = 7; + else + *bits = 8; + + quot = (((__raw_readl(port->membase + HW_UARTAPP_LINECTRL) + & BM_UARTAPP_LINECTRL_BAUD_DIVINT)) + >> (BP_UARTAPP_LINECTRL_BAUD_DIVINT - 6)) + | (((__raw_readl(port->membase + HW_UARTAPP_LINECTRL) + & BM_UARTAPP_LINECTRL_BAUD_DIVFRAC)) + >> BP_UARTAPP_LINECTRL_BAUD_DIVFRAC); + if (quot == 0) + quot = 1; + *baud = (port->uartclk << 2) / quot; + } +} + +static int __init auart_console_setup(struct console *co, char *options) +{ + struct mxs_auart_port *port; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index > CONFIG_MXS_AUART_PORTS || co->index < 0) + return -EINVAL; + + port = &auart_port[co->index].port; + + if (port->port.membase == 0) { + if (cpu_is_mx23()) { + if (co->index == 1) { + port->port.membase = IO_ADDRESS(0x8006C000); + port->port.mapbase = 0x8006C000; + } else { + port->port.membase = IO_ADDRESS(0x8006E000); + port->port.mapbase = 0x8006E000; + } + } + + port->port.fifosize = 16; + port->port.ops = &mxs_auart_ops; + port->port.flags = ASYNC_BOOT_AUTOCONF; + port->port.line = 0; + } + mxs_auart_reset(port); + + __raw_writel(BM_UARTAPP_CTRL2_UARTEN, + port->port.membase + HW_UARTAPP_CTRL2_SET); + + if (port->clk == NULL || IS_ERR(port->clk)) { + port->clk = clk_get(NULL, "uart"); + if (port->clk == NULL || IS_ERR(port->clk)) + return -ENODEV; + port->port.uartclk = clk_get_rate(port->clk); + } + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + auart_console_get_options(port, &baud, &parity, &bits); + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct console auart_console = { + .name = "ttySP", + .write = auart_console_write, + .device = uart_console_device, + .setup = auart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &auart_driver, +}; +#ifdef CONFIG_MXS_EARLY_CONSOLE +static int __init auart_console_init(void) +{ + register_console(&auart_console); + return 0; +} + +console_initcall(auart_console_init); +#endif + +#endif static struct uart_driver auart_driver = { .owner = THIS_MODULE, .driver_name = "auart", @@ -769,6 +949,9 @@ static struct uart_driver auart_driver = { .major = MXS_AUART_MAJOR, .minor = 0, .nr = CONFIG_MXS_AUART_PORTS, +#ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE + .cons = &auart_console, +#endif }; static int __devinit mxs_auart_probe(struct platform_device *pdev) @@ -849,6 +1032,10 @@ static int __devinit mxs_auart_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); +#ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE + memcpy(&auart_port[pdev->id], s, sizeof(struct mxs_auart_port)); +#endif + ret = uart_add_one_port(&auart_driver, &s->port); if (ret) goto out_free_clk; |