aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/pmc-sierra/msp71xx/msp_serial.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-10-26 09:11:09 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-10-26 09:11:09 -0400
commitefb8d21b2c6db3497655cc6a033ae8a9883e4063 (patch)
treea14a0dbb9fec3a6db5e542ba7ed4a49681706420 /arch/mips/pmc-sierra/msp71xx/msp_serial.c
parent3cb603284b3d256ae9ae9e65887cee8416bfef15 (diff)
parentd208a3bf77f902283894f546b6b5383202cf7882 (diff)
Merge branch 'tty-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
* 'tty-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (79 commits) TTY: serial_core: Fix crash if DCD drop during suspend tty/serial: atmel_serial: bootconsole removed from auto-enumerates Revert "TTY: call tty_driver_lookup_tty unconditionally" tty/serial: atmel_serial: add device tree support tty/serial: atmel_serial: auto-enumerate ports tty/serial: atmel_serial: whitespace and braces modifications tty/serial: atmel_serial: change platform_data variable name tty/serial: RS485 bindings for device tree TTY: call tty_driver_lookup_tty unconditionally TTY: pty, release tty in all ptmx_open fail paths TTY: make tty_add_file non-failing TTY: drop driver reference in tty_open fail path 8250_pci: Fix kernel panic when pch_uart is disabled h8300: drivers/serial/Kconfig was moved parport_pc: release IO region properly if unsupported ITE887x card is found tty: Support compat_ioctl get/set termios_locked hvc_console: display printk messages on console. TTY: snyclinkmp: forever loop in tx_load_dma_buffer() tty/n_gsm: avoid fifo overflow in gsm_dlci_data_output tty/n_gsm: fix a bug in gsm_dlci_data_output (adaption = 2 case) ... Fix up Conflicts in: - drivers/tty/serial/8250_pci.c Trivial conflict with removed duplicate device ID - drivers/tty/serial/atmel_serial.c Annoying silly conflict between "specify the port num via platform_data" and other changes to atmel_console_init
Diffstat (limited to 'arch/mips/pmc-sierra/msp71xx/msp_serial.c')
-rw-r--r--arch/mips/pmc-sierra/msp71xx/msp_serial.c73
1 files changed, 67 insertions, 6 deletions
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_serial.c b/arch/mips/pmc-sierra/msp71xx/msp_serial.c
index f7261628d8a6..a1c7c7da2336 100644
--- a/arch/mips/pmc-sierra/msp71xx/msp_serial.c
+++ b/arch/mips/pmc-sierra/msp71xx/msp_serial.c
@@ -27,6 +27,7 @@
27#include <linux/serial.h> 27#include <linux/serial.h>
28#include <linux/serial_core.h> 28#include <linux/serial_core.h>
29#include <linux/serial_reg.h> 29#include <linux/serial_reg.h>
30#include <linux/slab.h>
30 31
31#include <asm/bootinfo.h> 32#include <asm/bootinfo.h>
32#include <asm/io.h> 33#include <asm/io.h>
@@ -38,6 +39,55 @@
38#include <msp_int.h> 39#include <msp_int.h>
39#include <msp_regs.h> 40#include <msp_regs.h>
40 41
42struct msp_uart_data {
43 int last_lcr;
44};
45
46static void msp_serial_out(struct uart_port *p, int offset, int value)
47{
48 struct msp_uart_data *d = p->private_data;
49
50 if (offset == UART_LCR)
51 d->last_lcr = value;
52
53 offset <<= p->regshift;
54 writeb(value, p->membase + offset);
55}
56
57static unsigned int msp_serial_in(struct uart_port *p, int offset)
58{
59 offset <<= p->regshift;
60
61 return readb(p->membase + offset);
62}
63
64static int msp_serial_handle_irq(struct uart_port *p)
65{
66 struct msp_uart_data *d = p->private_data;
67 unsigned int iir = readb(p->membase + (UART_IIR << p->regshift));
68
69 if (serial8250_handle_irq(p, iir)) {
70 return 1;
71 } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
72 /*
73 * The DesignWare APB UART has an Busy Detect (0x07) interrupt
74 * meaning an LCR write attempt occurred while the UART was
75 * busy. The interrupt must be cleared by reading the UART
76 * status register (USR) and the LCR re-written.
77 *
78 * Note: MSP reserves 0x20 bytes of address space for the UART
79 * and the USR is mapped in a separate block at an offset of
80 * 0xc0 from the start of the UART.
81 */
82 (void)readb(p->membase + 0xc0);
83 writeb(d->last_lcr, p->membase + (UART_LCR << p->regshift));
84
85 return 1;
86 }
87
88 return 0;
89}
90
41void __init msp_serial_setup(void) 91void __init msp_serial_setup(void)
42{ 92{
43 char *s; 93 char *s;
@@ -59,13 +109,22 @@ void __init msp_serial_setup(void)
59 up.irq = MSP_INT_UART0; 109 up.irq = MSP_INT_UART0;
60 up.uartclk = uartclk; 110 up.uartclk = uartclk;
61 up.regshift = 2; 111 up.regshift = 2;
62 up.iotype = UPIO_DWAPB; /* UPIO_MEM like */ 112 up.iotype = UPIO_MEM;
63 up.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST; 113 up.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
64 up.type = PORT_16550A; 114 up.type = PORT_16550A;
65 up.line = 0; 115 up.line = 0;
66 up.private_data = (void*)UART0_STATUS_REG; 116 up.serial_out = msp_serial_out;
67 if (early_serial_setup(&up)) 117 up.serial_in = msp_serial_in;
68 printk(KERN_ERR "Early serial init of port 0 failed\n"); 118 up.handle_irq = msp_serial_handle_irq;
119 up.private_data = kzalloc(sizeof(struct msp_uart_data), GFP_KERNEL);
120 if (!up.private_data) {
121 pr_err("failed to allocate uart private data\n");
122 return;
123 }
124 if (early_serial_setup(&up)) {
125 kfree(up.private_data);
126 pr_err("Early serial init of port 0 failed\n");
127 }
69 128
70 /* Initialize the second serial port, if one exists */ 129 /* Initialize the second serial port, if one exists */
71 switch (mips_machtype) { 130 switch (mips_machtype) {
@@ -88,6 +147,8 @@ void __init msp_serial_setup(void)
88 up.irq = MSP_INT_UART1; 147 up.irq = MSP_INT_UART1;
89 up.line = 1; 148 up.line = 1;
90 up.private_data = (void*)UART1_STATUS_REG; 149 up.private_data = (void*)UART1_STATUS_REG;
91 if (early_serial_setup(&up)) 150 if (early_serial_setup(&up)) {
92 printk(KERN_ERR "Early serial init of port 1 failed\n"); 151 kfree(up.private_data);
152 pr_err("Early serial init of port 1 failed\n");
153 }
93} 154}