diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-12-28 16:54:33 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-12-28 16:54:33 -0800 |
commit | 3c92ec8ae91ecf59d88c798301833d7cf83f2179 (patch) | |
tree | 08a38cd3523c42bd49882f17cd501fd879e7ca1c /drivers/serial/mpc52xx_uart.c | |
parent | c4c9f0183b7c4e97836e8fecbb67898b06c47e78 (diff) | |
parent | ca9153a3a2a7556d091dfe080e42b0e67881fff6 (diff) |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc: (144 commits)
powerpc/44x: Support 16K/64K base page sizes on 44x
powerpc: Force memory size to be a multiple of PAGE_SIZE
powerpc/32: Wire up the trampoline code for kdump
powerpc/32: Add the ability for a classic ppc kernel to be loaded at 32M
powerpc/32: Allow __ioremap on RAM addresses for kdump kernel
powerpc/32: Setup OF properties for kdump
powerpc/32/kdump: Implement crash_setup_regs() using ppc_save_regs()
powerpc: Prepare xmon_save_regs for use with kdump
powerpc: Remove default kexec/crash_kernel ops assignments
powerpc: Make default kexec/crash_kernel ops implicit
powerpc: Setup OF properties for ppc32 kexec
powerpc/pseries: Fix cpu hotplug
powerpc: Fix KVM build on ppc440
powerpc/cell: add QPACE as a separate Cell platform
powerpc/cell: fix build breakage with CONFIG_SPUFS disabled
powerpc/mpc5200: fix error paths in PSC UART probe function
powerpc/mpc5200: add rts/cts handling in PSC UART driver
powerpc/mpc5200: Make PSC UART driver update serial errors counters
powerpc/mpc5200: Remove obsolete code from mpc5200 MDIO driver
powerpc/mpc5200: Add MDMA/UDMA support to MPC5200 ATA driver
...
Fix trivial conflict in drivers/char/Makefile as per Paul's directions
Diffstat (limited to 'drivers/serial/mpc52xx_uart.c')
-rw-r--r-- | drivers/serial/mpc52xx_uart.c | 74 |
1 files changed, 60 insertions, 14 deletions
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index 28c00c3d58f..0c3a2ab1612 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -429,14 +429,24 @@ mpc52xx_uart_tx_empty(struct uart_port *port) static void mpc52xx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) { - /* Not implemented */ + if (mctrl & TIOCM_RTS) + out_8(&PSC(port)->op1, MPC52xx_PSC_OP_RTS); + else + out_8(&PSC(port)->op0, MPC52xx_PSC_OP_RTS); } static unsigned int mpc52xx_uart_get_mctrl(struct uart_port *port) { - /* Not implemented */ - return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; + unsigned int ret = TIOCM_DSR; + u8 status = in_8(&PSC(port)->mpc52xx_psc_ipcr); + + if (!(status & MPC52xx_PSC_CTS)) + ret |= TIOCM_CTS; + if (!(status & MPC52xx_PSC_DCD)) + ret |= TIOCM_CAR; + + return ret; } static void @@ -479,7 +489,15 @@ mpc52xx_uart_stop_rx(struct uart_port *port) static void mpc52xx_uart_enable_ms(struct uart_port *port) { - /* Not implemented */ + struct mpc52xx_psc __iomem *psc = PSC(port); + + /* clear D_*-bits by reading them */ + in_8(&psc->mpc52xx_psc_ipcr); + /* enable CTS and DCD as IPC interrupts */ + out_8(&psc->mpc52xx_psc_acr, MPC52xx_PSC_IEC_CTS | MPC52xx_PSC_IEC_DCD); + + port->read_status_mask |= MPC52xx_PSC_IMR_IPC; + out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); } static void @@ -580,6 +598,10 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new, MPC52xx_PSC_MODE_ONE_STOP_5_BITS : MPC52xx_PSC_MODE_ONE_STOP; + if (new->c_cflag & CRTSCTS) { + mr1 |= MPC52xx_PSC_MODE_RXRTS; + mr2 |= MPC52xx_PSC_MODE_TXCTS; + } baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16); quot = uart_get_divisor(port, baud); @@ -617,6 +639,9 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new, out_8(&psc->ctur, ctr >> 8); out_8(&psc->ctlr, ctr & 0xff); + if (UART_ENABLE_MS(port, new->c_cflag)) + mpc52xx_uart_enable_ms(port); + /* Reenable TX & RX */ out_8(&psc->command, MPC52xx_PSC_TX_ENABLE); out_8(&psc->command, MPC52xx_PSC_RX_ENABLE); @@ -752,10 +777,15 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port) if (status & MPC52xx_PSC_SR_RB) { flag = TTY_BREAK; uart_handle_break(port); - } else if (status & MPC52xx_PSC_SR_PE) + port->icount.brk++; + } else if (status & MPC52xx_PSC_SR_PE) { flag = TTY_PARITY; - else if (status & MPC52xx_PSC_SR_FE) + port->icount.parity++; + } + else if (status & MPC52xx_PSC_SR_FE) { flag = TTY_FRAME; + port->icount.frame++; + } /* Clear error condition */ out_8(&PSC(port)->command, MPC52xx_PSC_RST_ERR_STAT); @@ -769,6 +799,7 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port) * affect the current character */ tty_insert_flip_char(tty, 0, TTY_OVERRUN); + port->icount.overrun++; } } @@ -826,6 +857,7 @@ mpc52xx_uart_int(int irq, void *dev_id) struct uart_port *port = dev_id; unsigned long pass = ISR_PASS_LIMIT; unsigned int keepgoing; + u8 status; spin_lock(&port->lock); @@ -842,6 +874,13 @@ mpc52xx_uart_int(int irq, void *dev_id) if (psc_ops->tx_rdy(port)) keepgoing |= mpc52xx_uart_int_tx_chars(port); + status = in_8(&PSC(port)->mpc52xx_psc_ipcr); + if (status & MPC52xx_PSC_D_DCD) + uart_handle_dcd_change(port, !(status & MPC52xx_PSC_DCD)); + + if (status & MPC52xx_PSC_D_CTS) + uart_handle_cts_change(port, !(status & MPC52xx_PSC_CTS)); + /* Limit number of iteration */ if (!(--pass)) keepgoing = 0; @@ -1109,22 +1148,29 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match) return ret; port->mapbase = res.start; + if (!port->mapbase) { + dev_dbg(&op->dev, "Could not allocate resources for PSC\n"); + return -EINVAL; + } + port->irq = irq_of_parse_and_map(op->node, 0); + if (port->irq == NO_IRQ) { + dev_dbg(&op->dev, "Could not get irq\n"); + return -EINVAL; + } dev_dbg(&op->dev, "mpc52xx-psc uart at %p, irq=%x, freq=%i\n", (void *)port->mapbase, port->irq, port->uartclk); - if ((port->irq == NO_IRQ) || !port->mapbase) { - printk(KERN_ERR "Could not allocate resources for PSC\n"); - return -EINVAL; - } - /* Add the port to the uart sub-system */ ret = uart_add_one_port(&mpc52xx_uart_driver, port); - if (!ret) - dev_set_drvdata(&op->dev, (void *)port); + if (ret) { + irq_dispose_mapping(port->irq); + return ret; + } - return ret; + dev_set_drvdata(&op->dev, (void *)port); + return 0; } static int |