X-Git-Url: https://git.kernelconcepts.de/?a=blobdiff_plain;f=drivers%2Ftty%2Fserial%2F8250%2F8250_ingenic.c;h=49394b4c5cfdc947dd2763dcb368bea49e6cf3e0;hb=b4e48c2aa148873ec3fe68bebbd6575d8b44c21f;hp=7c1e4be48e7b3b96b975b29ba4d2053083bd9700;hpb=db66e32e0d2ae1f5070faa589aa460b75780ab47;p=karo-tx-linux.git diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c index 7c1e4be48e7b..49394b4c5cfd 100644 --- a/drivers/tty/serial/8250/8250_ingenic.c +++ b/drivers/tty/serial/8250/8250_ingenic.c @@ -21,19 +21,33 @@ #include #include #include +#include #include #include #include #include +#include "8250.h" + +/** ingenic_uart_config: SOC specific config data. */ +struct ingenic_uart_config { + int tx_loadsz; + int fifosize; +}; + struct ingenic_uart_data { struct clk *clk_module; struct clk *clk_baud; int line; }; +static const struct of_device_id of_match[]; + #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 +143,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 +152,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,14 +175,45 @@ 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 = {}; struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); struct ingenic_uart_data *data; + const struct ingenic_uart_config *cdata; + const struct of_device_id *match; int err, line; + match = of_match_device(of_match, &pdev->dev); + if (!match) { + dev_err(&pdev->dev, "Error: No device match found\n"); + return -ENODEV; + } + cdata = match->data; + if (!regs || !irq) { dev_err(&pdev->dev, "no registers/irq defined\n"); return -EINVAL; @@ -164,14 +224,18 @@ static int ingenic_uart_probe(struct platform_device *pdev) return -ENOMEM; spin_lock_init(&uart.port.lock); - uart.port.type = PORT_16550; + uart.port.type = PORT_16550A; uart.port.flags = UPF_SKIP_TEST | UPF_IOREMAP | UPF_FIXED_TYPE; uart.port.iotype = UPIO_MEM; 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; + uart.port.fifosize = cdata->fifosize; + uart.tx_loadsz = cdata->tx_loadsz; + uart.capabilities = UART_CAP_FIFO | UART_CAP_RTOIE; /* Check for a fixed line number */ line = of_alias_get_id(pdev->dev.of_node, "serial"); @@ -241,10 +305,26 @@ static int ingenic_uart_remove(struct platform_device *pdev) return 0; } +static const struct ingenic_uart_config jz4740_uart_config = { + .tx_loadsz = 8, + .fifosize = 16, +}; + +static const struct ingenic_uart_config jz4760_uart_config = { + .tx_loadsz = 16, + .fifosize = 32, +}; + +static const struct ingenic_uart_config jz4780_uart_config = { + .tx_loadsz = 32, + .fifosize = 64, +}; + static const struct of_device_id of_match[] = { - { .compatible = "ingenic,jz4740-uart" }, - { .compatible = "ingenic,jz4775-uart" }, - { .compatible = "ingenic,jz4780-uart" }, + { .compatible = "ingenic,jz4740-uart", .data = &jz4740_uart_config }, + { .compatible = "ingenic,jz4760-uart", .data = &jz4760_uart_config }, + { .compatible = "ingenic,jz4775-uart", .data = &jz4760_uart_config }, + { .compatible = "ingenic,jz4780-uart", .data = &jz4780_uart_config }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, of_match);