diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-07 12:17:06 +0900 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-07 12:17:06 +0900 |
commit | 56edff7529d0baa6d7b38b58f46631c7b9f4136e (patch) | |
tree | 37729cd0a56ad31601fb573ccf3f5a2d7bee52e8 /drivers/tty/serial/8250/8250_dw.c | |
parent | 0324e74534241f3f00910ec04ef67de1fe1542f4 (diff) | |
parent | 80d8611dd07603736d14e4a942546bdc84dd5477 (diff) |
Merge tag 'tty-3.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty/serial driver updates from Greg KH:
"Here's the big tty/serial driver update for 3.13-rc1.
There's some more minor n_tty work here, but nothing like previous
kernel releases. Also some new driver ids, driver updates for new
hardware, and other small things.
All of this has been in linux-next for a while with no issues"
* tag 'tty-3.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (84 commits)
serial: omap: fix missing comma
serial: sh-sci: Enable the driver on all ARM platforms
serial: mfd: Staticize local symbols
serial: omap: fix a few checkpatch warnings
serial: omap: improve RS-485 performance
mrst_max3110: fix unbalanced IRQ issue during resume
serial: omap: Add support for optional wake-up
serial: sirf: remove duplicate defines
tty: xuartps: Fix build error when COMMON_CLK is not set
tty: xuartps: Fix build error due to missing forward declaration
tty: xuartps: Fix "may be used uninitialized" build warning
serial: 8250_pci: add Pericom PCIe Serial board Support (12d8:7952/4/8) - Chip PI7C9X7952/4/8
tty: xuartps: Update copyright information
tty: xuartps: Implement suspend/resume callbacks
tty: xuartps: Dynamically adjust to input frequency changes
tty: xuartps: Updating set_baud_rate()
tty: xuartps: Force enable the UART in xuartps_console_write
tty: xuartps: support 64 byte FIFO size
tty: xuartps: Add polled mode support for xuartps
tty: xuartps: Implement BREAK detection, add SYSRQ support
...
Diffstat (limited to 'drivers/tty/serial/8250/8250_dw.c')
-rw-r--r-- | drivers/tty/serial/8250/8250_dw.c | 76 |
1 files changed, 57 insertions, 19 deletions
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index daf710f5c3fc..4658e3e0ec42 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -56,11 +56,11 @@ struct dw8250_data { - int last_lcr; - int last_mcr; - int line; - struct clk *clk; - u8 usr_reg; + u8 usr_reg; + int last_mcr; + int line; + struct clk *clk; + struct uart_8250_dma dma; }; static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value) @@ -76,17 +76,33 @@ static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value) return value; } +static void dw8250_force_idle(struct uart_port *p) +{ + serial8250_clear_and_reinit_fifos(container_of + (p, struct uart_8250_port, port)); + (void)p->serial_in(p, UART_RX); +} + static void dw8250_serial_out(struct uart_port *p, int offset, int value) { struct dw8250_data *d = p->private_data; - if (offset == UART_LCR) - d->last_lcr = value; - if (offset == UART_MCR) d->last_mcr = value; writeb(value, p->membase + (offset << p->regshift)); + + /* Make sure LCR write wasn't ignored */ + if (offset == UART_LCR) { + int tries = 1000; + while (tries--) { + if (value == p->serial_in(p, UART_LCR)) + return; + dw8250_force_idle(p); + writeb(value, p->membase + (UART_LCR << p->regshift)); + } + dev_err(p->dev, "Couldn't set LCR to %d\n", value); + } } static unsigned int dw8250_serial_in(struct uart_port *p, int offset) @@ -107,13 +123,22 @@ static void dw8250_serial_out32(struct uart_port *p, int offset, int value) { struct dw8250_data *d = p->private_data; - if (offset == UART_LCR) - d->last_lcr = value; - if (offset == UART_MCR) d->last_mcr = value; writel(value, p->membase + (offset << p->regshift)); + + /* Make sure LCR write wasn't ignored */ + if (offset == UART_LCR) { + int tries = 1000; + while (tries--) { + if (value == p->serial_in(p, UART_LCR)) + return; + dw8250_force_idle(p); + writel(value, p->membase + (UART_LCR << p->regshift)); + } + dev_err(p->dev, "Couldn't set LCR to %d\n", value); + } } static unsigned int dw8250_serial_in32(struct uart_port *p, int offset) @@ -131,9 +156,8 @@ static int dw8250_handle_irq(struct uart_port *p) if (serial8250_handle_irq(p, iir)) { return 1; } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) { - /* Clear the USR and write the LCR again. */ + /* Clear the USR */ (void)p->serial_in(p, d->usr_reg); - p->serial_out(p, UART_LCR, d->last_lcr); return 1; } @@ -153,6 +177,14 @@ dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old) pm_runtime_put_sync_suspend(port->dev); } +static bool dw8250_dma_filter(struct dma_chan *chan, void *param) +{ + struct dw8250_data *data = param; + + return chan->chan_id == data->dma.tx_chan_id || + chan->chan_id == data->dma.rx_chan_id; +} + static void dw8250_setup_port(struct uart_8250_port *up) { struct uart_port *p = &up->port; @@ -241,7 +273,8 @@ static int dw8250_probe_of(struct uart_port *p, } #ifdef CONFIG_ACPI -static int dw8250_probe_acpi(struct uart_8250_port *up) +static int dw8250_probe_acpi(struct uart_8250_port *up, + struct dw8250_data *data) { const struct acpi_device_id *id; struct uart_port *p = &up->port; @@ -260,9 +293,7 @@ static int dw8250_probe_acpi(struct uart_8250_port *up) if (!p->uartclk) p->uartclk = (unsigned int)id->driver_data; - up->dma = devm_kzalloc(p->dev, sizeof(*up->dma), GFP_KERNEL); - if (!up->dma) - return -ENOMEM; + up->dma = &data->dma; up->dma->rxconf.src_maxburst = p->fifosize / 4; up->dma->txconf.dst_maxburst = p->fifosize / 4; @@ -270,7 +301,8 @@ static int dw8250_probe_acpi(struct uart_8250_port *up) return 0; } #else -static inline int dw8250_probe_acpi(struct uart_8250_port *up) +static inline int dw8250_probe_acpi(struct uart_8250_port *up, + struct dw8250_data *data) { return -ENODEV; } @@ -314,6 +346,12 @@ static int dw8250_probe(struct platform_device *pdev) uart.port.uartclk = clk_get_rate(data->clk); } + data->dma.rx_chan_id = -1; + data->dma.tx_chan_id = -1; + data->dma.rx_param = data; + data->dma.tx_param = data; + data->dma.fn = dw8250_dma_filter; + uart.port.iotype = UPIO_MEM; uart.port.serial_in = dw8250_serial_in; uart.port.serial_out = dw8250_serial_out; @@ -324,7 +362,7 @@ static int dw8250_probe(struct platform_device *pdev) if (err) return err; } else if (ACPI_HANDLE(&pdev->dev)) { - err = dw8250_probe_acpi(&uart); + err = dw8250_probe_acpi(&uart, data); if (err) return err; } else { |