diff options
Diffstat (limited to 'drivers/tty/serial')
46 files changed, 1941 insertions, 352 deletions
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 570df9d2a5d2..e33d38cb170f 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -2322,7 +2322,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) { fcr = uart_config[port->type].fcr; - if (baud < 2400 || fifo_bug) { + if ((baud < 2400 && !up->dma) || fifo_bug) { fcr &= ~UART_FCR_TRIGGER_MASK; fcr |= UART_FCR_TRIGGER_1; } diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index daf710f5c3fc..4658e3e0ec42 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -56,11 +56,11 @@ struct dw8250_data { - int last_lcr; - int last_mcr; - int line; - struct clk *clk; - u8 usr_reg; + u8 usr_reg; + int last_mcr; + int line; + struct clk *clk; + struct uart_8250_dma dma; }; static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value) @@ -76,17 +76,33 @@ static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value) return value; } +static void dw8250_force_idle(struct uart_port *p) +{ + serial8250_clear_and_reinit_fifos(container_of + (p, struct uart_8250_port, port)); + (void)p->serial_in(p, UART_RX); +} + static void dw8250_serial_out(struct uart_port *p, int offset, int value) { struct dw8250_data *d = p->private_data; - if (offset == UART_LCR) - d->last_lcr = value; - if (offset == UART_MCR) d->last_mcr = value; writeb(value, p->membase + (offset << p->regshift)); + + /* Make sure LCR write wasn't ignored */ + if (offset == UART_LCR) { + int tries = 1000; + while (tries--) { + if (value == p->serial_in(p, UART_LCR)) + return; + dw8250_force_idle(p); + writeb(value, p->membase + (UART_LCR << p->regshift)); + } + dev_err(p->dev, "Couldn't set LCR to %d\n", value); + } } static unsigned int dw8250_serial_in(struct uart_port *p, int offset) @@ -107,13 +123,22 @@ static void dw8250_serial_out32(struct uart_port *p, int offset, int value) { struct dw8250_data *d = p->private_data; - if (offset == UART_LCR) - d->last_lcr = value; - if (offset == UART_MCR) d->last_mcr = value; writel(value, p->membase + (offset << p->regshift)); + + /* Make sure LCR write wasn't ignored */ + if (offset == UART_LCR) { + int tries = 1000; + while (tries--) { + if (value == p->serial_in(p, UART_LCR)) + return; + dw8250_force_idle(p); + writel(value, p->membase + (UART_LCR << p->regshift)); + } + dev_err(p->dev, "Couldn't set LCR to %d\n", value); + } } static unsigned int dw8250_serial_in32(struct uart_port *p, int offset) @@ -131,9 +156,8 @@ static int dw8250_handle_irq(struct uart_port *p) if (serial8250_handle_irq(p, iir)) { return 1; } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) { - /* Clear the USR and write the LCR again. */ + /* Clear the USR */ (void)p->serial_in(p, d->usr_reg); - p->serial_out(p, UART_LCR, d->last_lcr); return 1; } @@ -153,6 +177,14 @@ dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old) pm_runtime_put_sync_suspend(port->dev); } +static bool dw8250_dma_filter(struct dma_chan *chan, void *param) +{ + struct dw8250_data *data = param; + + return chan->chan_id == data->dma.tx_chan_id || + chan->chan_id == data->dma.rx_chan_id; +} + static void dw8250_setup_port(struct uart_8250_port *up) { struct uart_port *p = &up->port; @@ -241,7 +273,8 @@ static int dw8250_probe_of(struct uart_port *p, } #ifdef CONFIG_ACPI -static int dw8250_probe_acpi(struct uart_8250_port *up) +static int dw8250_probe_acpi(struct uart_8250_port *up, + struct dw8250_data *data) { const struct acpi_device_id *id; struct uart_port *p = &up->port; @@ -260,9 +293,7 @@ static int dw8250_probe_acpi(struct uart_8250_port *up) if (!p->uartclk) p->uartclk = (unsigned int)id->driver_data; - up->dma = devm_kzalloc(p->dev, sizeof(*up->dma), GFP_KERNEL); - if (!up->dma) - return -ENOMEM; + up->dma = &data->dma; up->dma->rxconf.src_maxburst = p->fifosize / 4; up->dma->txconf.dst_maxburst = p->fifosize / 4; @@ -270,7 +301,8 @@ static int dw8250_probe_acpi(struct uart_8250_port *up) return 0; } #else -static inline int dw8250_probe_acpi(struct uart_8250_port *up) +static inline int dw8250_probe_acpi(struct uart_8250_port *up, + struct dw8250_data *data) { return -ENODEV; } @@ -314,6 +346,12 @@ static int dw8250_probe(struct platform_device *pdev) uart.port.uartclk = clk_get_rate(data->clk); } + data->dma.rx_chan_id = -1; + data->dma.tx_chan_id = -1; + data->dma.rx_param = data; + data->dma.tx_param = data; + data->dma.fn = dw8250_dma_filter; + uart.port.iotype = UPIO_MEM; uart.port.serial_in = dw8250_serial_in; uart.port.serial_out = dw8250_serial_out; @@ -324,7 +362,7 @@ static int dw8250_probe(struct platform_device *pdev) if (err) return err; } else if (ACPI_HANDLE(&pdev->dev)) { - err = dw8250_probe_acpi(&uart); + err = dw8250_probe_acpi(&uart, data); if (err) return err; } else { diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c index 5f3bba12c159..d1a9078003bd 100644 --- a/drivers/tty/serial/8250/8250_em.c +++ b/drivers/tty/serial/8250/8250_em.c @@ -122,7 +122,7 @@ static int serial8250_em_probe(struct platform_device *pdev) up.port.dev = &pdev->dev; up.port.private_data = priv; - clk_enable(priv->sclk); + clk_prepare_enable(priv->sclk); up.port.uartclk = clk_get_rate(priv->sclk); up.port.iotype = UPIO_MEM32; @@ -134,7 +134,7 @@ static int serial8250_em_probe(struct platform_device *pdev) ret = serial8250_register_8250_port(&up); if (ret < 0) { dev_err(&pdev->dev, "unable to register 8250 port\n"); - clk_disable(priv->sclk); + clk_disable_unprepare(priv->sclk); return ret; } @@ -148,7 +148,7 @@ static int serial8250_em_remove(struct platform_device *pdev) struct serial8250_em_priv *priv = platform_get_drvdata(pdev); serial8250_unregister_port(priv->line); - clk_disable(priv->sclk); + clk_disable_unprepare(priv->sclk); return 0; } diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index c810da7c7a88..4697a514b80a 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -9,6 +9,7 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License. */ +#undef DEBUG #include <linux/module.h> #include <linux/init.h> #include <linux/pci.h> @@ -27,8 +28,6 @@ #include "8250.h" -#undef SERIAL_DEBUG_PCI - /* * init function returns: * > 0 - number of ports @@ -63,7 +62,7 @@ static int pci_default_setup(struct serial_private*, static void moan_device(const char *str, struct pci_dev *dev) { - printk(KERN_WARNING + dev_err(&dev->dev, "%s: %s\n" "Please send the output of lspci -vv, this\n" "message (0x%04x,0x%04x,0x%04x,0x%04x), the\n" @@ -233,7 +232,7 @@ static int pci_inteli960ni_init(struct pci_dev *dev) /* is firmware started? */ pci_read_config_dword(dev, 0x44, (void *)&oldval); if (oldval == 0x00001000L) { /* RESET value */ - printk(KERN_DEBUG "Local i960 firmware missing"); + dev_dbg(&dev->dev, "Local i960 firmware missing\n"); return -ENODEV; } return 0; @@ -827,7 +826,7 @@ static int pci_netmos_9900_numports(struct pci_dev *dev) if (sub_serports > 0) { return sub_serports; } else { - printk(KERN_NOTICE "NetMos/Mostech serial driver ignoring port on ambiguous config.\n"); + dev_err(&dev->dev, "NetMos/Mostech serial driver ignoring port on ambiguous config.\n"); return 0; } } @@ -931,7 +930,7 @@ static int pci_ite887x_init(struct pci_dev *dev) } if (!inta_addr[i]) { - printk(KERN_ERR "ite887x: could not find iobase\n"); + dev_err(&dev->dev, "ite887x: could not find iobase\n"); return -ENODEV; } @@ -1024,9 +1023,9 @@ static int pci_oxsemi_tornado_init(struct pci_dev *dev) /* Tornado device */ if (deviceID == 0x07000200) { number_uarts = ioread8(p + 4); - printk(KERN_DEBUG + dev_dbg(&dev->dev, "%d ports detected on Oxford PCI Express device\n", - number_uarts); + number_uarts); } pci_iounmap(dev, p); return number_uarts; @@ -1308,6 +1307,29 @@ static int pci_default_setup(struct serial_private *priv, return setup_port(priv, port, bar, offset, board->reg_shift); } +static int pci_pericom_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + unsigned int bar, offset = board->first_offset, maxnr; + + bar = FL_GET_BASE(board->flags); + if (board->flags & FL_BASE_BARS) + bar += idx; + else + offset += idx * board->uart_offset; + + maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >> + (board->reg_shift + 3); + + if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr) + return 1; + + port->port.uartclk = 14745600; + + return setup_port(priv, port, bar, offset, board->reg_shift); +} + static int ce4100_serial_setup(struct serial_private *priv, const struct pciserial_board *board, @@ -1324,6 +1346,120 @@ ce4100_serial_setup(struct serial_private *priv, return ret; } +#define PCI_DEVICE_ID_INTEL_BYT_UART1 0x0f0a +#define PCI_DEVICE_ID_INTEL_BYT_UART2 0x0f0c + +#define BYT_PRV_CLK 0x800 +#define BYT_PRV_CLK_EN (1 << 0) +#define BYT_PRV_CLK_M_VAL_SHIFT 1 +#define BYT_PRV_CLK_N_VAL_SHIFT 16 +#define BYT_PRV_CLK_UPDATE (1 << 31) + +#define BYT_GENERAL_REG 0x808 +#define BYT_GENERAL_DIS_RTS_N_OVERRIDE (1 << 3) + +#define BYT_TX_OVF_INT 0x820 +#define BYT_TX_OVF_INT_MASK (1 << 1) + +static void +byt_set_termios(struct uart_port *p, struct ktermios *termios, + struct ktermios *old) +{ + unsigned int baud = tty_termios_baud_rate(termios); + unsigned int m = 6912; + unsigned int n = 15625; + u32 reg; + + /* For baud rates 1M, 2M, 3M and 4M the dividers must be adjusted. */ + if (baud == 1000000 || baud == 2000000 || baud == 4000000) { + m = 64; + n = 100; + + p->uartclk = 64000000; + } else if (baud == 3000000) { + m = 48; + n = 100; + + p->uartclk = 48000000; + } else { + p->uartclk = 44236800; + } + + /* Reset the clock */ + reg = (m << BYT_PRV_CLK_M_VAL_SHIFT) | (n << BYT_PRV_CLK_N_VAL_SHIFT); + writel(reg, p->membase + BYT_PRV_CLK); + reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE; + writel(reg, p->membase + BYT_PRV_CLK); + + /* + * If auto-handshake mechanism is not enabled, + * disable rts_n override + */ + reg = readl(p->membase + BYT_GENERAL_REG); + reg &= ~BYT_GENERAL_DIS_RTS_N_OVERRIDE; + if (termios->c_cflag & CRTSCTS) + reg |= BYT_GENERAL_DIS_RTS_N_OVERRIDE; + writel(reg, p->membase + BYT_GENERAL_REG); + + serial8250_do_set_termios(p, termios, old); +} + +static bool byt_dma_filter(struct dma_chan *chan, void *param) +{ + return chan->chan_id == *(int *)param; +} + +static int +byt_serial_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + struct uart_8250_dma *dma; + int ret; + + dma = devm_kzalloc(port->port.dev, sizeof(*dma), GFP_KERNEL); + if (!dma) + return -ENOMEM; + + switch (priv->dev->device) { + case PCI_DEVICE_ID_INTEL_BYT_UART1: + dma->rx_chan_id = 3; + dma->tx_chan_id = 2; + break; + case PCI_DEVICE_ID_INTEL_BYT_UART2: + dma->rx_chan_id = 5; + dma->tx_chan_id = 4; + break; + default: + return -EINVAL; + } + + dma->rxconf.slave_id = dma->rx_chan_id; + dma->rxconf.src_maxburst = 16; + + dma->txconf.slave_id = dma->tx_chan_id; + dma->txconf.dst_maxburst = 16; + + dma->fn = byt_dma_filter; + dma->rx_param = &dma->rx_chan_id; + dma->tx_param = &dma->tx_chan_id; + + ret = pci_default_setup(priv, board, port, idx); + port->port.iotype = UPIO_MEM; + port->port.type = PORT_16550A; + port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE); + port->port.set_termios = byt_set_termios; + port->port.fifosize = 64; + port->tx_loadsz = 64; + port->dma = dma; + port->capabilities = UART_CAP_FIFO | UART_CAP_AFE; + + /* Disable Tx counter interrupts */ + writel(BYT_TX_OVF_INT_MASK, port->port.membase + BYT_TX_OVF_INT); + + return ret; +} + static int pci_omegapci_setup(struct serial_private *priv, const struct pciserial_board *board, @@ -1344,17 +1480,80 @@ pci_brcm_trumanage_setup(struct serial_private *priv, return ret; } +static int pci_fintek_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + struct pci_dev *pdev = priv->dev; + unsigned long base; + unsigned long iobase; + unsigned long ciobase = 0; + u8 config_base; + + /* + * We are supposed to be able to read these from the PCI config space, + * but the values there don't seem to match what we need to use, so + * just use these hard-coded values for now, as they are correct. + */ + switch (idx) { + case 0: iobase = 0xe000; config_base = 0x40; break; + case 1: iobase = 0xe008; config_base = 0x48; break; + case 2: iobase = 0xe010; config_base = 0x50; break; + case 3: iobase = 0xe018; config_base = 0x58; break; + case 4: iobase = 0xe020; config_base = 0x60; break; + case 5: iobase = 0xe028; config_base = 0x68; break; + case 6: iobase = 0xe030; config_base = 0x70; break; + case 7: iobase = 0xe038; config_base = 0x78; break; + case 8: iobase = 0xe040; config_base = 0x80; break; + case 9: iobase = 0xe048; config_base = 0x88; break; + case 10: iobase = 0xe050; config_base = 0x90; break; + case 11: iobase = 0xe058; config_base = 0x98; break; + default: + /* Unknown number of ports, get out of here */ + return -EINVAL; + } + + if (idx < 4) { + base = pci_resource_start(priv->dev, 3); + ciobase = (int)(base + (0x8 * idx)); + } + + dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%lx ciobase=0x%lx config_base=0x%2x\n", + __func__, idx, iobase, ciobase, config_base); + + /* Enable UART I/O port */ + pci_write_config_byte(pdev, config_base + 0x00, 0x01); + + /* Select 128-byte FIFO and 8x FIFO threshold */ + pci_write_config_byte(pdev, config_base + 0x01, 0x33); + + /* LSB UART */ + pci_write_config_byte(pdev, config_base + 0x04, (u8)(iobase & 0xff)); + + /* MSB UART */ + pci_write_config_byte(pdev, config_base + 0x05, (u8)((iobase & 0xff00) >> 8)); + + /* irq number, this usually fails, but the spec says to do it anyway. */ + pci_write_config_byte(pdev, config_base + 0x06, pdev->irq); + + port->port.iotype = UPIO_PORT; + port->port.iobase = iobase; + port->port.mapbase = 0; + port->port.membase = NULL; + port->port.regshift = 0; + + return 0; +} + static int skip_tx_en_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { port->port.flags |= UPF_NO_TXEN_TEST; - printk(KERN_DEBUG "serial8250: skipping TxEn test for device " - "[%04x:%04x] subsystem [%04x:%04x]\n", - priv->dev->vendor, - priv->dev->device, - priv->dev->subsystem_vendor, - priv->dev->subsystem_device); + dev_dbg(&priv->dev->dev, + "serial8250: skipping TxEn test for device [%04x:%04x] subsystem [%04x:%04x]\n", + priv->dev->vendor, priv->dev->device, + priv->dev->subsystem_vendor, priv->dev->subsystem_device); return pci_default_setup(priv, board, port, idx); } @@ -1662,6 +1861,20 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .setup = kt_serial_setup, }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_BYT_UART1, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = byt_serial_setup, + }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_BYT_UART2, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = byt_serial_setup, + }, /* * ITE */ @@ -1826,6 +2039,31 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .exit = pci_plx9050_exit, }, /* + * Pericom + */ + { + .vendor = 0x12d8, + .device = 0x7952, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = 0x12d8, + .device = 0x7954, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = 0x12d8, + .device = 0x7958, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + + /* * PLX */ { @@ -2255,6 +2493,27 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .setup = pci_brcm_trumanage_setup, }, + { + .vendor = 0x1c29, + .device = 0x1104, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_fintek_setup, + }, + { + .vendor = 0x1c29, + .device = 0x1108, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_fintek_setup, + }, + { + .vendor = 0x1c29, + .device = 0x1112, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_fintek_setup, + }, /* * Default "match everything" terminator entry @@ -2449,9 +2708,13 @@ enum pci_board_num_t { pbn_ADDIDATA_PCIe_4_3906250, pbn_ADDIDATA_PCIe_8_3906250, pbn_ce4100_1_115200, + pbn_byt, pbn_omegapci, pbn_NETMOS9900_2s_115200, pbn_brcm_trumanage, + pbn_fintek_4, + pbn_fintek_8, + pbn_fintek_12, }; /* @@ -3185,6 +3448,13 @@ static struct pciserial_board pci_boards[] = { .base_baud = 921600, .reg_shift = 2, }, + [pbn_byt] = { + .flags = FL_BASE0, + .num_ports = 1, + .base_baud = 2764800, + .uart_offset = 0x80, + .reg_shift = 2, + }, [pbn_omegapci] = { .flags = FL_BASE0, .num_ports = 8, @@ -3202,6 +3472,24 @@ static struct pciserial_board pci_boards[] = { .reg_shift = 2, .base_baud = 115200, }, + [pbn_fintek_4] = { + .num_ports = 4, + .uart_offset = 8, + .base_baud = 115200, + .first_offset = 0x40, + }, + [pbn_fintek_8] = { + .num_ports = 8, + .uart_offset = 8, + .base_baud = 115200, + .first_offset = 0x40, + }, + [pbn_fintek_12] = { + .num_ports = 12, + .uart_offset = 8, + .base_baud = 115200, + .first_offset = 0x40, + }, }; static const struct pci_device_id blacklist[] = { @@ -3362,14 +3650,15 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board) if (quirk->setup(priv, board, &uart, i)) break; -#ifdef SERIAL_DEBUG_PCI - printk(KERN_DEBUG "Setup PCI port: port %lx, irq %d, type %d\n", - uart.port.iobase, uart.port.irq, uart.port.iotype); -#endif + dev_dbg(&dev->dev, "Setup PCI port: port %lx, irq %d, type %d\n", + uart.port.iobase, uart.port.irq, uart.port.iotype); priv->line[i] = serial8250_register_8250_port(&uart); if (priv->line[i] < 0) { - printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), priv->line[i]); + dev_err(&dev->dev, + "Couldn't register serial port %lx, irq %d, type %d, error %d\n", + uart.port.iobase, uart.port.irq, + uart.port.iotype, priv->line[i]); break; } } @@ -3462,7 +3751,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) } if (ent->driver_data >= ARRAY_SIZE(pci_boards)) { - printk(KERN_ERR "pci_init_one: invalid driver_data: %ld\n", + dev_err(&dev->dev, "invalid driver_data: %ld\n", ent->driver_data); return -EINVAL; } @@ -3520,8 +3809,6 @@ static void pciserial_remove_one(struct pci_dev *dev) { struct serial_private *priv = pci_get_drvdata(dev); - pci_set_drvdata(dev, NULL); - pciserial_remove_ports(priv); pci_disable_device(dev); @@ -3555,7 +3842,7 @@ static int pciserial_resume_one(struct pci_dev *dev) err = pci_enable_device(dev); /* FIXME: We cannot simply error out here */ if (err) - printk(KERN_ERR "pciserial: Unable to re-enable ports, trying to continue.\n"); + dev_err(&dev->dev, "Unable to re-enable ports, trying to continue.\n"); pciserial_resume_ports(priv); } return 0; @@ -4848,6 +5135,15 @@ static struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CE4100_UART, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_ce4100_1_115200 }, + /* Intel BayTrail */ + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_UART1, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000, + pbn_byt }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_UART2, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000, + pbn_byt }, /* * Cronyx Omega PCI @@ -4918,6 +5214,11 @@ static struct pci_device_id serial_pci_tbl[] = { 0, 0, pbn_exar_XR17V358 }, + /* Fintek PCI serial cards */ + { PCI_DEVICE(0x1c29, 0x1104), .driver_data = pbn_fintek_4 }, + { PCI_DEVICE(0x1c29, 0x1108), .driver_data = pbn_fintek_8 }, + { PCI_DEVICE(0x1c29, 0x1112), .driver_data = pbn_fintek_12 }, + /* * These entries match devices with class COMMUNICATION_SERIAL, * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index f3b306efaa59..23329918f229 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -41,7 +41,7 @@ config SERIAL_8250_DEPRECATED_OPTIONS accept kernel parameters in both forms like 8250_core.nr_uarts=4 and 8250.nr_uarts=4. We now renamed the module back to 8250, but if anybody noticed in 3.7 and changed their userspace we still have to - keep the 8350_core.* options around until they revert the changes + keep the 8250_core.* options around until they revert the changes they already did. If 8250 is built as a module, this adds 8250_core alias instead. diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index cc4c8682b47b..a3817ab8602f 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -5,7 +5,7 @@ if TTY menu "Serial drivers" - depends on HAS_IOMEM && GENERIC_HARDIRQS + depends on HAS_IOMEM source "drivers/tty/serial/8250/Kconfig" @@ -709,7 +709,7 @@ config SERIAL_IP22_ZILOG_CONSOLE config SERIAL_SH_SCI tristate "SuperH SCI(F) serial port support" - depends on HAVE_CLK && (SUPERH || ARCH_SHMOBILE) + depends on HAVE_CLK && (SUPERH || ARM || COMPILE_TEST) select SERIAL_CORE config SERIAL_SH_SCI_NR_UARTS @@ -1439,6 +1439,15 @@ config SERIAL_EFM32_UART_CONSOLE depends on SERIAL_EFM32_UART=y select SERIAL_CORE_CONSOLE +config SERIAL_TILEGX + tristate "TILE-Gx on-chip serial port support" + depends on TILEGX + select TILE_GXIO_UART + select SERIAL_CORE + ---help--- + This device provides access to the on-chip UARTs on the TILE-Gx + processor. + config SERIAL_ARC tristate "ARC UART driver support" select SERIAL_CORE @@ -1503,6 +1512,7 @@ config SERIAL_FSL_LPUART_CONSOLE config SERIAL_ST_ASC tristate "ST ASC serial port support" select SERIAL_CORE + depends on ARM || COMPILE_TEST help This driver is for the on-chip Asychronous Serial Controller on STMicroelectronics STi SoCs. diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 47b679c547e9..3068c7722087 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -66,6 +66,7 @@ obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o obj-$(CONFIG_SERIAL_ST_ASC) += st-asc.o +obj-$(CONFIG_SERIAL_TILEGX) += tilegx.o obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o obj-$(CONFIG_SERIAL_QE) += ucc_uart.o obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c index 18e038fbdcdc..59b3da9bcc3f 100644 --- a/drivers/tty/serial/altera_jtaguart.c +++ b/drivers/tty/serial/altera_jtaguart.c @@ -473,6 +473,7 @@ static int altera_jtaguart_remove(struct platform_device *pdev) #ifdef CONFIG_OF static struct of_device_id altera_jtaguart_match[] = { { .compatible = "ALTR,juart-1.0", }, + { .compatible = "altr,juart-1.0", }, {}, }; MODULE_DEVICE_TABLE(of, altera_jtaguart_match); diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 6431472aeb1f..501667e3e3f5 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -615,6 +615,7 @@ static int altera_uart_remove(struct platform_device *pdev) #ifdef CONFIG_OF static struct of_device_id altera_uart_match[] = { { .compatible = "ALTR,uart-1.0", }, + { .compatible = "altr,uart-1.0", }, {}, }; MODULE_DEVICE_TABLE(of, altera_uart_match); diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c index 8b90f0b6dfdf..33bd8606be62 100644 --- a/drivers/tty/serial/amba-pl010.c +++ b/drivers/tty/serial/amba-pl010.c @@ -728,7 +728,6 @@ static int pl010_probe(struct amba_device *dev, const struct amba_id *id) amba_set_drvdata(dev, uap); ret = uart_add_one_port(&amba_reg, &uap->port); if (ret) { - amba_set_drvdata(dev, NULL); amba_ports[i] = NULL; clk_put(uap->clk); unmap: @@ -745,8 +744,6 @@ static int pl010_remove(struct amba_device *dev) struct uart_amba_port *uap = amba_get_drvdata(dev); int i; - amba_set_drvdata(dev, NULL); - uart_remove_one_port(&amba_reg, &uap->port); for (i = 0; i < ARRAY_SIZE(amba_ports); i++) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index aaa22867e656..7203864992a5 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -2147,7 +2147,6 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) amba_set_drvdata(dev, uap); ret = uart_add_one_port(&amba_reg, &uap->port); if (ret) { - amba_set_drvdata(dev, NULL); amba_ports[i] = NULL; pl011_dma_remove(uap); } @@ -2160,8 +2159,6 @@ static int pl011_remove(struct amba_device *dev) struct uart_amba_port *uap = amba_get_drvdata(dev); int i; - amba_set_drvdata(dev, NULL); - uart_remove_one_port(&amba_reg, &uap->port); for (i = 0; i < ARRAY_SIZE(amba_ports); i++) diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index 569872f4c9b8..c9f5c9dcc15c 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -533,7 +533,7 @@ arc_uart_init_one(struct platform_device *pdev, int dev_id) unsigned long *plat_data; struct arc_uart_port *uart = &arc_uart_ports[dev_id]; - plat_data = (unsigned long *)dev_get_platdata(&pdev->dev); + plat_data = dev_get_platdata(&pdev->dev); if (!plat_data) return -ENODEV; diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index d067285a2d20..c7d99af46a96 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -99,6 +99,7 @@ static void atmel_stop_rx(struct uart_port *port); #define UART_PUT_RTOR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_RTOR) #define UART_PUT_TTGR(port, v) __raw_writel(v, (port)->membase + ATMEL_US_TTGR) #define UART_GET_IP_NAME(port) __raw_readl((port)->membase + ATMEL_US_NAME) +#define UART_GET_IP_VERSION(port) __raw_readl((port)->membase + ATMEL_US_VERSION) /* PDC registers */ #define UART_PUT_PTCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR) @@ -1499,10 +1500,11 @@ static void atmel_set_ops(struct uart_port *port) /* * Get ip name usart or uart */ -static int atmel_get_ip_name(struct uart_port *port) +static void atmel_get_ip_name(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); int name = UART_GET_IP_NAME(port); + u32 version; int usart, uart; /* usart and uart ascii */ usart = 0x55534152; @@ -1517,11 +1519,23 @@ static int atmel_get_ip_name(struct uart_port *port) dev_dbg(port->dev, "This is uart\n"); atmel_port->is_usart = false; } else { - dev_err(port->dev, "Not supported ip name, set to uart\n"); - return -EINVAL; + /* fallback for older SoCs: use version field */ + version = UART_GET_IP_VERSION(port); + switch (version) { + case 0x302: + case 0x10213: + dev_dbg(port->dev, "This version is usart\n"); + atmel_port->is_usart = true; + break; + case 0x203: + case 0x10202: + dev_dbg(port->dev, "This version is uart\n"); + atmel_port->is_usart = false; + break; + default: + dev_err(port->dev, "Not supported ip name nor version, set to uart\n"); + } } - - return 0; } /* @@ -2405,9 +2419,7 @@ static int atmel_serial_probe(struct platform_device *pdev) /* * Get port name of usart or uart */ - ret = atmel_get_ip_name(&port->uart); - if (ret < 0) - goto err_add_port; + atmel_get_ip_name(&port->uart); return 0; diff --git a/drivers/tty/serial/bfin_sport_uart.c b/drivers/tty/serial/bfin_sport_uart.c index 87636cc61a21..4f229703328b 100644 --- a/drivers/tty/serial/bfin_sport_uart.c +++ b/drivers/tty/serial/bfin_sport_uart.c @@ -766,9 +766,8 @@ static int sport_uart_probe(struct platform_device *pdev) return -ENOMEM; } - ret = peripheral_request_list( - (unsigned short *)dev_get_platdata(&pdev->dev), - DRV_NAME); + ret = peripheral_request_list(dev_get_platdata(&pdev->dev), + DRV_NAME); if (ret) { dev_err(&pdev->dev, "Fail to request SPORT peripherals\n"); @@ -844,8 +843,7 @@ static int sport_uart_probe(struct platform_device *pdev) out_error_unmap: iounmap(sport->port.membase); out_error_free_peripherals: - peripheral_free_list( - (unsigned short *)dev_get_platdata(&pdev->dev)); + peripheral_free_list(dev_get_platdata(&pdev->dev)); out_error_free_mem: kfree(sport); bfin_sport_uart_ports[pdev->id] = NULL; @@ -864,8 +862,7 @@ static int sport_uart_remove(struct platform_device *pdev) if (sport) { uart_remove_one_port(&sport_uart_reg, &sport->port); iounmap(sport->port.membase); - peripheral_free_list( - (unsigned short *)dev_get_platdata(&pdev->dev)); + peripheral_free_list(dev_get_platdata(&pdev->dev)); kfree(sport); bfin_sport_uart_ports[pdev->id] = NULL; } diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c index 3c75e8e04028..869ceba2ec57 100644 --- a/drivers/tty/serial/bfin_uart.c +++ b/drivers/tty/serial/bfin_uart.c @@ -680,7 +680,7 @@ static int bfin_serial_startup(struct uart_port *port) default: uart_dma_ch_rx = uart_dma_ch_tx = 0; break; - }; + } if (uart_dma_ch_rx && request_dma(uart_dma_ch_rx, "BFIN_UART_RX") < 0) { @@ -726,7 +726,7 @@ static int bfin_serial_startup(struct uart_port *port) #ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS if (uart->cts_pin >= 0) { if (request_irq(uart->status_irq, bfin_serial_mctrl_cts_int, - IRQF_DISABLED, "BFIN_UART_MODEM_STATUS", uart)) { + 0, "BFIN_UART_MODEM_STATUS", uart)) { uart->cts_pin = -1; dev_info(port->dev, "Unable to attach BlackFin UART Modem Status interrupt.\n"); } @@ -765,7 +765,7 @@ static void bfin_serial_shutdown(struct uart_port *port) break; default: break; - }; + } #endif free_irq(uart->rx_irq, uart); free_irq(uart->tx_irq, uart); @@ -1240,7 +1240,7 @@ static int bfin_serial_probe(struct platform_device *pdev) */ #endif ret = peripheral_request_list( - (unsigned short *)dev_get_platdata(&pdev->dev), + dev_get_platdata(&pdev->dev), DRIVER_NAME); if (ret) { dev_err(&pdev->dev, @@ -1358,8 +1358,7 @@ static int bfin_serial_probe(struct platform_device *pdev) out_error_unmap: iounmap(uart->port.membase); out_error_free_peripherals: - peripheral_free_list( - (unsigned short *)dev_get_platdata(&pdev->dev)); + peripheral_free_list(dev_get_platdata(&pdev->dev)); out_error_free_mem: kfree(uart); bfin_serial_ports[pdev->id] = NULL; @@ -1377,8 +1376,7 @@ static int bfin_serial_remove(struct platform_device *pdev) if (uart) { uart_remove_one_port(&bfin_serial_reg, &uart->port); iounmap(uart->port.membase); - peripheral_free_list( - (unsigned short *)dev_get_platdata(&pdev->dev)); + peripheral_free_list(dev_get_platdata(&pdev->dev)); kfree(uart); bfin_serial_ports[pdev->id] = NULL; } @@ -1432,8 +1430,8 @@ static int bfin_earlyprintk_probe(struct platform_device *pdev) return -ENOENT; } - ret = peripheral_request_list( - (unsigned short *)dev_get_platdata(&pdev->dev), DRIVER_NAME); + ret = peripheral_request_list(dev_get_platdata(&pdev->dev), + DRIVER_NAME); if (ret) { dev_err(&pdev->dev, "fail to request bfin serial peripherals\n"); @@ -1463,8 +1461,7 @@ static int bfin_earlyprintk_probe(struct platform_device *pdev) return 0; out_error_free_peripherals: - peripheral_free_list( - (unsigned short *)dev_get_platdata(&pdev->dev)); + peripheral_free_list(dev_get_platdata(&pdev->dev)); return ret; } diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c index 7e4e4088471c..8d0b994357c8 100644 --- a/drivers/tty/serial/clps711x.c +++ b/drivers/tty/serial/clps711x.c @@ -459,7 +459,6 @@ static int uart_clps711x_probe(struct platform_device *pdev) ret = uart_register_driver(&s->uart); if (ret) { dev_err(&pdev->dev, "Registering UART driver failed\n"); - devm_clk_put(&pdev->dev, s->uart_clk); return ret; } @@ -487,7 +486,6 @@ static int uart_clps711x_remove(struct platform_device *pdev) for (i = 0; i < UART_CLPS711X_NR; i++) uart_remove_one_port(&s->uart, &s->port[i]); - devm_clk_put(&pdev->dev, s->uart_clk); uart_unregister_driver(&s->uart); return 0; diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c index 1a535f70dc41..7d76214612c7 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c @@ -41,6 +41,8 @@ #include <linux/bootmem.h> #include <linux/dma-mapping.h> #include <linux/fs_uart_pd.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/gpio.h> #include <linux/of_gpio.h> @@ -1207,7 +1209,7 @@ static int cpm_uart_init_port(struct device_node *np, pinfo->port.fifosize = pinfo->tx_nrfifos * pinfo->tx_fifosize; spin_lock_init(&pinfo->port.lock); - pinfo->port.irq = of_irq_to_resource(np, 0, NULL); + pinfo->port.irq = irq_of_parse_and_map(np, 0); if (pinfo->port.irq == NO_IRQ) { ret = -EINVAL; goto out_pram; diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c index 18f79575894a..527a969b0952 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c @@ -45,6 +45,7 @@ #include <linux/kernel.h> #include <linux/of.h> +#include <linux/of_address.h> #include "cpm_uart.h" diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c index af286e6713eb..590390970996 100644 --- a/drivers/tty/serial/ifx6x60.c +++ b/drivers/tty/serial/ifx6x60.c @@ -1008,7 +1008,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi) return -ENODEV; } - pl_data = (struct ifx_modem_platform_data *)dev_get_platdata(&spi->dev); + pl_data = dev_get_platdata(&spi->dev); if (!pl_data) { dev_err(&spi->dev, "missing platform data!"); return -ENODEV; diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index a0ebbc9ce5cd..b2cfdb661947 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -223,8 +223,7 @@ struct imx_port { struct dma_chan *dma_chan_rx, *dma_chan_tx; struct scatterlist rx_sgl, tx_sgl[2]; void *rx_buf; - unsigned int rx_bytes, tx_bytes; - struct work_struct tsk_dma_rx, tsk_dma_tx; + unsigned int tx_bytes; unsigned int dma_tx_nents; wait_queue_head_t dma_wait; }; @@ -505,34 +504,25 @@ static void dma_tx_callback(void *data) dev_dbg(sport->port.dev, "exit in %s.\n", __func__); return; } - - schedule_work(&sport->tsk_dma_tx); } -static void dma_tx_work(struct work_struct *w) +static void imx_dma_tx(struct imx_port *sport) { - struct imx_port *sport = container_of(w, struct imx_port, tsk_dma_tx); struct circ_buf *xmit = &sport->port.state->xmit; struct scatterlist *sgl = sport->tx_sgl; struct dma_async_tx_descriptor *desc; struct dma_chan *chan = sport->dma_chan_tx; struct device *dev = sport->port.dev; enum dma_status status; - unsigned long flags; int ret; - status = chan->device->device_tx_status(chan, (dma_cookie_t)0, NULL); + status = dmaengine_tx_status(chan, (dma_cookie_t)0, NULL); if (DMA_IN_PROGRESS == status) return; - spin_lock_irqsave(&sport->port.lock, flags); sport->tx_bytes = uart_circ_chars_pending(xmit); - if (sport->tx_bytes == 0) { - spin_unlock_irqrestore(&sport->port.lock, flags); - return; - } - if (xmit->tail > xmit->head) { + if (xmit->tail > xmit->head && xmit->head > 0) { sport->dma_tx_nents = 2; sg_init_table(sgl, 2); sg_set_buf(sgl, xmit->buf + xmit->tail, @@ -542,7 +532,6 @@ static void dma_tx_work(struct work_struct *w) sport->dma_tx_nents = 1; sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes); } - spin_unlock_irqrestore(&sport->port.lock, flags); ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); if (ret == 0) { @@ -609,11 +598,7 @@ static void imx_start_tx(struct uart_port *port) } if (sport->dma_is_enabled) { - /* - * We may in the interrupt context, so arise a work_struct to - * do the real job. - */ - schedule_work(&sport->tsk_dma_tx); + imx_dma_tx(sport); return; } @@ -732,6 +717,7 @@ out: return IRQ_HANDLED; } +static int start_rx_dma(struct imx_port *sport); /* * If the RXFIFO is filled with some data, and then we * arise a DMA operation to receive them. @@ -750,7 +736,7 @@ static void imx_dma_rxint(struct imx_port *sport) writel(temp, sport->port.membase + UCR1); /* tell the DMA to receive the data. */ - schedule_work(&sport->tsk_dma_rx); + start_rx_dma(sport); } } @@ -795,8 +781,15 @@ static irqreturn_t imx_int(int irq, void *dev_id) static unsigned int imx_tx_empty(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; + unsigned int ret; + + ret = (readl(sport->port.membase + USR2) & USR2_TXDC) ? TIOCSER_TEMT : 0; - return (readl(sport->port.membase + USR2) & USR2_TXDC) ? TIOCSER_TEMT : 0; + /* If the TX DMA is working, return 0. */ + if (sport->dma_is_enabled && sport->dma_is_txing) + ret = 0; + + return ret; } /* @@ -865,22 +858,6 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) } #define RX_BUF_SIZE (PAGE_SIZE) -static int start_rx_dma(struct imx_port *sport); -static void dma_rx_work(struct work_struct *w) -{ - struct imx_port *sport = container_of(w, struct imx_port, tsk_dma_rx); - struct tty_port *port = &sport->port.state->port; - - if (sport->rx_bytes) { - tty_insert_flip_string(port, sport->rx_buf, sport->rx_bytes); - tty_flip_buffer_push(port); - sport->rx_bytes = 0; - } - - if (sport->dma_is_rxing) - start_rx_dma(sport); -} - static void imx_rx_dma_done(struct imx_port *sport) { unsigned long temp; @@ -912,6 +889,7 @@ static void dma_rx_callback(void *data) struct imx_port *sport = data; struct dma_chan *chan = sport->dma_chan_rx; struct scatterlist *sgl = &sport->rx_sgl; + struct tty_port *port = &sport->port.state->port; struct dma_tx_state state; enum dma_status status; unsigned int count; @@ -919,13 +897,15 @@ static void dma_rx_callback(void *data) /* unmap it first */ dma_unmap_sg(sport->port.dev, sgl, 1, DMA_FROM_DEVICE); - status = chan->device->device_tx_status(chan, (dma_cookie_t)0, &state); + status = dmaengine_tx_status(chan, (dma_cookie_t)0, &state); count = RX_BUF_SIZE - state.residue; dev_dbg(sport->port.dev, "We get %d bytes.\n", count); if (count) { - sport->rx_bytes = count; - schedule_work(&sport->tsk_dma_rx); + tty_insert_flip_string(port, sport->rx_buf, count); + tty_flip_buffer_push(port); + + start_rx_dma(sport); } else imx_rx_dma_done(sport); } @@ -1007,7 +987,6 @@ static int imx_uart_dma_init(struct imx_port *sport) ret = -ENOMEM; goto err; } - sport->rx_bytes = 0; /* Prepare for TX : */ sport->dma_chan_tx = dma_request_slave_channel(dev, "tx"); @@ -1038,11 +1017,7 @@ err: static void imx_enable_dma(struct imx_port *sport) { unsigned long temp; - struct tty_port *port = &sport->port.state->port; - port->low_latency = 1; - INIT_WORK(&sport->tsk_dma_tx, dma_tx_work); - INIT_WORK(&sport->tsk_dma_rx, dma_rx_work); init_waitqueue_head(&sport->dma_wait); /* set UCR1 */ @@ -1063,7 +1038,6 @@ static void imx_enable_dma(struct imx_port *sport) static void imx_disable_dma(struct imx_port *sport) { unsigned long temp; - struct tty_port *port = &sport->port.state->port; /* clear UCR1 */ temp = readl(sport->port.membase + UCR1); @@ -1081,7 +1055,6 @@ static void imx_disable_dma(struct imx_port *sport) writel(temp, sport->port.membase + UCR4); sport->dma_is_enabled = 0; - port->low_latency = 0; } /* half the RX buffer size */ @@ -1303,6 +1276,16 @@ static void imx_shutdown(struct uart_port *port) clk_disable_unprepare(sport->clk_ipg); } +static void imx_flush_buffer(struct uart_port *port) +{ + struct imx_port *sport = (struct imx_port *)port; + + if (sport->dma_is_enabled) { + sport->tx_bytes = 0; + dmaengine_terminate_all(sport->dma_chan_tx); + } +} + static void imx_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) @@ -1539,7 +1522,7 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser) ret = -EINVAL; if (sport->port.uartclk / 16 != ser->baud_base) ret = -EINVAL; - if ((void *)sport->port.mapbase != ser->iomem_base) + if (sport->port.mapbase != (unsigned long)ser->iomem_base) ret = -EINVAL; if (sport->port.iobase != ser->port) ret = -EINVAL; @@ -1623,6 +1606,7 @@ static struct uart_ops imx_pops = { .break_ctl = imx_break_ctl, .startup = imx_startup, .shutdown = imx_shutdown, + .flush_buffer = imx_flush_buffer, .set_termios = imx_set_termios, .type = imx_type, .release_port = imx_release_port, @@ -1912,9 +1896,6 @@ static int serial_imx_probe_dt(struct imx_port *sport, sport->devdata = of_id->data; - if (of_device_is_stdout_path(np)) - add_preferred_console(imx_reg.cons->name, sport->port.line, 0); - return 0; } #else diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c index cb3c81eb0996..1d9420548e16 100644 --- a/drivers/tty/serial/ip22zilog.c +++ b/drivers/tty/serial/ip22zilog.c @@ -832,7 +832,7 @@ ip22zilog_convert_to_zs(struct uart_ip22zilog_port *up, unsigned int cflag, up->curregs[5] |= Tx8; up->parity_mask = 0xff; break; - }; + } up->curregs[4] &= ~0x0c; if (cflag & CSTOPB) up->curregs[4] |= SB2; diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index b2e707aa603a..8d71e4047bb3 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -690,7 +690,7 @@ static void max310x_handle_tx(struct uart_port *port) max310x_port_write(port, MAX310X_THR_REG, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - }; + } } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c index d3db042f649e..52c930fac210 100644 --- a/drivers/tty/serial/mfd.c +++ b/drivers/tty/serial/mfd.c @@ -293,7 +293,7 @@ static void serial_hsu_enable_ms(struct uart_port *port) serial_out(up, UART_IER, up->ier); } -void hsu_dma_tx(struct uart_hsu_port *up) +static void hsu_dma_tx(struct uart_hsu_port *up) { struct circ_buf *xmit = &up->port.state->xmit; struct hsu_dma_buffer *dbuf = &up->txbuf; @@ -340,7 +340,8 @@ void hsu_dma_tx(struct uart_hsu_port *up) } /* The buffer is already cache coherent */ -void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc, struct hsu_dma_buffer *dbuf) +static void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc, + struct hsu_dma_buffer *dbuf) { dbuf->ofs = 0; @@ -386,7 +387,8 @@ static void serial_hsu_stop_tx(struct uart_port *port) /* This is always called in spinlock protected mode, so * modify timeout timer is safe here */ -void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts, unsigned long *flags) +static void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts, + unsigned long *flags) { struct hsu_dma_buffer *dbuf = &up->rxbuf; struct hsu_dma_chan *chan = up->rxc; @@ -1183,7 +1185,7 @@ static struct console serial_hsu_console = { #define SERIAL_HSU_CONSOLE NULL #endif -struct uart_ops serial_hsu_pops = { +static struct uart_ops serial_hsu_pops = { .tx_empty = serial_hsu_tx_empty, .set_mctrl = serial_hsu_set_mctrl, .get_mctrl = serial_hsu_get_mctrl, @@ -1451,7 +1453,6 @@ static void serial_hsu_remove(struct pci_dev *pdev) uart_remove_one_port(&serial_hsu_reg, &up->port); } - pci_set_drvdata(pdev, NULL); free_irq(pdev->irq, priv); pci_disable_device(pdev); } @@ -1504,4 +1505,4 @@ module_init(hsu_pci_init); module_exit(hsu_pci_exit); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:medfield-hsu"); +MODULE_DEVICE_TABLE(pci, pci_ids); diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index e1280a20b7a2..ec06505e3ae6 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -107,6 +107,8 @@ struct psc_ops { unsigned int (*set_baudrate)(struct uart_port *port, struct ktermios *new, struct ktermios *old); + int (*clock_alloc)(struct uart_port *port); + void (*clock_relse)(struct uart_port *port); int (*clock)(struct uart_port *port, int enable); int (*fifoc_init)(void); void (*fifoc_uninit)(void); @@ -616,31 +618,73 @@ static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port) return IRQ_NONE; } -static int mpc512x_psc_clock(struct uart_port *port, int enable) +static struct clk *psc_mclk_clk[MPC52xx_PSC_MAXNUM]; + +/* called from within the .request_port() callback (allocation) */ +static int mpc512x_psc_alloc_clock(struct uart_port *port) +{ + int psc_num; + char clk_name[16]; + struct clk *clk; + int err; + + psc_num = (port->mapbase & 0xf00) >> 8; + snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num); + clk = devm_clk_get(port->dev, clk_name); + if (IS_ERR(clk)) { + dev_err(port->dev, "Failed to get MCLK!\n"); + return PTR_ERR(clk); + } + err = clk_prepare_enable(clk); + if (err) { + dev_err(port->dev, "Failed to enable MCLK!\n"); + return err; + } + psc_mclk_clk[psc_num] = clk; + return 0; +} + +/* called from within the .release_port() callback (release) */ +static void mpc512x_psc_relse_clock(struct uart_port *port) { - struct clk *psc_clk; int psc_num; - char clk_name[10]; + struct clk *clk; + + psc_num = (port->mapbase & 0xf00) >> 8; + clk = psc_mclk_clk[psc_num]; + if (clk) { + clk_disable_unprepare(clk); + psc_mclk_clk[psc_num] = NULL; + } +} + +/* implementation of the .clock() callback (enable/disable) */ +static int mpc512x_psc_endis_clock(struct uart_port *port, int enable) +{ + int psc_num; + struct clk *psc_clk; + int ret; if (uart_console(port)) return 0; psc_num = (port->mapbase & 0xf00) >> 8; - snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num); - psc_clk = clk_get(port->dev, clk_name); - if (IS_ERR(psc_clk)) { + psc_clk = psc_mclk_clk[psc_num]; + if (!psc_clk) { dev_err(port->dev, "Failed to get PSC clock entry!\n"); return -ENODEV; } - dev_dbg(port->dev, "%s %sable\n", clk_name, enable ? "en" : "dis"); - - if (enable) - clk_enable(psc_clk); - else + dev_dbg(port->dev, "mclk %sable\n", enable ? "en" : "dis"); + if (enable) { + ret = clk_enable(psc_clk); + if (ret) + dev_err(port->dev, "Failed to enable MCLK!\n"); + return ret; + } else { clk_disable(psc_clk); - - return 0; + return 0; + } } static void mpc512x_psc_get_irq(struct uart_port *port, struct device_node *np) @@ -873,7 +917,9 @@ static struct psc_ops mpc5125_psc_ops = { .cw_disable_ints = mpc5125_psc_cw_disable_ints, .cw_restore_ints = mpc5125_psc_cw_restore_ints, .set_baudrate = mpc5125_psc_set_baudrate, - .clock = mpc512x_psc_clock, + .clock_alloc = mpc512x_psc_alloc_clock, + .clock_relse = mpc512x_psc_relse_clock, + .clock = mpc512x_psc_endis_clock, .fifoc_init = mpc512x_psc_fifoc_init, .fifoc_uninit = mpc512x_psc_fifoc_uninit, .get_irq = mpc512x_psc_get_irq, @@ -906,7 +952,9 @@ static struct psc_ops mpc512x_psc_ops = { .cw_disable_ints = mpc512x_psc_cw_disable_ints, .cw_restore_ints = mpc512x_psc_cw_restore_ints, .set_baudrate = mpc512x_psc_set_baudrate, - .clock = mpc512x_psc_clock, + .clock_alloc = mpc512x_psc_alloc_clock, + .clock_relse = mpc512x_psc_relse_clock, + .clock = mpc512x_psc_endis_clock, .fifoc_init = mpc512x_psc_fifoc_init, .fifoc_uninit = mpc512x_psc_fifoc_uninit, .get_irq = mpc512x_psc_get_irq, @@ -1166,6 +1214,9 @@ mpc52xx_uart_type(struct uart_port *port) static void mpc52xx_uart_release_port(struct uart_port *port) { + if (psc_ops->clock_relse) + psc_ops->clock_relse(port); + /* remapped by us ? */ if (port->flags & UPF_IOREMAP) { iounmap(port->membase); @@ -1190,11 +1241,24 @@ mpc52xx_uart_request_port(struct uart_port *port) err = request_mem_region(port->mapbase, sizeof(struct mpc52xx_psc), "mpc52xx_psc_uart") != NULL ? 0 : -EBUSY; - if (err && (port->flags & UPF_IOREMAP)) { + if (err) + goto out_membase; + + if (psc_ops->clock_alloc) { + err = psc_ops->clock_alloc(port); + if (err) + goto out_mapregion; + } + + return 0; + +out_mapregion: + release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc)); +out_membase: + if (port->flags & UPF_IOREMAP) { iounmap(port->membase); port->membase = NULL; } - return err; } @@ -1237,7 +1301,6 @@ static struct uart_ops mpc52xx_uart_ops = { .shutdown = mpc52xx_uart_shutdown, .set_termios = mpc52xx_uart_set_termios, /* .pm = mpc52xx_uart_pm, Not supported yet */ -/* .set_wake = mpc52xx_uart_set_wake, Not supported yet */ .type = mpc52xx_uart_type, .release_port = mpc52xx_uart_release_port, .request_port = mpc52xx_uart_request_port, @@ -1702,7 +1765,7 @@ mpc52xx_uart_of_remove(struct platform_device *op) static int mpc52xx_uart_of_suspend(struct platform_device *op, pm_message_t state) { - struct uart_port *port = (struct uart_port *) platform_get_drvdata(op); + struct uart_port *port = platform_get_drvdata(op); if (port) uart_suspend_port(&mpc52xx_uart_driver, port); @@ -1713,7 +1776,7 @@ mpc52xx_uart_of_suspend(struct platform_device *op, pm_message_t state) static int mpc52xx_uart_of_resume(struct platform_device *op) { - struct uart_port *port = (struct uart_port *) platform_get_drvdata(op); + struct uart_port *port = platform_get_drvdata(op); if (port) uart_resume_port(&mpc52xx_uart_driver, port); diff --git a/drivers/tty/serial/mpsc.c b/drivers/tty/serial/mpsc.c index 8d702677acc5..e30a3ca3cea3 100644 --- a/drivers/tty/serial/mpsc.c +++ b/drivers/tty/serial/mpsc.c @@ -2030,7 +2030,7 @@ static void mpsc_drv_get_platform_data(struct mpsc_port_info *pi, { struct mpsc_pdata *pdata; - pdata = (struct mpsc_pdata *)dev_get_platdata(&pd->dev); + pdata = dev_get_platdata(&pd->dev); pi->port.uartclk = pdata->brg_clk_freq; pi->port.iotype = UPIO_MEM; diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c index a67e7081f001..db0448ae59dc 100644 --- a/drivers/tty/serial/mrst_max3110.c +++ b/drivers/tty/serial/mrst_max3110.c @@ -43,6 +43,7 @@ #include <linux/kthread.h> #include <linux/spi/spi.h> +#include <linux/pm.h> #include "mrst_max3110.h" @@ -61,6 +62,7 @@ struct uart_max3110 { struct task_struct *main_thread; struct task_struct *read_thread; struct mutex thread_mutex; + struct mutex io_mutex; u32 baud; u16 cur_conf; @@ -90,6 +92,7 @@ static int max3110_write_then_read(struct uart_max3110 *max, struct spi_transfer x; int ret; + mutex_lock(&max->io_mutex); spi_message_init(&message); memset(&x, 0, sizeof x); x.len = len; @@ -104,6 +107,7 @@ static int max3110_write_then_read(struct uart_max3110 *max, /* Do the i/o */ ret = spi_sync(spi, &message); + mutex_unlock(&max->io_mutex); return ret; } @@ -491,19 +495,9 @@ static int serial_m3110_startup(struct uart_port *port) port->state->port.low_latency = 1; if (max->irq) { - max->read_thread = NULL; - ret = request_irq(max->irq, serial_m3110_irq, - IRQ_TYPE_EDGE_FALLING, "max3110", max); - if (ret) { - max->irq = 0; - pr_err(PR_FMT "unable to allocate IRQ, polling\n"); - } else { - /* Enable RX IRQ only */ - config |= WC_RXA_IRQ_ENABLE; - } - } - - if (max->irq == 0) { + /* Enable RX IRQ only */ + config |= WC_RXA_IRQ_ENABLE; + } else { /* If IRQ is disabled, start a read thread for input data */ max->read_thread = kthread_run(max3110_read_thread, max, "max3110_read"); @@ -517,8 +511,6 @@ static int serial_m3110_startup(struct uart_port *port) ret = max3110_out(max, config); if (ret) { - if (max->irq) - free_irq(max->irq, max); if (max->read_thread) kthread_stop(max->read_thread); max->read_thread = NULL; @@ -540,9 +532,6 @@ static void serial_m3110_shutdown(struct uart_port *port) max->read_thread = NULL; } - if (max->irq) - free_irq(max->irq, max); - /* Disable interrupts from this port */ config = WC_TAG | WC_SW_SHDI; max3110_out(max, config); @@ -749,7 +738,8 @@ static int serial_m3110_suspend(struct device *dev) struct spi_device *spi = to_spi_device(dev); struct uart_max3110 *max = spi_get_drvdata(spi); - disable_irq(max->irq); + if (max->irq > 0) + disable_irq(max->irq); uart_suspend_port(&serial_m3110_reg, &max->port); max3110_out(max, max->cur_conf | WC_SW_SHDI); return 0; @@ -762,7 +752,8 @@ static int serial_m3110_resume(struct device *dev) max3110_out(max, max->cur_conf); uart_resume_port(&serial_m3110_reg, &max->port); - enable_irq(max->irq); + if (max->irq > 0) + enable_irq(max->irq); return 0; } @@ -803,6 +794,7 @@ static int serial_m3110_probe(struct spi_device *spi) max->irq = (u16)spi->irq; mutex_init(&max->thread_mutex); + mutex_init(&max->io_mutex); max->word_7bits = 0; max->parity = 0; @@ -840,6 +832,16 @@ static int serial_m3110_probe(struct spi_device *spi) goto err_kthread; } + if (max->irq) { + ret = request_irq(max->irq, serial_m3110_irq, + IRQ_TYPE_EDGE_FALLING, "max3110", max); + if (ret) { + max->irq = 0; + dev_warn(&spi->dev, + "unable to allocate IRQ, will use polling method\n"); + } + } + spi_set_drvdata(spi, max); pmax = max; @@ -867,6 +869,9 @@ static int serial_m3110_remove(struct spi_device *dev) free_page((unsigned long)max->con_xmit.buf); + if (max->irq) + free_irq(max->irq, max); + if (max->main_thread) kthread_stop(max->main_thread); diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index 10e9d70b5c40..d8b6fee77a03 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -39,6 +39,7 @@ #include <asm/cacheflush.h> #define MXS_AUART_PORTS 5 +#define MXS_AUART_FIFO_SIZE 16 #define AUART_CTRL0 0x00000000 #define AUART_CTRL0_SET 0x00000004 @@ -548,6 +549,9 @@ static int mxs_auart_dma_init(struct mxs_auart_port *s) s->flags |= MXS_AUART_DMA_ENABLED; dev_dbg(s->dev, "enabled the DMA support."); + /* The DMA buffer is now the FIFO the TTY subsystem can use */ + s->port.fifosize = UART_XMIT_SIZE; + return 0; err_out: @@ -741,6 +745,9 @@ static int mxs_auart_startup(struct uart_port *u) writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN, u->membase + AUART_INTR); + /* Reset FIFO size (it could have changed if DMA was enabled) */ + u->fifosize = MXS_AUART_FIFO_SIZE; + /* * Enable fifo so all four bytes of a DMA word are written to * output (otherwise, only the LSB is written, ie. 1 in 4 bytes) @@ -1056,7 +1063,7 @@ static int mxs_auart_probe(struct platform_device *pdev) s->port.membase = ioremap(r->start, resource_size(r)); s->port.ops = &mxs_auart_ops; s->port.iotype = UPIO_MEM; - s->port.fifosize = 16; + s->port.fifosize = MXS_AUART_FIFO_SIZE; s->port.uartclk = clk_get_rate(s->clk); s->port.type = PORT_IMX; s->port.dev = s->dev = &pdev->dev; diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 816d1a23f9d0..fa511ebab67c 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -39,6 +39,7 @@ #include <linux/irq.h> #include <linux/pm_runtime.h> #include <linux/of.h> +#include <linux/of_irq.h> #include <linux/gpio.h> #include <linux/of_gpio.h> #include <linux/platform_data/serial-omap.h> @@ -134,6 +135,7 @@ struct uart_omap_port { struct uart_port port; struct uart_omap_dma uart_dma; struct device *dev; + int wakeirq; unsigned char ier; unsigned char lcr; @@ -175,7 +177,7 @@ struct uart_omap_port { bool is_suspending; }; -#define to_uart_omap_port(p) ((container_of((p), struct uart_omap_port, port))) +#define to_uart_omap_port(p) ((container_of((p), struct uart_omap_port, port))) static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS]; @@ -214,10 +216,23 @@ static int serial_omap_get_context_loss_count(struct uart_omap_port *up) return pdata->get_context_loss_count(up->dev); } +static inline void serial_omap_enable_wakeirq(struct uart_omap_port *up, + bool enable) +{ + if (!up->wakeirq) + return; + + if (enable) + enable_irq(up->wakeirq); + else + disable_irq(up->wakeirq); +} + static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable) { struct omap_uart_port_info *pdata = dev_get_platdata(up->dev); + serial_omap_enable_wakeirq(up, enable); if (!pdata || !pdata->enable_wakeup) return; @@ -242,12 +257,12 @@ serial_omap_baud_is_mode16(struct uart_port *port, unsigned int baud) unsigned int n16 = port->uartclk / (16 * baud); int baudAbsDiff13 = baud - (port->uartclk / (13 * n13)); int baudAbsDiff16 = baud - (port->uartclk / (16 * n16)); - if(baudAbsDiff13 < 0) + if (baudAbsDiff13 < 0) baudAbsDiff13 = -baudAbsDiff13; - if(baudAbsDiff16 < 0) + if (baudAbsDiff16 < 0) baudAbsDiff16 = -baudAbsDiff16; - return (baudAbsDiff13 > baudAbsDiff16); + return (baudAbsDiff13 >= baudAbsDiff16); } /* @@ -258,13 +273,13 @@ serial_omap_baud_is_mode16(struct uart_port *port, unsigned int baud) static unsigned int serial_omap_get_divisor(struct uart_port *port, unsigned int baud) { - unsigned int divisor; + unsigned int mode; if (!serial_omap_baud_is_mode16(port, baud)) - divisor = 13; + mode = 13; else - divisor = 16; - return port->uartclk/(baud * divisor); + mode = 16; + return port->uartclk/(mode * baud); } static void serial_omap_enable_ms(struct uart_port *port) @@ -283,28 +298,40 @@ static void serial_omap_enable_ms(struct uart_port *port) static void serial_omap_stop_tx(struct uart_port *port) { struct uart_omap_port *up = to_uart_omap_port(port); - struct circ_buf *xmit = &up->port.state->xmit; int res; pm_runtime_get_sync(up->dev); - /* handle rs485 */ + /* Handle RS-485 */ if (up->rs485.flags & SER_RS485_ENABLED) { - /* do nothing if current tx not yet completed */ - res = serial_in(up, UART_LSR) & UART_LSR_TEMT; - if (!res) - return; - - /* if there's no more data to send, turn off rts */ - if (uart_circ_empty(xmit)) { - /* if rts not already disabled */ + if (up->scr & OMAP_UART_SCR_TX_EMPTY) { + /* THR interrupt is fired when both TX FIFO and TX + * shift register are empty. This means there's nothing + * left to transmit now, so make sure the THR interrupt + * is fired when TX FIFO is below the trigger level, + * disable THR interrupts and toggle the RS-485 GPIO + * data direction pin if needed. + */ + up->scr &= ~OMAP_UART_SCR_TX_EMPTY; + serial_out(up, UART_OMAP_SCR, up->scr); res = (up->rs485.flags & SER_RS485_RTS_AFTER_SEND) ? 1 : 0; if (gpio_get_value(up->rts_gpio) != res) { - if (up->rs485.delay_rts_after_send > 0) { + if (up->rs485.delay_rts_after_send > 0) mdelay(up->rs485.delay_rts_after_send); - } gpio_set_value(up->rts_gpio, res); } + } else { + /* We're asked to stop, but there's still stuff in the + * UART FIFO, so make sure the THR interrupt is fired + * when both TX FIFO and TX shift register are empty. + * The next THR interrupt (if no transmission is started + * in the meantime) will indicate the end of a + * transmission. Therefore we _don't_ disable THR + * interrupts in this situation. + */ + up->scr |= OMAP_UART_SCR_TX_EMPTY; + serial_out(up, UART_OMAP_SCR, up->scr); + return; } } @@ -384,15 +411,18 @@ static void serial_omap_start_tx(struct uart_port *port) pm_runtime_get_sync(up->dev); - /* handle rs485 */ + /* Handle RS-485 */ if (up->rs485.flags & SER_RS485_ENABLED) { + /* Fire THR interrupts when FIFO is below trigger level */ + up->scr &= ~OMAP_UART_SCR_TX_EMPTY; + serial_out(up, UART_OMAP_SCR, up->scr); + /* if rts not already enabled */ res = (up->rs485.flags & SER_RS485_RTS_ON_SEND) ? 1 : 0; if (gpio_get_value(up->rts_gpio) != res) { gpio_set_value(up->rts_gpio, res); - if (up->rs485.delay_rts_before_send > 0) { + if (up->rs485.delay_rts_before_send > 0) mdelay(up->rs485.delay_rts_before_send); - } } } @@ -699,6 +729,20 @@ static int serial_omap_startup(struct uart_port *port) if (retval) return retval; + /* Optional wake-up IRQ */ + if (up->wakeirq) { + retval = request_irq(up->wakeirq, serial_omap_irq, + up->port.irqflags, up->name, up); + if (retval) { + free_irq(up->port.irq, up); + return retval; + } + disable_irq(up->wakeirq); + } else { + dev_info(up->port.dev, "no wakeirq for uart%d\n", + up->port.line); + } + dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->port.line); pm_runtime_get_sync(up->dev); @@ -787,6 +831,8 @@ static void serial_omap_shutdown(struct uart_port *port) pm_runtime_mark_last_busy(up->dev); pm_runtime_put_autosuspend(up->dev); free_irq(up->port.irq, up); + if (up->wakeirq) + free_irq(up->wakeirq, up); } static void serial_omap_uart_qos_work(struct work_struct *work) @@ -938,7 +984,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, */ /* Set receive FIFO threshold to 16 characters and - * transmit FIFO threshold to 16 spaces + * transmit FIFO threshold to 32 spaces */ up->fcr &= ~OMAP_UART_FCR_RX_FIFO_TRIG_MASK; up->fcr &= ~OMAP_UART_FCR_TX_FIFO_TRIG_MASK; @@ -1060,15 +1106,6 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->port.line); } -static int serial_omap_set_wake(struct uart_port *port, unsigned int state) -{ - struct uart_omap_port *up = to_uart_omap_port(port); - - serial_omap_enable_wakeup(up, state); - - return 0; -} - static void serial_omap_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) @@ -1353,6 +1390,15 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf) up->ier = mode; serial_out(up, UART_IER, up->ier); + /* If RS-485 is disabled, make sure the THR interrupt is fired when + * TX FIFO is below the trigger level. + */ + if (!(up->rs485.flags & SER_RS485_ENABLED) && + (up->scr & OMAP_UART_SCR_TX_EMPTY)) { + up->scr &= ~OMAP_UART_SCR_TX_EMPTY; + serial_out(up, UART_OMAP_SCR, up->scr); + } + spin_unlock_irqrestore(&up->port.lock, flags); pm_runtime_mark_last_busy(up->dev); pm_runtime_put_autosuspend(up->dev); @@ -1401,7 +1447,6 @@ static struct uart_ops serial_omap_pops = { .shutdown = serial_omap_shutdown, .set_termios = serial_omap_set_termios, .pm = serial_omap_pm, - .set_wake = serial_omap_set_wake, .type = serial_omap_type, .release_port = serial_omap_release_port, .request_port = serial_omap_request_port, @@ -1582,11 +1627,23 @@ static int serial_omap_probe(struct platform_device *pdev) struct uart_omap_port *up; struct resource *mem, *irq; struct omap_uart_port_info *omap_up_info = dev_get_platdata(&pdev->dev); - int ret; + int ret, uartirq = 0, wakeirq = 0; + /* The optional wakeirq may be specified in the board dts file */ if (pdev->dev.of_node) { + uartirq = irq_of_parse_and_map(pdev->dev.of_node, 0); + if (!uartirq) + return -EPROBE_DEFER; + wakeirq = irq_of_parse_and_map(pdev->dev.of_node, 1); omap_up_info = of_get_uart_port_info(&pdev->dev); pdev->dev.platform_data = omap_up_info; + } else { + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!irq) { + dev_err(&pdev->dev, "no irq resource?\n"); + return -ENODEV; + } + uartirq = irq->start; } mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1595,12 +1652,6 @@ static int serial_omap_probe(struct platform_device *pdev) return -ENODEV; } - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!irq) { - dev_err(&pdev->dev, "no irq resource?\n"); - return -ENODEV; - } - if (!devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem), pdev->dev.driver->name)) { dev_err(&pdev->dev, "memory region already claimed\n"); @@ -1634,7 +1685,8 @@ static int serial_omap_probe(struct platform_device *pdev) up->port.dev = &pdev->dev; up->port.type = PORT_OMAP; up->port.iotype = UPIO_MEM; - up->port.irq = irq->start; + up->port.irq = uartirq; + up->wakeirq = wakeirq; up->port.regshift = 2; up->port.fifosize = 64; @@ -1670,8 +1722,9 @@ static int serial_omap_probe(struct platform_device *pdev) up->port.uartclk = omap_up_info->uartclk; if (!up->port.uartclk) { up->port.uartclk = DEFAULT_CLK_SPEED; - dev_warn(&pdev->dev, "No clock speed specified: using default:" - "%d\n", DEFAULT_CLK_SPEED); + dev_warn(&pdev->dev, + "No clock speed specified: using default: %d\n", + DEFAULT_CLK_SPEED); } up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 52379e56a31e..0aa2b528ef3d 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -667,30 +667,21 @@ static int pop_tx_x(struct eg20t_port *priv, unsigned char *buf) static int dma_push_rx(struct eg20t_port *priv, int size) { - struct tty_struct *tty; int room; struct uart_port *port = &priv->port; struct tty_port *tport = &port->state->port; - port = &priv->port; - tty = tty_port_tty_get(tport); - if (!tty) { - dev_dbg(priv->port.dev, "%s:tty is busy now", __func__); - return 0; - } - room = tty_buffer_request_room(tport, size); if (room < size) dev_warn(port->dev, "Rx overrun: dropping %u bytes\n", size - room); if (!room) - return room; + return 0; tty_insert_flip_string(tport, sg_virt(&priv->sg_rx), size); port->icount.rx += room; - tty_kref_put(tty); return room; } @@ -1098,6 +1089,8 @@ static void pch_uart_err_ir(struct eg20t_port *priv, unsigned int lsr) if (tty == NULL) { for (i = 0; error_msg[i] != NULL; i++) dev_err(&priv->pdev->dev, error_msg[i]); + } else { + tty_kref_put(tty); } } @@ -1621,7 +1614,6 @@ static struct uart_ops pch_uart_ops = { .shutdown = pch_uart_shutdown, .set_termios = pch_uart_set_termios, /* .pm = pch_uart_pm, Not supported yet */ -/* .set_wake = pch_uart_set_wake, Not supported yet */ .type = pch_uart_type, .release_port = pch_uart_release_port, .request_port = pch_uart_request_port, @@ -2003,6 +1995,8 @@ module_exit(pch_uart_module_exit); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Intel EG20T PCH UART PCI Driver"); +MODULE_DEVICE_TABLE(pci, pch_uart_pci_id); + module_param(default_baud, uint, S_IRUGO); MODULE_PARM_DESC(default_baud, "Default BAUD for initial driver state and console (default 9600)"); diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index f87f1a0c8c6e..e9d420ff3931 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -57,6 +57,8 @@ #include <linux/bitops.h> #include <linux/sysrq.h> #include <linux/mutex.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <asm/sections.h> #include <asm/io.h> #include <asm/irq.h> @@ -1072,7 +1074,7 @@ static void pmz_convert_to_zs(struct uart_pmac_port *uap, unsigned int cflag, uap->curregs[5] |= Tx8; uap->parity_mask = 0xff; break; - }; + } uap->curregs[4] &= ~(SB_MASK); if (cflag & CSTOPB) uap->curregs[4] |= SB2; @@ -2050,6 +2052,9 @@ static int __init pmz_console_init(void) /* Probe ports */ pmz_probe(); + if (pmz_ports_count == 0) + return -ENODEV; + /* TODO: Autoprobe console based on OF */ /* pmz_console.index = i; */ register_console(&pmz_console); diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c index ba25722a7131..753d4525b367 100644 --- a/drivers/tty/serial/sa1100.c +++ b/drivers/tty/serial/sa1100.c @@ -647,7 +647,10 @@ void sa1100_register_uart_fns(struct sa1100_port_fns *fns) sa1100_pops.set_mctrl = fns->set_mctrl; sa1100_pops.pm = fns->pm; - sa1100_pops.set_wake = fns->set_wake; + /* + * FIXME: fns->set_wake is unused - this should be called from + * the suspend() callback if device_may_wakeup(dev)) is set. + */ } void __init sa1100_register_uart(int idx, int port) diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index f3dfa19a1cb8..c1af04d46682 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -407,7 +407,14 @@ static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port) static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl) { - /* todo - possibly remove AFC and do manual CTS */ + unsigned int umcon = rd_regl(port, S3C2410_UMCON); + + if (mctrl & TIOCM_RTS) + umcon |= S3C2410_UMCOM_RTS_LOW; + else + umcon &= ~S3C2410_UMCOM_RTS_LOW; + + wr_regl(port, S3C2410_UMCON, umcon); } static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state) @@ -774,8 +781,6 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, if (termios->c_cflag & CSTOPB) ulcon |= S3C2410_LCON_STOPB; - umcon = (termios->c_cflag & CRTSCTS) ? S3C2410_UMCOM_AFC : 0; - if (termios->c_cflag & PARENB) { if (termios->c_cflag & PARODD) ulcon |= S3C2410_LCON_PODD; @@ -792,6 +797,15 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, wr_regl(port, S3C2410_ULCON, ulcon); wr_regl(port, S3C2410_UBRDIV, quot); + + umcon = rd_regl(port, S3C2410_UMCON); + if (termios->c_cflag & CRTSCTS) { + umcon |= S3C2410_UMCOM_AFC; + /* Disable RTS when RX FIFO contains 63 bytes */ + umcon &= ~S3C2412_UMCON_AFC_8; + } else { + umcon &= ~S3C2410_UMCOM_AFC; + } wr_regl(port, S3C2410_UMCON, umcon); if (ourport->info->has_divslot) @@ -1254,7 +1268,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) ourport->baudclk = ERR_PTR(-EINVAL); ourport->info = ourport->drv_data->info; ourport->cfg = (dev_get_platdata(&pdev->dev)) ? - (struct s3c2410_uartcfg *)dev_get_platdata(&pdev->dev) : + dev_get_platdata(&pdev->dev) : ourport->drv_data->def_cfg; ourport->port.fifosize = (ourport->info->fifosize) ? diff --git a/drivers/tty/serial/samsung.h b/drivers/tty/serial/samsung.h index aaa617a6c499..8827e5424cef 100644 --- a/drivers/tty/serial/samsung.h +++ b/drivers/tty/serial/samsung.h @@ -63,7 +63,7 @@ struct s3c24xx_uart_port { /* conversion functions */ -#define s3c24xx_dev_to_port(__dev) (struct uart_port *)dev_get_drvdata(__dev) +#define s3c24xx_dev_to_port(__dev) dev_get_drvdata(__dev) /* register access controls */ diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index 49e9bbfe6cab..a447f71538ef 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -986,6 +986,7 @@ static int sccnxp_probe(struct platform_device *pdev) return 0; } + uart_unregister_driver(&s->uart); err_out: if (!IS_ERR(s->regulator)) return regulator_disable(s->regulator); diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index d0d972f7e43e..dfe79ccc4fb3 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -732,7 +732,7 @@ static irqreturn_t tegra_uart_isr(int irq, void *data) static void tegra_uart_stop_rx(struct uart_port *u) { struct tegra_uart_port *tup = to_tegra_uport(u); - struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port); + struct tty_struct *tty; struct tty_port *port = &u->state->port; struct dma_tx_state state; unsigned long ier; @@ -744,6 +744,8 @@ static void tegra_uart_stop_rx(struct uart_port *u) if (!tup->rx_in_progress) return; + tty = tty_port_tty_get(&tup->uport.state->port); + tegra_uart_wait_sym_time(tup, 1); /* wait a character interval */ ier = tup->ier_shadow; @@ -1016,7 +1018,7 @@ static int tegra_uart_startup(struct uart_port *u) goto fail_hw_init; } - ret = request_irq(u->irq, tegra_uart_isr, IRQF_DISABLED, + ret = request_irq(u->irq, tegra_uart_isr, 0, dev_name(u->dev), tup); if (ret < 0) { dev_err(u->dev, "Failed to register ISR for IRQ %d\n", u->irq); diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c index 440a962412da..90a080b1f9ee 100644 --- a/drivers/tty/serial/serial_txx9.c +++ b/drivers/tty/serial/serial_txx9.c @@ -1220,8 +1220,6 @@ static void pciserial_txx9_remove_one(struct pci_dev *dev) { struct uart_txx9_port *up = pci_get_drvdata(dev); - pci_set_drvdata(dev, NULL); - if (up) { serial_txx9_unregister_port(up->port.line); pci_disable_device(dev); diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 537750261aaa..7d8103cd3e2e 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1433,7 +1433,7 @@ static void work_fn_rx(struct work_struct *work) desc = s->desc_rx[new]; if (dma_async_is_tx_complete(s->chan_rx, s->active_rx, NULL, NULL) != - DMA_SUCCESS) { + DMA_COMPLETE) { /* Handle incomplete DMA receive */ struct dma_chan *chan = s->chan_rx; struct shdma_desc *sh_desc = container_of(desc, diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c index 61c1ad03db5b..f186a8fb8887 100644 --- a/drivers/tty/serial/sirfsoc_uart.c +++ b/drivers/tty/serial/sirfsoc_uart.c @@ -529,7 +529,7 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param) while (sirfport->rx_completed != sirfport->rx_issued) { sirfsoc_uart_insert_rx_buf_to_tty(sirfport, SIRFSOC_RX_DMA_BUF_SIZE); - sirfsoc_rx_submit_one_dma_desc(port, sirfport->rx_completed++); + sirfport->rx_completed++; sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT; } count = CIRC_CNT(sirfport->rx_dma_items[sirfport->rx_issued].xmit.head, @@ -706,12 +706,19 @@ static void sirfsoc_uart_rx_dma_complete_tl(unsigned long param) { struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param; struct uart_port *port = &sirfport->port; + struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; + struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; unsigned long flags; spin_lock_irqsave(&sirfport->rx_lock, flags); while (sirfport->rx_completed != sirfport->rx_issued) { sirfsoc_uart_insert_rx_buf_to_tty(sirfport, SIRFSOC_RX_DMA_BUF_SIZE); - sirfsoc_rx_submit_one_dma_desc(port, sirfport->rx_completed++); + if (rd_regl(port, ureg->sirfsoc_int_en_reg) & + uint_en->sirfsoc_rx_timeout_en) + sirfsoc_rx_submit_one_dma_desc(port, + sirfport->rx_completed++); + else + sirfport->rx_completed++; sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT; } spin_unlock_irqrestore(&sirfport->rx_lock, flags); diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h index fb8d0a002607..b7d679c0881b 100644 --- a/drivers/tty/serial/sirfsoc_uart.h +++ b/drivers/tty/serial/sirfsoc_uart.h @@ -368,15 +368,6 @@ struct sirfsoc_uart_register sirfsoc_uart = { #define SIRFSOC_UART_NR 6 #define SIRFSOC_PORT_TYPE 0xa5 -/* Baud Rate Calculation */ -#define SIRF_MIN_SAMPLE_DIV 0xf -#define SIRF_MAX_SAMPLE_DIV 0x3f -#define SIRF_IOCLK_DIV_MAX 0xffff -#define SIRF_SAMPLE_DIV_SHIFT 16 -#define SIRF_IOCLK_DIV_MASK 0xffff -#define SIRF_SAMPLE_DIV_MASK 0x3f0000 -#define SIRF_BAUD_RATE_SUPPORT_NR 18 - /* Uart Common Use Macro*/ #define SIRFSOC_RX_DMA_BUF_SIZE 256 #define BYTES_TO_ALIGN(dma_addr) ((unsigned long)(dma_addr) & 0x3) @@ -453,9 +444,6 @@ struct sirfsoc_uart_port { int rx_issued; }; -/* Hardware Flow Control */ -#define SIRFUART_AFC_CTRL_RX_THD 0x70 - /* Register Access Control */ #define portaddr(port, reg) ((port)->membase + (reg)) #define rd_regb(port, reg) (__raw_readb(portaddr(port, reg))) diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c index 5d6136b2a04a..380fb5355cb2 100644 --- a/drivers/tty/serial/sunsab.c +++ b/drivers/tty/serial/sunsab.c @@ -894,7 +894,7 @@ static int sunsab_console_setup(struct console *con, char *options) case B115200: baud = 115200; break; case B230400: baud = 230400; break; case B460800: baud = 460800; break; - }; + } /* * Temporary fix. diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index 699cc1b5f6aa..db79b76f5c8e 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -522,7 +522,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, int is_break) serio_interrupt(&up->serio, ch, 0); #endif break; - }; + } } } while (serial_in(up, UART_LSR) & UART_LSR_DR); } diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c index 135a15203532..45a8c6aa5837 100644 --- a/drivers/tty/serial/sunzilog.c +++ b/drivers/tty/serial/sunzilog.c @@ -319,7 +319,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up, serio_interrupt(&up->serio, ch, 0); #endif break; - }; + } } } @@ -897,7 +897,7 @@ sunzilog_convert_to_zs(struct uart_sunzilog_port *up, unsigned int cflag, up->curregs[R5] |= Tx8; up->parity_mask = 0xff; break; - }; + } up->curregs[R4] &= ~0x0c; if (cflag & CSTOPB) up->curregs[R4] |= SB2; @@ -1239,7 +1239,7 @@ static int __init sunzilog_console_setup(struct console *con, char *options) default: case B9600: baud = 9600; break; case B19200: baud = 19200; break; case B38400: baud = 38400; break; - }; + } brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); diff --git a/drivers/tty/serial/tilegx.c b/drivers/tty/serial/tilegx.c new file mode 100644 index 000000000000..f92d7e6bd876 --- /dev/null +++ b/drivers/tty/serial/tilegx.c @@ -0,0 +1,708 @@ +/* + * Copyright 2013 Tilera Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + * + * TILEGx UART driver. + */ + +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/module.h> +#include <linux/serial_core.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> + +#include <gxio/common.h> +#include <gxio/iorpc_globals.h> +#include <gxio/iorpc_uart.h> +#include <gxio/kiorpc.h> + +#include <hv/drv_uart_intf.h> + +/* + * Use device name ttyS, major 4, minor 64-65. + * This is the usual serial port name, 8250 conventional range. + */ +#define TILEGX_UART_MAJOR TTY_MAJOR +#define TILEGX_UART_MINOR 64 +#define TILEGX_UART_NAME "ttyS" +#define DRIVER_NAME_STRING "TILEGx_Serial" +#define TILEGX_UART_REF_CLK 125000000; /* REF_CLK is always 125 MHz. */ + +struct tile_uart_port { + /* UART port. */ + struct uart_port uart; + + /* GXIO device context. */ + gxio_uart_context_t context; + + /* UART access mutex. */ + struct mutex mutex; + + /* CPU receiving interrupts. */ + int irq_cpu; +}; + +static struct tile_uart_port tile_uart_ports[TILEGX_UART_NR]; +static struct uart_driver tilegx_uart_driver; + + +/* + * Read UART rx fifo, and insert the chars into tty buffer. + */ +static void receive_chars(struct tile_uart_port *tile_uart, + struct tty_struct *tty) +{ + int i; + char c; + UART_FIFO_COUNT_t count; + gxio_uart_context_t *context = &tile_uart->context; + struct tty_port *port = tty->port; + + count.word = gxio_uart_read(context, UART_FIFO_COUNT); + for (i = 0; i < count.rfifo_count; i++) { + c = (char)gxio_uart_read(context, UART_RECEIVE_DATA); + tty_insert_flip_char(port, c, TTY_NORMAL); + } +} + + +/* + * Drain the Rx FIFO, called by interrupt handler. + */ +static void handle_receive(struct tile_uart_port *tile_uart) +{ + struct tty_port *port = &tile_uart->uart.state->port; + struct tty_struct *tty = tty_port_tty_get(port); + gxio_uart_context_t *context = &tile_uart->context; + + if (!tty) + return; + + /* First read UART rx fifo. */ + receive_chars(tile_uart, tty); + + /* Reset RFIFO_WE interrupt. */ + gxio_uart_write(context, UART_INTERRUPT_STATUS, + UART_INTERRUPT_MASK__RFIFO_WE_MASK); + + /* Final read, if any chars comes between the first read and + * the interrupt reset. + */ + receive_chars(tile_uart, tty); + + spin_unlock(&tile_uart->uart.lock); + tty_flip_buffer_push(port); + spin_lock(&tile_uart->uart.lock); + tty_kref_put(tty); +} + + +/* + * Push one char to UART Write FIFO. + * Return 0 on success, -1 if write filo is full. + */ +static int tilegx_putchar(gxio_uart_context_t *context, char c) +{ + UART_FLAG_t flag; + flag.word = gxio_uart_read(context, UART_FLAG); + if (flag.wfifo_full) + return -1; + + gxio_uart_write(context, UART_TRANSMIT_DATA, (unsigned long)c); + return 0; +} + + +/* + * Send chars to UART Write FIFO; called by interrupt handler. + */ +static void handle_transmit(struct tile_uart_port *tile_uart) +{ + unsigned char ch; + struct uart_port *port; + struct circ_buf *xmit; + gxio_uart_context_t *context = &tile_uart->context; + + /* First reset WFIFO_RE interrupt. */ + gxio_uart_write(context, UART_INTERRUPT_STATUS, + UART_INTERRUPT_MASK__WFIFO_RE_MASK); + + port = &tile_uart->uart; + xmit = &port->state->xmit; + if (port->x_char) { + if (tilegx_putchar(context, port->x_char)) + return; + port->x_char = 0; + port->icount.tx++; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) + return; + + while (!uart_circ_empty(xmit)) { + ch = xmit->buf[xmit->tail]; + if (tilegx_putchar(context, ch)) + break; + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + } + + /* Reset WFIFO_RE interrupt. */ + gxio_uart_write(context, UART_INTERRUPT_STATUS, + UART_INTERRUPT_MASK__WFIFO_RE_MASK); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); +} + + +/* + * UART Interrupt handler. + */ +static irqreturn_t tilegx_interrupt(int irq, void *dev_id) +{ + unsigned long flags; + UART_INTERRUPT_STATUS_t intr_stat; + struct tile_uart_port *tile_uart; + gxio_uart_context_t *context; + struct uart_port *port = dev_id; + irqreturn_t ret = IRQ_NONE; + + spin_lock_irqsave(&port->lock, flags); + + tile_uart = container_of(port, struct tile_uart_port, uart); + context = &tile_uart->context; + intr_stat.word = gxio_uart_read(context, UART_INTERRUPT_STATUS); + + if (intr_stat.rfifo_we) { + handle_receive(tile_uart); + ret = IRQ_HANDLED; + } + if (intr_stat.wfifo_re) { + handle_transmit(tile_uart); + ret = IRQ_HANDLED; + } + + spin_unlock_irqrestore(&port->lock, flags); + return ret; +} + + +/* + * Return TIOCSER_TEMT when transmitter FIFO is empty. + */ +static u_int tilegx_tx_empty(struct uart_port *port) +{ + int ret; + UART_FLAG_t flag; + struct tile_uart_port *tile_uart; + gxio_uart_context_t *context; + + tile_uart = container_of(port, struct tile_uart_port, uart); + if (!mutex_trylock(&tile_uart->mutex)) + return 0; + context = &tile_uart->context; + + flag.word = gxio_uart_read(context, UART_FLAG); + ret = (flag.wfifo_empty) ? TIOCSER_TEMT : 0; + mutex_unlock(&tile_uart->mutex); + + return ret; +} + + +/* + * Set state of the modem control output lines. + */ +static void tilegx_set_mctrl(struct uart_port *port, u_int mctrl) +{ + /* N/A */ +} + + +/* + * Get state of the modem control input lines. + */ +static u_int tilegx_get_mctrl(struct uart_port *port) +{ + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; +} + + +/* + * Stop transmitting. + */ +static void tilegx_stop_tx(struct uart_port *port) +{ + /* N/A */ +} + + +/* + * Start transmitting. + */ +static void tilegx_start_tx(struct uart_port *port) +{ + unsigned char ch; + struct circ_buf *xmit; + struct tile_uart_port *tile_uart; + gxio_uart_context_t *context; + + tile_uart = container_of(port, struct tile_uart_port, uart); + if (!mutex_trylock(&tile_uart->mutex)) + return; + context = &tile_uart->context; + xmit = &port->state->xmit; + if (port->x_char) { + if (tilegx_putchar(context, port->x_char)) + return; + port->x_char = 0; + port->icount.tx++; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + mutex_unlock(&tile_uart->mutex); + return; + } + + while (!uart_circ_empty(xmit)) { + ch = xmit->buf[xmit->tail]; + if (tilegx_putchar(context, ch)) + break; + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + mutex_unlock(&tile_uart->mutex); +} + + +/* + * Stop receiving - port is in process of being closed. + */ +static void tilegx_stop_rx(struct uart_port *port) +{ + int err; + struct tile_uart_port *tile_uart; + gxio_uart_context_t *context; + int cpu; + + tile_uart = container_of(port, struct tile_uart_port, uart); + if (!mutex_trylock(&tile_uart->mutex)) + return; + + context = &tile_uart->context; + cpu = tile_uart->irq_cpu; + err = gxio_uart_cfg_interrupt(context, cpu_x(cpu), cpu_y(cpu), + KERNEL_PL, -1); + mutex_unlock(&tile_uart->mutex); +} + + +/* + * Enable modem status interrupts. + */ +static void tilegx_enable_ms(struct uart_port *port) +{ + /* N/A */ +} + +/* + * Control the transmission of a break signal. + */ +static void tilegx_break_ctl(struct uart_port *port, int break_state) +{ + /* N/A */ +} + + +/* + * Perform initialization and enable port for reception. + */ +static int tilegx_startup(struct uart_port *port) +{ + struct tile_uart_port *tile_uart; + gxio_uart_context_t *context; + int ret = 0; + int cpu = raw_smp_processor_id(); /* pick an arbitrary cpu */ + + tile_uart = container_of(port, struct tile_uart_port, uart); + if (mutex_lock_interruptible(&tile_uart->mutex)) + return -EBUSY; + context = &tile_uart->context; + + /* Now open the hypervisor device if we haven't already. */ + if (context->fd < 0) { + UART_INTERRUPT_MASK_t intr_mask; + + /* Initialize UART device. */ + ret = gxio_uart_init(context, port->line); + if (ret) { + ret = -ENXIO; + goto err; + } + + /* Create our IRQs. */ + port->irq = create_irq(); + if (port->irq < 0) + goto err_uart_dest; + tile_irq_activate(port->irq, TILE_IRQ_PERCPU); + + /* Register our IRQs. */ + ret = request_irq(port->irq, tilegx_interrupt, 0, + tilegx_uart_driver.driver_name, port); + if (ret) + goto err_dest_irq; + + /* Request that the hardware start sending us interrupts. */ + tile_uart->irq_cpu = cpu; + ret = gxio_uart_cfg_interrupt(context, cpu_x(cpu), cpu_y(cpu), + KERNEL_PL, port->irq); + if (ret) + goto err_free_irq; + + /* Enable UART Tx/Rx Interrupt. */ + intr_mask.word = gxio_uart_read(context, UART_INTERRUPT_MASK); + intr_mask.wfifo_re = 0; + intr_mask.rfifo_we = 0; + gxio_uart_write(context, UART_INTERRUPT_MASK, intr_mask.word); + + /* Reset the Tx/Rx interrupt in case it's set. */ + gxio_uart_write(context, UART_INTERRUPT_STATUS, + UART_INTERRUPT_MASK__WFIFO_RE_MASK | + UART_INTERRUPT_MASK__RFIFO_WE_MASK); + } + + mutex_unlock(&tile_uart->mutex); + return ret; + +err_free_irq: + free_irq(port->irq, port); +err_dest_irq: + destroy_irq(port->irq); +err_uart_dest: + gxio_uart_destroy(context); + ret = -ENXIO; +err: + mutex_unlock(&tile_uart->mutex); + return ret; +} + + +/* + * Release kernel resources if it is the last close, disable the port, + * free IRQ and close the port. + */ +static void tilegx_shutdown(struct uart_port *port) +{ + int err; + UART_INTERRUPT_MASK_t intr_mask; + struct tile_uart_port *tile_uart; + gxio_uart_context_t *context; + int cpu; + + tile_uart = container_of(port, struct tile_uart_port, uart); + if (mutex_lock_interruptible(&tile_uart->mutex)) + return; + context = &tile_uart->context; + + /* Disable UART Tx/Rx Interrupt. */ + intr_mask.word = gxio_uart_read(context, UART_INTERRUPT_MASK); + intr_mask.wfifo_re = 1; + intr_mask.rfifo_we = 1; + gxio_uart_write(context, UART_INTERRUPT_MASK, intr_mask.word); + + /* Request that the hardware stop sending us interrupts. */ + cpu = tile_uart->irq_cpu; + err = gxio_uart_cfg_interrupt(context, cpu_x(cpu), cpu_y(cpu), + KERNEL_PL, -1); + + if (port->irq > 0) { + free_irq(port->irq, port); + destroy_irq(port->irq); + port->irq = 0; + } + + gxio_uart_destroy(context); + + mutex_unlock(&tile_uart->mutex); +} + + +/* + * Flush the buffer. + */ +static void tilegx_flush_buffer(struct uart_port *port) +{ + /* N/A */ +} + + +/* + * Change the port parameters. + */ +static void tilegx_set_termios(struct uart_port *port, + struct ktermios *termios, struct ktermios *old) +{ + int err; + UART_DIVISOR_t divisor; + UART_TYPE_t type; + unsigned int baud; + struct tile_uart_port *tile_uart; + gxio_uart_context_t *context; + + tile_uart = container_of(port, struct tile_uart_port, uart); + if (!mutex_trylock(&tile_uart->mutex)) + return; + context = &tile_uart->context; + + /* Open the hypervisor device if we haven't already. */ + if (context->fd < 0) { + err = gxio_uart_init(context, port->line); + if (err) { + mutex_unlock(&tile_uart->mutex); + return; + } + } + + divisor.word = gxio_uart_read(context, UART_DIVISOR); + type.word = gxio_uart_read(context, UART_TYPE); + + /* Divisor. */ + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); + divisor.divisor = uart_get_divisor(port, baud); + + /* Byte size. */ + if ((termios->c_cflag & CSIZE) == CS7) + type.dbits = UART_TYPE__DBITS_VAL_SEVEN_DBITS; + else + type.dbits = UART_TYPE__DBITS_VAL_EIGHT_DBITS; + + /* Parity. */ + if (termios->c_cflag & PARENB) { + /* Mark or Space parity. */ + if (termios->c_cflag & CMSPAR) + if (termios->c_cflag & PARODD) + type.ptype = UART_TYPE__PTYPE_VAL_MARK; + else + type.ptype = UART_TYPE__PTYPE_VAL_SPACE; + else if (termios->c_cflag & PARODD) + type.ptype = UART_TYPE__PTYPE_VAL_ODD; + else + type.ptype = UART_TYPE__PTYPE_VAL_EVEN; + } else + type.ptype = UART_TYPE__PTYPE_VAL_NONE; + + /* Stop bits. */ + if (termios->c_cflag & CSTOPB) + type.sbits = UART_TYPE__SBITS_VAL_TWO_SBITS; + else + type.sbits = UART_TYPE__SBITS_VAL_ONE_SBITS; + + /* Set the uart paramters. */ + gxio_uart_write(context, UART_DIVISOR, divisor.word); + gxio_uart_write(context, UART_TYPE, type.word); + + mutex_unlock(&tile_uart->mutex); +} + + +/* + * Return string describing the specified port. + */ +static const char *tilegx_type(struct uart_port *port) +{ + return port->type == PORT_TILEGX ? DRIVER_NAME_STRING : NULL; +} + + +/* + * Release the resources being used by 'port'. + */ +static void tilegx_release_port(struct uart_port *port) +{ + /* Nothing to release. */ +} + + +/* + * Request the resources being used by 'port'. + */ +static int tilegx_request_port(struct uart_port *port) +{ + /* Always present. */ + return 0; +} + + +/* + * Configure/autoconfigure the port. + */ +static void tilegx_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) + port->type = PORT_TILEGX; +} + + +/* + * Verify the new serial_struct (for TIOCSSERIAL). + */ +static int tilegx_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_TILEGX)) + return -EINVAL; + + return 0; +} + +#ifdef CONFIG_CONSOLE_POLL + +/* + * Console polling routines for writing and reading from the uart while + * in an interrupt or debug context. + */ + +static int tilegx_poll_get_char(struct uart_port *port) +{ + UART_FIFO_COUNT_t count; + gxio_uart_context_t *context; + struct tile_uart_port *tile_uart; + + tile_uart = container_of(port, struct tile_uart_port, uart); + context = &tile_uart->context; + count.word = gxio_uart_read(context, UART_FIFO_COUNT); + if (count.rfifo_count == 0) + return NO_POLL_CHAR; + return (char)gxio_uart_read(context, UART_RECEIVE_DATA); +} + +static void tilegx_poll_put_char(struct uart_port *port, unsigned char c) +{ + gxio_uart_context_t *context; + struct tile_uart_port *tile_uart; + + tile_uart = container_of(port, struct tile_uart_port, uart); + context = &tile_uart->context; + gxio_uart_write(context, UART_TRANSMIT_DATA, (unsigned long)c); +} + +#endif /* CONFIG_CONSOLE_POLL */ + + +static const struct uart_ops tilegx_ops = { + .tx_empty = tilegx_tx_empty, + .set_mctrl = tilegx_set_mctrl, + .get_mctrl = tilegx_get_mctrl, + .stop_tx = tilegx_stop_tx, + .start_tx = tilegx_start_tx, + .stop_rx = tilegx_stop_rx, + .enable_ms = tilegx_enable_ms, + .break_ctl = tilegx_break_ctl, + .startup = tilegx_startup, + .shutdown = tilegx_shutdown, + .flush_buffer = tilegx_flush_buffer, + .set_termios = tilegx_set_termios, + .type = tilegx_type, + .release_port = tilegx_release_port, + .request_port = tilegx_request_port, + .config_port = tilegx_config_port, + .verify_port = tilegx_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = tilegx_poll_get_char, + .poll_put_char = tilegx_poll_put_char, +#endif +}; + + +static void tilegx_init_ports(void) +{ + int i; + struct uart_port *port; + + for (i = 0; i < TILEGX_UART_NR; i++) { + port = &tile_uart_ports[i].uart; + port->ops = &tilegx_ops; + port->line = i; + port->type = PORT_TILEGX; + port->uartclk = TILEGX_UART_REF_CLK; + port->flags = UPF_BOOT_AUTOCONF; + + tile_uart_ports[i].context.fd = -1; + mutex_init(&tile_uart_ports[i].mutex); + } +} + + +static struct uart_driver tilegx_uart_driver = { + .owner = THIS_MODULE, + .driver_name = DRIVER_NAME_STRING, + .dev_name = TILEGX_UART_NAME, + .major = TILEGX_UART_MAJOR, + .minor = TILEGX_UART_MINOR, + .nr = TILEGX_UART_NR, +}; + + +static int __init tilegx_init(void) +{ + int i; + int ret; + struct tty_driver *tty_drv; + + ret = uart_register_driver(&tilegx_uart_driver); + if (ret) + return ret; + tty_drv = tilegx_uart_driver.tty_driver; + tty_drv->init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; + tty_drv->init_termios.c_ispeed = 115200; + tty_drv->init_termios.c_ospeed = 115200; + + tilegx_init_ports(); + + for (i = 0; i < TILEGX_UART_NR; i++) { + struct uart_port *port = &tile_uart_ports[i].uart; + ret = uart_add_one_port(&tilegx_uart_driver, port); + } + + return 0; +} + + +static void __exit tilegx_exit(void) +{ + int i; + struct uart_port *port; + + for (i = 0; i < TILEGX_UART_NR; i++) { + port = &tile_uart_ports[i].uart; + uart_remove_one_port(&tilegx_uart_driver, port); + } + + uart_unregister_driver(&tilegx_uart_driver); +} + + +module_init(tilegx_init); +module_exit(tilegx_exit); + +MODULE_AUTHOR("Tilera Corporation"); +MODULE_DESCRIPTION("TILEGx serial port driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index 88317482b81f..d569ca58bab6 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -25,6 +25,8 @@ #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/io.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/dma-mapping.h> @@ -269,7 +271,7 @@ static unsigned int qe_uart_tx_empty(struct uart_port *port) return 1; bdp++; - }; + } } /* diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c index 93b697a0de65..15ad6fcda88b 100644 --- a/drivers/tty/serial/vt8500_serial.c +++ b/drivers/tty/serial/vt8500_serial.c @@ -561,12 +561,13 @@ static int vt8500_serial_probe(struct platform_device *pdev) if (!mmres || !irqres) return -ENODEV; - if (np) + if (np) { port = of_alias_get_id(np, "serial"); if (port >= VT8500_MAX_PORTS) port = -1; - else + } else { port = -1; + } if (port < 0) { /* calculate the port id */ diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 7e4150aa69c6..e46e9f3f19b9 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -1,7 +1,7 @@ /* * Xilinx PS UART driver * - * 2011 (c) Xilinx Inc. + * 2011 - 2013 (C) Xilinx Inc. * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General Public @@ -11,13 +11,17 @@ * */ +#if defined(CONFIG_SERIAL_XILINX_PS_UART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + #include <linux/platform_device.h> #include <linux/serial.h> +#include <linux/console.h> #include <linux/serial_core.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_flip.h> -#include <linux/console.h> #include <linux/clk.h> #include <linux/irq.h> #include <linux/io.h> @@ -29,12 +33,22 @@ #define XUARTPS_MAJOR 0 /* use dynamic node allocation */ #define XUARTPS_MINOR 0 /* works best with devtmpfs */ #define XUARTPS_NR_PORTS 2 -#define XUARTPS_FIFO_SIZE 16 /* FIFO size */ +#define XUARTPS_FIFO_SIZE 64 /* FIFO size */ #define XUARTPS_REGISTER_SPACE 0xFFF #define xuartps_readl(offset) ioread32(port->membase + offset) #define xuartps_writel(val, offset) iowrite32(val, port->membase + offset) +/* Rx Trigger level */ +static int rx_trigger_level = 56; +module_param(rx_trigger_level, uint, S_IRUGO); +MODULE_PARM_DESC(rx_trigger_level, "Rx trigger level, 1-63 bytes"); + +/* Rx Timeout */ +static int rx_timeout = 10; +module_param(rx_timeout, uint, S_IRUGO); +MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255"); + /********************************Register Map********************************/ /** UART * @@ -128,6 +142,9 @@ #define XUARTPS_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */ #define XUARTPS_IXR_MASK 0x00001FFF /* Valid bit mask */ +/* Goes in read_status_mask for break detection as the HW doesn't do it*/ +#define XUARTPS_IXR_BRK 0x80000000 + /** Channel Status Register * * The channel status register (CSR) is provided to enable the control logic @@ -139,15 +156,27 @@ #define XUARTPS_SR_TXFULL 0x00000010 /* TX FIFO full */ #define XUARTPS_SR_RXTRIG 0x00000001 /* Rx Trigger */ +/* baud dividers min/max values */ +#define XUARTPS_BDIV_MIN 4 +#define XUARTPS_BDIV_MAX 255 +#define XUARTPS_CD_MAX 65535 + /** * struct xuartps - device data - * @refclk Reference clock - * @aperclk APB clock + * @port Pointer to the UART port + * @refclk Reference clock + * @aperclk APB clock + * @baud Current baud rate + * @clk_rate_change_nb Notifier block for clock changes */ struct xuartps { + struct uart_port *port; struct clk *refclk; struct clk *aperclk; + unsigned int baud; + struct notifier_block clk_rate_change_nb; }; +#define to_xuartps(_nb) container_of(_nb, struct xuartps, clk_rate_change_nb); /** * xuartps_isr - Interrupt handler @@ -171,6 +200,23 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) */ isrstatus = xuartps_readl(XUARTPS_ISR_OFFSET); + /* + * There is no hardware break detection, so we interpret framing + * error with all-zeros data as a break sequence. Most of the time, + * there's another non-zero byte at the end of the sequence. + */ + + if (isrstatus & XUARTPS_IXR_FRAMING) { + while (!(xuartps_readl(XUARTPS_SR_OFFSET) & + XUARTPS_SR_RXEMPTY)) { + if (!xuartps_readl(XUARTPS_FIFO_OFFSET)) { + port->read_status_mask |= XUARTPS_IXR_BRK; + isrstatus &= ~XUARTPS_IXR_FRAMING; + } + } + xuartps_writel(XUARTPS_IXR_FRAMING, XUARTPS_ISR_OFFSET); + } + /* drop byte with parity error if IGNPAR specified */ if (isrstatus & port->ignore_status_mask & XUARTPS_IXR_PARITY) isrstatus &= ~(XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT); @@ -184,6 +230,30 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) while ((xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_RXEMPTY) != XUARTPS_SR_RXEMPTY) { data = xuartps_readl(XUARTPS_FIFO_OFFSET); + + /* Non-NULL byte after BREAK is garbage (99%) */ + if (data && (port->read_status_mask & + XUARTPS_IXR_BRK)) { + port->read_status_mask &= ~XUARTPS_IXR_BRK; + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } + + /* + * uart_handle_sysrq_char() doesn't work if + * spinlocked, for some reason + */ + if (port->sysrq) { + spin_unlock(&port->lock); + if (uart_handle_sysrq_char(port, + (unsigned char)data)) { + spin_lock(&port->lock); + continue; + } + spin_lock(&port->lock); + } + port->icount.rx++; if (isrstatus & XUARTPS_IXR_PARITY) { @@ -247,63 +317,196 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) } /** - * xuartps_set_baud_rate - Calculate and set the baud rate - * @port: Handle to the uart port structure - * @baud: Baud rate to set - * + * xuartps_calc_baud_divs - Calculate baud rate divisors + * @clk: UART module input clock + * @baud: Desired baud rate + * @rbdiv: BDIV value (return value) + * @rcd: CD value (return value) + * @div8: Value for clk_sel bit in mod (return value) * Returns baud rate, requested baud when possible, or actual baud when there - * was too much error - **/ -static unsigned int xuartps_set_baud_rate(struct uart_port *port, - unsigned int baud) + * was too much error, zero if no valid divisors are found. + * + * Formula to obtain baud rate is + * baud_tx/rx rate = clk/CD * (BDIV + 1) + * input_clk = (Uart User Defined Clock or Apb Clock) + * depends on UCLKEN in MR Reg + * clk = input_clk or input_clk/8; + * depends on CLKS in MR reg + * CD and BDIV depends on values in + * baud rate generate register + * baud rate clock divisor register + */ +static unsigned int xuartps_calc_baud_divs(unsigned int clk, unsigned int baud, + u32 *rbdiv, u32 *rcd, int *div8) { - unsigned int sel_clk; - unsigned int calc_baud = 0; - unsigned int brgr_val, brdiv_val; + u32 cd, bdiv; + unsigned int calc_baud; + unsigned int bestbaud = 0; unsigned int bauderror; + unsigned int besterror = ~0; - /* Formula to obtain baud rate is - * baud_tx/rx rate = sel_clk/CD * (BDIV + 1) - * input_clk = (Uart User Defined Clock or Apb Clock) - * depends on UCLKEN in MR Reg - * sel_clk = input_clk or input_clk/8; - * depends on CLKS in MR reg - * CD and BDIV depends on values in - * baud rate generate register - * baud rate clock divisor register - */ - sel_clk = port->uartclk; - if (xuartps_readl(XUARTPS_MR_OFFSET) & XUARTPS_MR_CLKSEL) - sel_clk = sel_clk / 8; - - /* Find the best values for baud generation */ - for (brdiv_val = 4; brdiv_val < 255; brdiv_val++) { + if (baud < clk / ((XUARTPS_BDIV_MAX + 1) * XUARTPS_CD_MAX)) { + *div8 = 1; + clk /= 8; + } else { + *div8 = 0; + } - brgr_val = sel_clk / (baud * (brdiv_val + 1)); - if (brgr_val < 2 || brgr_val > 65535) + for (bdiv = XUARTPS_BDIV_MIN; bdiv <= XUARTPS_BDIV_MAX; bdiv++) { + cd = DIV_ROUND_CLOSEST(clk, baud * (bdiv + 1)); + if (cd < 1 || cd > XUARTPS_CD_MAX) continue; - calc_baud = sel_clk / (brgr_val * (brdiv_val + 1)); + calc_baud = clk / (cd * (bdiv + 1)); if (baud > calc_baud) bauderror = baud - calc_baud; else bauderror = calc_baud - baud; - /* use the values when percent error is acceptable */ - if (((bauderror * 100) / baud) < 3) { - calc_baud = baud; - break; + if (besterror > bauderror) { + *rbdiv = bdiv; + *rcd = cd; + bestbaud = calc_baud; + besterror = bauderror; } } + /* use the values when percent error is acceptable */ + if (((besterror * 100) / baud) < 3) + bestbaud = baud; + + return bestbaud; +} - /* Set the values for the new baud rate */ - xuartps_writel(brgr_val, XUARTPS_BAUDGEN_OFFSET); - xuartps_writel(brdiv_val, XUARTPS_BAUDDIV_OFFSET); +/** + * xuartps_set_baud_rate - Calculate and set the baud rate + * @port: Handle to the uart port structure + * @baud: Baud rate to set + * Returns baud rate, requested baud when possible, or actual baud when there + * was too much error, zero if no valid divisors are found. + */ +static unsigned int xuartps_set_baud_rate(struct uart_port *port, + unsigned int baud) +{ + unsigned int calc_baud; + u32 cd = 0, bdiv = 0; + u32 mreg; + int div8; + struct xuartps *xuartps = port->private_data; + + calc_baud = xuartps_calc_baud_divs(port->uartclk, baud, &bdiv, &cd, + &div8); + + /* Write new divisors to hardware */ + mreg = xuartps_readl(XUARTPS_MR_OFFSET); + if (div8) + mreg |= XUARTPS_MR_CLKSEL; + else + mreg &= ~XUARTPS_MR_CLKSEL; + xuartps_writel(mreg, XUARTPS_MR_OFFSET); + xuartps_writel(cd, XUARTPS_BAUDGEN_OFFSET); + xuartps_writel(bdiv, XUARTPS_BAUDDIV_OFFSET); + xuartps->baud = baud; return calc_baud; } +#ifdef CONFIG_COMMON_CLK +/** + * xuartps_clk_notitifer_cb - Clock notifier callback + * @nb: Notifier block + * @event: Notify event + * @data: Notifier data + * Returns NOTIFY_OK on success, NOTIFY_BAD on error. + */ +static int xuartps_clk_notifier_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + u32 ctrl_reg; + struct uart_port *port; + int locked = 0; + struct clk_notifier_data *ndata = data; + unsigned long flags = 0; + struct xuartps *xuartps = to_xuartps(nb); + + port = xuartps->port; + if (port->suspended) + return NOTIFY_OK; + + switch (event) { + case PRE_RATE_CHANGE: + { + u32 bdiv; + u32 cd; + int div8; + + /* + * Find out if current baud-rate can be achieved with new clock + * frequency. + */ + if (!xuartps_calc_baud_divs(ndata->new_rate, xuartps->baud, + &bdiv, &cd, &div8)) + return NOTIFY_BAD; + + spin_lock_irqsave(&xuartps->port->lock, flags); + + /* Disable the TX and RX to set baud rate */ + xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) | + (XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS), + XUARTPS_CR_OFFSET); + + spin_unlock_irqrestore(&xuartps->port->lock, flags); + + return NOTIFY_OK; + } + case POST_RATE_CHANGE: + /* + * Set clk dividers to generate correct baud with new clock + * frequency. + */ + + spin_lock_irqsave(&xuartps->port->lock, flags); + + locked = 1; + port->uartclk = ndata->new_rate; + + xuartps->baud = xuartps_set_baud_rate(xuartps->port, + xuartps->baud); + /* fall through */ + case ABORT_RATE_CHANGE: + if (!locked) + spin_lock_irqsave(&xuartps->port->lock, flags); + + /* Set TX/RX Reset */ + xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) | + (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST), + XUARTPS_CR_OFFSET); + + while (xuartps_readl(XUARTPS_CR_OFFSET) & + (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST)) + cpu_relax(); + + /* + * Clear the RX disable and TX disable bits and then set the TX + * enable bit and RX enable bit to enable the transmitter and + * receiver. + */ + xuartps_writel(rx_timeout, XUARTPS_RXTOUT_OFFSET); + ctrl_reg = xuartps_readl(XUARTPS_CR_OFFSET); + xuartps_writel( + (ctrl_reg & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS)) | + (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN), + XUARTPS_CR_OFFSET); + + spin_unlock_irqrestore(&xuartps->port->lock, flags); + + return NOTIFY_OK; + default: + return NOTIFY_DONE; + } +} +#endif + /*----------------------Uart Operations---------------------------*/ /** @@ -346,7 +549,7 @@ static void xuartps_start_tx(struct uart_port *port) port->state->xmit.tail = (port->state->xmit.tail + 1) & (UART_XMIT_SIZE - 1); } - + xuartps_writel(XUARTPS_IXR_TXEMPTY, XUARTPS_ISR_OFFSET); /* Enable the TX Empty interrupt */ xuartps_writel(XUARTPS_IXR_TXEMPTY, XUARTPS_IER_OFFSET); @@ -437,7 +640,7 @@ static void xuartps_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { unsigned int cval = 0; - unsigned int baud; + unsigned int baud, minbaud, maxbaud; unsigned long flags; unsigned int ctrl_reg, mode_reg; @@ -454,8 +657,14 @@ static void xuartps_set_termios(struct uart_port *port, (XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS), XUARTPS_CR_OFFSET); - /* Min baud rate = 6bps and Max Baud Rate is 10Mbps for 100Mhz clk */ - baud = uart_get_baud_rate(port, termios, old, 0, 10000000); + /* + * Min baud rate = 6bps and Max Baud Rate is 10Mbps for 100Mhz clk + * min and max baud should be calculated here based on port->uartclk. + * this way we get a valid baud and can safely call set_baud() + */ + minbaud = port->uartclk / ((XUARTPS_BDIV_MAX + 1) * XUARTPS_CD_MAX * 8); + maxbaud = port->uartclk / (XUARTPS_BDIV_MIN + 1); + baud = uart_get_baud_rate(port, termios, old, minbaud, maxbaud); baud = xuartps_set_baud_rate(port, baud); if (tty_termios_baud_rate(termios)) tty_termios_encode_baud_rate(termios, baud, baud); @@ -480,7 +689,7 @@ static void xuartps_set_termios(struct uart_port *port, | (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN), XUARTPS_CR_OFFSET); - xuartps_writel(10, XUARTPS_RXTOUT_OFFSET); + xuartps_writel(rx_timeout, XUARTPS_RXTOUT_OFFSET); port->read_status_mask = XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_RXTRIG | XUARTPS_IXR_OVERRUN | XUARTPS_IXR_TOUT; @@ -531,13 +740,17 @@ static void xuartps_set_termios(struct uart_port *port, cval |= XUARTPS_MR_PARITY_MARK; else cval |= XUARTPS_MR_PARITY_SPACE; - } else if (termios->c_cflag & PARODD) + } else { + if (termios->c_cflag & PARODD) cval |= XUARTPS_MR_PARITY_ODD; else cval |= XUARTPS_MR_PARITY_EVEN; - } else + } + } else { cval |= XUARTPS_MR_PARITY_NONE; - xuartps_writel(cval , XUARTPS_MR_OFFSET); + } + cval |= mode_reg & 1; + xuartps_writel(cval, XUARTPS_MR_OFFSET); spin_unlock_irqrestore(&port->lock, flags); } @@ -583,11 +796,17 @@ static int xuartps_startup(struct uart_port *port) | XUARTPS_MR_PARITY_NONE | XUARTPS_MR_CHARLEN_8_BIT, XUARTPS_MR_OFFSET); - /* Set the RX FIFO Trigger level to 14 assuming FIFO size as 16 */ - xuartps_writel(14, XUARTPS_RXWM_OFFSET); + /* + * Set the RX FIFO Trigger level to use most of the FIFO, but it + * can be tuned with a module parameter + */ + xuartps_writel(rx_trigger_level, XUARTPS_RXWM_OFFSET); - /* Receive Timeout register is enabled with value of 10 */ - xuartps_writel(10, XUARTPS_RXTOUT_OFFSET); + /* + * Receive Timeout register is enabled but it + * can be tuned with a module parameter + */ + xuartps_writel(rx_timeout, XUARTPS_RXTOUT_OFFSET); /* Clear out any pending interrupts before enabling them */ xuartps_writel(xuartps_readl(XUARTPS_ISR_OFFSET), XUARTPS_ISR_OFFSET); @@ -727,6 +946,54 @@ static void xuartps_enable_ms(struct uart_port *port) /* N/A */ } +#ifdef CONFIG_CONSOLE_POLL +static int xuartps_poll_get_char(struct uart_port *port) +{ + u32 imr; + int c; + + /* Disable all interrupts */ + imr = xuartps_readl(XUARTPS_IMR_OFFSET); + xuartps_writel(imr, XUARTPS_IDR_OFFSET); + + /* Check if FIFO is empty */ + if (xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_RXEMPTY) + c = NO_POLL_CHAR; + else /* Read a character */ + c = (unsigned char) xuartps_readl(XUARTPS_FIFO_OFFSET); + + /* Enable interrupts */ + xuartps_writel(imr, XUARTPS_IER_OFFSET); + + return c; +} + +static void xuartps_poll_put_char(struct uart_port *port, unsigned char c) +{ + u32 imr; + + /* Disable all interrupts */ + imr = xuartps_readl(XUARTPS_IMR_OFFSET); + xuartps_writel(imr, XUARTPS_IDR_OFFSET); + + /* Wait until FIFO is empty */ + while (!(xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_TXEMPTY)) + cpu_relax(); + + /* Write a character */ + xuartps_writel(c, XUARTPS_FIFO_OFFSET); + + /* Wait until FIFO is empty */ + while (!(xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_TXEMPTY)) + cpu_relax(); + + /* Enable interrupts */ + xuartps_writel(imr, XUARTPS_IER_OFFSET); + + return; +} +#endif + /** The UART operations structure */ static struct uart_ops xuartps_ops = { @@ -759,6 +1026,10 @@ static struct uart_ops xuartps_ops = { .config_port = xuartps_config_port, /* Configure when driver * adds a xuartps port */ +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = xuartps_poll_get_char, + .poll_put_char = xuartps_poll_put_char, +#endif }; static struct uart_port xuartps_port[2]; @@ -837,7 +1108,7 @@ static void xuartps_console_write(struct console *co, const char *s, { struct uart_port *port = &xuartps_port[co->index]; unsigned long flags; - unsigned int imr; + unsigned int imr, ctrl; int locked = 1; if (oops_in_progress) @@ -849,9 +1120,19 @@ static void xuartps_console_write(struct console *co, const char *s, imr = xuartps_readl(XUARTPS_IMR_OFFSET); xuartps_writel(imr, XUARTPS_IDR_OFFSET); + /* + * Make sure that the tx part is enabled. Set the TX enable bit and + * clear the TX disable bit to enable the transmitter. + */ + ctrl = xuartps_readl(XUARTPS_CR_OFFSET); + xuartps_writel((ctrl & ~XUARTPS_CR_TX_DIS) | XUARTPS_CR_TX_EN, + XUARTPS_CR_OFFSET); + uart_console_write(port, s, count, xuartps_console_putchar); xuartps_console_wait_tx(port); + xuartps_writel(ctrl, XUARTPS_CR_OFFSET); + /* restore interrupt state, it seems like there may be a h/w bug * in that the interrupt enable register should not need to be * written based on the data sheet @@ -933,6 +1214,119 @@ static struct uart_driver xuartps_uart_driver = { #endif }; +#ifdef CONFIG_PM_SLEEP +/** + * xuartps_suspend - suspend event + * @device: Pointer to the device structure + * + * Returns 0 + */ +static int xuartps_suspend(struct device *device) +{ + struct uart_port *port = dev_get_drvdata(device); + struct tty_struct *tty; + struct device *tty_dev; + int may_wake = 0; + + /* Get the tty which could be NULL so don't assume it's valid */ + tty = tty_port_tty_get(&port->state->port); + if (tty) { + tty_dev = tty->dev; + may_wake = device_may_wakeup(tty_dev); + tty_kref_put(tty); + } + + /* + * Call the API provided in serial_core.c file which handles + * the suspend. + */ + uart_suspend_port(&xuartps_uart_driver, port); + if (console_suspend_enabled && !may_wake) { + struct xuartps *xuartps = port->private_data; + + clk_disable(xuartps->refclk); + clk_disable(xuartps->aperclk); + } else { + unsigned long flags = 0; + + spin_lock_irqsave(&port->lock, flags); + /* Empty the receive FIFO 1st before making changes */ + while (!(xuartps_readl(XUARTPS_SR_OFFSET) & XUARTPS_SR_RXEMPTY)) + xuartps_readl(XUARTPS_FIFO_OFFSET); + /* set RX trigger level to 1 */ + xuartps_writel(1, XUARTPS_RXWM_OFFSET); + /* disable RX timeout interrups */ + xuartps_writel(XUARTPS_IXR_TOUT, XUARTPS_IDR_OFFSET); + spin_unlock_irqrestore(&port->lock, flags); + } + + return 0; +} + +/** + * xuartps_resume - Resume after a previous suspend + * @device: Pointer to the device structure + * + * Returns 0 + */ +static int xuartps_resume(struct device *device) +{ + struct uart_port *port = dev_get_drvdata(device); + unsigned long flags = 0; + u32 ctrl_reg; + struct tty_struct *tty; + struct device *tty_dev; + int may_wake = 0; + + /* Get the tty which could be NULL so don't assume it's valid */ + tty = tty_port_tty_get(&port->state->port); + if (tty) { + tty_dev = tty->dev; + may_wake = device_may_wakeup(tty_dev); + tty_kref_put(tty); + } + + if (console_suspend_enabled && !may_wake) { + struct xuartps *xuartps = port->private_data; + + clk_enable(xuartps->aperclk); + clk_enable(xuartps->refclk); + + spin_lock_irqsave(&port->lock, flags); + + /* Set TX/RX Reset */ + xuartps_writel(xuartps_readl(XUARTPS_CR_OFFSET) | + (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST), + XUARTPS_CR_OFFSET); + while (xuartps_readl(XUARTPS_CR_OFFSET) & + (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST)) + cpu_relax(); + + /* restore rx timeout value */ + xuartps_writel(rx_timeout, XUARTPS_RXTOUT_OFFSET); + /* Enable Tx/Rx */ + ctrl_reg = xuartps_readl(XUARTPS_CR_OFFSET); + xuartps_writel( + (ctrl_reg & ~(XUARTPS_CR_TX_DIS | XUARTPS_CR_RX_DIS)) | + (XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN), + XUARTPS_CR_OFFSET); + + spin_unlock_irqrestore(&port->lock, flags); + } else { + spin_lock_irqsave(&port->lock, flags); + /* restore original rx trigger level */ + xuartps_writel(rx_trigger_level, XUARTPS_RXWM_OFFSET); + /* enable RX timeout interrupt */ + xuartps_writel(XUARTPS_IXR_TOUT, XUARTPS_IER_OFFSET); + spin_unlock_irqrestore(&port->lock, flags); + } + + return uart_resume_port(&xuartps_uart_driver, port); +} +#endif /* ! CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(xuartps_dev_pm_ops, xuartps_suspend, xuartps_resume); + /* --------------------------------------------------------------------- * Platform bus binding */ @@ -949,27 +1343,26 @@ static int xuartps_probe(struct platform_device *pdev) struct resource *res, *res2; struct xuartps *xuartps_data; - xuartps_data = kzalloc(sizeof(*xuartps_data), GFP_KERNEL); + xuartps_data = devm_kzalloc(&pdev->dev, sizeof(*xuartps_data), + GFP_KERNEL); if (!xuartps_data) return -ENOMEM; - xuartps_data->aperclk = clk_get(&pdev->dev, "aper_clk"); + xuartps_data->aperclk = devm_clk_get(&pdev->dev, "aper_clk"); if (IS_ERR(xuartps_data->aperclk)) { dev_err(&pdev->dev, "aper_clk clock not found.\n"); - rc = PTR_ERR(xuartps_data->aperclk); - goto err_out_free; + return PTR_ERR(xuartps_data->aperclk); } - xuartps_data->refclk = clk_get(&pdev->dev, "ref_clk"); + xuartps_data->refclk = devm_clk_get(&pdev->dev, "ref_clk"); if (IS_ERR(xuartps_data->refclk)) { dev_err(&pdev->dev, "ref_clk clock not found.\n"); - rc = PTR_ERR(xuartps_data->refclk); - goto err_out_clk_put_aper; + return PTR_ERR(xuartps_data->refclk); } rc = clk_prepare_enable(xuartps_data->aperclk); if (rc) { dev_err(&pdev->dev, "Unable to enable APER clock.\n"); - goto err_out_clk_put; + return rc; } rc = clk_prepare_enable(xuartps_data->refclk); if (rc) { @@ -989,13 +1382,21 @@ static int xuartps_probe(struct platform_device *pdev) goto err_out_clk_disable; } +#ifdef CONFIG_COMMON_CLK + xuartps_data->clk_rate_change_nb.notifier_call = + xuartps_clk_notifier_cb; + if (clk_notifier_register(xuartps_data->refclk, + &xuartps_data->clk_rate_change_nb)) + dev_warn(&pdev->dev, "Unable to register clock notifier.\n"); +#endif + /* Initialize the port structure */ port = xuartps_get_port(); if (!port) { dev_err(&pdev->dev, "Cannot get uart_port structure\n"); rc = -ENODEV; - goto err_out_clk_disable; + goto err_out_notif_unreg; } else { /* Register the port. * This function also registers this device with the tty layer @@ -1006,26 +1407,26 @@ static int xuartps_probe(struct platform_device *pdev) port->dev = &pdev->dev; port->uartclk = clk_get_rate(xuartps_data->refclk); port->private_data = xuartps_data; + xuartps_data->port = port; platform_set_drvdata(pdev, port); rc = uart_add_one_port(&xuartps_uart_driver, port); if (rc) { dev_err(&pdev->dev, "uart_add_one_port() failed; err=%i\n", rc); - goto err_out_clk_disable; + goto err_out_notif_unreg; } return 0; } +err_out_notif_unreg: +#ifdef CONFIG_COMMON_CLK + clk_notifier_unregister(xuartps_data->refclk, + &xuartps_data->clk_rate_change_nb); +#endif err_out_clk_disable: clk_disable_unprepare(xuartps_data->refclk); err_out_clk_dis_aper: clk_disable_unprepare(xuartps_data->aperclk); -err_out_clk_put: - clk_put(xuartps_data->refclk); -err_out_clk_put_aper: - clk_put(xuartps_data->aperclk); -err_out_free: - kfree(xuartps_data); return rc; } @@ -1043,13 +1444,14 @@ static int xuartps_remove(struct platform_device *pdev) int rc; /* Remove the xuartps port from the serial core */ +#ifdef CONFIG_COMMON_CLK + clk_notifier_unregister(xuartps_data->refclk, + &xuartps_data->clk_rate_change_nb); +#endif rc = uart_remove_one_port(&xuartps_uart_driver, port); port->mapbase = 0; clk_disable_unprepare(xuartps_data->refclk); clk_disable_unprepare(xuartps_data->aperclk); - clk_put(xuartps_data->refclk); - clk_put(xuartps_data->aperclk); - kfree(xuartps_data); return rc; } @@ -1067,6 +1469,7 @@ static struct platform_driver xuartps_platform_driver = { .owner = THIS_MODULE, .name = XUARTPS_NAME, /* Driver name */ .of_match_table = xuartps_of_match, + .pm = &xuartps_dev_pm_ops, }, }; |