summaryrefslogtreecommitdiff
path: root/drivers/tty/serial/mcf.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/serial/mcf.c')
-rw-r--r--drivers/tty/serial/mcf.c167
1 files changed, 47 insertions, 120 deletions
diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c
index 65be0c00c4bf..93e7dda4d39a 100644
--- a/drivers/tty/serial/mcf.c
+++ b/drivers/tty/serial/mcf.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
/****************************************************************************/
/*
* mcf.c -- Freescale ColdFire UART driver
*
- * (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
- *
- * 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.
+ * (C) Copyright 2003-2007, Greg Ungerer <gerg@uclinux.org>
*/
/****************************************************************************/
@@ -24,6 +20,7 @@
#include <linux/serial_core.h>
#include <linux/io.h>
#include <linux/uaccess.h>
+#include <linux/platform_device.h>
#include <asm/coldfire.h>
#include <asm/mcfsim.h>
#include <asm/mcfuart.h>
@@ -56,7 +53,6 @@ struct mcf_uart {
struct uart_port port;
unsigned int sigs; /* Local copy of line sigs */
unsigned char imr; /* Local IMR mirror */
- struct serial_rs485 rs485; /* RS485 settings */
};
/****************************************************************************/
@@ -103,7 +99,7 @@ static void mcf_start_tx(struct uart_port *port)
{
struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
- if (pp->rs485.flags & SER_RS485_ENABLED) {
+ if (port->rs485.flags & SER_RS485_ENABLED) {
/* Enable Transmitter */
writeb(MCFUART_UCR_TXENABLE, port->membase + MCFUART_UCR);
/* Manually assert RTS */
@@ -139,18 +135,12 @@ static void mcf_break_ctl(struct uart_port *port, int break_state)
{
unsigned long flags;
- spin_lock_irqsave(&port->lock, flags);
+ uart_port_lock_irqsave(port, &flags);
if (break_state == -1)
writeb(MCFUART_UCR_CMDBREAKSTART, port->membase + MCFUART_UCR);
else
writeb(MCFUART_UCR_CMDBREAKSTOP, port->membase + MCFUART_UCR);
- spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/****************************************************************************/
-
-static void mcf_enable_ms(struct uart_port *port)
-{
+ uart_port_unlock_irqrestore(port, flags);
}
/****************************************************************************/
@@ -160,7 +150,7 @@ static int mcf_startup(struct uart_port *port)
struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
unsigned long flags;
- spin_lock_irqsave(&port->lock, flags);
+ uart_port_lock_irqsave(port, &flags);
/* Reset UART, get it into known state... */
writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
@@ -174,7 +164,7 @@ static int mcf_startup(struct uart_port *port)
pp->imr = MCFUART_UIR_RXREADY;
writeb(pp->imr, port->membase + MCFUART_UIMR);
- spin_unlock_irqrestore(&port->lock, flags);
+ uart_port_unlock_irqrestore(port, flags);
return 0;
}
@@ -186,7 +176,7 @@ static void mcf_shutdown(struct uart_port *port)
struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
unsigned long flags;
- spin_lock_irqsave(&port->lock, flags);
+ uart_port_lock_irqsave(port, &flags);
/* Disable all interrupts now */
pp->imr = 0;
@@ -196,15 +186,14 @@ static void mcf_shutdown(struct uart_port *port)
writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
- spin_unlock_irqrestore(&port->lock, flags);
+ uart_port_unlock_irqrestore(port, flags);
}
/****************************************************************************/
static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
- struct ktermios *old)
+ const struct ktermios *old)
{
- struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
unsigned long flags;
unsigned int baud, baudclk;
#if defined(CONFIG_M5272)
@@ -247,6 +236,12 @@ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
mr1 |= MCFUART_MR1_PARITYNONE;
}
+ /*
+ * FIXME: port->read_status_mask and port->ignore_status_mask
+ * need to be initialized based on termios settings for
+ * INPCK, IGNBRK, IGNPAR, PARMRK, BRKINT
+ */
+
if (termios->c_cflag & CSTOPB)
mr2 |= MCFUART_MR2_STOP2;
else
@@ -257,12 +252,12 @@ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
mr2 |= MCFUART_MR2_TXCTS;
}
- if (pp->rs485.flags & SER_RS485_ENABLED) {
+ uart_port_lock_irqsave(port, &flags);
+ if (port->rs485.flags & SER_RS485_ENABLED) {
dev_dbg(port->dev, "Setting UART to RS485\n");
mr2 |= MCFUART_MR2_TXRTS;
}
- spin_lock_irqsave(&port->lock, flags);
uart_update_timeout(port, termios->c_cflag, baud);
writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
@@ -278,7 +273,7 @@ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
port->membase + MCFUART_UCSR);
writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE,
port->membase + MCFUART_UCR);
- spin_unlock_irqrestore(&port->lock, flags);
+ uart_port_unlock_irqrestore(port, flags);
}
/****************************************************************************/
@@ -286,7 +281,7 @@ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
static void mcf_rx_chars(struct mcf_uart *pp)
{
struct uart_port *port = &pp->port;
- unsigned char status, ch, flag;
+ u8 status, ch, flag;
while ((status = readb(port->membase + MCFUART_USR)) & MCFUART_USR_RXREADY) {
ch = readb(port->membase + MCFUART_URB);
@@ -332,35 +327,16 @@ static void mcf_rx_chars(struct mcf_uart *pp)
static void mcf_tx_chars(struct mcf_uart *pp)
{
struct uart_port *port = &pp->port;
- struct circ_buf *xmit = &port->state->xmit;
-
- if (port->x_char) {
- /* Send special char - probably flow control */
- writeb(port->x_char, port->membase + MCFUART_UTB);
- port->x_char = 0;
- port->icount.tx++;
- return;
- }
-
- while (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) {
- if (xmit->head == xmit->tail)
- break;
- writeb(xmit->buf[xmit->tail], port->membase + MCFUART_UTB);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1);
- port->icount.tx++;
- }
+ bool pending;
+ u8 ch;
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(port);
+ pending = uart_port_tx(port, ch,
+ readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY,
+ writeb(ch, port->membase + MCFUART_UTB));
- if (xmit->head == xmit->tail) {
- pp->imr &= ~MCFUART_UIR_TXREADY;
- writeb(pp->imr, port->membase + MCFUART_UIMR);
- /* Disable TX to negate RTS automatically */
- if (pp->rs485.flags & SER_RS485_ENABLED)
- writeb(MCFUART_UCR_TXDISABLE,
- port->membase + MCFUART_UCR);
- }
+ /* Disable TX to negate RTS automatically */
+ if (!pending && (port->rs485.flags & SER_RS485_ENABLED))
+ writeb(MCFUART_UCR_TXDISABLE, port->membase + MCFUART_UCR);
}
/****************************************************************************/
@@ -374,7 +350,7 @@ static irqreturn_t mcf_interrupt(int irq, void *data)
isr = readb(port->membase + MCFUART_UISR) & pp->imr;
- spin_lock(&port->lock);
+ uart_port_lock(port);
if (isr & MCFUART_UIR_RXREADY) {
mcf_rx_chars(pp);
ret = IRQ_HANDLED;
@@ -383,7 +359,7 @@ static irqreturn_t mcf_interrupt(int irq, void *data)
mcf_tx_chars(pp);
ret = IRQ_HANDLED;
}
- spin_unlock(&port->lock);
+ uart_port_unlock(port);
return ret;
}
@@ -437,13 +413,11 @@ static int mcf_verify_port(struct uart_port *port, struct serial_struct *ser)
/****************************************************************************/
/* Enable or disable the RS485 support */
-static void mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
+static int mcf_config_rs485(struct uart_port *port, struct ktermios *termios,
+ struct serial_rs485 *rs485)
{
- struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
- unsigned long flags;
unsigned char mr1, mr2;
- spin_lock_irqsave(&port->lock, flags);
/* Get mode registers */
mr1 = readb(port->membase + MCFUART_UMR);
mr2 = readb(port->membase + MCFUART_UMR);
@@ -457,35 +431,14 @@ static void mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
}
writeb(mr1, port->membase + MCFUART_UMR);
writeb(mr2, port->membase + MCFUART_UMR);
- pp->rs485 = *rs485;
- spin_unlock_irqrestore(&port->lock, flags);
-}
-static int mcf_ioctl(struct uart_port *port, unsigned int cmd,
- unsigned long arg)
-{
- switch (cmd) {
- case TIOCSRS485: {
- struct serial_rs485 rs485;
- if (copy_from_user(&rs485, (struct serial_rs485 *)arg,
- sizeof(struct serial_rs485)))
- return -EFAULT;
- mcf_config_rs485(port, &rs485);
- break;
- }
- case TIOCGRS485: {
- struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
- if (copy_to_user((struct serial_rs485 *)arg, &pp->rs485,
- sizeof(struct serial_rs485)))
- return -EFAULT;
- break;
- }
- default:
- return -ENOIOCTLCMD;
- }
return 0;
}
+static const struct serial_rs485 mcf_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_AFTER_SEND,
+};
+
/****************************************************************************/
/*
@@ -498,7 +451,6 @@ static const struct uart_ops mcf_uart_ops = {
.start_tx = mcf_start_tx,
.stop_tx = mcf_stop_tx,
.stop_rx = mcf_stop_rx,
- .enable_ms = mcf_enable_ms,
.break_ctl = mcf_break_ctl,
.startup = mcf_startup,
.shutdown = mcf_shutdown,
@@ -508,10 +460,9 @@ static const struct uart_ops mcf_uart_ops = {
.release_port = mcf_release_port,
.config_port = mcf_config_port,
.verify_port = mcf_verify_port,
- .ioctl = mcf_ioctl,
};
-static struct mcf_uart mcf_ports[4];
+static struct mcf_uart mcf_ports[10];
#define MCF_MAXPORTS ARRAY_SIZE(mcf_ports)
@@ -519,31 +470,6 @@ static struct mcf_uart mcf_ports[4];
#if defined(CONFIG_SERIAL_MCF_CONSOLE)
/****************************************************************************/
-int __init early_mcf_setup(struct mcf_platform_uart *platp)
-{
- struct uart_port *port;
- int i;
-
- for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) {
- port = &mcf_ports[i].port;
-
- port->line = i;
- port->type = PORT_MCF;
- port->mapbase = platp[i].mapbase;
- port->membase = (platp[i].membase) ? platp[i].membase :
- (unsigned char __iomem *) port->mapbase;
- port->iotype = SERIAL_IO_MEM;
- port->irq = platp[i].irq;
- port->uartclk = MCF_BUSCLK;
- port->flags = ASYNC_BOOT_AUTOCONF;
- port->ops = &mcf_uart_ops;
- }
-
- return 0;
-}
-
-/****************************************************************************/
-
static void mcf_console_putc(struct console *co, const char c)
{
struct uart_port *port = &(mcf_ports + co->index)->port;
@@ -624,7 +550,7 @@ console_initcall(mcf_console_init);
#define MCF_CONSOLE NULL
/****************************************************************************/
-#endif /* CONFIG_MCF_CONSOLE */
+#endif /* CONFIG_SERIAL_MCF_CONSOLE */
/****************************************************************************/
/*
@@ -644,7 +570,7 @@ static struct uart_driver mcf_driver = {
static int mcf_probe(struct platform_device *pdev)
{
- struct mcf_platform_uart *platp = pdev->dev.platform_data;
+ struct mcf_platform_uart *platp = dev_get_platdata(&pdev->dev);
struct uart_port *port;
int i;
@@ -656,11 +582,15 @@ static int mcf_probe(struct platform_device *pdev)
port->mapbase = platp[i].mapbase;
port->membase = (platp[i].membase) ? platp[i].membase :
(unsigned char __iomem *) platp[i].mapbase;
+ port->dev = &pdev->dev;
port->iotype = SERIAL_IO_MEM;
port->irq = platp[i].irq;
port->uartclk = MCF_BUSCLK;
port->ops = &mcf_uart_ops;
- port->flags = ASYNC_BOOT_AUTOCONF;
+ port->flags = UPF_BOOT_AUTOCONF;
+ port->rs485_config = mcf_config_rs485;
+ port->rs485_supported = mcf_rs485_supported;
+ port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_MCF_CONSOLE);
uart_add_one_port(&mcf_driver, port);
}
@@ -670,7 +600,7 @@ static int mcf_probe(struct platform_device *pdev)
/****************************************************************************/
-static int mcf_remove(struct platform_device *pdev)
+static void mcf_remove(struct platform_device *pdev)
{
struct uart_port *port;
int i;
@@ -680,8 +610,6 @@ static int mcf_remove(struct platform_device *pdev)
if (port)
uart_remove_one_port(&mcf_driver, port);
}
-
- return 0;
}
/****************************************************************************/
@@ -691,7 +619,6 @@ static struct platform_driver mcf_platform_driver = {
.remove = mcf_remove,
.driver = {
.name = "mcfuart",
- .owner = THIS_MODULE,
},
};
@@ -727,7 +654,7 @@ static void __exit mcf_exit(void)
module_init(mcf_init);
module_exit(mcf_exit);
-MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>");
+MODULE_AUTHOR("Greg Ungerer <gerg@uclinux.org>");
MODULE_DESCRIPTION("Freescale ColdFire UART driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:mcfuart");