diff options
-rw-r--r-- | drivers/tty/serial/8250_dw.c | 99 | ||||
-rw-r--r-- | drivers/tty/serial/Kconfig | 7 | ||||
-rw-r--r-- | drivers/tty/serial/Makefile | 1 | ||||
-rw-r--r-- | include/linux/serial_8250.h | 8 |
4 files changed, 115 insertions, 0 deletions
diff --git a/drivers/tty/serial/8250_dw.c b/drivers/tty/serial/8250_dw.c new file mode 100644 index 000000000000..e25782aeec7a --- /dev/null +++ b/drivers/tty/serial/8250_dw.c | |||
@@ -0,0 +1,99 @@ | |||
1 | /* | ||
2 | * Synopsys DesignWare specific 8250 operations. | ||
3 | * | ||
4 | * Copyright 2011 Picochip, Jamie Iles. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * The Synopsys DesignWare 8250 has an extra feature whereby it detects if the | ||
12 | * LCR is written whilst busy. If it is, then a busy detect interrupt is | ||
13 | * raised, the LCR needs to be rewritten and the uart status register read. | ||
14 | */ | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/serial_8250.h> | ||
17 | #include <linux/serial_core.h> | ||
18 | #include <linux/serial_reg.h> | ||
19 | #include <linux/slab.h> | ||
20 | |||
21 | struct dw8250_data { | ||
22 | int last_lcr; | ||
23 | }; | ||
24 | |||
25 | static void dw8250_serial_out(struct uart_port *p, int offset, int value) | ||
26 | { | ||
27 | struct dw8250_data *d = p->private_data; | ||
28 | |||
29 | if (offset == UART_LCR) | ||
30 | d->last_lcr = value; | ||
31 | |||
32 | offset <<= p->regshift; | ||
33 | writeb(value, p->membase + offset); | ||
34 | } | ||
35 | |||
36 | static unsigned int dw8250_serial_in(struct uart_port *p, int offset) | ||
37 | { | ||
38 | offset <<= p->regshift; | ||
39 | |||
40 | return readb(p->membase + offset); | ||
41 | } | ||
42 | |||
43 | static void dw8250_serial_out32(struct uart_port *p, int offset, | ||
44 | int value) | ||
45 | { | ||
46 | struct dw8250_data *d = p->private_data; | ||
47 | |||
48 | if (offset == UART_LCR) | ||
49 | d->last_lcr = value; | ||
50 | |||
51 | offset <<= p->regshift; | ||
52 | writel(value, p->membase + offset); | ||
53 | } | ||
54 | |||
55 | static unsigned int dw8250_serial_in32(struct uart_port *p, int offset) | ||
56 | { | ||
57 | offset <<= p->regshift; | ||
58 | |||
59 | return readl(p->membase + offset); | ||
60 | } | ||
61 | |||
62 | /* Offset for the DesignWare's UART Status Register. */ | ||
63 | #define UART_USR 0x1f | ||
64 | |||
65 | static int dw8250_handle_irq(struct uart_port *p) | ||
66 | { | ||
67 | struct dw8250_data *d = p->private_data; | ||
68 | unsigned int iir = p->serial_in(p, UART_IIR); | ||
69 | |||
70 | if (serial8250_handle_irq(p, iir)) { | ||
71 | return 1; | ||
72 | } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) { | ||
73 | /* Clear the USR and write the LCR again. */ | ||
74 | (void)p->serial_in(p, UART_USR); | ||
75 | p->serial_out(p, d->last_lcr, UART_LCR); | ||
76 | |||
77 | return 1; | ||
78 | } | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | int serial8250_use_designware_io(struct uart_port *up) | ||
84 | { | ||
85 | up->private_data = kzalloc(sizeof(struct dw8250_data), GFP_KERNEL); | ||
86 | if (!up->private_data) | ||
87 | return -ENOMEM; | ||
88 | |||
89 | if (up->iotype == UPIO_MEM32) { | ||
90 | up->serial_out = dw8250_serial_out32; | ||
91 | up->serial_in = dw8250_serial_in32; | ||
92 | } else { | ||
93 | up->serial_out = dw8250_serial_out; | ||
94 | up->serial_in = dw8250_serial_in; | ||
95 | } | ||
96 | up->handle_irq = dw8250_handle_irq; | ||
97 | |||
98 | return 0; | ||
99 | } | ||
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index a9b307f582e1..d2d1cc2329b7 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig | |||
@@ -267,6 +267,13 @@ config SERIAL_8250_RM9K | |||
267 | port hardware found on MIPS RM9122 and similar processors. | 267 | port hardware found on MIPS RM9122 and similar processors. |
268 | If unsure, say N. | 268 | If unsure, say N. |
269 | 269 | ||
270 | config SERIAL_8250_DW | ||
271 | bool "Support for Synopsys DesignWare 8250 quirks" | ||
272 | depends on SERIAL_8250 | ||
273 | help | ||
274 | Selecting this option will enable handling of the extra features | ||
275 | present in the Synopsys DesignWare APB UART. | ||
276 | |||
270 | comment "Non-8250 serial port support" | 277 | comment "Non-8250 serial port support" |
271 | 278 | ||
272 | config SERIAL_AMBA_PL010 | 279 | config SERIAL_AMBA_PL010 |
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 78748136ccc8..7b59958f50ec 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile | |||
@@ -28,6 +28,7 @@ obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o | |||
28 | obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o | 28 | obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o |
29 | obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o | 29 | obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o |
30 | obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o | 30 | obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o |
31 | obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o | ||
31 | obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o | 32 | obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o |
32 | obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o | 33 | obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o |
33 | obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o | 34 | obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o |
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index 1f05bbeac01e..09e2dbcd7ca3 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h | |||
@@ -86,5 +86,13 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir); | |||
86 | extern void serial8250_set_isa_configurator(void (*v) | 86 | extern void serial8250_set_isa_configurator(void (*v) |
87 | (int port, struct uart_port *up, | 87 | (int port, struct uart_port *up, |
88 | unsigned short *capabilities)); | 88 | unsigned short *capabilities)); |
89 | #ifndef SERIAL_8250_DW | ||
90 | extern int serial8250_use_designware_io(struct uart_port *up); | ||
91 | #else | ||
92 | static inline int serial8250_use_designware_io(struct uart_port *up) | ||
93 | { | ||
94 | return -EIO; | ||
95 | } | ||
96 | #endif | ||
89 | 97 | ||
90 | #endif | 98 | #endif |