diff options
Diffstat (limited to 'drivers/tty/serial/8250')
-rw-r--r-- | drivers/tty/serial/8250/8250_dw.c | 33 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_exar.c | 34 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_ingenic.c | 17 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_of.c | 5 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_omap.c | 2 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_port.c | 26 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_uniphier.c | 5 | ||||
-rw-r--r-- | drivers/tty/serial/8250/Kconfig | 1 |
8 files changed, 68 insertions, 55 deletions
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 5bb0c42c88dd..cd1b94a0f451 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -252,31 +252,25 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, struct ktermios *old) { unsigned int baud = tty_termios_baud_rate(termios); - unsigned int target_rate, min_rate, max_rate; struct dw8250_data *d = p->private_data; long rate; - int i, ret; + int ret; if (IS_ERR(d->clk) || !old) goto out; - /* Find a clk rate within +/-1.6% of an integer multiple of baudx16 */ - target_rate = baud * 16; - min_rate = target_rate - (target_rate >> 6); - max_rate = target_rate + (target_rate >> 6); - - for (i = 1; i <= UART_DIV_MAX; i++) { - rate = clk_round_rate(d->clk, i * target_rate); - if (rate >= i * min_rate && rate <= i * max_rate) - break; - } - if (i <= UART_DIV_MAX) { - clk_disable_unprepare(d->clk); + clk_disable_unprepare(d->clk); + rate = clk_round_rate(d->clk, baud * 16); + if (rate < 0) + ret = rate; + else if (rate == 0) + ret = -ENOENT; + else ret = clk_set_rate(d->clk, rate); - clk_prepare_enable(d->clk); - if (!ret) - p->uartclk = rate; - } + clk_prepare_enable(d->clk); + + if (!ret) + p->uartclk = rate; out: p->status &= ~UPSTAT_AUTOCTS; @@ -515,7 +509,8 @@ static int dw8250_probe(struct platform_device *pdev) /* If no clock rate is defined, fail. */ if (!p->uartclk) { dev_err(dev, "clock rate not defined\n"); - return -EINVAL; + err = -EINVAL; + goto err_clk; } data->pclk = devm_clk_get(dev, "apb_pclk"); diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index a402878c9f30..38af306ca0e8 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -34,6 +34,7 @@ #define PCI_DEVICE_ID_EXAR_XR17V4358 0x4358 #define PCI_DEVICE_ID_EXAR_XR17V8358 0x8358 +#define UART_EXAR_INT0 0x80 #define UART_EXAR_8XMODE 0x88 /* 8X sampling rate select */ #define UART_EXAR_FCTR 0x08 /* Feature Control Register */ @@ -121,6 +122,7 @@ struct exar8250_board { struct exar8250 { unsigned int nr; struct exar8250_board *board; + void __iomem *virt; int line[0]; }; @@ -131,12 +133,9 @@ static int default_setup(struct exar8250 *priv, struct pci_dev *pcidev, const struct exar8250_board *board = priv->board; unsigned int bar = 0; - if (!pcim_iomap_table(pcidev)[bar] && !pcim_iomap(pcidev, bar, 0)) - return -ENOMEM; - port->port.iotype = UPIO_MEM; port->port.mapbase = pci_resource_start(pcidev, bar) + offset; - port->port.membase = pcim_iomap_table(pcidev)[bar] + offset; + port->port.membase = priv->virt + offset; port->port.regshift = board->reg_shift; return 0; @@ -420,6 +419,25 @@ static void pci_xr17v35x_exit(struct pci_dev *pcidev) port->port.private_data = NULL; } +/* + * These Exar UARTs have an extra interrupt indicator that could fire for a + * few interrupts that are not presented/cleared through IIR. One of which is + * a wakeup interrupt when coming out of sleep. These interrupts are only + * cleared by reading global INT0 or INT1 registers as interrupts are + * associated with channel 0. The INT[3:0] registers _are_ accessible from each + * channel's address space, but for the sake of bus efficiency we register a + * dedicated handler at the PCI device level to handle them. + */ +static irqreturn_t exar_misc_handler(int irq, void *data) +{ + struct exar8250 *priv = data; + + /* Clear all PCI interrupts by reading INT0. No effect on IIR */ + ioread8(priv->virt + UART_EXAR_INT0); + + return IRQ_HANDLED; +} + static int exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) { @@ -448,6 +466,9 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) return -ENOMEM; priv->board = board; + priv->virt = pcim_iomap(pcidev, bar, 0); + if (!priv->virt) + return -ENOMEM; pci_set_master(pcidev); @@ -461,6 +482,11 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) uart.port.irq = pci_irq_vector(pcidev, 0); uart.port.dev = &pcidev->dev; + rc = devm_request_irq(&pcidev->dev, uart.port.irq, exar_misc_handler, + IRQF_SHARED, "exar_uart", priv); + if (rc) + return rc; + for (i = 0; i < nr_ports && i < maxnr; i++) { rc = board->setup(priv, pcidev, &uart, i); if (rc) { diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c index 6af84900870e..15a8c8dfa92b 100644 --- a/drivers/tty/serial/8250/8250_ingenic.c +++ b/drivers/tty/serial/8250/8250_ingenic.c @@ -91,14 +91,22 @@ static int __init ingenic_early_console_setup(struct earlycon_device *dev, const char *opt) { struct uart_port *port = &dev->port; - unsigned int baud, divisor; + unsigned int divisor; + int baud = 115200; if (!dev->port.membase) return -ENODEV; + if (opt) { + unsigned int parity, bits, flow; /* unused for now */ + + uart_parse_options(opt, &baud, &parity, &bits, &flow); + } + ingenic_early_console_setup_clock(dev); - baud = dev->baud ?: 115200; + if (dev->baud) + baud = dev->baud; divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud); early_out(port, UART_IER, 0); @@ -125,6 +133,10 @@ EARLYCON_DECLARE(jz4740_uart, ingenic_early_console_setup); OF_EARLYCON_DECLARE(jz4740_uart, "ingenic,jz4740-uart", ingenic_early_console_setup); +EARLYCON_DECLARE(jz4770_uart, ingenic_early_console_setup); +OF_EARLYCON_DECLARE(jz4770_uart, "ingenic,jz4770-uart", + ingenic_early_console_setup); + EARLYCON_DECLARE(jz4775_uart, ingenic_early_console_setup); OF_EARLYCON_DECLARE(jz4775_uart, "ingenic,jz4775-uart", ingenic_early_console_setup); @@ -319,6 +331,7 @@ static const struct ingenic_uart_config jz4780_uart_config = { static const struct of_device_id of_match[] = { { .compatible = "ingenic,jz4740-uart", .data = &jz4740_uart_config }, { .compatible = "ingenic,jz4760-uart", .data = &jz4760_uart_config }, + { .compatible = "ingenic,jz4770-uart", .data = &jz4760_uart_config }, { .compatible = "ingenic,jz4775-uart", .data = &jz4760_uart_config }, { .compatible = "ingenic,jz4780-uart", .data = &jz4780_uart_config }, { /* sentinel */ } diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index 1e67a7e4a5fd..160b8906d9b9 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -136,8 +136,11 @@ static int of_platform_serial_setup(struct platform_device *ofdev, } info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL); - if (IS_ERR(info->rst)) + if (IS_ERR(info->rst)) { + ret = PTR_ERR(info->rst); goto err_dispose; + } + ret = reset_control_deassert(info->rst); if (ret) goto err_dispose; diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index bd40ba402410..57f6eba47f44 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -414,7 +414,7 @@ static void omap_8250_set_termios(struct uart_port *port, /* Up to here it was mostly serial8250_do_set_termios() */ /* - * We enable TRIG_GRANU for RX and TX and additionaly we set + * We enable TRIG_GRANU for RX and TX and additionally we set * SCR_TX_EMPTY bit. The result is the following: * - RX_TRIGGER amount of bytes in the FIFO will cause an interrupt. * - less than RX_TRIGGER number of bytes will also cause an interrupt diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 11434551ac0a..1328c7e70108 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -441,7 +441,6 @@ static void io_serial_out(struct uart_port *p, int offset, int value) } static int serial8250_default_handle_irq(struct uart_port *port); -static int exar_handle_irq(struct uart_port *port); static void set_io_from_upio(struct uart_port *p) { @@ -1884,26 +1883,6 @@ static int serial8250_default_handle_irq(struct uart_port *port) } /* - * These Exar UARTs have an extra interrupt indicator that could - * fire for a few unimplemented interrupts. One of which is a - * wakeup event when coming out of sleep. Put this here just - * to be on the safe side that these interrupts don't go unhandled. - */ -static int exar_handle_irq(struct uart_port *port) -{ - unsigned int iir = serial_port_in(port, UART_IIR); - int ret = 0; - - if (((port->type == PORT_XR17V35X) || (port->type == PORT_XR17D15X)) && - serial_port_in(port, UART_EXAR_INT0) != 0) - ret = 1; - - ret |= serial8250_handle_irq(port, iir); - - return ret; -} - -/* * Newer 16550 compatible parts such as the SC16C650 & Altera 16550 Soft IP * have a programmable TX threshold that triggers the THRE interrupt in * the IIR register. In this case, the THRE interrupt indicates the FIFO @@ -3067,11 +3046,6 @@ static void serial8250_config_port(struct uart_port *port, int flags) if (port->type == PORT_UNKNOWN) serial8250_release_std_resource(up); - /* Fixme: probably not the best place for this */ - if ((port->type == PORT_XR17V35X) || - (port->type == PORT_XR17D15X)) - port->handle_irq = exar_handle_irq; - register_dev_spec_attr_grp(up); up->fcr = uart_config[up->port.type].fcr; } diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c index 45ef506293ae..28d88ccf5a0c 100644 --- a/drivers/tty/serial/8250/8250_uniphier.c +++ b/drivers/tty/serial/8250/8250_uniphier.c @@ -250,12 +250,13 @@ static int uniphier_uart_probe(struct platform_device *pdev) up.dl_read = uniphier_serial_dl_read; up.dl_write = uniphier_serial_dl_write; - priv->line = serial8250_register_8250_port(&up); - if (priv->line < 0) { + ret = serial8250_register_8250_port(&up); + if (ret < 0) { dev_err(dev, "failed to register 8250 port\n"); clk_disable_unprepare(priv->clk); return ret; } + priv->line = ret; platform_set_drvdata(pdev, priv); diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index a5c0ef1e7695..16b1496e6105 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -5,6 +5,7 @@ config SERIAL_8250 tristate "8250/16550 and compatible serial support" + depends on !S390 select SERIAL_CORE ---help--- This selects whether you want to include the driver for the standard |