diff options
Diffstat (limited to 'drivers/tty/serial/pxa.c')
| -rw-r--r-- | drivers/tty/serial/pxa.c | 203 |
1 files changed, 54 insertions, 149 deletions
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index 05f504e0c271..e395ff29c1a2 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Based on drivers/serial/8250.c by Russell King. * @@ -5,11 +6,6 @@ * Created: Feb 20, 2003 * Copyright: (C) 2003 Monta Vista Software, Inc. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * * Note 1: This driver is made separate from the already too overloaded * 8250.c because it needs some kirks of its own and that'll make it * easier to add DMA support. @@ -23,15 +19,11 @@ */ -#if defined(CONFIG_SERIAL_PXA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include <linux/module.h> #include <linux/ioport.h> #include <linux/init.h> #include <linux/console.h> #include <linux/sysrq.h> +#include <linux/serial.h> #include <linux/serial_reg.h> #include <linux/circ_buf.h> #include <linux/delay.h> @@ -98,7 +90,7 @@ static void serial_pxa_stop_rx(struct uart_port *port) static inline void receive_chars(struct uart_pxa_port *up, int *status) { - unsigned int ch, flag; + u8 ch, flag; int max_count = 256; do { @@ -159,7 +151,7 @@ static inline void receive_chars(struct uart_pxa_port *up, int *status) flag = TTY_FRAME; } - if (uart_handle_sysrq_char(&up->port, ch)) + if (uart_prepare_sysrq_char(&up->port, ch)) goto ignore_char; uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag); @@ -182,35 +174,12 @@ static inline void receive_chars(struct uart_pxa_port *up, int *status) static void transmit_chars(struct uart_pxa_port *up) { - struct circ_buf *xmit = &up->port.state->xmit; - int count; - - if (up->port.x_char) { - serial_out(up, UART_TX, up->port.x_char); - up->port.icount.tx++; - up->port.x_char = 0; - return; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { - serial_pxa_stop_tx(&up->port); - return; - } - - count = up->port.fifosize / 2; - do { - serial_out(up, UART_TX, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - up->port.icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&up->port); - + u8 ch; - if (uart_circ_empty(xmit)) - serial_pxa_stop_tx(&up->port); + uart_port_tx_limited(&up->port, ch, up->port.fifosize / 2, + true, + serial_out(up, UART_TX, ch), + ({})); } static void serial_pxa_start_tx(struct uart_port *port) @@ -223,6 +192,7 @@ static void serial_pxa_start_tx(struct uart_port *port) } } +/* should hold up->port.lock */ static inline void check_modem_status(struct uart_pxa_port *up) { int status; @@ -255,12 +225,14 @@ static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id) iir = serial_in(up, UART_IIR); if (iir & UART_IIR_NO_INT) return IRQ_NONE; + uart_port_lock(&up->port); lsr = serial_in(up, UART_LSR); if (lsr & UART_LSR_DR) receive_chars(up, &lsr); check_modem_status(up); if (lsr & UART_LSR_THRE) transmit_chars(up); + uart_unlock_and_check_sysrq(&up->port); return IRQ_HANDLED; } @@ -270,9 +242,9 @@ static unsigned int serial_pxa_tx_empty(struct uart_port *port) unsigned long flags; unsigned int ret; - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0; - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); return ret; } @@ -323,39 +295,14 @@ static void serial_pxa_break_ctl(struct uart_port *port, int break_state) struct uart_pxa_port *up = (struct uart_pxa_port *)port; unsigned long flags; - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); if (break_state == -1) up->lcr |= UART_LCR_SBC; else up->lcr &= ~UART_LCR_SBC; serial_out(up, UART_LCR, up->lcr); - spin_unlock_irqrestore(&up->port.lock, flags); -} - -#if 0 -static void serial_pxa_dma_init(struct pxa_uart *up) -{ - up->rxdma = - pxa_request_dma(up->name, DMA_PRIO_LOW, pxa_receive_dma, up); - if (up->rxdma < 0) - goto out; - up->txdma = - pxa_request_dma(up->name, DMA_PRIO_LOW, pxa_transmit_dma, up); - if (up->txdma < 0) - goto err_txdma; - up->dmadesc = kmalloc(4 * sizeof(pxa_dma_desc), GFP_KERNEL); - if (!up->dmadesc) - goto err_alloc; - - /* ... */ -err_alloc: - pxa_free_dma(up->txdma); -err_rxdma: - pxa_free_dma(up->rxdma); -out: - return; + uart_port_unlock_irqrestore(&up->port, flags); } -#endif static int serial_pxa_startup(struct uart_port *port) { @@ -399,10 +346,10 @@ static int serial_pxa_startup(struct uart_port *port) */ serial_out(up, UART_LCR, UART_LCR_WLEN8); - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); up->port.mctrl |= TIOCM_OUT2; serial_pxa_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); /* * Finally, enable interrupts. Note: Modem status interrupts @@ -436,10 +383,10 @@ static void serial_pxa_shutdown(struct uart_port *port) up->ier = 0; serial_out(up, UART_IER, 0); - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); up->port.mctrl &= ~TIOCM_OUT2; serial_pxa_set_mctrl(&up->port, up->port.mctrl); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); /* * Disable break condition and FIFOs @@ -453,7 +400,7 @@ static void serial_pxa_shutdown(struct uart_port *port) static void serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) + const struct ktermios *old) { struct uart_pxa_port *up = (struct uart_pxa_port *)port; unsigned char cval, fcr = 0; @@ -461,21 +408,7 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, unsigned int baud, quot; unsigned int dll; - switch (termios->c_cflag & CSIZE) { - case CS5: - cval = UART_LCR_WLEN5; - break; - case CS6: - cval = UART_LCR_WLEN6; - break; - case CS7: - cval = UART_LCR_WLEN7; - break; - default: - case CS8: - cval = UART_LCR_WLEN8; - break; - } + cval = UART_LCR_WLEN(tty_get_char_size(termios->c_cflag)); if (termios->c_cflag & CSTOPB) cval |= UART_LCR_STOP; @@ -501,7 +434,7 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, * Ok, we're now changing the port state. Do it with * interrupts disabled. */ - spin_lock_irqsave(&up->port.lock, flags); + uart_port_lock_irqsave(&up->port, &flags); /* * Ensure the port will be enabled. @@ -517,7 +450,7 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; if (termios->c_iflag & INPCK) up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (termios->c_iflag & (BRKINT | PARMRK)) + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) up->port.read_status_mask |= UART_LSR_BI; /* @@ -571,7 +504,7 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, up->lcr = cval; /* Save LCR */ serial_pxa_set_mctrl(&up->port, up->port.mctrl); serial_out(up, UART_FCR, fcr); - spin_unlock_irqrestore(&up->port.lock, flags); + uart_port_unlock_irqrestore(&up->port, flags); } static void @@ -620,12 +553,10 @@ static struct uart_driver serial_pxa_reg; #ifdef CONFIG_SERIAL_PXA_CONSOLE -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - /* * Wait for transmitter & holding register to empty */ -static inline void wait_for_xmitr(struct uart_pxa_port *up) +static void wait_for_xmitr(struct uart_pxa_port *up) { unsigned int status, tmout = 10000; @@ -639,7 +570,7 @@ static inline void wait_for_xmitr(struct uart_pxa_port *up) if (--tmout == 0) break; udelay(1); - } while ((status & BOTH_EMPTY) != BOTH_EMPTY); + } while (!uart_lsr_tx_empty(status)); /* Wait up to 1s for flow control if necessary */ if (up->port.flags & UPF_CONS_FLOW) { @@ -650,7 +581,7 @@ static inline void wait_for_xmitr(struct uart_pxa_port *up) } } -static void serial_pxa_console_putchar(struct uart_port *port, int ch) +static void serial_pxa_console_putchar(struct uart_port *port, unsigned char ch) { struct uart_pxa_port *up = (struct uart_pxa_port *)port; @@ -673,13 +604,10 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count) int locked = 1; clk_enable(up->clk); - local_irq_save(flags); - if (up->port.sysrq) - locked = 0; - else if (oops_in_progress) - locked = spin_trylock(&up->port.lock); + if (oops_in_progress) + locked = uart_port_trylock_irqsave(&up->port, &flags); else - spin_lock(&up->port.lock); + uart_port_lock_irqsave(&up->port, &flags); /* * First save the IER then disable the interrupts @@ -697,10 +625,8 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count) serial_out(up, UART_IER, ier); if (locked) - spin_unlock(&up->port.lock); - local_irq_restore(flags); + uart_port_unlock_irqrestore(&up->port, flags); clk_disable(up->clk); - } #ifdef CONFIG_CONSOLE_POLL @@ -736,13 +662,8 @@ static void serial_pxa_put_poll_char(struct uart_port *port, wait_for_xmitr(up); /* * Send the character out. - * If a LF, also do CR... */ serial_out(up, UART_TX, c); - if (c == 10) { - wait_for_xmitr(up); - serial_out(up, UART_TX, 13); - } /* * Finally, wait for transmitter to become empty @@ -790,7 +711,7 @@ static struct console serial_pxa_console = { #define PXA_CONSOLE NULL #endif -struct uart_ops serial_pxa_pops = { +static const struct uart_ops serial_pxa_pops = { .tx_empty = serial_pxa_tx_empty, .set_mctrl = serial_pxa_set_mctrl, .get_mctrl = serial_pxa_get_mctrl, @@ -808,7 +729,7 @@ struct uart_ops serial_pxa_pops = { .request_port = serial_pxa_request_port, .config_port = serial_pxa_config_port, .verify_port = serial_pxa_verify_port, -#ifdef CONFIG_CONSOLE_POLL +#if defined(CONFIG_CONSOLE_POLL) && defined(CONFIG_SERIAL_PXA_CONSOLE) .poll_get_char = serial_pxa_get_poll_char, .poll_put_char = serial_pxa_put_poll_char, #endif @@ -851,12 +772,11 @@ static const struct dev_pm_ops serial_pxa_pm_ops = { }; #endif -static struct of_device_id serial_pxa_dt_ids[] = { +static const struct of_device_id serial_pxa_dt_ids[] = { { .compatible = "mrvl,pxa-uart", }, { .compatible = "mrvl,mmp-uart", }, {} }; -MODULE_DEVICE_TABLE(of, serial_pxa_dt_ids); static int serial_pxa_probe_dt(struct platform_device *pdev, struct uart_pxa_port *sport) @@ -879,14 +799,18 @@ static int serial_pxa_probe_dt(struct platform_device *pdev, static int serial_pxa_probe(struct platform_device *dev) { struct uart_pxa_port *sport; - struct resource *mmres, *irqres; + struct resource *mmres; int ret; + int irq; mmres = platform_get_resource(dev, IORESOURCE_MEM, 0); - irqres = platform_get_resource(dev, IORESOURCE_IRQ, 0); - if (!mmres || !irqres) + if (!mmres) return -ENODEV; + irq = platform_get_irq(dev, 0); + if (irq < 0) + return irq; + sport = kzalloc(sizeof(struct uart_pxa_port), GFP_KERNEL); if (!sport) return -ENOMEM; @@ -906,18 +830,24 @@ static int serial_pxa_probe(struct platform_device *dev) sport->port.type = PORT_PXA; sport->port.iotype = UPIO_MEM; sport->port.mapbase = mmres->start; - sport->port.irq = irqres->start; + sport->port.irq = irq; sport->port.fifosize = 64; sport->port.ops = &serial_pxa_pops; sport->port.dev = &dev->dev; sport->port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; sport->port.uartclk = clk_get_rate(sport->clk); + sport->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_PXA_CONSOLE); ret = serial_pxa_probe_dt(dev, sport); if (ret > 0) sport->port.line = dev->id; else if (ret < 0) goto err_clk; + if (sport->port.line >= ARRAY_SIZE(serial_pxa_ports)) { + dev_err(&dev->dev, "serial%d out of range\n", sport->port.line); + ret = -EINVAL; + goto err_clk; + } snprintf(sport->name, PXA_NAME_LEN - 1, "UART%d", sport->port.line + 1); sport->port.membase = ioremap(mmres->start, resource_size(mmres)); @@ -941,36 +871,22 @@ static int serial_pxa_probe(struct platform_device *dev) return ret; } -static int serial_pxa_remove(struct platform_device *dev) -{ - struct uart_pxa_port *sport = platform_get_drvdata(dev); - - platform_set_drvdata(dev, NULL); - - uart_remove_one_port(&serial_pxa_reg, &sport->port); - - clk_unprepare(sport->clk); - clk_put(sport->clk); - kfree(sport); - - return 0; -} - static struct platform_driver serial_pxa_driver = { .probe = serial_pxa_probe, - .remove = serial_pxa_remove, .driver = { .name = "pxa2xx-uart", - .owner = THIS_MODULE, #ifdef CONFIG_PM .pm = &serial_pxa_pm_ops, #endif + .suppress_bind_attrs = true, .of_match_table = serial_pxa_dt_ids, }, }; -int __init serial_pxa_init(void) + +/* 8250 driver for PXA serial ports should be used */ +static int __init serial_pxa_init(void) { int ret; @@ -984,15 +900,4 @@ int __init serial_pxa_init(void) return ret; } - -void __exit serial_pxa_exit(void) -{ - platform_driver_unregister(&serial_pxa_driver); - uart_unregister_driver(&serial_pxa_reg); -} - -module_init(serial_pxa_init); -module_exit(serial_pxa_exit); - -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:pxa2xx-uart"); +device_initcall(serial_pxa_init); |
