mirror of https://gitee.com/openkylin/linux.git
serial: mcf: Add support RS485 in ColdFire serial driver
Signed-off-by: Quoc-Viet Nguyen <afelion@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
b81273a132
commit
496c907740
|
@ -23,6 +23,7 @@
|
||||||
#include <linux/serial.h>
|
#include <linux/serial.h>
|
||||||
#include <linux/serial_core.h>
|
#include <linux/serial_core.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
#include <asm/coldfire.h>
|
#include <asm/coldfire.h>
|
||||||
#include <asm/mcfsim.h>
|
#include <asm/mcfsim.h>
|
||||||
#include <asm/mcfuart.h>
|
#include <asm/mcfuart.h>
|
||||||
|
@ -55,6 +56,7 @@ struct mcf_uart {
|
||||||
struct uart_port port;
|
struct uart_port port;
|
||||||
unsigned int sigs; /* Local copy of line sigs */
|
unsigned int sigs; /* Local copy of line sigs */
|
||||||
unsigned char imr; /* Local IMR mirror */
|
unsigned char imr; /* Local IMR mirror */
|
||||||
|
struct serial_rs485 rs485; /* RS485 settings */
|
||||||
};
|
};
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
@ -101,6 +103,12 @@ static void mcf_start_tx(struct uart_port *port)
|
||||||
{
|
{
|
||||||
struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
|
struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
|
||||||
|
|
||||||
|
if (pp->rs485.flags & SER_RS485_ENABLED) {
|
||||||
|
/* Enable Transmitter */
|
||||||
|
writeb(MCFUART_UCR_TXENABLE, port->membase + MCFUART_UCR);
|
||||||
|
/* Manually assert RTS */
|
||||||
|
writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP1);
|
||||||
|
}
|
||||||
pp->imr |= MCFUART_UIR_TXREADY;
|
pp->imr |= MCFUART_UIR_TXREADY;
|
||||||
writeb(pp->imr, port->membase + MCFUART_UIMR);
|
writeb(pp->imr, port->membase + MCFUART_UIMR);
|
||||||
}
|
}
|
||||||
|
@ -196,6 +204,7 @@ static void mcf_shutdown(struct uart_port *port)
|
||||||
static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
|
static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||||
struct ktermios *old)
|
struct ktermios *old)
|
||||||
{
|
{
|
||||||
|
struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned int baud, baudclk;
|
unsigned int baud, baudclk;
|
||||||
#if defined(CONFIG_M5272)
|
#if defined(CONFIG_M5272)
|
||||||
|
@ -248,6 +257,11 @@ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||||
mr2 |= MCFUART_MR2_TXCTS;
|
mr2 |= MCFUART_MR2_TXCTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pp->rs485.flags & SER_RS485_ENABLED) {
|
||||||
|
dev_dbg(port->dev, "Setting UART to RS485\n");
|
||||||
|
mr2 |= MCFUART_MR2_TXRTS;
|
||||||
|
}
|
||||||
|
|
||||||
spin_lock_irqsave(&port->lock, flags);
|
spin_lock_irqsave(&port->lock, flags);
|
||||||
uart_update_timeout(port, termios->c_cflag, baud);
|
uart_update_timeout(port, termios->c_cflag, baud);
|
||||||
writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
|
writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
|
||||||
|
@ -342,6 +356,10 @@ static void mcf_tx_chars(struct mcf_uart *pp)
|
||||||
if (xmit->head == xmit->tail) {
|
if (xmit->head == xmit->tail) {
|
||||||
pp->imr &= ~MCFUART_UIR_TXREADY;
|
pp->imr &= ~MCFUART_UIR_TXREADY;
|
||||||
writeb(pp->imr, port->membase + MCFUART_UIMR);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,6 +436,58 @@ 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)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
if (rs485->flags & SER_RS485_ENABLED) {
|
||||||
|
dev_dbg(port->dev, "Setting UART to RS485\n");
|
||||||
|
/* Automatically negate RTS after TX completes */
|
||||||
|
mr2 |= MCFUART_MR2_TXRTS;
|
||||||
|
} else {
|
||||||
|
dev_dbg(port->dev, "Setting UART to RS232\n");
|
||||||
|
mr2 &= ~MCFUART_MR2_TXRTS;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Define the basic serial functions we support.
|
* Define the basic serial functions we support.
|
||||||
*/
|
*/
|
||||||
|
@ -438,6 +508,7 @@ static const struct uart_ops mcf_uart_ops = {
|
||||||
.release_port = mcf_release_port,
|
.release_port = mcf_release_port,
|
||||||
.config_port = mcf_config_port,
|
.config_port = mcf_config_port,
|
||||||
.verify_port = mcf_verify_port,
|
.verify_port = mcf_verify_port,
|
||||||
|
.ioctl = mcf_ioctl,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct mcf_uart mcf_ports[4];
|
static struct mcf_uart mcf_ports[4];
|
||||||
|
|
Loading…
Reference in New Issue