summaryrefslogtreecommitdiff
path: root/drivers/serial
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-12-28 16:54:33 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2008-12-28 16:54:33 -0800
commit3c92ec8ae91ecf59d88c798301833d7cf83f2179 (patch)
tree08a38cd3523c42bd49882f17cd501fd879e7ca1c /drivers/serial
parentc4c9f0183b7c4e97836e8fecbb67898b06c47e78 (diff)
parentca9153a3a2a7556d091dfe080e42b0e67881fff6 (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')
-rw-r--r--drivers/serial/mpc52xx_uart.c74
-rw-r--r--drivers/serial/pmac_zilog.c27
2 files changed, 87 insertions, 14 deletions
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 28c00c3d58f5..0c3a2ab1612c 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
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
index 317b061f7641..ad3488504010 100644
--- a/drivers/serial/pmac_zilog.c
+++ b/drivers/serial/pmac_zilog.c
@@ -1383,6 +1383,29 @@ static int pmz_verify_port(struct uart_port *port, struct serial_struct *ser)
return -EINVAL;
}
+#ifdef CONFIG_CONSOLE_POLL
+
+static int pmz_poll_get_char(struct uart_port *port)
+{
+ struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
+
+ while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0)
+ udelay(5);
+ return read_zsdata(uap);
+}
+
+static void pmz_poll_put_char(struct uart_port *port, unsigned char c)
+{
+ struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
+
+ /* Wait for the transmit buffer to empty. */
+ while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0)
+ udelay(5);
+ write_zsdata(uap, c);
+}
+
+#endif
+
static struct uart_ops pmz_pops = {
.tx_empty = pmz_tx_empty,
.set_mctrl = pmz_set_mctrl,
@@ -1400,6 +1423,10 @@ static struct uart_ops pmz_pops = {
.request_port = pmz_request_port,
.config_port = pmz_config_port,
.verify_port = pmz_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_get_char = pmz_poll_get_char,
+ .poll_put_char = pmz_poll_put_char,
+#endif
};
/*