diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-02 20:32:06 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-02 20:32:06 +0200 |
commit | 0de10f9ea67d1046b1e16c91fa26accf23939aab (patch) | |
tree | 1255e106529d0c708b3744dfd10367a535bda6f9 /drivers/tty/serial | |
parent | Merge tag 'usb-3.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gre... (diff) | |
parent | Revert "serial: 8250_pci: add support for another kind of NetMos Technology P... (diff) | |
download | linux-0de10f9ea67d1046b1e16c91fa26accf23939aab.tar.xz linux-0de10f9ea67d1046b1e16c91fa26accf23939aab.zip |
Merge tag 'tty-3.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty/serial updates from Greg KH:
"Here is the big TTY / Serial driver merge for 3.11-rc1.
It's not all that big, nothing major changed in the tty api, which is
a nice change, just a number of serial driver fixes and updates and
new drivers, along with some n_tty fixes to help resolve some reported
issues.
All of these have been in the linux-next releases for a while, with
the exception of the last revert patch, which was reported this past
weekend by two different people as being needed."
* tag 'tty-3.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (51 commits)
Revert "serial: 8250_pci: add support for another kind of NetMos Technology PCI 9835 Multi-I/O Controller"
pch_uart: Add uart_clk selection for the MinnowBoard
tty: atmel_serial: prepare clk before calling enable
tty: Reset itty for other pty
n_tty: Buffer work should not reschedule itself
n_tty: Fix unsafe update of available buffer space
n_tty: Untangle read completion variables
n_tty: Encapsulate minimum_to_wake within N_TTY
serial: omap: Fix device tree based PM runtime
serial: imx: Fix serial clock unbalance
serial/mpc52xx_uart: fix kernel panic when system reboot
serial: mfd: Add sysrq support
serial: imx: enable the clocks for console
tty: serial: add Freescale lpuart driver support
serial: imx: Improve Kconfig text
serial: imx: Allow module build
serial: imx: Fix warning when !CONFIG_SERIAL_IMX_CONSOLE
tty/serial/sirf: fix error propagation in sirfsoc_uart_probe()
serial: omap: fix potential NULL pointer dereference in serial_omap_runtime_suspend()
tty: serial: Enable uartlite for ARM zynq
...
Diffstat (limited to 'drivers/tty/serial')
26 files changed, 1423 insertions, 169 deletions
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 26e3a97ab157..c52948b368d8 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -4797,10 +4797,6 @@ static struct pci_device_id serial_pci_tbl[] = { PCI_VENDOR_ID_IBM, 0x0299, 0, 0, pbn_b0_bt_2_115200 }, - { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835, - 0x1000, 0x0012, - 0, 0, pbn_b0_bt_2_115200 }, - { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901, 0xA000, 0x1000, 0, 0, pbn_b0_1_115200 }, diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 80fe91e64a52..a1ba94d64885 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -12,9 +12,8 @@ config SERIAL_8250 here are those that are setting up dedicated Ethernet WWW/FTP servers, or users that have one of the various bus mice instead of a serial mouse and don't intend to use their machine's standard serial - port for anything. (Note that the Cyclades and Stallion multi - serial port drivers do not need this driver built in for them to - work.) + port for anything. (Note that the Cyclades multi serial port driver + does not need this driver built in for it to work.) To compile this driver as a module, choose M here: the module will be called 8250. diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 7e7006fd404e..46dd1c72feda 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -551,7 +551,7 @@ config BFIN_UART3_CTSRTS Enable hardware flow control in the driver. config SERIAL_IMX - bool "IMX serial port support" + tristate "IMX serial port support" depends on ARCH_MXC select SERIAL_CORE select RATIONAL @@ -561,22 +561,21 @@ config SERIAL_IMX config SERIAL_IMX_CONSOLE bool "Console on IMX serial port" - depends on SERIAL_IMX + depends on SERIAL_IMX=y select SERIAL_CORE_CONSOLE help - If you have enabled the serial port on the Motorola IMX + If you have enabled the serial port on the Freescale IMX CPU you can make it the console by answering Y to this option. Even if you say Y here, the currently visible virtual console (/dev/tty0) will still be used as the system console by default, but you can alter that using a kernel command line option such as - "console=ttySA0". (Try "man bootparam" or see the documentation of - your boot loader (lilo or loadlin) about how to pass options to the - kernel at boot time.) + "console=ttymxc0". (Try "man bootparam" or see the documentation of + your bootloader about how to pass options to the kernel at boot time.) config SERIAL_UARTLITE tristate "Xilinx uartlite serial port support" - depends on PPC32 || MICROBLAZE || MFD_TIMBERDALE + depends on PPC32 || MICROBLAZE || MFD_TIMBERDALE || ARCH_ZYNQ select SERIAL_CORE help Say Y here if you want to use the Xilinx uartlite serial controller. @@ -1484,6 +1483,20 @@ config SERIAL_RP2_NR_UARTS If multiple cards are present, the default limit of 32 ports may need to be increased. +config SERIAL_FSL_LPUART + tristate "Freescale lpuart serial port support" + select SERIAL_CORE + help + Support for the on-chip lpuart on some Freescale SOCs. + +config SERIAL_FSL_LPUART_CONSOLE + bool "Console on Freescale lpuart serial port" + depends on SERIAL_FSL_LPUART=y + select SERIAL_CORE_CONSOLE + help + If you have enabled the lpuart serial port on the Freescale SoCs, + you can make it the console by answering Y to this option. + endmenu endif # TTY diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index eedfec40e3dd..cf650f0cd6e4 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -85,3 +85,4 @@ obj-$(CONFIG_SERIAL_AR933X) += ar933x_uart.o obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o obj-$(CONFIG_SERIAL_ARC) += arc_uart.o obj-$(CONFIG_SERIAL_RP2) += rp2.o +obj-$(CONFIG_SERIAL_FSL_LPUART) += fsl_lpuart.o diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 13471dd95793..1d46966e2a65 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -604,7 +604,6 @@ static int altera_uart_remove(struct platform_device *pdev) if (port) { uart_remove_one_port(&altera_uart_driver, port); - platform_set_drvdata(pdev, NULL); port->mapbase = 0; } diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index e2774f9ecd59..ad41319d1d9b 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -79,13 +79,12 @@ struct vendor_data { bool dma_threshold; bool cts_event_workaround; - unsigned int (*get_fifosize)(unsigned int periphid); + unsigned int (*get_fifosize)(struct amba_device *dev); }; -static unsigned int get_fifosize_arm(unsigned int periphid) +static unsigned int get_fifosize_arm(struct amba_device *dev) { - unsigned int rev = (periphid >> 20) & 0xf; - return rev < 3 ? 16 : 32; + return amba_rev(dev) < 3 ? 16 : 32; } static struct vendor_data vendor_arm = { @@ -98,7 +97,7 @@ static struct vendor_data vendor_arm = { .get_fifosize = get_fifosize_arm, }; -static unsigned int get_fifosize_st(unsigned int periphid) +static unsigned int get_fifosize_st(struct amba_device *dev) { return 64; } @@ -2157,7 +2156,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) uap->lcrh_rx = vendor->lcrh_rx; uap->lcrh_tx = vendor->lcrh_tx; uap->old_cr = 0; - uap->fifosize = vendor->get_fifosize(dev->periphid); + uap->fifosize = vendor->get_fifosize(dev); uap->port.dev = &dev->dev; uap->port.mapbase = dev->res.start; uap->port.membase = base; diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 3467462869ce..691265faebbe 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -1100,7 +1100,7 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, * Enable the peripheral clock for this serial port. * This is called on uart_open() or a resume event. */ - clk_enable(atmel_port->clk); + clk_prepare_enable(atmel_port->clk); /* re-enable interrupts if we disabled some on suspend */ UART_PUT_IER(port, atmel_port->backup_imr); @@ -1114,7 +1114,7 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, * Disable the peripheral clock for this serial port. * This is called on uart_close() or a suspend event. */ - clk_disable(atmel_port->clk); + clk_disable_unprepare(atmel_port->clk); break; default: printk(KERN_ERR "atmel_serial: unknown pm %d\n", state); @@ -1458,9 +1458,10 @@ static void atmel_of_init_port(struct atmel_uart_port *atmel_port, /* * Configure the port from the platform device resource info. */ -static void atmel_init_port(struct atmel_uart_port *atmel_port, +static int atmel_init_port(struct atmel_uart_port *atmel_port, struct platform_device *pdev) { + int ret; struct uart_port *port = &atmel_port->uart; struct atmel_uart_data *pdata = pdev->dev.platform_data; @@ -1496,9 +1497,19 @@ static void atmel_init_port(struct atmel_uart_port *atmel_port, /* for console, the clock could already be configured */ if (!atmel_port->clk) { atmel_port->clk = clk_get(&pdev->dev, "usart"); - clk_enable(atmel_port->clk); + if (IS_ERR(atmel_port->clk)) { + ret = PTR_ERR(atmel_port->clk); + atmel_port->clk = NULL; + return ret; + } + ret = clk_prepare_enable(atmel_port->clk); + if (ret) { + clk_put(atmel_port->clk); + atmel_port->clk = NULL; + return ret; + } port->uartclk = clk_get_rate(atmel_port->clk); - clk_disable(atmel_port->clk); + clk_disable_unprepare(atmel_port->clk); /* only enable clock when USART is in use */ } @@ -1511,6 +1522,8 @@ static void atmel_init_port(struct atmel_uart_port *atmel_port, } else { atmel_port->tx_done_mask = ATMEL_US_TXRDY; } + + return 0; } struct platform_device *atmel_default_console_device; /* the serial console device */ @@ -1601,6 +1614,7 @@ static void __init atmel_console_get_options(struct uart_port *port, int *baud, static int __init atmel_console_setup(struct console *co, char *options) { + int ret; struct uart_port *port = &atmel_ports[co->index].uart; int baud = 115200; int bits = 8; @@ -1612,7 +1626,9 @@ static int __init atmel_console_setup(struct console *co, char *options) return -ENODEV; } - clk_enable(atmel_ports[co->index].clk); + ret = clk_prepare_enable(atmel_ports[co->index].clk); + if (ret) + return ret; UART_PUT_IDR(port, -1); UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); @@ -1645,6 +1661,7 @@ static struct console atmel_console = { */ static int __init atmel_console_init(void) { + int ret; if (atmel_default_console_device) { struct atmel_uart_data *pdata = atmel_default_console_device->dev.platform_data; @@ -1655,7 +1672,9 @@ static int __init atmel_console_init(void) port->uart.line = id; add_preferred_console(ATMEL_DEVICENAME, id, NULL); - atmel_init_port(port, atmel_default_console_device); + ret = atmel_init_port(port, atmel_default_console_device); + if (ret) + return ret; register_console(&atmel_console); } @@ -1786,7 +1805,9 @@ static int atmel_serial_probe(struct platform_device *pdev) port->backup_imr = 0; port->uart.line = ret; - atmel_init_port(port, pdev); + ret = atmel_init_port(port, pdev); + if (ret) + goto err; pinctrl = devm_pinctrl_get_select_default(&pdev->dev); if (IS_ERR(pinctrl)) { @@ -1812,9 +1833,9 @@ static int atmel_serial_probe(struct platform_device *pdev) && ATMEL_CONSOLE_DEVICE->flags & CON_ENABLED) { /* * The serial core enabled the clock for us, so undo - * the clk_enable() in atmel_console_setup() + * the clk_prepare_enable() in atmel_console_setup() */ - clk_disable(port->clk); + clk_disable_unprepare(port->clk); } #endif diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c index 97f4e1858649..f7672cae5321 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c @@ -1384,7 +1384,7 @@ static int cpm_uart_probe(struct platform_device *ofdev) if (index >= UART_NR) return -ENODEV; - dev_set_drvdata(&ofdev->dev, pinfo); + platform_set_drvdata(ofdev, pinfo); /* initialize the device pointer for the port */ pinfo->port.dev = &ofdev->dev; @@ -1398,7 +1398,7 @@ static int cpm_uart_probe(struct platform_device *ofdev) static int cpm_uart_remove(struct platform_device *ofdev) { - struct uart_cpm_port *pinfo = dev_get_drvdata(&ofdev->dev); + struct uart_cpm_port *pinfo = platform_get_drvdata(ofdev); return uart_remove_one_port(&cpm_reg, &pinfo->port); } diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c new file mode 100644 index 000000000000..263cfaabe9e2 --- /dev/null +++ b/drivers/tty/serial/fsl_lpuart.c @@ -0,0 +1,874 @@ +/* + * Freescale lpuart serial port driver + * + * Copyright 2012-2013 Freescale Semiconductor, 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. + */ + +#if defined(CONFIG_SERIAL_FSL_LPUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include <linux/module.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/clk.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/console.h> +#include <linux/serial_core.h> +#include <linux/tty_flip.h> + +/* All registers are 8-bit width */ +#define UARTBDH 0x00 +#define UARTBDL 0x01 +#define UARTCR1 0x02 +#define UARTCR2 0x03 +#define UARTSR1 0x04 +#define UARTCR3 0x06 +#define UARTDR 0x07 +#define UARTCR4 0x0a +#define UARTCR5 0x0b +#define UARTMODEM 0x0d +#define UARTPFIFO 0x10 +#define UARTCFIFO 0x11 +#define UARTSFIFO 0x12 +#define UARTTWFIFO 0x13 +#define UARTTCFIFO 0x14 +#define UARTRWFIFO 0x15 + +#define UARTBDH_LBKDIE 0x80 +#define UARTBDH_RXEDGIE 0x40 +#define UARTBDH_SBR_MASK 0x1f + +#define UARTCR1_LOOPS 0x80 +#define UARTCR1_RSRC 0x20 +#define UARTCR1_M 0x10 +#define UARTCR1_WAKE 0x08 +#define UARTCR1_ILT 0x04 +#define UARTCR1_PE 0x02 +#define UARTCR1_PT 0x01 + +#define UARTCR2_TIE 0x80 +#define UARTCR2_TCIE 0x40 +#define UARTCR2_RIE 0x20 +#define UARTCR2_ILIE 0x10 +#define UARTCR2_TE 0x08 +#define UARTCR2_RE 0x04 +#define UARTCR2_RWU 0x02 +#define UARTCR2_SBK 0x01 + +#define UARTSR1_TDRE 0x80 +#define UARTSR1_TC 0x40 +#define UARTSR1_RDRF 0x20 +#define UARTSR1_IDLE 0x10 +#define UARTSR1_OR 0x08 +#define UARTSR1_NF 0x04 +#define UARTSR1_FE 0x02 +#define UARTSR1_PE 0x01 + +#define UARTCR3_R8 0x80 +#define UARTCR3_T8 0x40 +#define UARTCR3_TXDIR 0x20 +#define UARTCR3_TXINV 0x10 +#define UARTCR3_ORIE 0x08 +#define UARTCR3_NEIE 0x04 +#define UARTCR3_FEIE 0x02 +#define UARTCR3_PEIE 0x01 + +#define UARTCR4_MAEN1 0x80 +#define UARTCR4_MAEN2 0x40 +#define UARTCR4_M10 0x20 +#define UARTCR4_BRFA_MASK 0x1f +#define UARTCR4_BRFA_OFF 0 + +#define UARTCR5_TDMAS 0x80 +#define UARTCR5_RDMAS 0x20 + +#define UARTMODEM_RXRTSE 0x08 +#define UARTMODEM_TXRTSPOL 0x04 +#define UARTMODEM_TXRTSE 0x02 +#define UARTMODEM_TXCTSE 0x01 + +#define UARTPFIFO_TXFE 0x80 +#define UARTPFIFO_FIFOSIZE_MASK 0x7 +#define UARTPFIFO_TXSIZE_OFF 4 +#define UARTPFIFO_RXFE 0x08 +#define UARTPFIFO_RXSIZE_OFF 0 + +#define UARTCFIFO_TXFLUSH 0x80 +#define UARTCFIFO_RXFLUSH 0x40 +#define UARTCFIFO_RXOFE 0x04 +#define UARTCFIFO_TXOFE 0x02 +#define UARTCFIFO_RXUFE 0x01 + +#define UARTSFIFO_TXEMPT 0x80 +#define UARTSFIFO_RXEMPT 0x40 +#define UARTSFIFO_RXOF 0x04 +#define UARTSFIFO_TXOF 0x02 +#define UARTSFIFO_RXUF 0x01 + +#define DRIVER_NAME "fsl-lpuart" +#define DEV_NAME "ttyLP" +#define UART_NR 6 + +struct lpuart_port { + struct uart_port port; + struct clk *clk; + unsigned int txfifo_size; + unsigned int rxfifo_size; +}; + +static struct of_device_id lpuart_dt_ids[] = { + { + .compatible = "fsl,vf610-lpuart", + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, lpuart_dt_ids); + +static void lpuart_stop_tx(struct uart_port *port) +{ + unsigned char temp; + + temp = readb(port->membase + UARTCR2); + temp &= ~(UARTCR2_TIE | UARTCR2_TCIE); + writeb(temp, port->membase + UARTCR2); +} + +static void lpuart_stop_rx(struct uart_port *port) +{ + unsigned char temp; + + temp = readb(port->membase + UARTCR2); + writeb(temp & ~UARTCR2_RE, port->membase + UARTCR2); +} + +static void lpuart_enable_ms(struct uart_port *port) +{ +} + +static inline void lpuart_transmit_buffer(struct lpuart_port *sport) +{ + struct circ_buf *xmit = &sport->port.state->xmit; + + while (!uart_circ_empty(xmit) && + (readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size)) { + writeb(xmit->buf[xmit->tail], sport->port.membase + UARTDR); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + sport->port.icount.tx++; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&sport->port); + + if (uart_circ_empty(xmit)) + lpuart_stop_tx(&sport->port); +} + +static void lpuart_start_tx(struct uart_port *port) +{ + struct lpuart_port *sport = container_of(port, struct lpuart_port, port); + unsigned char temp; + + temp = readb(port->membase + UARTCR2); + writeb(temp | UARTCR2_TIE, port->membase + UARTCR2); + + if (readb(port->membase + UARTSR1) & UARTSR1_TDRE) + lpuart_transmit_buffer(sport); +} + +static irqreturn_t lpuart_txint(int irq, void *dev_id) +{ + struct lpuart_port *sport = dev_id; + struct circ_buf *xmit = &sport->port.state->xmit; + unsigned long flags; + + spin_lock_irqsave(&sport->port.lock, flags); + if (sport->port.x_char) { + writeb(sport->port.x_char, sport->port.membase + UARTDR); + goto out; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { + lpuart_stop_tx(&sport->port); + goto out; + } + + lpuart_transmit_buffer(sport); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&sport->port); + +out: + spin_unlock_irqrestore(&sport->port.lock, flags); + return IRQ_HANDLED; +} + +static irqreturn_t lpuart_rxint(int irq, void *dev_id) +{ + struct lpuart_port *sport = dev_id; + unsigned int flg, ignored = 0; + struct tty_port *port = &sport->port.state->port; + unsigned long flags; + unsigned char rx, sr; + + spin_lock_irqsave(&sport->port.lock, flags); + + while (!(readb(sport->port.membase + UARTSFIFO) & UARTSFIFO_RXEMPT)) { + flg = TTY_NORMAL; + sport->port.icount.rx++; + /* + * to clear the FE, OR, NF, FE, PE flags, + * read SR1 then read DR + */ + sr = readb(sport->port.membase + UARTSR1); + rx = readb(sport->port.membase + UARTDR); + + if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx)) + continue; + + if (sr & (UARTSR1_PE | UARTSR1_OR | UARTSR1_FE)) { + if (sr & UARTSR1_PE) + sport->port.icount.parity++; + else if (sr & UARTSR1_FE) + sport->port.icount.frame++; + + if (sr & UARTSR1_OR) + sport->port.icount.overrun++; + + if (sr & sport->port.ignore_status_mask) { + if (++ignored > 100) + goto out; + continue; + } + + sr &= sport->port.read_status_mask; + + if (sr & UARTSR1_PE) + flg = TTY_PARITY; + else if (sr & UARTSR1_FE) + flg = TTY_FRAME; + + if (sr & UARTSR1_OR) + flg = TTY_OVERRUN; + +#ifdef SUPPORT_SYSRQ + sport->port.sysrq = 0; +#endif + } + + tty_insert_flip_char(port, rx, flg); + } + +out: + spin_unlock_irqrestore(&sport->port.lock, flags); + + tty_flip_buffer_push(port); + return IRQ_HANDLED; +} + +static irqreturn_t lpuart_int(int irq, void *dev_id) +{ + struct lpuart_port *sport = dev_id; + unsigned char sts; + + sts = readb(sport->port.membase + UARTSR1); + + if (sts & UARTSR1_RDRF) + lpuart_rxint(irq, dev_id); + + if (sts & UARTSR1_TDRE && + !(readb(sport->port.membase + UARTCR5) & UARTCR5_TDMAS)) + lpuart_txint(irq, dev_id); + + return IRQ_HANDLED; +} + +/* return TIOCSER_TEMT when transmitter is not busy */ +static unsigned int lpuart_tx_empty(struct uart_port *port) +{ + return (readb(port->membase + UARTSR1) & UARTSR1_TC) ? + TIOCSER_TEMT : 0; +} + +static unsigned int lpuart_get_mctrl(struct uart_port *port) +{ + unsigned int temp = 0; + unsigned char reg; + + reg = readb(port->membase + UARTMODEM); + if (reg & UARTMODEM_TXCTSE) + temp |= TIOCM_CTS; + + if (reg & UARTMODEM_RXRTSE) + temp |= TIOCM_RTS; + + return temp; +} + +static void lpuart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + unsigned char temp; + + temp = readb(port->membase + UARTMODEM) & + ~(UARTMODEM_RXRTSE | UARTMODEM_TXCTSE); + + if (mctrl & TIOCM_RTS) + temp |= UARTMODEM_RXRTSE; + + if (mctrl & TIOCM_CTS) + temp |= UARTMODEM_TXCTSE; + + writeb(temp, port->membase + UARTMODEM); +} + +static void lpuart_break_ctl(struct uart_port *port, int break_state) +{ + unsigned char temp; + + temp = readb(port->membase + UARTCR2) & ~UARTCR2_SBK; + + if (break_state != 0) + temp |= UARTCR2_SBK; + + writeb(temp, port->membase + UARTCR2); +} + +static void lpuart_setup_watermark(struct lpuart_port *sport) +{ + unsigned char val, cr2; + + cr2 = readb(sport->port.membase + UARTCR2); + cr2 &= ~(UARTCR2_TIE | UARTCR2_TCIE | UARTCR2_TE | + UARTCR2_RIE | UARTCR2_RE); + writeb(cr2, sport->port.membase + UARTCR2); + + /* determine FIFO size and enable FIFO mode */ + val = readb(sport->port.membase + UARTPFIFO); + + sport->txfifo_size = 0x1 << (((val >> UARTPFIFO_TXSIZE_OFF) & + UARTPFIFO_FIFOSIZE_MASK) + 1); + + sport->rxfifo_size = 0x1 << (((val >> UARTPFIFO_RXSIZE_OFF) & + UARTPFIFO_FIFOSIZE_MASK) + 1); + + writeb(val | UARTPFIFO_TXFE | UARTPFIFO_RXFE, + sport->port.membase + UARTPFIFO); + + /* flush Tx and Rx FIFO */ + writeb(UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH, + sport->port.membase + UARTCFIFO); + + writeb(2, sport->port.membase + UARTTWFIFO); + writeb(1, sport->port.membase + UARTRWFIFO); +} + +static int lpuart_startup(struct uart_port *port) +{ + struct lpuart_port *sport = container_of(port, struct lpuart_port, port); + int ret; + unsigned long flags; + unsigned char temp; + + ret = devm_request_irq(port->dev, port->irq, lpuart_int, 0, + DRIVER_NAME, sport); + if (ret) + return ret; + + spin_lock_irqsave(&sport->port.lock, flags); + + lpuart_setup_watermark(sport); + + temp = readb(sport->port.membase + UARTCR2); + temp |= (UARTCR2_RIE | UARTCR2_TIE | UARTCR2_RE | UARTCR2_TE); + writeb(temp, sport->port.membase + UARTCR2); + + spin_unlock_irqrestore(&sport->port.lock, flags); + return 0; +} + +static void lpuart_shutdown(struct uart_port *port) +{ + struct lpuart_port *sport = container_of(port, struct lpuart_port, port); + unsigned char temp; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + /* disable Rx/Tx and interrupts */ + temp = readb(port->membase + UARTCR2); + temp &= ~(UARTCR2_TE | UARTCR2_RE | + UARTCR2_TIE | UARTCR2_TCIE | UARTCR2_RIE); + writeb(temp, port->membase + UARTCR2); + + spin_unlock_irqrestore(&port->lock, flags); + + devm_free_irq(port->dev, port->irq, sport); +} + +static void +lpuart_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct lpuart_port *sport = container_of(port, struct lpuart_port, port); + unsigned long flags; + unsigned char cr1, old_cr1, old_cr2, cr4, bdh, modem; + unsigned int baud; + unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; + unsigned int sbr, brfa; + + cr1 = old_cr1 = readb(sport->port.membase + UARTCR1); + old_cr2 = readb(sport->port.membase + UARTCR2); + cr4 = readb(sport->port.membase + UARTCR4); + bdh = readb(sport->port.membase + UARTBDH); + modem = readb(sport->port.membase + UARTMODEM); + /* + * only support CS8 and CS7, and for CS7 must enable PE. + * supported mode: + * - (7,e/o,1) + * - (8,n,1) + * - (8,m/s,1) + * - (8,e/o,1) + */ + while ((termios->c_cflag & CSIZE) != CS8 && + (termios->c_cflag & CSIZE) != CS7) { + termios->c_cflag &= ~CSIZE; + termios->c_cflag |= old_csize; + old_csize = CS8; + } + + if ((termios->c_cflag & CSIZE) == CS8 || + (termios->c_cflag & CSIZE) == CS7) + cr1 = old_cr1 & ~UARTCR1_M; + + if (termios->c_cflag & CMSPAR) { + if ((termios->c_cflag & CSIZE) != CS8) { + termios->c_cflag &= ~CSIZE; + termios->c_cflag |= CS8; + } + cr1 |= UARTCR1_M; + } + + if (termios->c_cflag & CRTSCTS) { + modem |= (UARTMODEM_RXRTSE | UARTMODEM_TXCTSE); + } else { + termios->c_cflag &= ~CRTSCTS; + modem &= ~(UARTMODEM_RXRTSE | UARTMODEM_TXCTSE); + } + + if (termios->c_cflag & CSTOPB) + termios->c_cflag &= ~CSTOPB; + + /* parity must be enabled when CS7 to match 8-bits format */ + if ((termios->c_cflag & CSIZE) == CS7) + termios->c_cflag |= PARENB; + + if ((termios->c_cflag & PARENB)) { + if (termios->c_cflag & CMSPAR) { + cr1 &= ~UARTCR1_PE; + cr1 |= UARTCR1_M; + } else { + cr1 |= UARTCR1_PE; + if ((termios->c_cflag & CSIZE) == CS8) + cr1 |= UARTCR1_M; + if (termios->c_cflag & PARODD) + cr1 |= UARTCR1_PT; + else + cr1 &= ~UARTCR1_PT; + } + } + + /* ask the core to calculate the divisor */ + baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16); + + spin_lock_irqsave(&sport->port.lock, flags); + + sport->port.read_status_mask = 0; + if (termios->c_iflag & INPCK) + sport->port.read_status_mask |= (UARTSR1_FE | UARTSR1_PE); + if (termios->c_iflag & (BRKINT | PARMRK)) + sport->port.read_status_mask |= UARTSR1_FE; + + /* characters to ignore */ + sport->port.ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + sport->port.ignore_status_mask |= UARTSR1_PE; + if (termios->c_iflag & IGNBRK) { + sport->port.ignore_status_mask |= UARTSR1_FE; + /* + * if we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + sport->port.ignore_status_mask |= UARTSR1_OR; + } + + /* update the per-port timeout */ + uart_update_timeout(port, termios->c_cflag, baud); + + /* wait transmit engin complete */ + while (!(readb(sport->port.membase + UARTSR1) & UARTSR1_TC)) + barrier(); + + /* disable transmit and receive */ + writeb(old_cr2 & ~(UARTCR2_TE | UARTCR2_RE), + sport->port.membase + UARTCR2); + + sbr = sport->port.uartclk / (16 * baud); + brfa = ((sport->port.uartclk - (16 * sbr * baud)) * 2) / baud; + bdh &= ~UARTBDH_SBR_MASK; + bdh |= (sbr >> 8) & 0x1F; + cr4 &= ~UARTCR4_BRFA_MASK; + brfa &= UARTCR4_BRFA_MASK; + writeb(cr4 | brfa, sport->port.membase + UARTCR4); + writeb(bdh, sport->port.membase + UARTBDH); + writeb(sbr & 0xFF, sport->port.membase + UARTBDL); + writeb(cr1, sport->port.membase + UARTCR1); + writeb(modem, sport->port.membase + UARTMODEM); + + /* restore control register */ + writeb(old_cr2, sport->port.membase + UARTCR2); + + spin_unlock_irqrestore(&sport->port.lock, flags); +} + +static const char *lpuart_type(struct uart_port *port) +{ + return "FSL_LPUART"; +} + +static void lpuart_release_port(struct uart_port *port) +{ + /* nothing to do */ +} + +static int lpuart_request_port(struct uart_port *port) +{ + return 0; +} + +/* configure/autoconfigure the port */ +static void lpuart_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) + port->type = PORT_LPUART; +} + +static int lpuart_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + int ret = 0; + + if (ser->type != PORT_UNKNOWN && ser->type != PORT_LPUART) + ret = -EINVAL; + if (port->irq != ser->irq) + ret = -EINVAL; + if (ser->io_type != UPIO_MEM) + ret = -EINVAL; + if (port->uartclk / 16 != ser->baud_base) + ret = -EINVAL; + if (port->iobase != ser->port) + ret = -EINVAL; + if (ser->hub6 != 0) + ret = -EINVAL; + return ret; +} + +static struct uart_ops lpuart_pops = { + .tx_empty = lpuart_tx_empty, + .set_mctrl = lpuart_set_mctrl, + .get_mctrl = lpuart_get_mctrl, + .stop_tx = lpuart_stop_tx, + .start_tx = lpuart_start_tx, + .stop_rx = lpuart_stop_rx, + .enable_ms = lpuart_enable_ms, + .break_ctl = lpuart_break_ctl, + .startup = lpuart_startup, + .shutdown = lpuart_shutdown, + .set_termios = lpuart_set_termios, + .type = lpuart_type, + .request_port = lpuart_request_port, + .release_port = lpuart_release_port, + .config_port = lpuart_config_port, + .verify_port = lpuart_verify_port, +}; + +static struct lpuart_port *lpuart_ports[UART_NR]; + +#ifdef CONFIG_SERIAL_FSL_LPUART_CONSOLE +static void lpuart_console_putchar(struct uart_port *port, int ch) +{ + while (!(readb(port->membase + UARTSR1) & UARTSR1_TDRE)) + barrier(); + + writeb(ch, port->membase + UARTDR); +} + +static void +lpuart_console_write(struct console *co, const char *s, unsigned int count) +{ + struct lpuart_port *sport = lpuart_ports[co->index]; + unsigned char old_cr2, cr2; + + /* first save CR2 and then disable interrupts */ + cr2 = old_cr2 = readb(sport->port.membase + UARTCR2); + cr2 |= (UARTCR2_TE | UARTCR2_RE); + cr2 &= ~(UARTCR2_TIE | UARTCR2_TCIE | UARTCR2_RIE); + writeb(cr2, sport->port.membase + UARTCR2); + + uart_console_write(&sport->port, s, count, lpuart_console_putchar); + + /* wait for transmitter finish complete and restore CR2 */ + while (!(readb(sport->port.membase + UARTSR1) & UARTSR1_TC)) + barrier(); + + writeb(old_cr2, sport->port.membase + UARTCR2); +} + +/* + * if the port was already initialised (eg, by a boot loader), + * try to determine the current setup. + */ +static void __init +lpuart_console_get_options(struct lpuart_port *sport, int *baud, + int *parity, int *bits) +{ + unsigned char cr, bdh, bdl, brfa; + unsigned int sbr, uartclk, baud_raw; + + cr = readb(sport->port.membase + UARTCR2); + cr &= UARTCR2_TE | UARTCR2_RE; + if (!cr) + return; + + /* ok, the port was enabled */ + + cr = readb(sport->port.membase + UARTCR1); + + *parity = 'n'; + if (cr & UARTCR1_PE) { + if (cr & UARTCR1_PT) + *parity = 'o'; + else + *parity = 'e'; + } + + if (cr & UARTCR1_M) + *bits = 9; + else + *bits = 8; + + bdh = readb(sport->port.membase + UARTBDH); + bdh &= UARTBDH_SBR_MASK; + bdl = readb(sport->port.membase + UARTBDL); + sbr = bdh; + sbr <<= 8; + sbr |= bdl; + brfa = readb(sport->port.membase + UARTCR4); + brfa &= UARTCR4_BRFA_MASK; + + uartclk = clk_get_rate(sport->clk); + /* + * baud = mod_clk/(16*(sbr[13]+(brfa)/32) + */ + baud_raw = uartclk / (16 * (sbr + brfa / 32)); + + if (*baud != baud_raw) + printk(KERN_INFO "Serial: Console lpuart rounded baud rate" + "from %d to %d\n", baud_raw, *baud); +} + +static int __init lpuart_console_setup(struct console *co, char *options) +{ + struct lpuart_port *sport; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + /* + * check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index == -1 || co->index >= ARRAY_SIZE(lpuart_ports)) + co->index = 0; + + sport = lpuart_ports[co->index]; + if (sport == NULL) + return -ENODEV; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + lpuart_console_get_options(sport, &baud, &parity, &bits); + + lpuart_setup_watermark(sport); + + return uart_set_options(&sport->port, co, baud, parity, bits, flow); +} + +static struct uart_driver lpuart_reg; +static struct console lpuart_console = { + .name = DEV_NAME, + .write = lpuart_console_write, + .device = uart_console_device, + .setup = lpuart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &lpuart_reg, +}; + +#define LPUART_CONSOLE (&lpuart_console) +#else +#define LPUART_CONSOLE NULL +#endif + +static struct uart_driver lpuart_reg = { + .owner = THIS_MODULE, + .driver_name = DRIVER_NAME, + .dev_name = DEV_NAME, + .nr = ARRAY_SIZE(lpuart_ports), + .cons = LPUART_CONSOLE, +}; + +static int lpuart_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct lpuart_port *sport; + struct resource *res; + int ret; + + sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL); + if (!sport) + return -ENOMEM; + + pdev->dev.coherent_dma_mask = 0; + + ret = of_alias_get_id(np, "serial"); + if (ret < 0) { + dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); + return ret; + } + sport->port.line = ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + sport->port.mapbase = res->start; + sport->port.membase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(sport->port.membase)) + return PTR_ERR(sport->port.membase); + + sport->port.dev = &pdev->dev; + sport->port.type = PORT_LPUART; + sport->port.iotype = UPIO_MEM; + sport->port.irq = platform_get_irq(pdev, 0); + sport->port.ops = &lpuart_pops; + sport->port.flags = UPF_BOOT_AUTOCONF; + + sport->clk = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(sport->clk)) { + ret = PTR_ERR(sport->clk); + dev_err(&pdev->dev, "failed to get uart clk: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(sport->clk); + if (ret) { + dev_err(&pdev->dev, "failed to enable uart clk: %d\n", ret); + return ret; + } + + sport->port.uartclk = clk_get_rate(sport->clk); + + lpuart_ports[sport->port.line] = sport; + + platform_set_drvdata(pdev, &sport->port); + + ret = uart_add_one_port(&lpuart_reg, &sport->port); + if (ret) { + clk_disable_unprepare(sport->clk); + return ret; + } + + return 0; +} + +static int lpuart_remove(struct platform_device *pdev) +{ + struct lpuart_port *sport = platform_get_drvdata(pdev); + + uart_remove_one_port(&lpuart_reg, &sport->port); + + clk_disable_unprepare(sport->clk); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int lpuart_suspend(struct device *dev) +{ + struct lpuart_port *sport = dev_get_drvdata(dev); + + uart_suspend_port(&lpuart_reg, &sport->port); + + return 0; +} + +static int lpuart_resume(struct device *dev) +{ + struct lpuart_port *sport = dev_get_drvdata(dev); + + uart_resume_port(&lpuart_reg, &sport->port); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(lpuart_pm_ops, lpuart_suspend, lpuart_resume); + +static struct platform_driver lpuart_driver = { + .probe = lpuart_probe, + .remove = lpuart_remove, + .driver = { + .name = "fsl-lpuart", + .owner = THIS_MODULE, + .of_match_table = lpuart_dt_ids, + .pm = &lpuart_pm_ops, + }, +}; + +static int __init lpuart_serial_init(void) +{ + int ret; + + pr_info("serial: Freescale lpuart driver\n"); + + ret = uart_register_driver(&lpuart_reg); + if (ret) + return ret; + + ret = platform_driver_register(&lpuart_driver); + if (ret) + uart_unregister_driver(&lpuart_reg); + + return 0; +} + +static void __exit lpuart_serial_exit(void) +{ + platform_driver_unregister(&lpuart_driver); + uart_unregister_driver(&lpuart_reg); +} + +module_init(lpuart_serial_init); +module_exit(lpuart_serial_exit); + +MODULE_DESCRIPTION("Freescale lpuart serial port driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 8cdfbd365892..415cec62073f 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -201,6 +201,7 @@ struct imx_port { unsigned int old_status; int txirq, rxirq, rtsirq; unsigned int have_rtscts:1; + unsigned int dte_mode:1; unsigned int use_irda:1; unsigned int irda_inv_rx:1; unsigned int irda_inv_tx:1; @@ -271,6 +272,7 @@ static inline int is_imx21_uart(struct imx_port *sport) /* * Save and restore functions for UCR1, UCR2 and UCR3 registers */ +#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_IMX_CONSOLE) static void imx_port_ucrs_save(struct uart_port *port, struct imx_port_ucrs *ucr) { @@ -288,6 +290,7 @@ static void imx_port_ucrs_restore(struct uart_port *port, writel(ucr->ucr2, port->membase + UCR2); writel(ucr->ucr3, port->membase + UCR3); } +#endif /* * Handle any change of modem status signal since we were last called. @@ -449,6 +452,13 @@ static void imx_start_tx(struct uart_port *port) temp &= ~(UCR1_RRDYEN); writel(temp, sport->port.membase + UCR1); } + /* Clear any pending ORE flag before enabling interrupt */ + temp = readl(sport->port.membase + USR2); + writel(temp | USR2_ORE, sport->port.membase + USR2); + + temp = readl(sport->port.membase + UCR4); + temp |= UCR4_OREN; + writel(temp, sport->port.membase + UCR4); temp = readl(sport->port.membase + UCR1); writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1); @@ -582,6 +592,7 @@ static irqreturn_t imx_int(int irq, void *dev_id) { struct imx_port *sport = dev_id; unsigned int sts; + unsigned int sts2; sts = readl(sport->port.membase + USR1); @@ -598,6 +609,13 @@ static irqreturn_t imx_int(int irq, void *dev_id) if (sts & USR1_AWAKE) writel(USR1_AWAKE, sport->port.membase + USR1); + sts2 = readl(sport->port.membase + USR2); + if (sts2 & USR2_ORE) { + dev_err(sport->port.dev, "Rx FIFO overrun\n"); + sport->port.icount.overrun++; + writel(sts2 | USR2_ORE, sport->port.membase + USR2); + } + return IRQ_HANDLED; } @@ -684,6 +702,17 @@ static int imx_startup(struct uart_port *port) int retval; unsigned long flags, temp; + if (!uart_console(port)) { + retval = clk_prepare_enable(sport->clk_per); + if (retval) + goto error_out1; + retval = clk_prepare_enable(sport->clk_ipg); + if (retval) { + clk_disable_unprepare(sport->clk_per); + goto error_out1; + } + } + imx_setup_ufcr(sport, 0); /* disable the DREN bit (Data Ready interrupt enable) before @@ -871,6 +900,11 @@ static void imx_shutdown(struct uart_port *port) writel(temp, sport->port.membase + UCR1); spin_unlock_irqrestore(&sport->port.lock, flags); + + if (!uart_console(&sport->port)) { + clk_disable_unprepare(sport->clk_per); + clk_disable_unprepare(sport->clk_ipg); + } } static void @@ -1007,6 +1041,8 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, ufcr = readl(sport->port.membase + UFCR); ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div); + if (sport->dte_mode) + ufcr |= UFCR_DCEDTE; writel(ufcr, sport->port.membase + UFCR); writel(num, sport->port.membase + UBIR); @@ -1431,6 +1467,9 @@ static int serial_imx_probe_dt(struct imx_port *sport, if (of_get_property(np, "fsl,irda-mode", NULL)) sport->use_irda = 1; + if (of_get_property(np, "fsl,dte-mode", NULL)) + sport->dte_mode = 1; + sport->devdata = of_id->data; return 0; @@ -1544,6 +1583,11 @@ static int serial_imx_probe(struct platform_device *pdev) goto deinit; platform_set_drvdata(pdev, sport); + if (!uart_console(&sport->port)) { + clk_disable_unprepare(sport->clk_per); + clk_disable_unprepare(sport->clk_ipg); + } + return 0; deinit: if (pdata && pdata->exit) @@ -1565,9 +1609,6 @@ static int serial_imx_remove(struct platform_device *pdev) uart_remove_one_port(&imx_reg, &sport->port); - clk_disable_unprepare(sport->clk_per); - clk_disable_unprepare(sport->clk_ipg); - if (pdata && pdata->exit) pdata->exit(pdev); diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c index 5f4765a7a5c5..e266eca0ec76 100644 --- a/drivers/tty/serial/mfd.c +++ b/drivers/tty/serial/mfd.c @@ -21,6 +21,10 @@ * be triggered */ +#if defined(CONFIG_SERIAL_MFD_HSU_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + #include <linux/module.h> #include <linux/init.h> #include <linux/console.h> diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index f51b280f3bf2..e1280a20b7a2 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -84,16 +84,6 @@ static void mpc52xx_uart_of_enumerate(void); static irqreturn_t mpc52xx_uart_int(int irq, void *dev_id); static irqreturn_t mpc5xxx_uart_process_int(struct uart_port *port); - -/* Simple macro to test if a port is console or not. This one is taken - * for serial_core.c and maybe should be moved to serial_core.h ? */ -#ifdef CONFIG_SERIAL_CORE_CONSOLE -#define uart_console(port) \ - ((port)->cons && (port)->cons->index == (port)->line) -#else -#define uart_console(port) (0) -#endif - /* ======================================================================== */ /* PSC fifo operations for isolating differences between 52xx and 512x */ /* ======================================================================== */ @@ -122,6 +112,15 @@ struct psc_ops { void (*fifoc_uninit)(void); void (*get_irq)(struct uart_port *, struct device_node *); irqreturn_t (*handle_irq)(struct uart_port *port); + u16 (*get_status)(struct uart_port *port); + u8 (*get_ipcr)(struct uart_port *port); + void (*command)(struct uart_port *port, u8 cmd); + void (*set_mode)(struct uart_port *port, u8 mr1, u8 mr2); + void (*set_rts)(struct uart_port *port, int state); + void (*enable_ms)(struct uart_port *port); + void (*set_sicr)(struct uart_port *port, u32 val); + void (*set_imr)(struct uart_port *port, u16 val); + u8 (*get_mr1)(struct uart_port *port); }; /* setting the prescaler and divisor reg is common for all chips */ @@ -134,6 +133,65 @@ static inline void mpc52xx_set_divisor(struct mpc52xx_psc __iomem *psc, out_8(&psc->ctlr, divisor & 0xff); } +static u16 mpc52xx_psc_get_status(struct uart_port *port) +{ + return in_be16(&PSC(port)->mpc52xx_psc_status); +} + +static u8 mpc52xx_psc_get_ipcr(struct uart_port *port) +{ + return in_8(&PSC(port)->mpc52xx_psc_ipcr); +} + +static void mpc52xx_psc_command(struct uart_port *port, u8 cmd) +{ + out_8(&PSC(port)->command, cmd); +} + +static void mpc52xx_psc_set_mode(struct uart_port *port, u8 mr1, u8 mr2) +{ + out_8(&PSC(port)->command, MPC52xx_PSC_SEL_MODE_REG_1); + out_8(&PSC(port)->mode, mr1); + out_8(&PSC(port)->mode, mr2); +} + +static void mpc52xx_psc_set_rts(struct uart_port *port, int state) +{ + if (state) + out_8(&PSC(port)->op1, MPC52xx_PSC_OP_RTS); + else + out_8(&PSC(port)->op0, MPC52xx_PSC_OP_RTS); +} + +static void mpc52xx_psc_enable_ms(struct uart_port *port) +{ + 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 mpc52xx_psc_set_sicr(struct uart_port *port, u32 val) +{ + out_be32(&PSC(port)->sicr, val); +} + +static void mpc52xx_psc_set_imr(struct uart_port *port, u16 val) +{ + out_be16(&PSC(port)->mpc52xx_psc_imr, val); +} + +static u8 mpc52xx_psc_get_mr1(struct uart_port *port) +{ + out_8(&PSC(port)->command, MPC52xx_PSC_SEL_MODE_REG_1); + return in_8(&PSC(port)->mode); +} + #ifdef CONFIG_PPC_MPC52xx #define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1)) static void mpc52xx_psc_fifo_init(struct uart_port *port) @@ -304,6 +362,15 @@ static struct psc_ops mpc52xx_psc_ops = { .set_baudrate = mpc5200_psc_set_baudrate, .get_irq = mpc52xx_psc_get_irq, .handle_irq = mpc52xx_psc_handle_irq, + .get_status = mpc52xx_psc_get_status, + .get_ipcr = mpc52xx_psc_get_ipcr, + .command = mpc52xx_psc_command, + .set_mode = mpc52xx_psc_set_mode, + .set_rts = mpc52xx_psc_set_rts, + .enable_ms = mpc52xx_psc_enable_ms, + .set_sicr = mpc52xx_psc_set_sicr, + .set_imr = mpc52xx_psc_set_imr, + .get_mr1 = mpc52xx_psc_get_mr1, }; static struct psc_ops mpc5200b_psc_ops = { @@ -325,6 +392,15 @@ static struct psc_ops mpc5200b_psc_ops = { .set_baudrate = mpc5200b_psc_set_baudrate, .get_irq = mpc52xx_psc_get_irq, .handle_irq = mpc52xx_psc_handle_irq, + .get_status = mpc52xx_psc_get_status, + .get_ipcr = mpc52xx_psc_get_ipcr, + .command = mpc52xx_psc_command, + .set_mode = mpc52xx_psc_set_mode, + .set_rts = mpc52xx_psc_set_rts, + .enable_ms = mpc52xx_psc_enable_ms, + .set_sicr = mpc52xx_psc_set_sicr, + .set_imr = mpc52xx_psc_set_imr, + .get_mr1 = mpc52xx_psc_get_mr1, }; #endif /* CONFIG_MPC52xx */ @@ -572,6 +648,246 @@ static void mpc512x_psc_get_irq(struct uart_port *port, struct device_node *np) port->irqflags = IRQF_SHARED; port->irq = psc_fifoc_irq; } +#endif + +#ifdef CONFIG_PPC_MPC512x + +#define PSC_5125(port) ((struct mpc5125_psc __iomem *)((port)->membase)) +#define FIFO_5125(port) ((struct mpc512x_psc_fifo __iomem *)(PSC_5125(port)+1)) + +static void mpc5125_psc_fifo_init(struct uart_port *port) +{ + /* /32 prescaler */ + out_8(&PSC_5125(port)->mpc52xx_psc_clock_select, 0xdd); + + out_be32(&FIFO_5125(port)->txcmd, MPC512x_PSC_FIFO_RESET_SLICE); + out_be32(&FIFO_5125(port)->txcmd, MPC512x_PSC_FIFO_ENABLE_SLICE); + out_be32(&FIFO_5125(port)->txalarm, 1); + out_be32(&FIFO_5125(port)->tximr, 0); + + out_be32(&FIFO_5125(port)->rxcmd, MPC512x_PSC_FIFO_RESET_SLICE); + out_be32(&FIFO_5125(port)->rxcmd, MPC512x_PSC_FIFO_ENABLE_SLICE); + out_be32(&FIFO_5125(port)->rxalarm, 1); + out_be32(&FIFO_5125(port)->rximr, 0); + + out_be32(&FIFO_5125(port)->tximr, MPC512x_PSC_FIFO_ALARM); + out_be32(&FIFO_5125(port)->rximr, MPC512x_PSC_FIFO_ALARM); +} + +static int mpc5125_psc_raw_rx_rdy(struct uart_port *port) +{ + return !(in_be32(&FIFO_5125(port)->rxsr) & MPC512x_PSC_FIFO_EMPTY); +} + +static int mpc5125_psc_raw_tx_rdy(struct uart_port *port) +{ + return !(in_be32(&FIFO_5125(port)->txsr) & MPC512x_PSC_FIFO_FULL); +} + +static int mpc5125_psc_rx_rdy(struct uart_port *port) +{ + return in_be32(&FIFO_5125(port)->rxsr) & + in_be32(&FIFO_5125(port)->rximr) & MPC512x_PSC_FIFO_ALARM; +} + +static int mpc5125_psc_tx_rdy(struct uart_port *port) +{ + return in_be32(&FIFO_5125(port)->txsr) & + in_be32(&FIFO_5125(port)->tximr) & MPC512x_PSC_FIFO_ALARM; +} + +static int mpc5125_psc_tx_empty(struct uart_port *port) +{ + return in_be32(&FIFO_5125(port)->txsr) & MPC512x_PSC_FIFO_EMPTY; +} + +static void mpc5125_psc_stop_rx(struct uart_port *port) +{ + unsigned long rx_fifo_imr; + + rx_fifo_imr = in_be32(&FIFO_5125(port)->rximr); + rx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM; + out_be32(&FIFO_5125(port)->rximr, rx_fifo_imr); +} + +static void mpc5125_psc_start_tx(struct uart_port *port) +{ + unsigned long tx_fifo_imr; + + tx_fifo_imr = in_be32(&FIFO_5125(port)->tximr); + tx_fifo_imr |= MPC512x_PSC_FIFO_ALARM; + out_be32(&FIFO_5125(port)->tximr, tx_fifo_imr); +} + +static void mpc5125_psc_stop_tx(struct uart_port *port) +{ + unsigned long tx_fifo_imr; + + tx_fifo_imr = in_be32(&FIFO_5125(port)->tximr); + tx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM; + out_be32(&FIFO_5125(port)->tximr, tx_fifo_imr); +} + +static void mpc5125_psc_rx_clr_irq(struct uart_port *port) +{ + out_be32(&FIFO_5125(port)->rxisr, in_be32(&FIFO_5125(port)->rxisr)); +} + +static void mpc5125_psc_tx_clr_irq(struct uart_port *port) +{ + out_be32(&FIFO_5125(port)->txisr, in_be32(&FIFO_5125(port)->txisr)); +} + +static void mpc5125_psc_write_char(struct uart_port *port, unsigned char c) +{ + out_8(&FIFO_5125(port)->txdata_8, c); +} + +static unsigned char mpc5125_psc_read_char(struct uart_port *port) +{ + return in_8(&FIFO_5125(port)->rxdata_8); +} + +static void mpc5125_psc_cw_disable_ints(struct uart_port *port) +{ + port->read_status_mask = + in_be32(&FIFO_5125(port)->tximr) << 16 | + in_be32(&FIFO_5125(port)->rximr); + out_be32(&FIFO_5125(port)->tximr, 0); + out_be32(&FIFO_5125(port)->rximr, 0); +} + +static void mpc5125_psc_cw_restore_ints(struct uart_port *port) +{ + out_be32(&FIFO_5125(port)->tximr, + (port->read_status_mask >> 16) & 0x7f); + out_be32(&FIFO_5125(port)->rximr, port->read_status_mask & 0x7f); +} + +static inline void mpc5125_set_divisor(struct mpc5125_psc __iomem *psc, + u8 prescaler, unsigned int divisor) +{ + /* select prescaler */ + out_8(&psc->mpc52xx_psc_clock_select, prescaler); + out_8(&psc->ctur, divisor >> 8); + out_8(&psc->ctlr, divisor & 0xff); +} + +static unsigned int mpc5125_psc_set_baudrate(struct uart_port *port, + struct ktermios *new, + struct ktermios *old) +{ + unsigned int baud; + unsigned int divisor; + + /* + * Calculate with a /16 prescaler here. + */ + + /* uartclk contains the ips freq */ + baud = uart_get_baud_rate(port, new, old, + port->uartclk / (16 * 0xffff) + 1, + port->uartclk / 16); + divisor = (port->uartclk + 8 * baud) / (16 * baud); + + /* enable the /16 prescaler and set the divisor */ + mpc5125_set_divisor(PSC_5125(port), 0xdd, divisor); + return baud; +} + +/* + * MPC5125 have compatible PSC FIFO Controller. + * Special init not needed. + */ +static u16 mpc5125_psc_get_status(struct uart_port *port) +{ + return in_be16(&PSC_5125(port)->mpc52xx_psc_status); +} + +static u8 mpc5125_psc_get_ipcr(struct uart_port *port) +{ + return in_8(&PSC_5125(port)->mpc52xx_psc_ipcr); +} + +static void mpc5125_psc_command(struct uart_port *port, u8 cmd) +{ + out_8(&PSC_5125(port)->command, cmd); +} + +static void mpc5125_psc_set_mode(struct uart_port *port, u8 mr1, u8 mr2) +{ + out_8(&PSC_5125(port)->mr1, mr1); + out_8(&PSC_5125(port)->mr2, mr2); +} + +static void mpc5125_psc_set_rts(struct uart_port *port, int state) +{ + if (state & TIOCM_RTS) + out_8(&PSC_5125(port)->op1, MPC52xx_PSC_OP_RTS); + else + out_8(&PSC_5125(port)->op0, MPC52xx_PSC_OP_RTS); +} + +static void mpc5125_psc_enable_ms(struct uart_port *port) +{ + struct mpc5125_psc __iomem *psc = PSC_5125(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 mpc5125_psc_set_sicr(struct uart_port *port, u32 val) +{ + out_be32(&PSC_5125(port)->sicr, val); +} + +static void mpc5125_psc_set_imr(struct uart_port *port, u16 val) +{ + out_be16(&PSC_5125(port)->mpc52xx_psc_imr, val); +} + +static u8 mpc5125_psc_get_mr1(struct uart_port *port) +{ + return in_8(&PSC_5125(port)->mr1); +} + +static struct psc_ops mpc5125_psc_ops = { + .fifo_init = mpc5125_psc_fifo_init, + .raw_rx_rdy = mpc5125_psc_raw_rx_rdy, + .raw_tx_rdy = mpc5125_psc_raw_tx_rdy, + .rx_rdy = mpc5125_psc_rx_rdy, + .tx_rdy = mpc5125_psc_tx_rdy, + .tx_empty = mpc5125_psc_tx_empty, + .stop_rx = mpc5125_psc_stop_rx, + .start_tx = mpc5125_psc_start_tx, + .stop_tx = mpc5125_psc_stop_tx, + .rx_clr_irq = mpc5125_psc_rx_clr_irq, + .tx_clr_irq = mpc5125_psc_tx_clr_irq, + .write_char = mpc5125_psc_write_char, + .read_char = mpc5125_psc_read_char, + .cw_disable_ints = mpc5125_psc_cw_disable_ints, + .cw_restore_ints = mpc5125_psc_cw_restore_ints, + .set_baudrate = mpc5125_psc_set_baudrate, + .clock = mpc512x_psc_clock, + .fifoc_init = mpc512x_psc_fifoc_init, + .fifoc_uninit = mpc512x_psc_fifoc_uninit, + .get_irq = mpc512x_psc_get_irq, + .handle_irq = mpc512x_psc_handle_irq, + .get_status = mpc5125_psc_get_status, + .get_ipcr = mpc5125_psc_get_ipcr, + .command = mpc5125_psc_command, + .set_mode = mpc5125_psc_set_mode, + .set_rts = mpc5125_psc_set_rts, + .enable_ms = mpc5125_psc_enable_ms, + .set_sicr = mpc5125_psc_set_sicr, + .set_imr = mpc5125_psc_set_imr, + .get_mr1 = mpc5125_psc_get_mr1, +}; static struct psc_ops mpc512x_psc_ops = { .fifo_init = mpc512x_psc_fifo_init, @@ -595,8 +911,18 @@ static struct psc_ops mpc512x_psc_ops = { .fifoc_uninit = mpc512x_psc_fifoc_uninit, .get_irq = mpc512x_psc_get_irq, .handle_irq = mpc512x_psc_handle_irq, + .get_status = mpc52xx_psc_get_status, + .get_ipcr = mpc52xx_psc_get_ipcr, + .command = mpc52xx_psc_command, + .set_mode = mpc52xx_psc_set_mode, + .set_rts = mpc52xx_psc_set_rts, + .enable_ms = mpc52xx_psc_enable_ms, + .set_sicr = mpc52xx_psc_set_sicr, + .set_imr = mpc52xx_psc_set_imr, + .get_mr1 = mpc52xx_psc_get_mr1, }; -#endif +#endif /* CONFIG_PPC_MPC512x */ + static const struct psc_ops *psc_ops; @@ -613,17 +939,14 @@ mpc52xx_uart_tx_empty(struct uart_port *port) static void mpc52xx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) { - if (mctrl & TIOCM_RTS) - out_8(&PSC(port)->op1, MPC52xx_PSC_OP_RTS); - else - out_8(&PSC(port)->op0, MPC52xx_PSC_OP_RTS); + psc_ops->set_rts(port, mctrl & TIOCM_RTS); } static unsigned int mpc52xx_uart_get_mctrl(struct uart_port *port) { unsigned int ret = TIOCM_DSR; - u8 status = in_8(&PSC(port)->mpc52xx_psc_ipcr); + u8 status = psc_ops->get_ipcr(port); if (!(status & MPC52xx_PSC_CTS)) ret |= TIOCM_CTS; @@ -673,15 +996,7 @@ mpc52xx_uart_stop_rx(struct uart_port *port) static void mpc52xx_uart_enable_ms(struct uart_port *port) { - 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); + psc_ops->enable_ms(port); } static void @@ -691,9 +1006,9 @@ mpc52xx_uart_break_ctl(struct uart_port *port, int ctl) spin_lock_irqsave(&port->lock, flags); if (ctl == -1) - out_8(&PSC(port)->command, MPC52xx_PSC_START_BRK); + psc_ops->command(port, MPC52xx_PSC_START_BRK); else - out_8(&PSC(port)->command, MPC52xx_PSC_STOP_BRK); + psc_ops->command(port, MPC52xx_PSC_STOP_BRK); spin_unlock_irqrestore(&port->lock, flags); } @@ -701,7 +1016,6 @@ mpc52xx_uart_break_ctl(struct uart_port *port, int ctl) static int mpc52xx_uart_startup(struct uart_port *port) { - struct mpc52xx_psc __iomem *psc = PSC(port); int ret; if (psc_ops->clock) { @@ -717,15 +1031,15 @@ mpc52xx_uart_startup(struct uart_port *port) return ret; /* Reset/activate the port, clear and enable interrupts */ - out_8(&psc->command, MPC52xx_PSC_RST_RX); - out_8(&psc->command, MPC52xx_PSC_RST_TX); + psc_ops->command(port, MPC52xx_PSC_RST_RX); + psc_ops->command(port, MPC52xx_PSC_RST_TX); - out_be32(&psc->sicr, 0); /* UART mode DCD ignored */ + psc_ops->set_sicr(port, 0); /* UART mode DCD ignored */ psc_ops->fifo_init(port); - out_8(&psc->command, MPC52xx_PSC_TX_ENABLE); - out_8(&psc->command, MPC52xx_PSC_RX_ENABLE); + psc_ops->command(port, MPC52xx_PSC_TX_ENABLE); + psc_ops->command(port, MPC52xx_PSC_RX_ENABLE); return 0; } @@ -733,19 +1047,20 @@ mpc52xx_uart_startup(struct uart_port *port) static void mpc52xx_uart_shutdown(struct uart_port *port) { - struct mpc52xx_psc __iomem *psc = PSC(port); - /* Shut down the port. Leave TX active if on a console port */ - out_8(&psc->command, MPC52xx_PSC_RST_RX); + psc_ops->command(port, MPC52xx_PSC_RST_RX); if (!uart_console(port)) - out_8(&psc->command, MPC52xx_PSC_RST_TX); + psc_ops->command(port, MPC52xx_PSC_RST_TX); port->read_status_mask = 0; - out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask); + psc_ops->set_imr(port, port->read_status_mask); if (psc_ops->clock) psc_ops->clock(port, 0); + /* Disable interrupt */ + psc_ops->cw_disable_ints(port); + /* Release interrupt */ free_irq(port->irq, port); } @@ -754,7 +1069,6 @@ static void mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new, struct ktermios *old) { - struct mpc52xx_psc __iomem *psc = PSC(port); unsigned long flags; unsigned char mr1, mr2; unsigned int j; @@ -818,13 +1132,11 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new, "Some chars may have been lost.\n"); /* Reset the TX & RX */ - out_8(&psc->command, MPC52xx_PSC_RST_RX); - out_8(&psc->command, MPC52xx_PSC_RST_TX); + psc_ops->command(port, MPC52xx_PSC_RST_RX); + psc_ops->command(port, MPC52xx_PSC_RST_TX); /* Send new mode settings */ - out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1); - out_8(&psc->mode, mr1); - out_8(&psc->mode, mr2); + psc_ops->set_mode(port, mr1, mr2); baud = psc_ops->set_baudrate(port, new, old); /* Update the per-port timeout */ @@ -834,8 +1146,8 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new, mpc52xx_uart_enable_ms(port); /* Reenable TX & RX */ - out_8(&psc->command, MPC52xx_PSC_TX_ENABLE); - out_8(&psc->command, MPC52xx_PSC_RX_ENABLE); + psc_ops->command(port, MPC52xx_PSC_TX_ENABLE); + psc_ops->command(port, MPC52xx_PSC_RX_ENABLE); /* We're all set, release the lock */ spin_unlock_irqrestore(&port->lock, flags); @@ -963,7 +1275,7 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port) flag = TTY_NORMAL; port->icount.rx++; - status = in_be16(&PSC(port)->mpc52xx_psc_status); + status = psc_ops->get_status(port); if (status & (MPC52xx_PSC_SR_PE | MPC52xx_PSC_SR_FE | @@ -983,7 +1295,7 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port) } /* Clear error condition */ - out_8(&PSC(port)->command, MPC52xx_PSC_RST_ERR_STAT); + psc_ops->command(port, MPC52xx_PSC_RST_ERR_STAT); } tty_insert_flip_char(tport, ch, flag); @@ -1066,7 +1378,7 @@ mpc5xxx_uart_process_int(struct uart_port *port) if (psc_ops->tx_rdy(port)) keepgoing |= mpc52xx_uart_int_tx_chars(port); - status = in_8(&PSC(port)->mpc52xx_psc_ipcr); + status = psc_ops->get_ipcr(port); if (status & MPC52xx_PSC_D_DCD) uart_handle_dcd_change(port, !(status & MPC52xx_PSC_DCD)); @@ -1107,14 +1419,12 @@ static void __init mpc52xx_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits, int *flow) { - struct mpc52xx_psc __iomem *psc = PSC(port); unsigned char mr1; pr_debug("mpc52xx_console_get_options(port=%p)\n", port); /* Read the mode registers */ - out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1); - mr1 = in_8(&psc->mode); + mr1 = psc_ops->get_mr1(port); /* CT{U,L}R are write-only ! */ *baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD; @@ -1304,6 +1614,7 @@ static struct of_device_id mpc52xx_uart_of_match[] = { #endif #ifdef CONFIG_PPC_MPC512x { .compatible = "fsl,mpc5121-psc-uart", .data = &mpc512x_psc_ops, }, + { .compatible = "fsl,mpc5125-psc-uart", .data = &mpc5125_psc_ops, }, #endif {}, }; @@ -1372,15 +1683,14 @@ static int mpc52xx_uart_of_probe(struct platform_device *op) if (ret) return ret; - dev_set_drvdata(&op->dev, (void *)port); + platform_set_drvdata(op, (void *)port); return 0; } static int mpc52xx_uart_of_remove(struct platform_device *op) { - struct uart_port *port = dev_get_drvdata(&op->dev); - dev_set_drvdata(&op->dev, NULL); + struct uart_port *port = platform_get_drvdata(op); if (port) uart_remove_one_port(&mpc52xx_uart_driver, port); @@ -1392,7 +1702,7 @@ mpc52xx_uart_of_remove(struct platform_device *op) static int mpc52xx_uart_of_suspend(struct platform_device *op, pm_message_t state) { - struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev); + struct uart_port *port = (struct uart_port *) platform_get_drvdata(op); if (port) uart_suspend_port(&mpc52xx_uart_driver, port); @@ -1403,7 +1713,7 @@ mpc52xx_uart_of_suspend(struct platform_device *op, pm_message_t state) static int mpc52xx_uart_of_resume(struct platform_device *op) { - struct uart_port *port = (struct uart_port *) dev_get_drvdata(&op->dev); + struct uart_port *port = (struct uart_port *) platform_get_drvdata(op); if (port) uart_resume_port(&mpc52xx_uart_driver, port); diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index 39c7ea4cb14f..2caf9c6f6149 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -204,7 +204,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev) info->type = port_type; info->line = ret; - dev_set_drvdata(&ofdev->dev, info); + platform_set_drvdata(ofdev, info); return 0; out: kfree(info); @@ -217,7 +217,7 @@ out: */ static int of_platform_serial_remove(struct platform_device *ofdev) { - struct of_serial_info *info = dev_get_drvdata(&ofdev->dev); + struct of_serial_info *info = platform_get_drvdata(ofdev); switch (info->type) { #ifdef CONFIG_SERIAL_8250 case PORT_8250 ... PORT_MAX_8250: diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index f0b9f6b52b32..b6d172873076 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -161,6 +161,7 @@ struct uart_omap_port { u32 calc_latency; struct work_struct qos_work; struct pinctrl *pins; + bool is_suspending; }; #define to_uart_omap_port(p) ((container_of((p), struct uart_omap_port, port))) @@ -197,7 +198,7 @@ static int serial_omap_get_context_loss_count(struct uart_omap_port *up) struct omap_uart_port_info *pdata = up->dev->platform_data; if (!pdata || !pdata->get_context_loss_count) - return 0; + return -EINVAL; return pdata->get_context_loss_count(up->dev); } @@ -1289,6 +1290,22 @@ static struct uart_driver serial_omap_reg = { }; #ifdef CONFIG_PM_SLEEP +static int serial_omap_prepare(struct device *dev) +{ + struct uart_omap_port *up = dev_get_drvdata(dev); + + up->is_suspending = true; + + return 0; +} + +static void serial_omap_complete(struct device *dev) +{ + struct uart_omap_port *up = dev_get_drvdata(dev); + + up->is_suspending = false; +} + static int serial_omap_suspend(struct device *dev) { struct uart_omap_port *up = dev_get_drvdata(dev); @@ -1307,7 +1324,10 @@ static int serial_omap_resume(struct device *dev) return 0; } -#endif +#else +#define serial_omap_prepare NULL +#define serial_omap_complete NULL +#endif /* CONFIG_PM_SLEEP */ static void omap_serial_fill_features_erratas(struct uart_omap_port *up) { @@ -1482,6 +1502,9 @@ static int serial_omap_probe(struct platform_device *pdev) platform_set_drvdata(pdev, up); pm_runtime_enable(&pdev->dev); + if (omap_up_info->autosuspend_timeout == 0) + omap_up_info->autosuspend_timeout = -1; + device_init_wakeup(up->dev, true); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, omap_up_info->autosuspend_timeout); @@ -1591,13 +1614,19 @@ static void serial_omap_restore_context(struct uart_omap_port *up) static int serial_omap_runtime_suspend(struct device *dev) { struct uart_omap_port *up = dev_get_drvdata(dev); - struct omap_uart_port_info *pdata = dev->platform_data; if (!up) return -EINVAL; - if (!pdata) - return 0; + /* + * When using 'no_console_suspend', the console UART must not be + * suspended. Since driver suspend is managed by runtime suspend, + * preventing runtime suspend (by returning error) will keep device + * active during suspend. + */ + if (up->is_suspending && !console_suspend_enabled && + uart_console(&up->port)) + return -EBUSY; up->context_loss_cnt = serial_omap_get_context_loss_count(up); @@ -1626,7 +1655,7 @@ static int serial_omap_runtime_resume(struct device *dev) int loss_cnt = serial_omap_get_context_loss_count(up); if (loss_cnt < 0) { - dev_err(dev, "serial_omap_get_context_loss_count failed : %d\n", + dev_dbg(dev, "serial_omap_get_context_loss_count failed : %d\n", loss_cnt); serial_omap_restore_context(up); } else if (up->context_loss_cnt != loss_cnt) { @@ -1643,6 +1672,8 @@ static const struct dev_pm_ops serial_omap_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(serial_omap_suspend, serial_omap_resume) SET_RUNTIME_PM_OPS(serial_omap_runtime_suspend, serial_omap_runtime_resume, NULL) + .prepare = serial_omap_prepare, + .complete = serial_omap_complete, }; #if defined(CONFIG_OF) diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 21a7e179edf3..572d48189de9 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -217,6 +217,7 @@ enum { #define FRI2_64_UARTCLK 64000000 /* 64.0000 MHz */ #define FRI2_48_UARTCLK 48000000 /* 48.0000 MHz */ #define NTC1_UARTCLK 64000000 /* 64.0000 MHz */ +#define MINNOW_UARTCLK 50000000 /* 50.0000 MHz */ struct pch_uart_buffer { unsigned char *buf; @@ -398,6 +399,10 @@ static int pch_uart_get_uartclk(void) strstr(cmp, "nanoETXexpress-TT"))) return NTC1_UARTCLK; + cmp = dmi_get_system_info(DMI_BOARD_NAME); + if (cmp && strstr(cmp, "MinnowBoard")) + return MINNOW_UARTCLK; + return DEFAULT_UARTCLK; } diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 0c8a9fa2be6c..81ebc86a9e23 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1811,7 +1811,13 @@ static int __init s3c24xx_serial_modinit(void) return ret; } - return platform_driver_register(&samsung_serial_driver); + ret = platform_driver_register(&samsung_serial_driver); + if (ret < 0) { + pr_err("Failed to register platform driver\n"); + uart_unregister_driver(&s3c24xx_uart_drv); + } + + return ret; } static void __exit s3c24xx_serial_modexit(void) diff --git a/drivers/tty/serial/sc26xx.c b/drivers/tty/serial/sc26xx.c index c9735680762d..4b1434d53e9d 100644 --- a/drivers/tty/serial/sc26xx.c +++ b/drivers/tty/serial/sc26xx.c @@ -696,7 +696,7 @@ static int sc26xx_probe(struct platform_device *dev) if (err) goto out_remove_ports; - dev_set_drvdata(&dev->dev, up); + platform_set_drvdata(dev, up); return 0; out_remove_ports: @@ -716,7 +716,7 @@ out_free_port: static int __exit sc26xx_driver_remove(struct platform_device *dev) { - struct uart_sc26xx_port *up = dev_get_drvdata(&dev->dev); + struct uart_sc26xx_port *up = platform_get_drvdata(dev); free_irq(up->port[0].irq, up); @@ -728,7 +728,6 @@ static int __exit sc26xx_driver_remove(struct platform_device *dev) kfree(up); sc26xx_port = NULL; - dev_set_drvdata(&dev->dev, NULL); return 0; } diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index f87dbfd32770..28cdd2829139 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -50,12 +50,6 @@ static struct lock_class_key port_lock_key; #define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) -#ifdef CONFIG_SERIAL_CORE_CONSOLE -#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line) -#else -#define uart_console(port) (0) -#endif - static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, struct ktermios *old_termios); static void uart_wait_until_sent(struct tty_struct *tty, int timeout); diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c index 03465b673945..1fd564b8194b 100644 --- a/drivers/tty/serial/sirfsoc_uart.c +++ b/drivers/tty/serial/sirfsoc_uart.c @@ -687,9 +687,10 @@ int sirfsoc_uart_probe(struct platform_device *pdev) if (sirfport->hw_flow_ctrl) { sirfport->p = pinctrl_get_select_default(&pdev->dev); - ret = IS_ERR(sirfport->p); - if (ret) + if (IS_ERR(sirfport->p)) { + ret = PTR_ERR(sirfport->p); goto err; + } } sirfport->clk = clk_get(&pdev->dev, NULL); diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c index ba60708053e0..cf86e729532b 100644 --- a/drivers/tty/serial/sunhv.c +++ b/drivers/tty/serial/sunhv.c @@ -577,7 +577,7 @@ static int hv_probe(struct platform_device *op) if (err) goto out_remove_port; - dev_set_drvdata(&op->dev, port); + platform_set_drvdata(op, port); return 0; @@ -601,7 +601,7 @@ out_free_port: static int hv_remove(struct platform_device *dev) { - struct uart_port *port = dev_get_drvdata(&dev->dev); + struct uart_port *port = platform_get_drvdata(dev); free_irq(port->irq, port); @@ -612,8 +612,6 @@ static int hv_remove(struct platform_device *dev) kfree(port); sunhv_port = NULL; - dev_set_drvdata(&dev->dev, NULL); - return 0; } diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c index a422c8b55a47..5d6136b2a04a 100644 --- a/drivers/tty/serial/sunsab.c +++ b/drivers/tty/serial/sunsab.c @@ -1037,7 +1037,7 @@ static int sab_probe(struct platform_device *op) if (err) goto out3; - dev_set_drvdata(&op->dev, &up[0]); + platform_set_drvdata(op, &up[0]); inst++; @@ -1059,7 +1059,7 @@ out: static int sab_remove(struct platform_device *op) { - struct uart_sunsab_port *up = dev_get_drvdata(&op->dev); + struct uart_sunsab_port *up = platform_get_drvdata(op); uart_remove_one_port(&sunsab_reg, &up[1].port); uart_remove_one_port(&sunsab_reg, &up[0].port); @@ -1070,8 +1070,6 @@ static int sab_remove(struct platform_device *op) up[0].port.membase, sizeof(union sab82532_async_regs)); - dev_set_drvdata(&op->dev, NULL); - return 0; } diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index 0d8465728473..699cc1b5f6aa 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -1454,7 +1454,7 @@ static int su_probe(struct platform_device *op) kfree(up); return err; } - dev_set_drvdata(&op->dev, up); + platform_set_drvdata(op, up); nr_inst++; @@ -1483,7 +1483,7 @@ static int su_probe(struct platform_device *op) if (err) goto out_unmap; - dev_set_drvdata(&op->dev, up); + platform_set_drvdata(op, up); nr_inst++; @@ -1496,7 +1496,7 @@ out_unmap: static int su_remove(struct platform_device *op) { - struct uart_sunsu_port *up = dev_get_drvdata(&op->dev); + struct uart_sunsu_port *up = platform_get_drvdata(op); bool kbdms = false; if (up->su_type == SU_PORT_MS || @@ -1516,8 +1516,6 @@ static int su_remove(struct platform_device *op) if (kbdms) kfree(up); - dev_set_drvdata(&op->dev, NULL); - return 0; } diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c index 813ef8eb8eff..135a15203532 100644 --- a/drivers/tty/serial/sunzilog.c +++ b/drivers/tty/serial/sunzilog.c @@ -1495,7 +1495,7 @@ static int zs_probe(struct platform_device *op) kbm_inst++; } - dev_set_drvdata(&op->dev, &up[0]); + platform_set_drvdata(op, &up[0]); return 0; } @@ -1512,7 +1512,7 @@ static void zs_remove_one(struct uart_sunzilog_port *up) static int zs_remove(struct platform_device *op) { - struct uart_sunzilog_port *up = dev_get_drvdata(&op->dev); + struct uart_sunzilog_port *up = platform_get_drvdata(op); struct zilog_layout __iomem *regs; zs_remove_one(&up[0]); @@ -1521,8 +1521,6 @@ static int zs_remove(struct platform_device *op) regs = sunzilog_chip_regs[up[0].port.line / 2]; of_iounmap(&op->resource[0], regs, sizeof(struct zilog_layout)); - dev_set_drvdata(&op->dev, NULL); - return 0; } diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index 7355303dad99..88317482b81f 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -1451,7 +1451,7 @@ static int ucc_uart_probe(struct platform_device *ofdev) goto out_np; } - dev_set_drvdata(&ofdev->dev, qe_port); + platform_set_drvdata(ofdev, qe_port); dev_info(&ofdev->dev, "UCC%u assigned to /dev/ttyQE%u\n", qe_port->ucc_num + 1, qe_port->port.line); @@ -1471,13 +1471,12 @@ out_free: static int ucc_uart_remove(struct platform_device *ofdev) { - struct uart_qe_port *qe_port = dev_get_drvdata(&ofdev->dev); + struct uart_qe_port *qe_port = platform_get_drvdata(ofdev); dev_info(&ofdev->dev, "removing /dev/ttyQE%u\n", qe_port->port.line); uart_remove_one_port(&ucc_uart_driver, &qe_port->port); - dev_set_drvdata(&ofdev->dev, NULL); kfree(qe_port); return 0; @@ -1518,9 +1517,11 @@ static int __init ucc_uart_init(void) } ret = platform_driver_register(&ucc_uart_of_driver); - if (ret) + if (ret) { printk(KERN_ERR "ucc-uart: could not register platform driver\n"); + uart_unregister_driver(&ucc_uart_driver); + } return ret; } diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c index 1a8bc2275ea4..48af43de3467 100644 --- a/drivers/tty/serial/vt8500_serial.c +++ b/drivers/tty/serial/vt8500_serial.c @@ -648,7 +648,7 @@ static struct platform_driver vt8500_platform_driver = { .driver = { .name = "vt8500_serial", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(wmt_dt_ids), + .of_match_table = wmt_dt_ids, }, }; diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 4e5c77834c50..6c9174530422 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -974,12 +974,11 @@ static int xuartps_probe(struct platform_device *pdev) port->dev = &pdev->dev; port->uartclk = clk_get_rate(clk); port->private_data = clk; - dev_set_drvdata(&pdev->dev, port); + platform_set_drvdata(pdev, port); rc = uart_add_one_port(&xuartps_uart_driver, port); if (rc) { dev_err(&pdev->dev, "uart_add_one_port() failed; err=%i\n", rc); - dev_set_drvdata(&pdev->dev, NULL); return rc; } return 0; @@ -994,46 +993,17 @@ static int xuartps_probe(struct platform_device *pdev) **/ static int xuartps_remove(struct platform_device *pdev) { - struct uart_port *port = dev_get_drvdata(&pdev->dev); + struct uart_port *port = platform_get_drvdata(pdev); struct clk *clk = port->private_data; int rc; /* Remove the xuartps port from the serial core */ rc = uart_remove_one_port(&xuartps_uart_driver, port); - dev_set_drvdata(&pdev->dev, NULL); port->mapbase = 0; clk_disable_unprepare(clk); return rc; } -/** - * xuartps_suspend - suspend event - * @pdev: Pointer to the platform device structure - * @state: State of the device - * - * Returns 0 - **/ -static int xuartps_suspend(struct platform_device *pdev, pm_message_t state) -{ - /* Call the API provided in serial_core.c file which handles - * the suspend. - */ - uart_suspend_port(&xuartps_uart_driver, &xuartps_port[pdev->id]); - return 0; -} - -/** - * xuartps_resume - Resume after a previous suspend - * @pdev: Pointer to the platform device structure - * - * Returns 0 - **/ -static int xuartps_resume(struct platform_device *pdev) -{ - uart_resume_port(&xuartps_uart_driver, &xuartps_port[pdev->id]); - return 0; -} - /* Match table for of_platform binding */ static struct of_device_id xuartps_of_match[] = { { .compatible = "xlnx,xuartps", }, @@ -1044,8 +1014,6 @@ MODULE_DEVICE_TABLE(of, xuartps_of_match); static struct platform_driver xuartps_platform_driver = { .probe = xuartps_probe, /* Probe method */ .remove = xuartps_remove, /* Detach method */ - .suspend = xuartps_suspend, /* Suspend */ - .resume = xuartps_resume, /* Resume after a suspend */ .driver = { .owner = THIS_MODULE, .name = XUARTPS_NAME, /* Driver name */ |