[PATCH 1/3] serial: 8250_ingenic: Enable hardware flow control

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The Ingenic UART is similar to a standard 16550, but hardware flow control
requires setting a couple of additional, non-standard bits in the MCR.

The non-standard "modem control enable" and "hardware flow control
mode" bits are set when writing to the MCR register, based
on whether the modem control interrupt is active.

Additionally the non-16550 compliant parts of the uart need to be
masked from higher layers.

Tested on Ingenic JZ4780 on MIPS Creator Ci20 board

Signed-off-by: Matt Redfearn <matt.redfearn@xxxxxxxxxx>
---
 drivers/tty/serial/8250/8250_ingenic.c | 41 ++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c
index 21bf81fe794f..c5cde57e2da3 100644
--- a/drivers/tty/serial/8250/8250_ingenic.c
+++ b/drivers/tty/serial/8250/8250_ingenic.c
@@ -34,6 +34,9 @@ struct ingenic_uart_data {
 
 #define UART_FCR_UME	BIT(4)
 
+#define UART_MCR_MDCE	BIT(7)
+#define UART_MCR_FCM	BIT(6)
+
 static struct earlycon_device *early_device;
 
 static uint8_t __init early_in(struct uart_port *port, int offset)
@@ -129,6 +132,8 @@ OF_EARLYCON_DECLARE(jz4780_uart, "ingenic,jz4780-uart",
 
 static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
 {
+	int ier;
+
 	switch (offset) {
 	case UART_FCR:
 		/* UART module enable */
@@ -136,9 +141,22 @@ static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
 		break;
 
 	case UART_IER:
+		/* Enable receive timeout interrupt with the
+		 * receive line status interrupt */
 		value |= (value & 0x4) << 2;
 		break;
 
+	case UART_MCR:
+		/* If we have enabled modem status IRQs we should enable modem
+		 * mode. */
+		ier = p->serial_in(p, UART_IER);
+
+		if (ier & UART_IER_MSI)
+			value |= UART_MCR_MDCE | UART_MCR_FCM;
+		else
+			value &= ~(UART_MCR_MDCE | UART_MCR_FCM);
+		break;
+
 	default:
 		break;
 	}
@@ -146,6 +164,28 @@ static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
 	writeb(value, p->membase + (offset << p->regshift));
 }
 
+static unsigned int ingenic_uart_serial_in(struct uart_port *p, int offset)
+{
+	unsigned int value;
+
+	value = readb(p->membase + (offset << p->regshift));
+
+	/* Hide non-16550 compliant bits from higher levels */
+	switch (offset) {
+	case UART_FCR:
+		value &= ~UART_FCR_UME;
+		break;
+
+	case UART_MCR:
+		value &= ~(UART_MCR_MDCE | UART_MCR_FCM);
+		break;
+
+	default:
+		break;
+	}
+	return value;
+}
+
 static int ingenic_uart_probe(struct platform_device *pdev)
 {
 	struct uart_8250_port uart = {};
@@ -170,6 +210,7 @@ static int ingenic_uart_probe(struct platform_device *pdev)
 	uart.port.mapbase = regs->start;
 	uart.port.regshift = 2;
 	uart.port.serial_out = ingenic_uart_serial_out;
+	uart.port.serial_in = ingenic_uart_serial_in;
 	uart.port.irq = irq->start;
 	uart.port.dev = &pdev->dev;
 
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux PPP]     [Linux FS]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Linmodem]     [Device Mapper]     [Linux Kernel for ARM]

  Powered by Linux