serial: 8250_ingenic: Enable hardware flow control
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@imgtec.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
20b5af9350
commit
129a45b1a9
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user