diff options
Diffstat (limited to 'drivers/tty/serial/8250')
-rw-r--r-- | drivers/tty/serial/8250/8250_core.c | 6 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_dw.c | 74 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_exar.c | 54 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_of.c | 6 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_omap.c | 1 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_port.c | 63 | ||||
-rw-r--r-- | drivers/tty/serial/8250/serial_cs.c | 6 |
7 files changed, 154 insertions, 56 deletions
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 9342fc2ee7df..8fe3d0ed229e 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -323,7 +323,7 @@ static int univ8250_setup_irq(struct uart_8250_port *up) * the port is opened so this value needs to be preserved. */ if (up->bugs & UART_BUG_THRE) { - pr_debug("ttyS%d - using backup timer\n", serial_index(port)); + pr_debug("%s - using backup timer\n", port->name); up->timer.function = serial8250_backup_timeout; mod_timer(&up->timer, jiffies + @@ -1023,6 +1023,10 @@ int serial8250_register_8250_port(struct uart_8250_port *up) uart->port.get_mctrl = up->port.get_mctrl; if (up->port.set_mctrl) uart->port.set_mctrl = up->port.set_mctrl; + if (up->port.get_divisor) + uart->port.get_divisor = up->port.get_divisor; + if (up->port.set_divisor) + uart->port.set_divisor = up->port.set_divisor; if (up->port.startup) uart->port.startup = up->port.startup; if (up->port.shutdown) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index aff04f1de3a5..fa8dcb470640 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -31,6 +31,7 @@ /* Offsets for the DesignWare specific registers */ #define DW_UART_USR 0x1f /* UART Status Register */ +#define DW_UART_DLF 0xc0 /* Divisor Latch Fraction Register */ #define DW_UART_CPR 0xf4 /* Component Parameter Register */ #define DW_UART_UCV 0xf8 /* UART Component Version */ @@ -55,6 +56,7 @@ struct dw8250_data { u8 usr_reg; + u8 dlf_size; int line; int msr_mask_on; int msr_mask_off; @@ -67,6 +69,21 @@ struct dw8250_data { unsigned int uart_16550_compatible:1; }; +static inline u32 dw8250_readl_ext(struct uart_port *p, int offset) +{ + if (p->iotype == UPIO_MEM32BE) + return ioread32be(p->membase + offset); + return readl(p->membase + offset); +} + +static inline void dw8250_writel_ext(struct uart_port *p, int offset, u32 reg) +{ + if (p->iotype == UPIO_MEM32BE) + iowrite32be(reg, p->membase + offset); + else + writel(reg, p->membase + offset); +} + static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value) { struct dw8250_data *d = p->private_data; @@ -293,7 +310,7 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, long rate; int ret; - if (IS_ERR(d->clk) || !old) + if (IS_ERR(d->clk)) goto out; clk_disable_unprepare(d->clk); @@ -351,6 +368,37 @@ static bool dw8250_idma_filter(struct dma_chan *chan, void *param) return param == chan->device->dev->parent; } +/* + * divisor = div(I) + div(F) + * "I" means integer, "F" means fractional + * quot = div(I) = clk / (16 * baud) + * frac = div(F) * 2^dlf_size + * + * let rem = clk % (16 * baud) + * we have: div(F) * (16 * baud) = rem + * so frac = 2^dlf_size * rem / (16 * baud) = (rem << dlf_size) / (16 * baud) + */ +static unsigned int dw8250_get_divisor(struct uart_port *p, + unsigned int baud, + unsigned int *frac) +{ + unsigned int quot, rem, base_baud = baud * 16; + struct dw8250_data *d = p->private_data; + + quot = p->uartclk / base_baud; + rem = p->uartclk % base_baud; + *frac = DIV_ROUND_CLOSEST(rem << d->dlf_size, base_baud); + + return quot; +} + +static void dw8250_set_divisor(struct uart_port *p, unsigned int baud, + unsigned int quot, unsigned int quot_frac) +{ + dw8250_writel_ext(p, DW_UART_DLF, quot_frac); + serial8250_do_set_divisor(p, baud, quot, quot_frac); +} + static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data) { if (p->dev->of_node) { @@ -404,20 +452,26 @@ static void dw8250_setup_port(struct uart_port *p) * If the Component Version Register returns zero, we know that * ADDITIONAL_FEATURES are not enabled. No need to go any further. */ - if (p->iotype == UPIO_MEM32BE) - reg = ioread32be(p->membase + DW_UART_UCV); - else - reg = readl(p->membase + DW_UART_UCV); + reg = dw8250_readl_ext(p, DW_UART_UCV); if (!reg) return; dev_dbg(p->dev, "Designware UART version %c.%c%c\n", (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff); - if (p->iotype == UPIO_MEM32BE) - reg = ioread32be(p->membase + DW_UART_CPR); - else - reg = readl(p->membase + DW_UART_CPR); + dw8250_writel_ext(p, DW_UART_DLF, ~0U); + reg = dw8250_readl_ext(p, DW_UART_DLF); + dw8250_writel_ext(p, DW_UART_DLF, 0); + + if (reg) { + struct dw8250_data *d = p->private_data; + + d->dlf_size = fls(reg); + p->get_divisor = dw8250_get_divisor; + p->set_divisor = dw8250_set_divisor; + } + + reg = dw8250_readl_ext(p, DW_UART_CPR); if (!reg) return; @@ -693,6 +747,7 @@ static const struct of_device_id dw8250_of_match[] = { { .compatible = "snps,dw-apb-uart" }, { .compatible = "cavium,octeon-3860-uart" }, { .compatible = "marvell,armada-38x-uart" }, + { .compatible = "renesas,rzn1-uart" }, { /* Sentinel */ } }; MODULE_DEVICE_TABLE(of, dw8250_of_match); @@ -707,6 +762,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = { { "APMC0D08", 0}, { "AMD0020", 0 }, { "AMDI0020", 0 }, + { "BRCM2032", 0 }, { "HISI0031", 0 }, { }, }; diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 38af306ca0e8..0089aa305ef9 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -109,11 +109,12 @@ struct exar8250_platform { * struct exar8250_board - board information * @num_ports: number of serial ports * @reg_shift: describes UART register mapping in PCI memory + * @setup: quirk run at ->probe() stage + * @exit: quirk run at ->remove() stage */ struct exar8250_board { unsigned int num_ports; unsigned int reg_shift; - bool has_slave; int (*setup)(struct exar8250 *, struct pci_dev *, struct uart_8250_port *, int); void (*exit)(struct pci_dev *pcidev); @@ -272,8 +273,32 @@ static int xr17v35x_register_gpio(struct pci_dev *pcidev, return 0; } +static int generic_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485) +{ + bool is_rs485 = !!(rs485->flags & SER_RS485_ENABLED); + u8 __iomem *p = port->membase; + u8 value; + + value = readb(p + UART_EXAR_FCTR); + if (is_rs485) + value |= UART_FCTR_EXAR_485; + else + value &= ~UART_FCTR_EXAR_485; + + writeb(value, p + UART_EXAR_FCTR); + + if (is_rs485) + writeb(UART_EXAR_RS485_DLY(4), p + UART_MSR); + + port->rs485 = *rs485; + + return 0; +} + static const struct exar8250_platform exar8250_default_platform = { .register_gpio = xr17v35x_register_gpio, + .rs485_config = generic_rs485_config, }; static int iot2040_rs485_config(struct uart_port *port, @@ -306,19 +331,7 @@ static int iot2040_rs485_config(struct uart_port *port, value |= mode; writeb(value, p + UART_EXAR_MPIOLVL_7_0); - value = readb(p + UART_EXAR_FCTR); - if (is_rs485) - value |= UART_FCTR_EXAR_485; - else - value &= ~UART_FCTR_EXAR_485; - writeb(value, p + UART_EXAR_FCTR); - - if (is_rs485) - writeb(UART_EXAR_RS485_DLY(4), p + UART_MSR); - - port->rs485 = *rs485; - - return 0; + return generic_rs485_config(port, rs485); } static const struct property_entry iot2040_gpio_properties[] = { @@ -364,7 +377,6 @@ static int pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev, struct uart_8250_port *port, int idx) { - const struct exar8250_board *board = priv->board; const struct exar8250_platform *platform; const struct dmi_system_id *dmi_match; unsigned int offset = idx * 0x400; @@ -382,10 +394,10 @@ pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev, port->port.rs485_config = platform->rs485_config; /* - * Setup the uart clock for the devices on expansion slot to + * Setup the UART clock for the devices on expansion slot to * half the clock speed of the main chip (which is 125MHz) */ - if (board->has_slave && idx >= 8) + if (idx >= 8) port->port.uartclk /= 2; ret = default_setup(priv, pcidev, idx, offset, port); @@ -433,7 +445,11 @@ 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); + readb(priv->virt + UART_EXAR_INT0); + + /* Clear INT0 for Expansion Interface slave ports, too */ + if (priv->board->num_ports > 8) + readb(priv->virt + 0x2000 + UART_EXAR_INT0); return IRQ_HANDLED; } @@ -590,14 +606,12 @@ static const struct exar8250_board pbn_exar_XR17V35x = { static const struct exar8250_board pbn_exar_XR17V4358 = { .num_ports = 12, - .has_slave = true, .setup = pci_xr17v35x_setup, .exit = pci_xr17v35x_exit, }; static const struct exar8250_board pbn_exar_XR17V8358 = { .num_ports = 16, - .has_slave = true, .setup = pci_xr17v35x_setup, .exit = pci_xr17v35x_exit, }; diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index bfb37f0be22f..af8beefe9b5c 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -124,7 +124,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev, dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n", prop); ret = -EINVAL; - goto err_dispose; + goto err_unprepare; } } port->flags |= UPF_IOREMAP; @@ -144,6 +144,10 @@ static int of_platform_serial_setup(struct platform_device *ofdev, port->line = ret; port->irq = irq_of_parse_and_map(np, 0); + if (!port->irq) { + ret = -EPROBE_DEFER; + goto err_unprepare; + } info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL); if (IS_ERR(info->rst)) { diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 1b337fee07ed..a019286f8bb6 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -1115,6 +1115,7 @@ static const u8 am3352_habit = OMAP_DMA_TX_KICK | UART_ERRATA_CLOCK_DISABLE; static const u8 dra742_habit = UART_ERRATA_CLOCK_DISABLE; static const struct of_device_id omap8250_dt_ids[] = { + { .compatible = "ti,am654-uart" }, { .compatible = "ti,omap2-uart" }, { .compatible = "ti,omap3-uart" }, { .compatible = "ti,omap4-uart", .data = &omap4_habit, }, diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index cf541aab2bd0..3f779d25ec0c 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -90,8 +90,7 @@ static const struct serial8250_config uart_config[] = { .name = "16550A", .fifo_size = 16, .tx_loadsz = 16, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, .rxtrig_bytes = {1, 4, 8, 14}, .flags = UART_CAP_FIFO, }, @@ -1211,8 +1210,8 @@ static void autoconfig(struct uart_8250_port *up) if (!port->iobase && !port->mapbase && !port->membase) return; - DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04lx, 0x%p): ", - serial_index(port), port->iobase, port->membase); + DEBUG_AUTOCONF("%s: autoconf (0x%04lx, 0x%p): ", + port->name, port->iobase, port->membase); /* * We really do need global IRQs disabled here - we're going to @@ -1363,9 +1362,8 @@ out_lock: fintek_8250_probe(up); if (up->capabilities != old_capabilities) { - pr_warn("ttyS%d: detected caps %08x should be %08x\n", - serial_index(port), old_capabilities, - up->capabilities); + pr_warn("%s: detected caps %08x should be %08x\n", + port->name, old_capabilities, up->capabilities); } out: DEBUG_AUTOCONF("iir=%d ", scratch); @@ -2212,8 +2210,7 @@ int serial8250_do_startup(struct uart_port *port) */ if (!(port->flags & UPF_BUGGY_UART) && (serial_port_in(port, UART_LSR) == 0xff)) { - printk_ratelimited(KERN_INFO "ttyS%d: LSR safety check engaged!\n", - serial_index(port)); + pr_info_ratelimited("%s: LSR safety check engaged!\n", port->name); retval = -ENODEV; goto out; } @@ -2245,8 +2242,8 @@ int serial8250_do_startup(struct uart_port *port) (port->type == PORT_ALTR_16550_F128)) && (port->fifosize > 1)) { /* Bounds checking of TX threshold (valid 0 to fifosize-2) */ if ((up->tx_loadsz < 2) || (up->tx_loadsz > port->fifosize)) { - pr_err("ttyS%d TX FIFO Threshold errors, skipping\n", - serial_index(port)); + pr_err("%s TX FIFO Threshold errors, skipping\n", + port->name); } else { serial_port_out(port, UART_ALTR_AFR, UART_ALTR_EN_TXFIFO_LW); @@ -2343,8 +2340,8 @@ int serial8250_do_startup(struct uart_port *port) if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) { if (!(up->bugs & UART_BUG_TXEN)) { up->bugs |= UART_BUG_TXEN; - pr_debug("ttyS%d - enabling bad tx status workarounds\n", - serial_index(port)); + pr_debug("%s - enabling bad tx status workarounds\n", + port->name); } } else { up->bugs &= ~UART_BUG_TXEN; @@ -2373,8 +2370,8 @@ dont_test_tx_en: if (up->dma) { retval = serial8250_request_dma(up); if (retval) { - pr_warn_ratelimited("ttyS%d - failed to request DMA\n", - serial_index(port)); + pr_warn_ratelimited("%s - failed to request DMA\n", + port->name); up->dma = NULL; } } @@ -2498,11 +2495,11 @@ static unsigned int npcm_get_divisor(struct uart_8250_port *up, return DIV_ROUND_CLOSEST(port->uartclk, 16 * baud + 2) - 2; } -static unsigned int serial8250_get_divisor(struct uart_8250_port *up, - unsigned int baud, - unsigned int *frac) +static unsigned int serial8250_do_get_divisor(struct uart_port *port, + unsigned int baud, + unsigned int *frac) { - struct uart_port *port = &up->port; + struct uart_8250_port *up = up_to_u8250p(port); unsigned int quot; /* @@ -2532,6 +2529,16 @@ static unsigned int serial8250_get_divisor(struct uart_8250_port *up, return quot; } +static unsigned int serial8250_get_divisor(struct uart_port *port, + unsigned int baud, + unsigned int *frac) +{ + if (port->get_divisor) + return port->get_divisor(port, baud, frac); + + return serial8250_do_get_divisor(port, baud, frac); +} + static unsigned char serial8250_compute_lcr(struct uart_8250_port *up, tcflag_t c_cflag) { @@ -2570,8 +2577,8 @@ static unsigned char serial8250_compute_lcr(struct uart_8250_port *up, return cval; } -static void serial8250_set_divisor(struct uart_port *port, unsigned int baud, - unsigned int quot, unsigned int quot_frac) +void serial8250_do_set_divisor(struct uart_port *port, unsigned int baud, + unsigned int quot, unsigned int quot_frac) { struct uart_8250_port *up = up_to_u8250p(port); @@ -2602,6 +2609,16 @@ static void serial8250_set_divisor(struct uart_port *port, unsigned int baud, serial_port_out(port, 0x2, quot_frac); } } +EXPORT_SYMBOL_GPL(serial8250_do_set_divisor); + +static void serial8250_set_divisor(struct uart_port *port, unsigned int baud, + unsigned int quot, unsigned int quot_frac) +{ + if (port->set_divisor) + port->set_divisor(port, baud, quot, quot_frac); + else + serial8250_do_set_divisor(port, baud, quot, quot_frac); +} static unsigned int serial8250_get_baud_rate(struct uart_port *port, struct ktermios *termios, @@ -2636,7 +2653,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, cval = serial8250_compute_lcr(up, termios->c_cflag); baud = serial8250_get_baud_rate(port, termios, old); - quot = serial8250_get_divisor(up, baud, &frac); + quot = serial8250_get_divisor(port, baud, &frac); /* * Ok, we're now changing the port state. Do it with @@ -3197,7 +3214,7 @@ static void serial8250_console_restore(struct uart_8250_port *up) termios.c_cflag = port->state->port.tty->termios.c_cflag; baud = serial8250_get_baud_rate(port, &termios, NULL); - quot = serial8250_get_divisor(up, baud, &frac); + quot = serial8250_get_divisor(port, baud, &frac); serial8250_set_divisor(port, baud, quot, frac); serial_port_out(port, UART_LCR, up->lcr); diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c index 9963a766dcfb..c8186a05a453 100644 --- a/drivers/tty/serial/8250/serial_cs.c +++ b/drivers/tty/serial/8250/serial_cs.c @@ -638,8 +638,10 @@ static int serial_config(struct pcmcia_device *link) (link->has_func_id) && (link->socket->pcmcia_pfc == 0) && ((link->func_id == CISTPL_FUNCID_MULTI) || - (link->func_id == CISTPL_FUNCID_SERIAL))) - pcmcia_loop_config(link, serial_check_for_multi, info); + (link->func_id == CISTPL_FUNCID_SERIAL))) { + if (pcmcia_loop_config(link, serial_check_for_multi, info)) + goto failed; + } /* * Apply any multi-port quirk. |