Merge 3.19-rc5 into tty-next
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 18 Jan 2015 23:02:50 +0000 (07:02 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 18 Jan 2015 23:02:50 +0000 (07:02 +0800)
We want those tty fixes in that release in this branch as well.

Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
32 files changed:
Documentation/devicetree/bindings/serial/digicolor-usart.txt [new file with mode: 0644]
Documentation/devicetree/bindings/serial/sirf-uart.txt
Documentation/devicetree/bindings/vendor-prefixes.txt
drivers/tty/amiserial.c
drivers/tty/rocket.c
drivers/tty/serial/8250/8250_core.c
drivers/tty/serial/8250/8250_dma.c
drivers/tty/serial/8250/8250_dw.c
drivers/tty/serial/8250/8250_early.c
drivers/tty/serial/8250/8250_omap.c
drivers/tty/serial/8250/Kconfig
drivers/tty/serial/Kconfig
drivers/tty/serial/Makefile
drivers/tty/serial/altera_jtaguart.c
drivers/tty/serial/altera_uart.c
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/digicolor-usart.c [new file with mode: 0644]
drivers/tty/serial/imx.c
drivers/tty/serial/mcf.c
drivers/tty/serial/mxs-auart.c
drivers/tty/serial/omap-serial.c
drivers/tty/serial/samsung.c
drivers/tty/serial/samsung.h
drivers/tty/serial/sirfsoc_uart.c
drivers/tty/serial/sirfsoc_uart.h
drivers/tty/tty_mutex.c
drivers/tty/vt/vt.c
include/linux/serial_8250.h
include/linux/serial_core.h
include/linux/serial_s3c.h
include/uapi/linux/serial_core.h
include/uapi/linux/serial_reg.h

diff --git a/Documentation/devicetree/bindings/serial/digicolor-usart.txt b/Documentation/devicetree/bindings/serial/digicolor-usart.txt
new file mode 100644 (file)
index 0000000..2d3ede6
--- /dev/null
@@ -0,0 +1,27 @@
+Binding for Conexant Digicolor USART
+
+Note: this binding is only applicable for using the USART peripheral as
+UART. USART also support synchronous serial protocols like SPI and I2S. Use
+the binding that matches the wiring of your system.
+
+Required properties:
+- compatible : should be "cnxt,cx92755-usart".
+- reg: Should contain USART controller registers location and length.
+- interrupts: Should contain a single USART controller interrupt.
+- clocks: Must contain phandles to the USART clock
+  See ../clocks/clock-bindings.txt for details.
+
+Note: Each UART port should have an alias correctly numbered
+in "aliases" node.
+
+Example:
+       aliases {
+               serial0 = &uart0;
+       };
+
+       uart0: uart@f0000740 {
+               compatible = "cnxt,cx92755-usart";
+               reg = <0xf0000740 0x20>;
+               clocks = <&main_clk>;
+               interrupts = <44>;
+       };
index 3acdd969edf14a1252cabc988cf0df38785ae768..f0c39261c5d4443927737eee98c73076fb0632ad 100644 (file)
@@ -2,7 +2,7 @@
 
 Required properties:
 - compatible : Should be "sirf,prima2-uart", "sirf, prima2-usp-uart",
-               "sirf,marco-uart" or "sirf,marco-bt-uart" which means
+               "sirf,atlas7-uart" or "sirf,atlas7-bt-uart" which means
                uart located in BT module and used for BT.
 - reg : Offset and length of the register set for the device
 - interrupts : Should contain uart interrupt
@@ -37,7 +37,7 @@ usp@b0090000 {
 for uart use in BT module,
 uart6: uart@11000000 {
        cell-index = <6>;
-       compatible = "sirf,marco-bt-uart", "sirf,marco-uart";
+       compatible = "sirf,atlas7-bt-uart", "sirf,atlas7-uart";
        reg = <0x11000000 0x1000>;
        interrupts = <0 100 0>;
        clocks = <&clks 138>, <&clks 140>, <&clks 141>;
index b1df0ad1306c73e89a4d4be90ef4892b511b6cf3..2c67a07d6bd6071c99b35ef024c5790641d47725 100644 (file)
@@ -35,6 +35,7 @@ chrp  Common Hardware Reference Platform
 chunghwa       Chunghwa Picture Tubes Ltd.
 cirrus Cirrus Logic, Inc.
 cnm    Chips&Media, Inc.
+cnxt   Conexant Systems, Inc.
 cortina        Cortina Systems, Inc.
 crystalfontz   Crystalfontz America, Inc.
 dallas Maxim Integrated Products (formerly Dallas Semiconductor)
index d9f85f95eb2a5bcbd24614da72aa5bc47e4af93e..b2d76005595225ebd9f1412bf250ad768132d660 100644 (file)
@@ -931,7 +931,7 @@ static void rs_send_xchar(struct tty_struct *tty, char ch)
        struct serial_state *info = tty->driver_data;
         unsigned long flags;
 
-       if (serial_paranoia_check(info, tty->name, "rs_send_char"))
+       if (serial_paranoia_check(info, tty->name, "rs_send_xchar"))
                return;
 
        info->x_char = ch;
index 383c4c796637713e12bede50677803a0d639a855..c8dd8dc31086ee5d373427dc5a7f04bee7cce1bb 100644 (file)
@@ -1390,7 +1390,7 @@ static void rp_unthrottle(struct tty_struct *tty)
               tty->ldisc.chars_in_buffer(tty));
 #endif
 
-       if (rocket_paranoia_check(info, "rp_throttle"))
+       if (rocket_paranoia_check(info, "rp_unthrottle"))
                return;
 
        if (I_IXOFF(tty))
@@ -1458,7 +1458,7 @@ static void rp_wait_until_sent(struct tty_struct *tty, int timeout)
 
        orig_jiffies = jiffies;
 #ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
-       printk(KERN_INFO "In RP_wait_until_sent(%d) (jiff=%lu)...\n", timeout,
+       printk(KERN_INFO "In %s(%d) (jiff=%lu)...\n", __func__, timeout,
               jiffies);
        printk(KERN_INFO "cps=%d...\n", info->cps);
 #endif
index 11c66856ba2fcb59edf96bba1459b0a9b5e4f9db..689169c11f0fc4153ad2a5e45d840a1712440faf 100644 (file)
@@ -329,6 +329,17 @@ static const struct serial8250_config uart_config[] = {
                .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
                .flags          = UART_CAP_FIFO | UART_CAP_AFE,
        },
+/* tx_loadsz is set to 63-bytes instead of 64-bytes to implement
+workaround of errata A-008006 which states that tx_loadsz should  be
+configured less than Maximum supported fifo bytes */
+       [PORT_16550A_FSL64] = {
+               .name           = "16550A_FSL64",
+               .fifo_size      = 64,
+               .tx_loadsz      = 63,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 |
+                                 UART_FCR7_64BYTE,
+               .flags          = UART_CAP_FIFO,
+       },
 };
 
 /* Uart divisor latch read */
@@ -956,7 +967,17 @@ static void autoconfig_16550a(struct uart_8250_port *up)
                        up->port.type = PORT_16650;
                        up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP;
                } else {
-                       DEBUG_AUTOCONF("Motorola 8xxx DUART ");
+                       serial_out(up, UART_LCR, 0);
+                       serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+                                  UART_FCR7_64BYTE);
+                       status1 = serial_in(up, UART_IIR) >> 5;
+                       serial_out(up, UART_FCR, 0);
+                       serial_out(up, UART_LCR, 0);
+
+                       if (status1 == 7)
+                               up->port.type = PORT_16550A_FSL64;
+                       else
+                               DEBUG_AUTOCONF("Motorola 8xxx DUART ");
                }
                serial_out(up, UART_EFR, 0);
                return;
@@ -1924,7 +1945,7 @@ static unsigned int serial8250_get_mctrl(struct uart_port *port)
        return ret;
 }
 
-static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
+void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
        struct uart_8250_port *up = up_to_u8250p(port);
        unsigned char mcr = 0;
@@ -1944,6 +1965,14 @@ static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
 
        serial_port_out(port, UART_MCR, mcr);
 }
+EXPORT_SYMBOL_GPL(serial8250_do_set_mctrl);
+
+static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       if (port->set_mctrl)
+               return port->set_mctrl(port, mctrl);
+       return serial8250_do_set_mctrl(port, mctrl);
+}
 
 static void serial8250_break_ctl(struct uart_port *port, int break_state)
 {
@@ -3605,6 +3634,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
                /*  Possibly override set_termios call */
                if (up->port.set_termios)
                        uart->port.set_termios = up->port.set_termios;
+               if (up->port.set_mctrl)
+                       uart->port.set_mctrl = up->port.set_mctrl;
                if (up->port.startup)
                        uart->port.startup = up->port.startup;
                if (up->port.shutdown)
index fcd7ac6af2fc25339600b5059a658ea052f14b91..e508939daea3f3128a2ada1e696a5f751d212077 100644 (file)
@@ -59,7 +59,6 @@ static void __dma_rx_complete(void *param)
 
        dma->rx_running = 0;
        dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
-       dmaengine_terminate_all(dma->rxchan);
 
        count = dma->rx_size - state.residue;
 
@@ -131,6 +130,7 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
                if (dma->rx_running) {
                        dmaengine_pause(dma->rxchan);
                        __dma_rx_complete(p);
+                       dmaengine_terminate_all(dma->rxchan);
                }
                return -ETIMEDOUT;
        default:
index 555de07db593a14adc74a2eda46a15847e8f3c07..e60116235836498e5b20ce56219b7d8c949acd25 100644 (file)
@@ -351,10 +351,20 @@ static int dw8250_probe_of(struct uart_port *p,
 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;
 
        dw8250_setup_port(up);
 
+       id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev);
+       if (!id)
+               return -ENODEV;
+
+       if (!p->uartclk)
+               if (device_property_read_u32(p->dev, "clock-frequency",
+                                            &p->uartclk))
+                       return -EINVAL;
+
        p->iotype = UPIO_MEM32;
        p->serial_in = dw8250_serial_in32;
        p->serial_out = dw8250_serial_out32;
@@ -577,6 +587,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = {
        { "INT3435", 0 },
        { "80860F0A", 0 },
        { "8086228A", 0 },
+       { "APMC0D08", 0},
        { },
 };
 MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
index 4858b8a99d3b4fcdbd4702c08a89442c6fb795fa..ce2a8abd1f549c8cd5e5e6451395a052e473acdd 100644 (file)
@@ -95,13 +95,16 @@ static void __init early_serial8250_write(struct console *console,
 
        /* Save the IER and disable interrupts */
        ier = serial8250_early_in(port, UART_IER);
-       serial8250_early_out(port, UART_IER, 0);
+       if (ier)
+               serial8250_early_out(port, UART_IER, 0);
 
        uart_console_write(port, s, count, serial_putc);
 
        /* Wait for transmitter to become empty and restore the IER */
        wait_for_xmitr(port);
-       serial8250_early_out(port, UART_IER, ier);
+
+       if (ier)
+               serial8250_early_out(port, UART_IER, ier);
 }
 
 static unsigned int __init probe_baud(struct uart_port *port)
index 96b69bfd773f025f6e86cff1cbfb1e2566c427ce..9191d05cfaf0af351b5fe697a4419b45481ec0b3 100644 (file)
@@ -106,6 +106,27 @@ static u32 uart_read(struct uart_8250_port *up, u32 reg)
        return readl(up->port.membase + (reg << up->port.regshift));
 }
 
+static void omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       struct uart_8250_port *up = up_to_u8250p(port);
+       struct omap8250_priv *priv = up->port.private_data;
+       u8 lcr;
+
+       serial8250_do_set_mctrl(port, mctrl);
+
+       /*
+        * Turn off autoRTS if RTS is lowered and restore autoRTS setting
+        * if RTS is raised
+        */
+       lcr = serial_in(up, UART_LCR);
+       serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+       if (mctrl & TIOCM_RTS)
+               serial_out(up, UART_EFR, priv->efr);
+       else
+               serial_out(up, UART_EFR, priv->efr & ~UART_EFR_RTS);
+       serial_out(up, UART_LCR, lcr);
+}
+
 /*
  * Work Around for Errata i202 (2430, 3430, 3630, 4430 and 4460)
  * The access to uart register after MDR1 Access
@@ -251,7 +272,10 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
        serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
        serial_dl_write(up, priv->quot);
 
-       serial_out(up, UART_EFR, priv->efr);
+       if (up->port.mctrl & TIOCM_RTS)
+               serial_out(up, UART_EFR, priv->efr);
+       else
+               serial_out(up, UART_EFR, priv->efr & ~UART_EFR_RTS);
 
        /* Configure flow control */
        serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
@@ -400,9 +424,6 @@ static void omap_8250_set_termios(struct uart_port *port,
        if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
                /* Enable AUTORTS and AUTOCTS */
                priv->efr |= UART_EFR_CTS | UART_EFR_RTS;
-
-               /* Ensure MCR RTS is asserted */
-               up->mcr |= UART_MCR_RTS;
        } else  if (up->port.flags & UPF_SOFT_FLOW) {
                /*
                 * IXON Flag:
@@ -450,18 +471,18 @@ static void omap_8250_set_termios(struct uart_port *port,
 static void omap_8250_pm(struct uart_port *port, unsigned int state,
                         unsigned int oldstate)
 {
-       struct uart_8250_port *up =
-               container_of(port, struct uart_8250_port, port);
-       struct omap8250_priv *priv = up->port.private_data;
+       struct uart_8250_port *up = up_to_u8250p(port);
+       u8 efr;
 
        pm_runtime_get_sync(port->dev);
        serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-       serial_out(up, UART_EFR, priv->efr | UART_EFR_ECB);
+       efr = serial_in(up, UART_EFR);
+       serial_out(up, UART_EFR, efr | UART_EFR_ECB);
        serial_out(up, UART_LCR, 0);
 
        serial_out(up, UART_IER, (state != 0) ? UART_IERX_SLEEP : 0);
        serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
-       serial_out(up, UART_EFR, priv->efr);
+       serial_out(up, UART_EFR, efr);
        serial_out(up, UART_LCR, 0);
 
        pm_runtime_mark_last_busy(port->dev);
@@ -1007,6 +1028,7 @@ static int omap8250_probe(struct platform_device *pdev)
        up.capabilities |= UART_CAP_RPM;
 #endif
        up.port.set_termios = omap_8250_set_termios;
+       up.port.set_mctrl = omap8250_set_mctrl;
        up.port.pm = omap_8250_pm;
        up.port.startup = omap_8250_startup;
        up.port.shutdown = omap_8250_shutdown;
@@ -1248,6 +1270,46 @@ static int omap8250_runtime_resume(struct device *dev)
 }
 #endif
 
+#ifdef CONFIG_SERIAL_8250_OMAP_TTYO_FIXUP
+static int __init omap8250_console_fixup(void)
+{
+       char *omap_str;
+       char *options;
+       u8 idx;
+
+       if (strstr(boot_command_line, "console=ttyS"))
+               /* user set a ttyS based name for the console */
+               return 0;
+
+       omap_str = strstr(boot_command_line, "console=ttyO");
+       if (!omap_str)
+               /* user did not set ttyO based console, so we don't care */
+               return 0;
+
+       omap_str += 12;
+       if ('0' <= *omap_str && *omap_str <= '9')
+               idx = *omap_str - '0';
+       else
+               return 0;
+
+       omap_str++;
+       if (omap_str[0] == ',') {
+               omap_str++;
+               options = omap_str;
+       } else {
+               options = NULL;
+       }
+
+       add_preferred_console("ttyS", idx, options);
+       pr_err("WARNING: Your 'console=ttyO%d' has been replaced by 'ttyS%d'\n",
+              idx, idx);
+       pr_err("This ensures that you still see kernel messages. Please\n");
+       pr_err("update your kernel commandline.\n");
+       return 0;
+}
+console_initcall(omap8250_console_fixup);
+#endif
+
 static const struct dev_pm_ops omap8250_dev_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(omap8250_suspend, omap8250_resume)
        SET_RUNTIME_PM_OPS(omap8250_runtime_suspend,
@@ -1269,7 +1331,6 @@ static struct platform_driver omap8250_platform_driver = {
                .name           = "omap8250",
                .pm             = &omap8250_dev_pm_ops,
                .of_match_table = omap8250_dt_ids,
-               .owner          = THIS_MODULE,
        },
        .probe                  = omap8250_probe,
        .remove                 = omap8250_remove,
index 0fcbcd29502fc0adda09ccef7227006e82ff1c49..6f7f2d753defe9695925ea9aaa0f503066858e55 100644 (file)
@@ -308,6 +308,25 @@ config SERIAL_8250_OMAP
 
          This driver uses ttyS instead of ttyO.
 
+config SERIAL_8250_OMAP_TTYO_FIXUP
+       bool "Replace ttyO with ttyS"
+       depends on SERIAL_8250_OMAP=y && SERIAL_8250_CONSOLE
+       default y
+       help
+         This option replaces the "console=ttyO" argument with the matching
+         ttyS argument if the user did not specified it on the command line.
+         This ensures that the user can see the kernel output during boot
+         which he wouldn't see otherwise. The getty has still to be configured
+         for ttyS instead of ttyO regardless of this option.
+         This option is intended for people who "automatically" enable this
+         driver without knowing that this driver requires a different console=
+         argument. If you read this, please keep this option disabled and
+         instead update your kernel command line. If you prepare a kernel for a
+         distribution or other kind of larger user base then you probably want
+         to keep this option enabled. Otherwise people might complain about a
+         not booting kernel because the serial console remains silent in case
+         they forgot to update the command line.
+
 config SERIAL_8250_FINTEK
        tristate "Support for Fintek F81216A LPC to 4 UART"
        depends on SERIAL_8250 && PNP
index c79b43cd6014a9916494230940b548f432b2e290..96ec6cfd74e804f1b9f2523e66eb400c4c4c6507 100644 (file)
@@ -1549,6 +1549,21 @@ config SERIAL_FSL_LPUART_CONSOLE
          If you have enabled the lpuart serial port on the Freescale SoCs,
          you can make it the console by answering Y to this option.
 
+config SERIAL_CONEXANT_DIGICOLOR
+       tristate "Conexant Digicolor CX92xxx USART serial port support"
+       depends on OF
+       select SERIAL_CORE
+       help
+         Support for the on-chip USART on Conexant Digicolor SoCs.
+
+config SERIAL_CONEXANT_DIGICOLOR_CONSOLE
+       bool "Console on Conexant Digicolor serial port"
+       depends on SERIAL_CONEXANT_DIGICOLOR=y
+       select SERIAL_CORE_CONSOLE
+       help
+         If you have enabled the USART serial port on Conexant Digicolor
+         SoCs, you can make it the console by answering Y to this option.
+
 config SERIAL_ST_ASC
        tristate "ST ASC serial port support"
        select SERIAL_CORE
index 9a548acf5fdc99eaae1bb767d80b041cfb674adb..770a19bb7fcb8f7f6ac458e5414c3c150634c9ca 100644 (file)
@@ -92,6 +92,7 @@ obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o
 obj-$(CONFIG_SERIAL_ARC)       += arc_uart.o
 obj-$(CONFIG_SERIAL_RP2)       += rp2.o
 obj-$(CONFIG_SERIAL_FSL_LPUART)        += fsl_lpuart.o
+obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR)        += digicolor-usart.o
 obj-$(CONFIG_SERIAL_MEN_Z135)  += men_z135_uart.o
 
 # GPIOLIB helpers for modem control lines
index 192d0435bb8683180f29d50f8aa9f39c28ac5e15..0fefdd8931a2a29ab77ee4a39433a35b2eb31637 100644 (file)
@@ -441,6 +441,7 @@ static int altera_jtaguart_probe(struct platform_device *pdev)
        port->iotype = SERIAL_IO_MEM;
        port->ops = &altera_jtaguart_ops;
        port->flags = UPF_BOOT_AUTOCONF;
+       port->dev = &pdev->dev;
 
        uart_add_one_port(&altera_jtaguart_driver, port);
 
index eb15a50623cb381ce9d98b9a1f56d78c14255284..b2859fe07e141a2a578e741412a2bd867f2c5ba2 100644 (file)
@@ -589,6 +589,7 @@ static int altera_uart_probe(struct platform_device *pdev)
        port->iotype = SERIAL_IO_MEM;
        port->ops = &altera_uart_ops;
        port->flags = UPF_BOOT_AUTOCONF;
+       port->dev = &pdev->dev;
 
        platform_set_drvdata(pdev, port);
 
index 4d848a29e2234588ca2095118afb702ee55a69e7..846552bff67d6f005c3966e80368134dcd9ab27f 100644 (file)
@@ -341,13 +341,37 @@ static u_int atmel_tx_empty(struct uart_port *port)
 static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
 {
        unsigned int control = 0;
-       unsigned int mode;
+       unsigned int mode = UART_GET_MR(port);
+       unsigned int rts_paused, rts_ready;
        struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
+       /* override mode to RS485 if needed, otherwise keep the current mode */
+       if (port->rs485.flags & SER_RS485_ENABLED) {
+               if ((port->rs485.delay_rts_after_send) > 0)
+                       UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
+               mode &= ~ATMEL_US_USMODE;
+               mode |= ATMEL_US_USMODE_RS485;
+       }
+
+       /* set the RTS line state according to the mode */
+       if ((mode & ATMEL_US_USMODE) == ATMEL_US_USMODE_HWHS) {
+               /* force RTS line to high level */
+               rts_paused = ATMEL_US_RTSEN;
+
+               /* give the control of the RTS line back to the hardware */
+               rts_ready = ATMEL_US_RTSDIS;
+       } else {
+               /* force RTS line to high level */
+               rts_paused = ATMEL_US_RTSDIS;
+
+               /* force RTS line to low level */
+               rts_ready = ATMEL_US_RTSEN;
+       }
+
        if (mctrl & TIOCM_RTS)
-               control |= ATMEL_US_RTSEN;
+               control |= rts_ready;
        else
-               control |= ATMEL_US_RTSDIS;
+               control |= rts_paused;
 
        if (mctrl & TIOCM_DTR)
                control |= ATMEL_US_DTREN;
@@ -359,23 +383,12 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
        mctrl_gpio_set(atmel_port->gpios, mctrl);
 
        /* Local loopback mode? */
-       mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE;
+       mode &= ~ATMEL_US_CHMODE;
        if (mctrl & TIOCM_LOOP)
                mode |= ATMEL_US_CHMODE_LOC_LOOP;
        else
                mode |= ATMEL_US_CHMODE_NORMAL;
 
-       /* Resetting serial mode to RS232 (0x0) */
-       mode &= ~ATMEL_US_USMODE;
-
-       if (port->rs485.flags & SER_RS485_ENABLED) {
-               dev_dbg(port->dev, "Setting UART to RS485\n");
-               if ((port->rs485.delay_rts_after_send) > 0)
-                       UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
-               mode |= ATMEL_US_USMODE_RS485;
-       } else {
-               dev_dbg(port->dev, "Setting UART to RS232\n");
-       }
        UART_PUT_MR(port, mode);
 }
 
@@ -725,7 +738,11 @@ static void atmel_complete_tx_dma(void *arg)
        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
                uart_write_wakeup(port);
 
-       /* Do we really need this? */
+       /*
+        * xmit is a circular buffer so, if we have just send data from
+        * xmit->tail to the end of xmit->buf, now we have to transmit the
+        * remaining data from the beginning of xmit->buf to xmit->head.
+        */
        if (!uart_circ_empty(xmit))
                tasklet_schedule(&atmel_port->tasklet);
 
@@ -784,17 +801,17 @@ static void atmel_tx_dma(struct uart_port *port)
                BUG_ON(!sg_dma_len(sg));
 
                desc = dmaengine_prep_slave_sg(chan,
-                                               sg,
-                                               1,
-                                               DMA_MEM_TO_DEV,
-                                               DMA_PREP_INTERRUPT |
-                                               DMA_CTRL_ACK);
+                                              sg,
+                                              1,
+                                              DMA_MEM_TO_DEV,
+                                              DMA_PREP_INTERRUPT |
+                                              DMA_CTRL_ACK);
                if (!desc) {
                        dev_err(port->dev, "Failed to send via dma!\n");
                        return;
                }
 
-               dma_sync_sg_for_device(port->dev, sg, 1, DMA_MEM_TO_DEV);
+               dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE);
 
                atmel_port->desc_tx = desc;
                desc->callback = atmel_complete_tx_dma;
@@ -927,7 +944,7 @@ static void atmel_rx_from_dma(struct uart_port *port)
        dma_sync_sg_for_cpu(port->dev,
                            &atmel_port->sg_rx,
                            1,
-                           DMA_DEV_TO_MEM);
+                           DMA_FROM_DEVICE);
 
        /*
         * ring->head points to the end of data already written by the DMA.
@@ -974,7 +991,7 @@ static void atmel_rx_from_dma(struct uart_port *port)
        dma_sync_sg_for_device(port->dev,
                               &atmel_port->sg_rx,
                               1,
-                              DMA_DEV_TO_MEM);
+                              DMA_FROM_DEVICE);
 
        /*
         * Drop the lock here since it might end up calling
@@ -1012,13 +1029,13 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
        /* UART circular rx buffer is an aligned page. */
        BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK);
        sg_set_page(&atmel_port->sg_rx,
-                       virt_to_page(ring->buf),
-                       ATMEL_SERIAL_RINGSIZE,
-                       (int)ring->buf & ~PAGE_MASK);
-                       nent = dma_map_sg(port->dev,
-                                       &atmel_port->sg_rx,
-                                       1,
-                                       DMA_FROM_DEVICE);
+                   virt_to_page(ring->buf),
+                   ATMEL_SERIAL_RINGSIZE,
+                   (int)ring->buf & ~PAGE_MASK);
+       nent = dma_map_sg(port->dev,
+                         &atmel_port->sg_rx,
+                         1,
+                         DMA_FROM_DEVICE);
 
        if (!nent) {
                dev_dbg(port->dev, "need to release resource of dma\n");
@@ -1047,11 +1064,11 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
         * each one is half ring buffer size
         */
        desc = dmaengine_prep_dma_cyclic(atmel_port->chan_rx,
-                               sg_dma_address(&atmel_port->sg_rx),
-                               sg_dma_len(&atmel_port->sg_rx),
-                               sg_dma_len(&atmel_port->sg_rx)/2,
-                               DMA_DEV_TO_MEM,
-                               DMA_PREP_INTERRUPT);
+                                        sg_dma_address(&atmel_port->sg_rx),
+                                        sg_dma_len(&atmel_port->sg_rx),
+                                        sg_dma_len(&atmel_port->sg_rx)/2,
+                                        DMA_DEV_TO_MEM,
+                                        DMA_PREP_INTERRUPT);
        desc->callback = atmel_complete_rx_dma;
        desc->callback_param = port;
        atmel_port->desc_rx = desc;
@@ -1921,12 +1938,14 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
                              struct ktermios *old)
 {
        unsigned long flags;
-       unsigned int mode, imr, quot, baud;
+       unsigned int old_mode, mode, imr, quot, baud;
 
-       /* Get current mode register */
-       mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL
-                                       | ATMEL_US_NBSTOP | ATMEL_US_PAR
-                                       | ATMEL_US_USMODE);
+       /* save the current mode register */
+       mode = old_mode = UART_GET_MR(port);
+
+       /* reset the mode, clock divisor, parity, stop bits and data size */
+       mode &= ~(ATMEL_US_USCLKS | ATMEL_US_CHRL | ATMEL_US_NBSTOP |
+                 ATMEL_US_PAR | ATMEL_US_USMODE);
 
        baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
        quot = uart_get_divisor(port, baud);
@@ -1971,12 +1990,6 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
        } else
                mode |= ATMEL_US_PAR_NONE;
 
-       /* hardware handshake (RTS/CTS) */
-       if (termios->c_cflag & CRTSCTS)
-               mode |= ATMEL_US_USMODE_HWHS;
-       else
-               mode |= ATMEL_US_USMODE_NORMAL;
-
        spin_lock_irqsave(&port->lock, flags);
 
        port->read_status_mask = ATMEL_US_OVRE;
@@ -2020,18 +2033,40 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
        /* disable receiver and transmitter */
        UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS);
 
-       /* Resetting serial mode to RS232 (0x0) */
-       mode &= ~ATMEL_US_USMODE;
-
+       /* mode */
        if (port->rs485.flags & SER_RS485_ENABLED) {
                if ((port->rs485.delay_rts_after_send) > 0)
                        UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
                mode |= ATMEL_US_USMODE_RS485;
+       } else if (termios->c_cflag & CRTSCTS) {
+               /* RS232 with hardware handshake (RTS/CTS) */
+               mode |= ATMEL_US_USMODE_HWHS;
+       } else {
+               /* RS232 without hadware handshake */
+               mode |= ATMEL_US_USMODE_NORMAL;
        }
 
-       /* set the parity, stop bits and data size */
+       /* set the mode, clock divisor, parity, stop bits and data size */
        UART_PUT_MR(port, mode);
 
+       /*
+        * when switching the mode, set the RTS line state according to the
+        * new mode, otherwise keep the former state
+        */
+       if ((old_mode & ATMEL_US_USMODE) != (mode & ATMEL_US_USMODE)) {
+               unsigned int rts_state;
+
+               if ((mode & ATMEL_US_USMODE) == ATMEL_US_USMODE_HWHS) {
+                       /* let the hardware control the RTS line */
+                       rts_state = ATMEL_US_RTSDIS;
+               } else {
+                       /* force RTS line to low level */
+                       rts_state = ATMEL_US_RTSEN;
+               }
+
+               UART_PUT_CR(port, rts_state);
+       }
+
        /* set the baud rate */
        UART_PUT_BRGR(port, quot);
        UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
@@ -2565,7 +2600,7 @@ static int atmel_serial_probe(struct platform_device *pdev)
 
        ret = atmel_init_port(port, pdev);
        if (ret)
-               goto err;
+               goto err_clear_bit;
 
        if (!atmel_use_pdc_rx(&port->uart)) {
                ret = -ENOMEM;
@@ -2596,6 +2631,12 @@ static int atmel_serial_probe(struct platform_device *pdev)
        device_init_wakeup(&pdev->dev, 1);
        platform_set_drvdata(pdev, port);
 
+       /*
+        * The peripheral clock has been disabled by atmel_init_port():
+        * enable it before accessing I/O registers
+        */
+       clk_prepare_enable(port->clk);
+
        if (rs485_enabled) {
                UART_PUT_MR(&port->uart, ATMEL_US_USMODE_NORMAL);
                UART_PUT_CR(&port->uart, ATMEL_US_RTSEN);
@@ -2606,6 +2647,12 @@ static int atmel_serial_probe(struct platform_device *pdev)
         */
        atmel_get_ip_name(&port->uart);
 
+       /*
+        * The peripheral clock can now safely be disabled till the port
+        * is used
+        */
+       clk_disable_unprepare(port->clk);
+
        return 0;
 
 err_add_port:
@@ -2616,6 +2663,8 @@ err_alloc_ring:
                clk_put(port->clk);
                port->clk = NULL;
        }
+err_clear_bit:
+       clear_bit(port->uart.line, atmel_ports_in_use);
 err:
        return ret;
 }
diff --git a/drivers/tty/serial/digicolor-usart.c b/drivers/tty/serial/digicolor-usart.c
new file mode 100644 (file)
index 0000000..09ce0b3
--- /dev/null
@@ -0,0 +1,563 @@
+/*
+ *  Driver for Conexant Digicolor serial ports (USART)
+ *
+ * Author: Baruch Siach <baruch@tkos.co.il>
+ *
+ * Copyright (C) 2014 Paradox Innovation Ltd.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+
+#define UA_ENABLE                      0x00
+#define UA_ENABLE_ENABLE               BIT(0)
+
+#define UA_CONTROL                     0x01
+#define UA_CONTROL_RX_ENABLE           BIT(0)
+#define UA_CONTROL_TX_ENABLE           BIT(1)
+#define UA_CONTROL_SOFT_RESET          BIT(2)
+
+#define UA_STATUS                      0x02
+#define UA_STATUS_PARITY_ERR           BIT(0)
+#define UA_STATUS_FRAME_ERR            BIT(1)
+#define UA_STATUS_OVERRUN_ERR          BIT(2)
+#define UA_STATUS_TX_READY             BIT(6)
+
+#define UA_CONFIG                      0x03
+#define UA_CONFIG_CHAR_LEN             BIT(0)
+#define UA_CONFIG_STOP_BITS            BIT(1)
+#define UA_CONFIG_PARITY               BIT(2)
+#define UA_CONFIG_ODD_PARITY           BIT(4)
+
+#define UA_EMI_REC                     0x04
+
+#define UA_HBAUD_LO                    0x08
+#define UA_HBAUD_HI                    0x09
+
+#define UA_STATUS_FIFO                 0x0a
+#define UA_STATUS_FIFO_RX_EMPTY                BIT(2)
+#define UA_STATUS_FIFO_RX_INT_ALMOST   BIT(3)
+#define UA_STATUS_FIFO_TX_FULL         BIT(4)
+#define UA_STATUS_FIFO_TX_INT_ALMOST   BIT(7)
+
+#define UA_CONFIG_FIFO                 0x0b
+#define UA_CONFIG_FIFO_RX_THRESH       7
+#define UA_CONFIG_FIFO_RX_FIFO_MODE    BIT(3)
+#define UA_CONFIG_FIFO_TX_FIFO_MODE    BIT(7)
+
+#define UA_INTFLAG_CLEAR               0x1c
+#define UA_INTFLAG_SET                 0x1d
+#define UA_INT_ENABLE                  0x1e
+#define UA_INT_STATUS                  0x1f
+
+#define UA_INT_TX                      BIT(0)
+#define UA_INT_RX                      BIT(1)
+
+#define DIGICOLOR_USART_NR             3
+
+/*
+ * We use the 16 bytes hardware FIFO to buffer Rx traffic. Rx interrupt is
+ * only produced when the FIFO is filled more than a certain configurable
+ * threshold. Unfortunately, there is no way to set this threshold below half
+ * FIFO. This means that we must periodically poll the FIFO status register to
+ * see whether there are waiting Rx bytes.
+ */
+
+struct digicolor_port {
+       struct uart_port port;
+       struct delayed_work rx_poll_work;
+};
+
+static struct uart_port *digicolor_ports[DIGICOLOR_USART_NR];
+
+static bool digicolor_uart_tx_full(struct uart_port *port)
+{
+       return !!(readb_relaxed(port->membase + UA_STATUS_FIFO) &
+                 UA_STATUS_FIFO_TX_FULL);
+}
+
+static bool digicolor_uart_rx_empty(struct uart_port *port)
+{
+       return !!(readb_relaxed(port->membase + UA_STATUS_FIFO) &
+                 UA_STATUS_FIFO_RX_EMPTY);
+}
+
+static void digicolor_uart_stop_tx(struct uart_port *port)
+{
+       u8 int_enable = readb_relaxed(port->membase + UA_INT_ENABLE);
+
+       int_enable &= ~UA_INT_TX;
+       writeb_relaxed(int_enable, port->membase + UA_INT_ENABLE);
+}
+
+static void digicolor_uart_start_tx(struct uart_port *port)
+{
+       u8 int_enable = readb_relaxed(port->membase + UA_INT_ENABLE);
+
+       int_enable |= UA_INT_TX;
+       writeb_relaxed(int_enable, port->membase + UA_INT_ENABLE);
+}
+
+static void digicolor_uart_stop_rx(struct uart_port *port)
+{
+       u8 int_enable = readb_relaxed(port->membase + UA_INT_ENABLE);
+
+       int_enable &= ~UA_INT_RX;
+       writeb_relaxed(int_enable, port->membase + UA_INT_ENABLE);
+}
+
+static void digicolor_rx_poll(struct work_struct *work)
+{
+       struct digicolor_port *dp =
+               container_of(to_delayed_work(work),
+                            struct digicolor_port, rx_poll_work);
+
+       if (!digicolor_uart_rx_empty(&dp->port))
+               /* force RX interrupt */
+               writeb_relaxed(UA_INT_RX, dp->port.membase + UA_INTFLAG_SET);
+
+       schedule_delayed_work(&dp->rx_poll_work, msecs_to_jiffies(100));
+}
+
+static void digicolor_uart_rx(struct uart_port *port)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       while (1) {
+               u8 status, ch;
+               unsigned int ch_flag;
+
+               if (digicolor_uart_rx_empty(port))
+                       break;
+
+               ch = readb_relaxed(port->membase + UA_EMI_REC);
+               status = readb_relaxed(port->membase + UA_STATUS);
+
+               port->icount.rx++;
+               ch_flag = TTY_NORMAL;
+
+               if (status) {
+                       if (status & UA_STATUS_PARITY_ERR)
+                               port->icount.parity++;
+                       else if (status & UA_STATUS_FRAME_ERR)
+                               port->icount.frame++;
+                       else if (status & UA_STATUS_OVERRUN_ERR)
+                               port->icount.overrun++;
+
+                       status &= port->read_status_mask;
+
+                       if (status & UA_STATUS_PARITY_ERR)
+                               ch_flag = TTY_PARITY;
+                       else if (status & UA_STATUS_FRAME_ERR)
+                               ch_flag = TTY_FRAME;
+                       else if (status & UA_STATUS_OVERRUN_ERR)
+                               ch_flag = TTY_OVERRUN;
+               }
+
+               if (uart_handle_sysrq_char(port, ch))
+                       continue;
+
+               if (status & port->ignore_status_mask)
+                       continue;
+
+               uart_insert_char(port, status, UA_STATUS_OVERRUN_ERR, ch,
+                                ch_flag);
+       }
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       tty_flip_buffer_push(&port->state->port);
+}
+
+static void digicolor_uart_tx(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->state->xmit;
+       unsigned long flags;
+
+       if (digicolor_uart_tx_full(port))
+               return;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       if (port->x_char) {
+               writeb_relaxed(port->x_char, port->membase + UA_EMI_REC);
+               port->icount.tx++;
+               port->x_char = 0;
+               goto out;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               digicolor_uart_stop_tx(port);
+               goto out;
+       }
+
+       while (!uart_circ_empty(xmit)) {
+               writeb(xmit->buf[xmit->tail], port->membase + UA_EMI_REC);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+
+               if (digicolor_uart_tx_full(port))
+                       break;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+out:
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static irqreturn_t digicolor_uart_int(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       u8 int_status = readb_relaxed(port->membase + UA_INT_STATUS);
+
+       writeb_relaxed(UA_INT_RX | UA_INT_TX,
+                      port->membase + UA_INTFLAG_CLEAR);
+
+       if (int_status & UA_INT_RX)
+               digicolor_uart_rx(port);
+       if (int_status & UA_INT_TX)
+               digicolor_uart_tx(port);
+
+       return IRQ_HANDLED;
+}
+
+static unsigned int digicolor_uart_tx_empty(struct uart_port *port)
+{
+       u8 status = readb_relaxed(port->membase + UA_STATUS);
+
+       return (status & UA_STATUS_TX_READY) ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int digicolor_uart_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_CTS;
+}
+
+static void digicolor_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static void digicolor_uart_break_ctl(struct uart_port *port, int state)
+{
+}
+
+static int digicolor_uart_startup(struct uart_port *port)
+{
+       struct digicolor_port *dp =
+               container_of(port, struct digicolor_port, port);
+
+       writeb_relaxed(UA_ENABLE_ENABLE, port->membase + UA_ENABLE);
+       writeb_relaxed(UA_CONTROL_SOFT_RESET, port->membase + UA_CONTROL);
+       writeb_relaxed(0, port->membase + UA_CONTROL);
+
+       writeb_relaxed(UA_CONFIG_FIFO_RX_FIFO_MODE
+                      | UA_CONFIG_FIFO_TX_FIFO_MODE | UA_CONFIG_FIFO_RX_THRESH,
+                      port->membase + UA_CONFIG_FIFO);
+       writeb_relaxed(UA_STATUS_FIFO_RX_INT_ALMOST,
+                      port->membase + UA_STATUS_FIFO);
+       writeb_relaxed(UA_CONTROL_RX_ENABLE | UA_CONTROL_TX_ENABLE,
+                      port->membase + UA_CONTROL);
+       writeb_relaxed(UA_INT_TX | UA_INT_RX,
+                      port->membase + UA_INT_ENABLE);
+
+       schedule_delayed_work(&dp->rx_poll_work, msecs_to_jiffies(100));
+
+       return 0;
+}
+
+static void digicolor_uart_shutdown(struct uart_port *port)
+{
+       struct digicolor_port *dp =
+               container_of(port, struct digicolor_port, port);
+
+       writeb_relaxed(0, port->membase + UA_ENABLE);
+       cancel_delayed_work_sync(&dp->rx_poll_work);
+}
+
+static void digicolor_uart_set_termios(struct uart_port *port,
+                                      struct ktermios *termios,
+                                      struct ktermios *old)
+{
+       unsigned int baud, divisor;
+       u8 config = 0;
+       unsigned long flags;
+
+       /* Mask termios capabilities we don't support */
+       termios->c_cflag &= ~CMSPAR;
+       termios->c_iflag &= ~(BRKINT | IGNBRK);
+
+       /* Limit baud rates so that we don't need the fractional divider */
+       baud = uart_get_baud_rate(port, termios, old,
+                                 port->uartclk / (0x10000*16),
+                                 port->uartclk / 256);
+       divisor = uart_get_divisor(port, baud) - 1;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS7:
+               break;
+       case CS8:
+       default:
+               config |= UA_CONFIG_CHAR_LEN;
+               break;
+       }
+
+       if (termios->c_cflag & CSTOPB)
+               config |= UA_CONFIG_STOP_BITS;
+
+       if (termios->c_cflag & PARENB) {
+               config |= UA_CONFIG_PARITY;
+               if (termios->c_cflag & PARODD)
+                       config |= UA_CONFIG_ODD_PARITY;
+       }
+
+       /* Set read status mask */
+       port->read_status_mask = UA_STATUS_OVERRUN_ERR;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= UA_STATUS_PARITY_ERR
+                       | UA_STATUS_FRAME_ERR;
+
+       /* Set status ignore mask */
+       port->ignore_status_mask = 0;
+       if (!(termios->c_cflag & CREAD))
+               port->ignore_status_mask |= UA_STATUS_OVERRUN_ERR
+                       | UA_STATUS_PARITY_ERR | UA_STATUS_FRAME_ERR;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       writeb_relaxed(config, port->membase + UA_CONFIG);
+       writeb_relaxed(divisor & 0xff, port->membase + UA_HBAUD_LO);
+       writeb_relaxed(divisor >> 8, port->membase + UA_HBAUD_HI);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *digicolor_uart_type(struct uart_port *port)
+{
+       return (port->type == PORT_DIGICOLOR) ? "DIGICOLOR USART" : NULL;
+}
+
+static void digicolor_uart_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE)
+               port->type = PORT_DIGICOLOR;
+}
+
+static void digicolor_uart_release_port(struct uart_port *port)
+{
+}
+
+static int digicolor_uart_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+static const struct uart_ops digicolor_uart_ops = {
+       .tx_empty       = digicolor_uart_tx_empty,
+       .set_mctrl      = digicolor_uart_set_mctrl,
+       .get_mctrl      = digicolor_uart_get_mctrl,
+       .stop_tx        = digicolor_uart_stop_tx,
+       .start_tx       = digicolor_uart_start_tx,
+       .stop_rx        = digicolor_uart_stop_rx,
+       .break_ctl      = digicolor_uart_break_ctl,
+       .startup        = digicolor_uart_startup,
+       .shutdown       = digicolor_uart_shutdown,
+       .set_termios    = digicolor_uart_set_termios,
+       .type           = digicolor_uart_type,
+       .config_port    = digicolor_uart_config_port,
+       .release_port   = digicolor_uart_release_port,
+       .request_port   = digicolor_uart_request_port,
+};
+
+static void digicolor_uart_console_putchar(struct uart_port *port, int ch)
+{
+       while (digicolor_uart_tx_full(port))
+               cpu_relax();
+
+       writeb_relaxed(ch, port->membase + UA_EMI_REC);
+}
+
+static void digicolor_uart_console_write(struct console *co, const char *c,
+                                        unsigned n)
+{
+       struct uart_port *port = digicolor_ports[co->index];
+       u8 status;
+       unsigned long flags;
+       int locked = 1;
+
+       if (port->sysrq || oops_in_progress)
+               locked = spin_trylock_irqsave(&port->lock, flags);
+       else
+               spin_lock_irqsave(&port->lock, flags);
+
+       uart_console_write(port, c, n, digicolor_uart_console_putchar);
+
+       if (locked)
+               spin_unlock_irqrestore(&port->lock, flags);
+
+       /* Wait for transmitter to become empty */
+       do {
+               status = readb_relaxed(port->membase + UA_STATUS);
+       } while ((status & UA_STATUS_TX_READY) == 0);
+}
+
+static int digicolor_uart_console_setup(struct console *co, char *options)
+{
+       int baud = 115200, bits = 8, parity = 'n', flow = 'n';
+       struct uart_port *port;
+
+       if (co->index < 0 || co->index >= DIGICOLOR_USART_NR)
+               return -EINVAL;
+
+       port = digicolor_ports[co->index];
+       if (!port)
+               return -ENODEV;
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct console digicolor_console = {
+       .name   = "ttyS",
+       .device = uart_console_device,
+       .write  = digicolor_uart_console_write,
+       .setup  = digicolor_uart_console_setup,
+       .flags  = CON_PRINTBUFFER,
+       .index  = -1,
+};
+
+static struct uart_driver digicolor_uart = {
+       .driver_name    = "digicolor-usart",
+       .dev_name       = "ttyS",
+       .nr             = DIGICOLOR_USART_NR,
+};
+
+static int digicolor_uart_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       int ret, index;
+       struct digicolor_port *dp;
+       struct resource *res;
+       struct clk *uart_clk;
+
+       if (!np) {
+               dev_err(&pdev->dev, "Missing device tree node\n");
+               return -ENXIO;
+       }
+
+       index = of_alias_get_id(np, "serial");
+       if (index < 0 || index >= DIGICOLOR_USART_NR)
+               return -EINVAL;
+
+       dp = devm_kzalloc(&pdev->dev, sizeof(*dp), GFP_KERNEL);
+       if (!dp)
+               return -ENOMEM;
+
+       uart_clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(uart_clk))
+               return PTR_ERR(uart_clk);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       dp->port.mapbase = res->start;
+       dp->port.membase = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(dp->port.membase))
+               return PTR_ERR(dp->port.membase);
+
+       dp->port.irq = platform_get_irq(pdev, 0);
+       if (IS_ERR_VALUE(dp->port.irq))
+               return dp->port.irq;
+
+       dp->port.iotype = UPIO_MEM;
+       dp->port.uartclk = clk_get_rate(uart_clk);
+       dp->port.fifosize = 16;
+       dp->port.dev = &pdev->dev;
+       dp->port.ops = &digicolor_uart_ops;
+       dp->port.line = index;
+       dp->port.type = PORT_DIGICOLOR;
+       spin_lock_init(&dp->port.lock);
+
+       digicolor_ports[index] = &dp->port;
+       platform_set_drvdata(pdev, &dp->port);
+
+       INIT_DELAYED_WORK(&dp->rx_poll_work, digicolor_rx_poll);
+
+       ret = devm_request_irq(&pdev->dev, dp->port.irq, digicolor_uart_int, 0,
+                              dev_name(&pdev->dev), &dp->port);
+       if (ret)
+               return ret;
+
+       return uart_add_one_port(&digicolor_uart, &dp->port);
+}
+
+static int digicolor_uart_remove(struct platform_device *pdev)
+{
+       struct uart_port *port = platform_get_drvdata(pdev);
+
+       uart_remove_one_port(&digicolor_uart, port);
+
+       return 0;
+}
+
+static const struct of_device_id digicolor_uart_dt_ids[] = {
+       { .compatible = "cnxt,cx92755-usart", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, digicolor_uart_dt_ids);
+
+static struct platform_driver digicolor_uart_platform = {
+       .driver = {
+               .name           = "digicolor-usart",
+               .of_match_table = of_match_ptr(digicolor_uart_dt_ids),
+       },
+       .probe  = digicolor_uart_probe,
+       .remove = digicolor_uart_remove,
+};
+
+static int __init digicolor_uart_init(void)
+{
+       int ret;
+
+       if (IS_ENABLED(CONFIG_SERIAL_CONEXANT_DIGICOLOR_CONSOLE)) {
+               digicolor_uart.cons = &digicolor_console;
+               digicolor_console.data = &digicolor_uart;
+       }
+
+       ret = uart_register_driver(&digicolor_uart);
+       if (ret)
+               return ret;
+
+       return platform_driver_register(&digicolor_uart_platform);
+}
+module_init(digicolor_uart_init);
+
+static void __exit digicolor_uart_exit(void)
+{
+       platform_driver_unregister(&digicolor_uart_platform);
+       uart_unregister_driver(&digicolor_uart);
+}
+module_exit(digicolor_uart_exit);
+
+MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
+MODULE_DESCRIPTION("Conexant Digicolor USART serial driver");
+MODULE_LICENSE("GPL");
index 4c5e9092e2d76751265143044b9f5d0b432baf34..59d9ef10b085f9102c6a9152be7728b16fa72ff4 100644 (file)
@@ -74,6 +74,7 @@
 #define IMX21_UTS 0xb4 /* UART Test Register on all other i.mx*/
 
 /* UART Control Register Bit Fields.*/
+#define URXD_DUMMY_READ (1<<16)
 #define URXD_CHARRDY   (1<<15)
 #define URXD_ERR       (1<<14)
 #define URXD_OVRRUN    (1<<13)
@@ -463,13 +464,17 @@ static void imx_enable_ms(struct uart_port *port)
        mod_timer(&sport->timer, jiffies);
 }
 
+static void imx_dma_tx(struct imx_port *sport);
 static inline void imx_transmit_buffer(struct imx_port *sport)
 {
        struct circ_buf *xmit = &sport->port.state->xmit;
+       unsigned long temp;
 
        if (sport->port.x_char) {
                /* Send next char */
                writel(sport->port.x_char, sport->port.membase + URTX0);
+               sport->port.icount.tx++;
+               sport->port.x_char = 0;
                return;
        }
 
@@ -478,6 +483,22 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
                return;
        }
 
+       if (sport->dma_is_enabled) {
+               /*
+                * We've just sent a X-char Ensure the TX DMA is enabled
+                * and the TX IRQ is disabled.
+                **/
+               temp = readl(sport->port.membase + UCR1);
+               temp &= ~UCR1_TXMPTYEN;
+               if (sport->dma_is_txing) {
+                       temp |= UCR1_TDMAEN;
+                       writel(temp, sport->port.membase + UCR1);
+               } else {
+                       writel(temp, sport->port.membase + UCR1);
+                       imx_dma_tx(sport);
+               }
+       }
+
        while (!uart_circ_empty(xmit) &&
               !(readl(sport->port.membase + uts_reg(sport)) & UTS_TXFULL)) {
                /* send xmit->buf[xmit->tail]
@@ -500,26 +521,39 @@ static void dma_tx_callback(void *data)
        struct scatterlist *sgl = &sport->tx_sgl[0];
        struct circ_buf *xmit = &sport->port.state->xmit;
        unsigned long flags;
+       unsigned long temp;
+
+       spin_lock_irqsave(&sport->port.lock, flags);
 
        dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
 
-       sport->dma_is_txing = 0;
+       temp = readl(sport->port.membase + UCR1);
+       temp &= ~UCR1_TDMAEN;
+       writel(temp, sport->port.membase + UCR1);
 
        /* update the stat */
-       spin_lock_irqsave(&sport->port.lock, flags);
        xmit->tail = (xmit->tail + sport->tx_bytes) & (UART_XMIT_SIZE - 1);
        sport->port.icount.tx += sport->tx_bytes;
-       spin_unlock_irqrestore(&sport->port.lock, flags);
 
        dev_dbg(sport->port.dev, "we finish the TX DMA.\n");
 
-       uart_write_wakeup(&sport->port);
+       sport->dma_is_txing = 0;
+
+       spin_unlock_irqrestore(&sport->port.lock, flags);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&sport->port);
 
        if (waitqueue_active(&sport->dma_wait)) {
                wake_up(&sport->dma_wait);
                dev_dbg(sport->port.dev, "exit in %s.\n", __func__);
                return;
        }
+
+       spin_lock_irqsave(&sport->port.lock, flags);
+       if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port))
+               imx_dma_tx(sport);
+       spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
 static void imx_dma_tx(struct imx_port *sport)
@@ -529,24 +563,23 @@ static void imx_dma_tx(struct imx_port *sport)
        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 temp;
        int ret;
 
-       status = dmaengine_tx_status(chan, (dma_cookie_t)0, NULL);
-       if (DMA_IN_PROGRESS == status)
+       if (sport->dma_is_txing)
                return;
 
        sport->tx_bytes = uart_circ_chars_pending(xmit);
 
-       if (xmit->tail > xmit->head && xmit->head > 0) {
+       if (xmit->tail < xmit->head) {
+               sport->dma_tx_nents = 1;
+               sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes);
+       } else {
                sport->dma_tx_nents = 2;
                sg_init_table(sgl, 2);
                sg_set_buf(sgl, xmit->buf + xmit->tail,
                                UART_XMIT_SIZE - xmit->tail);
                sg_set_buf(sgl + 1, xmit->buf, xmit->head);
-       } else {
-               sport->dma_tx_nents = 1;
-               sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes);
        }
 
        ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
@@ -557,6 +590,8 @@ static void imx_dma_tx(struct imx_port *sport)
        desc = dmaengine_prep_slave_sg(chan, sgl, sport->dma_tx_nents,
                                        DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
        if (!desc) {
+               dma_unmap_sg(dev, sgl, sport->dma_tx_nents,
+                            DMA_TO_DEVICE);
                dev_err(dev, "We cannot prepare for the TX slave dma!\n");
                return;
        }
@@ -565,6 +600,11 @@ static void imx_dma_tx(struct imx_port *sport)
 
        dev_dbg(dev, "TX: prepare to send %lu bytes by DMA.\n",
                        uart_circ_chars_pending(xmit));
+
+       temp = readl(sport->port.membase + UCR1);
+       temp |= UCR1_TDMAEN;
+       writel(temp, sport->port.membase + UCR1);
+
        /* fire it */
        sport->dma_is_txing = 1;
        dmaengine_submit(desc);
@@ -590,13 +630,6 @@ static void imx_start_tx(struct uart_port *port)
                temp &= ~(UCR1_RRDYEN);
                writel(temp, sport->port.membase + UCR1);
        }
-       /* Clear any pending ORE flag before enabling interrupt */
-       temp = readl(sport->port.membase + USR2);
-       writel(temp | USR2_ORE, sport->port.membase + USR2);
-
-       temp = readl(sport->port.membase + UCR4);
-       temp |= UCR4_OREN;
-       writel(temp, sport->port.membase + UCR4);
 
        if (!sport->dma_is_enabled) {
                temp = readl(sport->port.membase + UCR1);
@@ -614,15 +647,21 @@ static void imx_start_tx(struct uart_port *port)
        }
 
        if (sport->dma_is_enabled) {
-               /* FIXME: port->x_char must be transmitted if != 0 */
+               if (sport->port.x_char) {
+                       /* We have X-char to send, so enable TX IRQ and
+                        * disable TX DMA to let TX interrupt to send X-char */
+                       temp = readl(sport->port.membase + UCR1);
+                       temp &= ~UCR1_TDMAEN;
+                       temp |= UCR1_TXMPTYEN;
+                       writel(temp, sport->port.membase + UCR1);
+                       return;
+               }
+
                if (!uart_circ_empty(&port->state->xmit) &&
                    !uart_tx_stopped(port))
                        imx_dma_tx(sport);
                return;
        }
-
-       if (readl(sport->port.membase + uts_reg(sport)) & UTS_TXEMPTY)
-               imx_transmit_buffer(sport);
 }
 
 static irqreturn_t imx_rtsint(int irq, void *dev_id)
@@ -694,7 +733,7 @@ static irqreturn_t imx_rxint(int irq, void *dev_id)
                                continue;
                        }
 
-                       rx &= sport->port.read_status_mask;
+                       rx &= (sport->port.read_status_mask | 0xFF);
 
                        if (rx & URXD_BRK)
                                flg = TTY_BREAK;
@@ -710,6 +749,9 @@ static irqreturn_t imx_rxint(int irq, void *dev_id)
 #endif
                }
 
+               if (sport->port.ignore_status_mask & URXD_DUMMY_READ)
+                       goto out;
+
                tty_insert_flip_char(port, rx, flg);
        }
 
@@ -727,6 +769,9 @@ static int start_rx_dma(struct imx_port *sport);
 static void imx_dma_rxint(struct imx_port *sport)
 {
        unsigned long temp;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sport->port.lock, flags);
 
        temp = readl(sport->port.membase + USR2);
        if ((temp & USR2_RDR) && !sport->dma_is_rxing) {
@@ -740,6 +785,8 @@ static void imx_dma_rxint(struct imx_port *sport)
                /* tell the DMA to receive the data. */
                start_rx_dma(sport);
        }
+
+       spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
 static irqreturn_t imx_int(int irq, void *dev_id)
@@ -869,6 +916,9 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
 static void imx_rx_dma_done(struct imx_port *sport)
 {
        unsigned long temp;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sport->port.lock, flags);
 
        /* Enable this interrupt when the RXFIFO is empty. */
        temp = readl(sport->port.membase + UCR1);
@@ -880,6 +930,8 @@ static void imx_rx_dma_done(struct imx_port *sport)
        /* Is the shutdown waiting for us? */
        if (waitqueue_active(&sport->dma_wait))
                wake_up(&sport->dma_wait);
+
+       spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
 /*
@@ -910,12 +962,26 @@ static void dma_rx_callback(void *data)
        dev_dbg(sport->port.dev, "We get %d bytes.\n", count);
 
        if (count) {
-               tty_insert_flip_string(port, sport->rx_buf, count);
+               if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ))
+                       tty_insert_flip_string(port, sport->rx_buf, count);
                tty_flip_buffer_push(port);
 
                start_rx_dma(sport);
-       } else
+       } else if (readl(sport->port.membase + USR2) & USR2_RDR) {
+               /*
+                * start rx_dma directly once data in RXFIFO, more efficient
+                * than before:
+                *      1. call imx_rx_dma_done to stop dma if no data received
+                *      2. wait next  RDR interrupt to start dma transfer.
+                */
+               start_rx_dma(sport);
+       } else {
+               /*
+                * stop dma to prevent too many IDLE event trigged if no data
+                * in RXFIFO
+                */
                imx_rx_dma_done(sport);
+       }
 }
 
 static int start_rx_dma(struct imx_port *sport)
@@ -935,6 +1001,7 @@ static int start_rx_dma(struct imx_port *sport)
        desc = dmaengine_prep_slave_sg(chan, sgl, 1, DMA_DEV_TO_MEM,
                                        DMA_PREP_INTERRUPT);
        if (!desc) {
+               dma_unmap_sg(dev, sgl, 1, DMA_FROM_DEVICE);
                dev_err(dev, "We cannot prepare for the RX slave dma!\n");
                return -EINVAL;
        }
@@ -1108,12 +1175,20 @@ static int imx_startup(struct uart_port *port)
        while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0))
                udelay(1);
 
+       /* Can we enable the DMA support? */
+       if (is_imx6q_uart(sport) && !uart_console(port) &&
+           !sport->dma_is_inited)
+               imx_uart_dma_init(sport);
+
        spin_lock_irqsave(&sport->port.lock, flags);
        /*
         * Finally, clear and enable interrupts
         */
        writel(USR1_RTSD, sport->port.membase + USR1);
 
+       if (sport->dma_is_inited && !sport->dma_is_enabled)
+               imx_enable_dma(sport);
+
        temp = readl(sport->port.membase + UCR1);
        temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
 
@@ -1124,6 +1199,14 @@ static int imx_startup(struct uart_port *port)
 
        writel(temp, sport->port.membase + UCR1);
 
+       /* Clear any pending ORE flag before enabling interrupt */
+       temp = readl(sport->port.membase + USR2);
+       writel(temp | USR2_ORE, sport->port.membase + USR2);
+
+       temp = readl(sport->port.membase + UCR4);
+       temp |= UCR4_OREN;
+       writel(temp, sport->port.membase + UCR4);
+
        temp = readl(sport->port.membase + UCR2);
        temp |= (UCR2_RXEN | UCR2_TXEN);
        if (!sport->have_rtscts)
@@ -1189,9 +1272,11 @@ static void imx_shutdown(struct uart_port *port)
                        dmaengine_terminate_all(sport->dma_chan_tx);
                        dmaengine_terminate_all(sport->dma_chan_rx);
                }
+               spin_lock_irqsave(&sport->port.lock, flags);
                imx_stop_tx(port);
                imx_stop_rx(port);
                imx_disable_dma(sport);
+               spin_unlock_irqrestore(&sport->port.lock, flags);
                imx_uart_dma_exit(sport);
        }
 
@@ -1233,10 +1318,21 @@ static void imx_shutdown(struct uart_port *port)
 static void imx_flush_buffer(struct uart_port *port)
 {
        struct imx_port *sport = (struct imx_port *)port;
+       struct scatterlist *sgl = &sport->tx_sgl[0];
+       unsigned long temp;
 
-       if (sport->dma_is_enabled) {
-               sport->tx_bytes = 0;
-               dmaengine_terminate_all(sport->dma_chan_tx);
+       if (!sport->dma_chan_tx)
+               return;
+
+       sport->tx_bytes = 0;
+       dmaengine_terminate_all(sport->dma_chan_tx);
+       if (sport->dma_is_txing) {
+               dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents,
+                            DMA_TO_DEVICE);
+               temp = readl(sport->port.membase + UCR1);
+               temp &= ~UCR1_TDMAEN;
+               writel(temp, sport->port.membase + UCR1);
+               sport->dma_is_txing = false;
        }
 }
 
@@ -1280,11 +1376,6 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
                if (sport->have_rtscts) {
                        ucr2 &= ~UCR2_IRTS;
                        ucr2 |= UCR2_CTSC;
-
-                       /* Can we enable the DMA support? */
-                       if (is_imx6q_uart(sport) && !uart_console(port)
-                               && !sport->dma_is_inited)
-                               imx_uart_dma_init(sport);
                } else {
                        termios->c_cflag &= ~CRTSCTS;
                }
@@ -1319,7 +1410,7 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
         */
        sport->port.ignore_status_mask = 0;
        if (termios->c_iflag & IGNPAR)
-               sport->port.ignore_status_mask |= URXD_PRERR;
+               sport->port.ignore_status_mask |= URXD_PRERR | URXD_FRMERR;
        if (termios->c_iflag & IGNBRK) {
                sport->port.ignore_status_mask |= URXD_BRK;
                /*
@@ -1330,6 +1421,9 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
                        sport->port.ignore_status_mask |= URXD_OVRRUN;
        }
 
+       if ((termios->c_cflag & CREAD) == 0)
+               sport->port.ignore_status_mask |= URXD_DUMMY_READ;
+
        /*
         * Update the per-port timeout.
         */
@@ -1403,8 +1497,6 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
        if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
                imx_enable_ms(&sport->port);
 
-       if (sport->dma_is_inited && !sport->dma_is_enabled)
-               imx_enable_dma(sport);
        spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
index 10496672dfdbfcad71de2259420aa8b085d883aa..a9b0ab38a68c1c529629d4ec526f51257d0efcdc 100644 (file)
@@ -3,7 +3,7 @@
 /*
  *     mcf.c -- Freescale ColdFire UART driver
  *
- *     (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
+ *     (C) Copyright 2003-2007, Greg Ungerer <gerg@uclinux.org>
  *
  * 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
@@ -198,7 +198,6 @@ static void mcf_shutdown(struct uart_port *port)
 static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
        struct ktermios *old)
 {
-       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
        unsigned long flags;
        unsigned int baud, baudclk;
 #if defined(CONFIG_M5272)
@@ -441,7 +440,6 @@ static int mcf_verify_port(struct uart_port *port, struct serial_struct *ser)
 /* Enable or disable the RS485 support */
 static int mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
 {
-       struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
        unsigned char mr1, mr2;
 
        /* Get mode registers */
@@ -631,6 +629,7 @@ static int mcf_probe(struct platform_device *pdev)
                port->mapbase = platp[i].mapbase;
                port->membase = (platp[i].membase) ? platp[i].membase :
                        (unsigned char __iomem *) platp[i].mapbase;
+               port->dev = &pdev->dev;
                port->iotype = SERIAL_IO_MEM;
                port->irq = platp[i].irq;
                port->uartclk = MCF_BUSCLK;
@@ -702,7 +701,7 @@ static void __exit mcf_exit(void)
 module_init(mcf_init);
 module_exit(mcf_exit);
 
-MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>");
+MODULE_AUTHOR("Greg Ungerer <gerg@uclinux.org>");
 MODULE_DESCRIPTION("Freescale ColdFire UART driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:mcfuart");
index ec553f8eb2185be6be4ce7fc445ece43ccc386ce..1e9fb370600b5028d9961c835cfd3d15c65aa25c 100644 (file)
@@ -1231,34 +1231,29 @@ static int mxs_auart_probe(struct platform_device *pdev)
        int ret = 0;
        struct resource *r;
 
-       s = kzalloc(sizeof(struct mxs_auart_port), GFP_KERNEL);
-       if (!s) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
+       if (!s)
+               return -ENOMEM;
 
        ret = serial_mxs_probe_dt(s, pdev);
        if (ret > 0)
                s->port.line = pdev->id < 0 ? 0 : pdev->id;
        else if (ret < 0)
-               goto out_free;
+               return ret;
 
        if (of_id) {
                pdev->id_entry = of_id->data;
                s->devtype = pdev->id_entry->driver_data;
        }
 
-       s->clk = clk_get(&pdev->dev, NULL);
-       if (IS_ERR(s->clk)) {
-               ret = PTR_ERR(s->clk);
-               goto out_free;
-       }
+       s->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(s->clk))
+               return PTR_ERR(s->clk);
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!r) {
-               ret = -ENXIO;
-               goto out_free_clk;
-       }
+       if (!r)
+               return -ENXIO;
+
 
        s->port.mapbase = r->start;
        s->port.membase = ioremap(r->start, resource_size(r));
@@ -1273,9 +1268,10 @@ static int mxs_auart_probe(struct platform_device *pdev)
 
        s->irq = platform_get_irq(pdev, 0);
        s->port.irq = s->irq;
-       ret = request_irq(s->irq, mxs_auart_irq_handle, 0, dev_name(&pdev->dev), s);
+       ret = devm_request_irq(&pdev->dev, s->irq, mxs_auart_irq_handle, 0,
+                              dev_name(&pdev->dev), s);
        if (ret)
-               goto out_free_clk;
+               return ret;
 
        platform_set_drvdata(pdev, s);
 
@@ -1288,7 +1284,7 @@ static int mxs_auart_probe(struct platform_device *pdev)
         */
        ret = mxs_auart_request_gpio_irq(s);
        if (ret)
-               goto out_free_irq;
+               return ret;
 
        auart_port[s->port.line] = s;
 
@@ -1307,14 +1303,7 @@ static int mxs_auart_probe(struct platform_device *pdev)
 
 out_free_gpio_irq:
        mxs_auart_free_gpio_irq(s);
-out_free_irq:
        auart_port[pdev->id] = NULL;
-       free_irq(s->irq, s);
-out_free_clk:
-       clk_put(s->clk);
-out_free:
-       kfree(s);
-out:
        return ret;
 }
 
@@ -1323,13 +1312,8 @@ static int mxs_auart_remove(struct platform_device *pdev)
        struct mxs_auart_port *s = platform_get_drvdata(pdev);
 
        uart_remove_one_port(&auart_driver, &s->port);
-
        auart_port[pdev->id] = NULL;
-
        mxs_auart_free_gpio_irq(s);
-       clk_put(s->clk);
-       free_irq(s->irq, s);
-       kfree(s);
 
        return 0;
 }
index 2e1073da6719b8877a1d07e488ffc933200797d5..b1cf9a3b673af0ce9a8220e9493c263a11ae48ab 100644 (file)
@@ -63,7 +63,7 @@
 #define UART_ERRATA_i202_MDR1_ACCESS   BIT(0)
 #define UART_ERRATA_i291_DMA_FORCEIDLE BIT(1)
 
-#define DEFAULT_CLK_SPEED 48000000 /* 48Mhz*/
+#define DEFAULT_CLK_SPEED 48000000 /* 48Mhz */
 
 /* SCR register bitmasks */
 #define OMAP_UART_SCR_RX_TRIG_GRANU1_MASK              (1 << 7)
@@ -93,7 +93,7 @@
 /* WER = 0x7F
  * Enable module level wakeup in WER reg
  */
-#define OMAP_UART_WER_MOD_WKUP 0X7F
+#define OMAP_UART_WER_MOD_WKUP 0x7F
 
 /* Enable XON/XOFF flow control on output */
 #define OMAP_UART_SW_TX                0x08
@@ -114,7 +114,7 @@ struct uart_omap_dma {
        dma_addr_t              tx_buf_dma_phys;
        unsigned int            uart_base;
        /*
-        * Buffer for rx dma.It is not required for tx because the buffer
+        * Buffer for rx dma. It is not required for tx because the buffer
         * comes from port structure.
         */
        unsigned char           *rx_buf;
@@ -151,7 +151,7 @@ struct uart_omap_port {
        int                     use_dma;
        /*
         * Some bits in registers are cleared on a read, so they must
-        * be saved whenever the register is read but the bits will not
+        * be saved whenever the register is read, but the bits will not
         * be immediately processed.
         */
        unsigned int            lsr_break_flag;
index 107e807225752623c7f8cae56b17f00d4d003d37..024e5ecee98512b587b7c34bfdb36c89f454ffef 100644 (file)
@@ -28,6 +28,9 @@
 #define SUPPORT_SYSRQ
 #endif
 
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/ioport.h>
 #include <linux/io.h>
@@ -78,6 +81,10 @@ static void dbg(const char *fmt, ...)
 #define S3C24XX_SERIAL_MAJOR   204
 #define S3C24XX_SERIAL_MINOR   64
 
+#define S3C24XX_TX_PIO                 1
+#define S3C24XX_TX_DMA                 2
+#define S3C24XX_RX_PIO                 1
+#define S3C24XX_RX_DMA                 2
 /* macros to change one thing to another */
 
 #define tx_enabled(port) ((port)->unused[0])
@@ -154,39 +161,279 @@ static void s3c24xx_serial_rx_disable(struct uart_port *port)
 static void s3c24xx_serial_stop_tx(struct uart_port *port)
 {
        struct s3c24xx_uart_port *ourport = to_ourport(port);
+       struct s3c24xx_uart_dma *dma = ourport->dma;
+       struct circ_buf *xmit = &port->state->xmit;
+       struct dma_tx_state state;
+       int count;
 
-       if (tx_enabled(port)) {
-               if (s3c24xx_serial_has_interrupt_mask(port))
-                       __set_bit(S3C64XX_UINTM_TXD,
-                               portaddrl(port, S3C64XX_UINTM));
-               else
-                       disable_irq_nosync(ourport->tx_irq);
-               tx_enabled(port) = 0;
-               if (port->flags & UPF_CONS_FLOW)
-                       s3c24xx_serial_rx_enable(port);
+       if (!tx_enabled(port))
+               return;
+
+       if (s3c24xx_serial_has_interrupt_mask(port))
+               __set_bit(S3C64XX_UINTM_TXD,
+                       portaddrl(port, S3C64XX_UINTM));
+       else
+               disable_irq_nosync(ourport->tx_irq);
+
+       if (dma && dma->tx_chan && ourport->tx_in_progress == S3C24XX_TX_DMA) {
+               dmaengine_pause(dma->tx_chan);
+               dmaengine_tx_status(dma->tx_chan, dma->tx_cookie, &state);
+               dmaengine_terminate_all(dma->tx_chan);
+               dma_sync_single_for_cpu(ourport->port.dev,
+                       dma->tx_transfer_addr, dma->tx_size, DMA_TO_DEVICE);
+               async_tx_ack(dma->tx_desc);
+               count = dma->tx_bytes_requested - state.residue;
+               xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
+               port->icount.tx += count;
+       }
+
+       tx_enabled(port) = 0;
+       ourport->tx_in_progress = 0;
+
+       if (port->flags & UPF_CONS_FLOW)
+               s3c24xx_serial_rx_enable(port);
+
+       ourport->tx_mode = 0;
+}
+
+static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport);
+
+static void s3c24xx_serial_tx_dma_complete(void *args)
+{
+       struct s3c24xx_uart_port *ourport = args;
+       struct uart_port *port = &ourport->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       struct s3c24xx_uart_dma *dma = ourport->dma;
+       struct dma_tx_state state;
+       unsigned long flags;
+       int count;
+
+
+       dmaengine_tx_status(dma->tx_chan, dma->tx_cookie, &state);
+       count = dma->tx_bytes_requested - state.residue;
+       async_tx_ack(dma->tx_desc);
+
+       dma_sync_single_for_cpu(ourport->port.dev, dma->tx_transfer_addr,
+                               dma->tx_size, DMA_TO_DEVICE);
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
+       port->icount.tx += count;
+       ourport->tx_in_progress = 0;
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       s3c24xx_serial_start_next_tx(ourport);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void enable_tx_dma(struct s3c24xx_uart_port *ourport)
+{
+       struct uart_port *port = &ourport->port;
+       u32 ucon;
+
+       /* Mask Tx interrupt */
+       if (s3c24xx_serial_has_interrupt_mask(port))
+               __set_bit(S3C64XX_UINTM_TXD,
+                         portaddrl(port, S3C64XX_UINTM));
+       else
+               disable_irq_nosync(ourport->tx_irq);
+
+       /* Enable tx dma mode */
+       ucon = rd_regl(port, S3C2410_UCON);
+       ucon &= ~(S3C64XX_UCON_TXBURST_MASK | S3C64XX_UCON_TXMODE_MASK);
+       ucon |= (dma_get_cache_alignment() >= 16) ?
+               S3C64XX_UCON_TXBURST_16 : S3C64XX_UCON_TXBURST_1;
+       ucon |= S3C64XX_UCON_TXMODE_DMA;
+       wr_regl(port,  S3C2410_UCON, ucon);
+
+       ourport->tx_mode = S3C24XX_TX_DMA;
+}
+
+static void enable_tx_pio(struct s3c24xx_uart_port *ourport)
+{
+       struct uart_port *port = &ourport->port;
+       u32 ucon, ufcon;
+
+       /* Set ufcon txtrig */
+       ourport->tx_in_progress = S3C24XX_TX_PIO;
+       ufcon = rd_regl(port, S3C2410_UFCON);
+       wr_regl(port,  S3C2410_UFCON, ufcon);
+
+       /* Enable tx pio mode */
+       ucon = rd_regl(port, S3C2410_UCON);
+       ucon &= ~(S3C64XX_UCON_TXMODE_MASK);
+       ucon |= S3C64XX_UCON_TXMODE_CPU;
+       wr_regl(port,  S3C2410_UCON, ucon);
+
+       /* Unmask Tx interrupt */
+       if (s3c24xx_serial_has_interrupt_mask(port))
+               __clear_bit(S3C64XX_UINTM_TXD,
+                           portaddrl(port, S3C64XX_UINTM));
+       else
+               enable_irq(ourport->tx_irq);
+
+       ourport->tx_mode = S3C24XX_TX_PIO;
+}
+
+static void s3c24xx_serial_start_tx_pio(struct s3c24xx_uart_port *ourport)
+{
+       if (ourport->tx_mode != S3C24XX_TX_PIO)
+               enable_tx_pio(ourport);
+}
+
+static int s3c24xx_serial_start_tx_dma(struct s3c24xx_uart_port *ourport,
+                                     unsigned int count)
+{
+       struct uart_port *port = &ourport->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       struct s3c24xx_uart_dma *dma = ourport->dma;
+
+
+       if (ourport->tx_mode != S3C24XX_TX_DMA)
+               enable_tx_dma(ourport);
+
+       while (xmit->tail & (dma_get_cache_alignment() - 1)) {
+               if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
+                       return 0;
+               wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               count--;
        }
+
+       dma->tx_size = count & ~(dma_get_cache_alignment() - 1);
+       dma->tx_transfer_addr = dma->tx_addr + xmit->tail;
+
+       dma_sync_single_for_device(ourport->port.dev, dma->tx_transfer_addr,
+                               dma->tx_size, DMA_TO_DEVICE);
+
+       dma->tx_desc = dmaengine_prep_slave_single(dma->tx_chan,
+                               dma->tx_transfer_addr, dma->tx_size,
+                               DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
+       if (!dma->tx_desc) {
+               dev_err(ourport->port.dev, "Unable to get desc for Tx\n");
+               return -EIO;
+       }
+
+       dma->tx_desc->callback = s3c24xx_serial_tx_dma_complete;
+       dma->tx_desc->callback_param = ourport;
+       dma->tx_bytes_requested = dma->tx_size;
+
+       ourport->tx_in_progress = S3C24XX_TX_DMA;
+       dma->tx_cookie = dmaengine_submit(dma->tx_desc);
+       dma_async_issue_pending(dma->tx_chan);
+       return 0;
 }
 
-static void s3c24xx_serial_start_tx(struct uart_port *port)
+static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport)
+{
+       struct uart_port *port = &ourport->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       unsigned long count;
+
+       /* Get data size up to the end of buffer */
+       count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+
+       if (!count) {
+               s3c24xx_serial_stop_tx(port);
+               return;
+       }
+
+       if (!ourport->dma || !ourport->dma->tx_chan || count < port->fifosize)
+               s3c24xx_serial_start_tx_pio(ourport);
+       else
+               s3c24xx_serial_start_tx_dma(ourport, count);
+}
+
+void s3c24xx_serial_start_tx(struct uart_port *port)
 {
        struct s3c24xx_uart_port *ourport = to_ourport(port);
+       struct circ_buf *xmit = &port->state->xmit;
 
        if (!tx_enabled(port)) {
                if (port->flags & UPF_CONS_FLOW)
                        s3c24xx_serial_rx_disable(port);
 
-               if (s3c24xx_serial_has_interrupt_mask(port))
-                       __clear_bit(S3C64XX_UINTM_TXD,
-                               portaddrl(port, S3C64XX_UINTM));
-               else
-                       enable_irq(ourport->tx_irq);
                tx_enabled(port) = 1;
+               if (!ourport->dma || !ourport->dma->tx_chan) {
+                       if (s3c24xx_serial_has_interrupt_mask(port))
+                               __clear_bit(S3C64XX_UINTM_TXD,
+                                               portaddrl(port, S3C64XX_UINTM));
+                       else
+                               enable_irq(ourport->tx_irq);
+
+                       s3c24xx_serial_start_tx_pio(ourport);
+               }
+       }
+
+       if (ourport->dma && ourport->dma->tx_chan) {
+               if (!uart_circ_empty(xmit) && !ourport->tx_in_progress)
+                       s3c24xx_serial_start_next_tx(ourport);
+       }
+}
+
+static void s3c24xx_uart_copy_rx_to_tty(struct s3c24xx_uart_port *ourport,
+               struct tty_port *tty, int count)
+{
+       struct s3c24xx_uart_dma *dma = ourport->dma;
+       int copied;
+
+       if (!count)
+               return;
+
+       dma_sync_single_for_cpu(ourport->port.dev, dma->rx_addr,
+                               dma->rx_size, DMA_FROM_DEVICE);
+
+       ourport->port.icount.rx += count;
+       if (!tty) {
+               dev_err(ourport->port.dev, "No tty port\n");
+               return;
+       }
+       copied = tty_insert_flip_string(tty,
+                       ((unsigned char *)(ourport->dma->rx_buf)), count);
+       if (copied != count) {
+               WARN_ON(1);
+               dev_err(ourport->port.dev, "RxData copy to tty layer failed\n");
        }
 }
 
+static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
+                                    unsigned long ufstat);
+
+static void uart_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
+{
+       struct uart_port *port = &ourport->port;
+       struct tty_port *tty = &port->state->port;
+       unsigned int ch, ufstat;
+       unsigned int count;
+
+       ufstat = rd_regl(port, S3C2410_UFSTAT);
+       count = s3c24xx_serial_rx_fifocnt(ourport, ufstat);
+
+       if (!count)
+               return;
+
+       while (count-- > 0) {
+               ch = rd_regb(port, S3C2410_URXH);
+
+               ourport->port.icount.rx++;
+               tty_insert_flip_char(tty, ch, TTY_NORMAL);
+       }
+
+       tty_flip_buffer_push(tty);
+}
+
 static void s3c24xx_serial_stop_rx(struct uart_port *port)
 {
        struct s3c24xx_uart_port *ourport = to_ourport(port);
+       struct s3c24xx_uart_dma *dma = ourport->dma;
+       struct tty_port *t = &port->state->port;
+       struct dma_tx_state state;
+       enum dma_status dma_status;
+       unsigned int received;
 
        if (rx_enabled(port)) {
                dbg("s3c24xx_serial_stop_rx: port=%p\n", port);
@@ -197,6 +444,17 @@ static void s3c24xx_serial_stop_rx(struct uart_port *port)
                        disable_irq_nosync(ourport->rx_irq);
                rx_enabled(port) = 0;
        }
+       if (dma && dma->rx_chan) {
+               dmaengine_pause(dma->tx_chan);
+               dma_status = dmaengine_tx_status(dma->rx_chan,
+                               dma->rx_cookie, &state);
+               if (dma_status == DMA_IN_PROGRESS ||
+                       dma_status == DMA_PAUSED) {
+                       received = dma->rx_bytes_requested - state.residue;
+                       dmaengine_terminate_all(dma->rx_chan);
+                       s3c24xx_uart_copy_rx_to_tty(ourport, t, received);
+               }
+       }
 }
 
 static inline struct s3c24xx_uart_info
@@ -228,12 +486,157 @@ static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
        return (ufstat & info->rx_fifomask) >> info->rx_fifoshift;
 }
 
+static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport);
+static void s3c24xx_serial_rx_dma_complete(void *args)
+{
+       struct s3c24xx_uart_port *ourport = args;
+       struct uart_port *port = &ourport->port;
+
+       struct s3c24xx_uart_dma *dma = ourport->dma;
+       struct tty_port *t = &port->state->port;
+       struct tty_struct *tty = tty_port_tty_get(&ourport->port.state->port);
+
+       struct dma_tx_state state;
+       unsigned long flags;
+       int received;
+
+       dmaengine_tx_status(dma->rx_chan,  dma->rx_cookie, &state);
+       received  = dma->rx_bytes_requested - state.residue;
+       async_tx_ack(dma->rx_desc);
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       if (received)
+               s3c24xx_uart_copy_rx_to_tty(ourport, t, received);
+
+       if (tty) {
+               tty_flip_buffer_push(t);
+               tty_kref_put(tty);
+       }
+
+       s3c64xx_start_rx_dma(ourport);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport)
+{
+       struct s3c24xx_uart_dma *dma = ourport->dma;
+
+       dma_sync_single_for_device(ourport->port.dev, dma->rx_addr,
+                               dma->rx_size, DMA_FROM_DEVICE);
+
+       dma->rx_desc = dmaengine_prep_slave_single(dma->rx_chan,
+                               dma->rx_addr, dma->rx_size, DMA_DEV_TO_MEM,
+                               DMA_PREP_INTERRUPT);
+       if (!dma->rx_desc) {
+               dev_err(ourport->port.dev, "Unable to get desc for Rx\n");
+               return;
+       }
+
+       dma->rx_desc->callback = s3c24xx_serial_rx_dma_complete;
+       dma->rx_desc->callback_param = ourport;
+       dma->rx_bytes_requested = dma->rx_size;
+
+       dma->rx_cookie = dmaengine_submit(dma->rx_desc);
+       dma_async_issue_pending(dma->rx_chan);
+}
 
 /* ? - where has parity gone?? */
 #define S3C2410_UERSTAT_PARITY (0x1000)
 
-static irqreturn_t
-s3c24xx_serial_rx_chars(int irq, void *dev_id)
+static void enable_rx_dma(struct s3c24xx_uart_port *ourport)
+{
+       struct uart_port *port = &ourport->port;
+       unsigned int ucon;
+
+       /* set Rx mode to DMA mode */
+       ucon = rd_regl(port, S3C2410_UCON);
+       ucon &= ~(S3C64XX_UCON_RXBURST_MASK |
+                       S3C64XX_UCON_TIMEOUT_MASK |
+                       S3C64XX_UCON_EMPTYINT_EN |
+                       S3C64XX_UCON_DMASUS_EN |
+                       S3C64XX_UCON_TIMEOUT_EN |
+                       S3C64XX_UCON_RXMODE_MASK);
+       ucon |= S3C64XX_UCON_RXBURST_16 |
+                       0xf << S3C64XX_UCON_TIMEOUT_SHIFT |
+                       S3C64XX_UCON_EMPTYINT_EN |
+                       S3C64XX_UCON_TIMEOUT_EN |
+                       S3C64XX_UCON_RXMODE_DMA;
+       wr_regl(port, S3C2410_UCON, ucon);
+
+       ourport->rx_mode = S3C24XX_RX_DMA;
+}
+
+static void enable_rx_pio(struct s3c24xx_uart_port *ourport)
+{
+       struct uart_port *port = &ourport->port;
+       unsigned int ucon;
+
+       /* set Rx mode to DMA mode */
+       ucon = rd_regl(port, S3C2410_UCON);
+       ucon &= ~(S3C64XX_UCON_TIMEOUT_MASK |
+                       S3C64XX_UCON_EMPTYINT_EN |
+                       S3C64XX_UCON_DMASUS_EN |
+                       S3C64XX_UCON_TIMEOUT_EN |
+                       S3C64XX_UCON_RXMODE_MASK);
+       ucon |= 0xf << S3C64XX_UCON_TIMEOUT_SHIFT |
+                       S3C64XX_UCON_TIMEOUT_EN |
+                       S3C64XX_UCON_RXMODE_CPU;
+       wr_regl(port, S3C2410_UCON, ucon);
+
+       ourport->rx_mode = S3C24XX_RX_PIO;
+}
+
+static irqreturn_t s3c24xx_serial_rx_chars_dma(int irq, void *dev_id)
+{
+       unsigned int utrstat, ufstat, received;
+       struct s3c24xx_uart_port *ourport = dev_id;
+       struct uart_port *port = &ourport->port;
+       struct s3c24xx_uart_dma *dma = ourport->dma;
+       struct tty_struct *tty = tty_port_tty_get(&ourport->port.state->port);
+       struct tty_port *t = &port->state->port;
+       unsigned long flags;
+       struct dma_tx_state state;
+
+       utrstat = rd_regl(port, S3C2410_UTRSTAT);
+       ufstat = rd_regl(port, S3C2410_UFSTAT);
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       if (!(utrstat & S3C2410_UTRSTAT_TIMEOUT)) {
+               s3c64xx_start_rx_dma(ourport);
+               if (ourport->rx_mode == S3C24XX_RX_PIO)
+                       enable_rx_dma(ourport);
+               goto finish;
+       }
+
+       if (ourport->rx_mode == S3C24XX_RX_DMA) {
+               dmaengine_pause(dma->rx_chan);
+               dmaengine_tx_status(dma->rx_chan, dma->rx_cookie, &state);
+               dmaengine_terminate_all(dma->rx_chan);
+               received = dma->rx_bytes_requested - state.residue;
+               s3c24xx_uart_copy_rx_to_tty(ourport, t, received);
+
+               enable_rx_pio(ourport);
+       }
+
+       uart_rx_drain_fifo(ourport);
+
+       if (tty) {
+               tty_flip_buffer_push(t);
+               tty_kref_put(tty);
+       }
+
+       wr_regl(port, S3C2410_UTRSTAT, S3C2410_UTRSTAT_TIMEOUT);
+
+finish:
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t s3c24xx_serial_rx_chars_pio(int irq, void *dev_id)
 {
        struct s3c24xx_uart_port *ourport = dev_id;
        struct uart_port *port = &ourport->port;
@@ -324,16 +727,33 @@ out:
        return IRQ_HANDLED;
 }
 
+
+static irqreturn_t s3c24xx_serial_rx_chars(int irq, void *dev_id)
+{
+       struct s3c24xx_uart_port *ourport = dev_id;
+
+       if (ourport->dma && ourport->dma->rx_chan)
+               return s3c24xx_serial_rx_chars_dma(irq, dev_id);
+       return s3c24xx_serial_rx_chars_pio(irq, dev_id);
+}
+
 static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
 {
        struct s3c24xx_uart_port *ourport = id;
        struct uart_port *port = &ourport->port;
        struct circ_buf *xmit = &port->state->xmit;
        unsigned long flags;
-       int count = port->fifosize;
+       int count;
 
        spin_lock_irqsave(&port->lock, flags);
 
+       count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+
+       if (ourport->dma && ourport->dma->tx_chan && count >= port->fifosize) {
+               s3c24xx_serial_start_tx_dma(ourport, count);
+               goto out;
+       }
+
        if (port->x_char) {
                wr_regb(port, S3C2410_UTXH, port->x_char);
                port->icount.tx++;
@@ -352,6 +772,7 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
 
        /* try and drain the buffer... */
 
+       count = port->fifosize;
        while (!uart_circ_empty(xmit) && count-- > 0) {
                if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
                        break;
@@ -453,6 +874,93 @@ static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
        spin_unlock_irqrestore(&port->lock, flags);
 }
 
+static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
+{
+       struct s3c24xx_uart_dma *dma = p->dma;
+       dma_cap_mask_t mask;
+       unsigned long flags;
+
+       /* Default slave configuration parameters */
+       dma->rx_conf.direction          = DMA_DEV_TO_MEM;
+       dma->rx_conf.src_addr_width     = DMA_SLAVE_BUSWIDTH_1_BYTE;
+       dma->rx_conf.src_addr           = p->port.mapbase + S3C2410_URXH;
+       dma->rx_conf.src_maxburst       = 16;
+
+       dma->tx_conf.direction          = DMA_MEM_TO_DEV;
+       dma->tx_conf.dst_addr_width     = DMA_SLAVE_BUSWIDTH_1_BYTE;
+       dma->tx_conf.dst_addr           = p->port.mapbase + S3C2410_UTXH;
+       if (dma_get_cache_alignment() >= 16)
+               dma->tx_conf.dst_maxburst = 16;
+       else
+               dma->tx_conf.dst_maxburst = 1;
+
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+
+       dma->rx_chan = dma_request_slave_channel_compat(mask, dma->fn,
+                                       dma->rx_param, p->port.dev, "rx");
+       if (!dma->rx_chan)
+               return -ENODEV;
+
+       dmaengine_slave_config(dma->rx_chan, &dma->rx_conf);
+
+       dma->tx_chan = dma_request_slave_channel_compat(mask, dma->fn,
+                                       dma->tx_param, p->port.dev, "tx");
+       if (!dma->tx_chan) {
+               dma_release_channel(dma->rx_chan);
+               return -ENODEV;
+       }
+
+       dmaengine_slave_config(dma->tx_chan, &dma->tx_conf);
+
+       /* RX buffer */
+       dma->rx_size = PAGE_SIZE;
+
+       dma->rx_buf = kmalloc(dma->rx_size, GFP_KERNEL);
+
+       if (!dma->rx_buf) {
+               dma_release_channel(dma->rx_chan);
+               dma_release_channel(dma->tx_chan);
+               return -ENOMEM;
+       }
+
+       dma->rx_addr = dma_map_single(dma->rx_chan->device->dev, dma->rx_buf,
+                               dma->rx_size, DMA_FROM_DEVICE);
+
+       spin_lock_irqsave(&p->port.lock, flags);
+
+       /* TX buffer */
+       dma->tx_addr = dma_map_single(dma->tx_chan->device->dev,
+                               p->port.state->xmit.buf,
+                               UART_XMIT_SIZE, DMA_TO_DEVICE);
+
+       spin_unlock_irqrestore(&p->port.lock, flags);
+
+       return 0;
+}
+
+static void s3c24xx_serial_release_dma(struct s3c24xx_uart_port *p)
+{
+       struct s3c24xx_uart_dma *dma = p->dma;
+
+       if (dma->rx_chan) {
+               dmaengine_terminate_all(dma->rx_chan);
+               dma_unmap_single(dma->rx_chan->device->dev, dma->rx_addr,
+                               dma->rx_size, DMA_FROM_DEVICE);
+               kfree(dma->rx_buf);
+               dma_release_channel(dma->rx_chan);
+               dma->rx_chan = NULL;
+       }
+
+       if (dma->tx_chan) {
+               dmaengine_terminate_all(dma->tx_chan);
+               dma_unmap_single(dma->tx_chan->device->dev, dma->tx_addr,
+                               UART_XMIT_SIZE, DMA_TO_DEVICE);
+               dma_release_channel(dma->tx_chan);
+               dma->tx_chan = NULL;
+       }
+}
+
 static void s3c24xx_serial_shutdown(struct uart_port *port)
 {
        struct s3c24xx_uart_port *ourport = to_ourport(port);
@@ -478,6 +986,11 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)
                wr_regl(port, S3C64XX_UINTP, 0xf);
                wr_regl(port, S3C64XX_UINTM, 0xf);
        }
+
+       if (ourport->dma)
+               s3c24xx_serial_release_dma(ourport);
+
+       ourport->tx_in_progress = 0;
 }
 
 static int s3c24xx_serial_startup(struct uart_port *port)
@@ -529,12 +1042,21 @@ err:
 static int s3c64xx_serial_startup(struct uart_port *port)
 {
        struct s3c24xx_uart_port *ourport = to_ourport(port);
+       unsigned long flags;
+       unsigned int ufcon;
        int ret;
 
        dbg("s3c64xx_serial_startup: port=%p (%08llx,%p)\n",
            port, (unsigned long long)port->mapbase, port->membase);
 
        wr_regl(port, S3C64XX_UINTM, 0xf);
+       if (ourport->dma) {
+               ret = s3c24xx_serial_request_dma(ourport);
+               if (ret < 0) {
+                       dev_warn(port->dev, "DMA request failed\n");
+                       return ret;
+               }
+       }
 
        ret = request_irq(port->irq, s3c64xx_serial_handle_irq, IRQF_SHARED,
                          s3c24xx_serial_portname(port), ourport);
@@ -549,8 +1071,20 @@ static int s3c64xx_serial_startup(struct uart_port *port)
        tx_enabled(port) = 0;
        ourport->tx_claimed = 1;
 
+       spin_lock_irqsave(&port->lock, flags);
+
+       ufcon = rd_regl(port, S3C2410_UFCON);
+       ufcon |= S3C2410_UFCON_RESETRX | S3C2410_UFCON_RESETTX |
+                       S5PV210_UFCON_RXTRIG8;
+       wr_regl(port, S3C2410_UFCON, ufcon);
+
+       enable_rx_pio(ourport);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
        /* Enable Rx Interrupt */
        __clear_bit(S3C64XX_UINTM_RXD, portaddrl(port, S3C64XX_UINTM));
+
        dbg("s3c64xx_serial_startup ok\n");
        return ret;
 }
@@ -1209,6 +1743,18 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
        ret = platform_get_irq(platdev, 1);
        if (ret > 0)
                ourport->tx_irq = ret;
+       /*
+        * DMA is currently supported only on DT platforms, if DMA properties
+        * are specified.
+        */
+       if (platdev->dev.of_node && of_find_property(platdev->dev.of_node,
+                                                    "dmas", NULL)) {
+               ourport->dma = devm_kzalloc(port->dev,
+                                           sizeof(*ourport->dma),
+                                           GFP_KERNEL);
+               if (!ourport->dma)
+                       return -ENOMEM;
+       }
 
        ourport->clk    = clk_get(&platdev->dev, "uart");
        if (IS_ERR(ourport->clk)) {
index eb071dd19b2d13deb189afba8a9bf6364d29e9ed..d275032aa68d47ee68c42a0370ff7eecc42fb192 100644 (file)
@@ -12,6 +12,8 @@
  * published by the Free Software Foundation.
 */
 
+#include <linux/dmaengine.h>
+
 struct s3c24xx_uart_info {
        char                    *name;
        unsigned int            type;
@@ -41,6 +43,40 @@ struct s3c24xx_serial_drv_data {
        unsigned int                    fifosize[CONFIG_SERIAL_SAMSUNG_UARTS];
 };
 
+struct s3c24xx_uart_dma {
+       dma_filter_fn                   fn;
+       void                            *rx_param;
+       void                            *tx_param;
+
+       unsigned int                    rx_chan_id;
+       unsigned int                    tx_chan_id;
+
+       struct dma_slave_config         rx_conf;
+       struct dma_slave_config         tx_conf;
+
+       struct dma_chan                 *rx_chan;
+       struct dma_chan                 *tx_chan;
+
+       dma_addr_t                      rx_addr;
+       dma_addr_t                      tx_addr;
+
+       dma_cookie_t                    rx_cookie;
+       dma_cookie_t                    tx_cookie;
+
+       char                            *rx_buf;
+
+       dma_addr_t                      tx_transfer_addr;
+
+       size_t                          rx_size;
+       size_t                          tx_size;
+
+       struct dma_async_tx_descriptor  *tx_desc;
+       struct dma_async_tx_descriptor  *rx_desc;
+
+       int                             tx_bytes_requested;
+       int                             rx_bytes_requested;
+};
+
 struct s3c24xx_uart_port {
        unsigned char                   rx_claimed;
        unsigned char                   tx_claimed;
@@ -50,6 +86,10 @@ struct s3c24xx_uart_port {
        unsigned int                    rx_irq;
        unsigned int                    tx_irq;
 
+       unsigned int                    tx_in_progress;
+       unsigned int                    tx_mode;
+       unsigned int                    rx_mode;
+
        struct s3c24xx_uart_info        *info;
        struct clk                      *clk;
        struct clk                      *baudclk;
@@ -59,6 +99,8 @@ struct s3c24xx_uart_port {
        /* reference to platform data */
        struct s3c2410_uartcfg          *cfg;
 
+       struct s3c24xx_uart_dma         *dma;
+
 #ifdef CONFIG_CPU_FREQ
        struct notifier_block           freq_transition;
 #endif
index b269f6bd16d69f67126d444e79ef154dabbe573e..27ed0e960880990c810fe4190e28f03dd455db4f 100644 (file)
@@ -177,7 +177,7 @@ static void sirfsoc_uart_stop_tx(struct uart_port *port)
                        dmaengine_pause(sirfport->tx_dma_chan);
                        sirfport->tx_dma_state = TX_DMA_PAUSE;
                } else {
-                       if (!sirfport->is_marco)
+                       if (!sirfport->is_atlas7)
                                wr_regl(port, ureg->sirfsoc_int_en_reg,
                                rd_regl(port, ureg->sirfsoc_int_en_reg) &
                                ~uint_en->sirfsoc_txfifo_empty_en);
@@ -186,7 +186,7 @@ static void sirfsoc_uart_stop_tx(struct uart_port *port)
                                uint_en->sirfsoc_txfifo_empty_en);
                }
        } else {
-               if (!sirfport->is_marco)
+               if (!sirfport->is_atlas7)
                        wr_regl(port, ureg->sirfsoc_int_en_reg,
                                rd_regl(port, ureg->sirfsoc_int_en_reg) &
                                ~uint_en->sirfsoc_txfifo_empty_en);
@@ -217,7 +217,7 @@ static void sirfsoc_uart_tx_with_dma(struct sirfsoc_uart_port *sirfport)
        }
        if (sirfport->tx_dma_state == TX_DMA_RUNNING)
                return;
-       if (!sirfport->is_marco)
+       if (!sirfport->is_atlas7)
                wr_regl(port, ureg->sirfsoc_int_en_reg,
                                rd_regl(port, ureg->sirfsoc_int_en_reg)&
                                ~(uint_en->sirfsoc_txfifo_empty_en));
@@ -244,7 +244,7 @@ static void sirfsoc_uart_tx_with_dma(struct sirfsoc_uart_port *sirfport)
                }
                if (tran_size < 4)
                        sirfsoc_uart_pio_tx_chars(sirfport, tran_size);
-               if (!sirfport->is_marco)
+               if (!sirfport->is_atlas7)
                        wr_regl(port, ureg->sirfsoc_int_en_reg,
                                rd_regl(port, ureg->sirfsoc_int_en_reg)|
                                uint_en->sirfsoc_txfifo_empty_en);
@@ -293,7 +293,7 @@ static void sirfsoc_uart_start_tx(struct uart_port *port)
                sirfsoc_uart_pio_tx_chars(sirfport,
                        SIRFSOC_UART_IO_TX_REASONABLE_CNT);
                wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START);
-               if (!sirfport->is_marco)
+               if (!sirfport->is_atlas7)
                        wr_regl(port, ureg->sirfsoc_int_en_reg,
                                        rd_regl(port, ureg->sirfsoc_int_en_reg)|
                                        uint_en->sirfsoc_txfifo_empty_en);
@@ -311,7 +311,7 @@ static void sirfsoc_uart_stop_rx(struct uart_port *port)
 
        wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
        if (sirfport->rx_dma_chan) {
-               if (!sirfport->is_marco)
+               if (!sirfport->is_atlas7)
                        wr_regl(port, ureg->sirfsoc_int_en_reg,
                                rd_regl(port, ureg->sirfsoc_int_en_reg) &
                                ~(SIRFUART_RX_DMA_INT_EN(port, uint_en) |
@@ -322,7 +322,7 @@ static void sirfsoc_uart_stop_rx(struct uart_port *port)
                                        uint_en->sirfsoc_rx_done_en);
                dmaengine_terminate_all(sirfport->rx_dma_chan);
        } else {
-               if (!sirfport->is_marco)
+               if (!sirfport->is_atlas7)
                        wr_regl(port, ureg->sirfsoc_int_en_reg,
                                rd_regl(port, ureg->sirfsoc_int_en_reg)&
                                ~(SIRFUART_RX_IO_INT_EN(port, uint_en)));
@@ -344,7 +344,7 @@ static void sirfsoc_uart_disable_ms(struct uart_port *port)
        if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
                wr_regl(port, ureg->sirfsoc_afc_ctrl,
                                rd_regl(port, ureg->sirfsoc_afc_ctrl) & ~0x3FF);
-               if (!sirfport->is_marco)
+               if (!sirfport->is_atlas7)
                        wr_regl(port, ureg->sirfsoc_int_en_reg,
                                        rd_regl(port, ureg->sirfsoc_int_en_reg)&
                                        ~uint_en->sirfsoc_cts_en);
@@ -380,7 +380,7 @@ static void sirfsoc_uart_enable_ms(struct uart_port *port)
                wr_regl(port, ureg->sirfsoc_afc_ctrl,
                                rd_regl(port, ureg->sirfsoc_afc_ctrl) |
                                SIRFUART_AFC_TX_EN | SIRFUART_AFC_RX_EN);
-               if (!sirfport->is_marco)
+               if (!sirfport->is_atlas7)
                        wr_regl(port, ureg->sirfsoc_int_en_reg,
                                        rd_regl(port, ureg->sirfsoc_int_en_reg)
                                        | uint_en->sirfsoc_cts_en);
@@ -544,7 +544,7 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
                sirfport->rx_io_count = 0;
                wr_regl(port, ureg->sirfsoc_int_st_reg,
                                uint_st->sirfsoc_rx_done);
-               if (!sirfport->is_marco)
+               if (!sirfport->is_atlas7)
                        wr_regl(port, ureg->sirfsoc_int_en_reg,
                                rd_regl(port, ureg->sirfsoc_int_en_reg) &
                                ~(uint_en->sirfsoc_rx_done_en));
@@ -555,7 +555,7 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
        } else {
                wr_regl(port, ureg->sirfsoc_int_st_reg,
                                uint_st->sirfsoc_rx_done);
-               if (!sirfport->is_marco)
+               if (!sirfport->is_atlas7)
                        wr_regl(port, ureg->sirfsoc_int_en_reg,
                                rd_regl(port, ureg->sirfsoc_int_en_reg) |
                                (uint_en->sirfsoc_rx_done_en));
@@ -578,7 +578,7 @@ static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport)
        dmaengine_terminate_all(sirfport->rx_dma_chan);
        sirfport->rx_dma_items[sirfport->rx_issued].xmit.head =
                SIRFSOC_RX_DMA_BUF_SIZE - tx_state.residue;
-       if (!sirfport->is_marco)
+       if (!sirfport->is_atlas7)
                wr_regl(port, ureg->sirfsoc_int_en_reg,
                        rd_regl(port, ureg->sirfsoc_int_en_reg) &
                        ~(uint_en->sirfsoc_rx_timeout_en));
@@ -598,7 +598,7 @@ static void sirfsoc_uart_handle_rx_done(struct sirfsoc_uart_port *sirfport)
        sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
        if (sirfport->rx_io_count == 4) {
                sirfport->rx_io_count = 0;
-               if (!sirfport->is_marco)
+               if (!sirfport->is_atlas7)
                        wr_regl(port, ureg->sirfsoc_int_en_reg,
                                rd_regl(port, ureg->sirfsoc_int_en_reg) &
                                ~(uint_en->sirfsoc_rx_done_en));
@@ -748,7 +748,7 @@ static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port)
        for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++)
                sirfsoc_rx_submit_one_dma_desc(port, i);
        sirfport->rx_completed = sirfport->rx_issued = 0;
-       if (!sirfport->is_marco)
+       if (!sirfport->is_atlas7)
                wr_regl(port, ureg->sirfsoc_int_en_reg,
                                rd_regl(port, ureg->sirfsoc_int_en_reg) |
                                SIRFUART_RX_DMA_INT_EN(port, uint_en));
@@ -770,7 +770,7 @@ static void sirfsoc_uart_start_rx(struct uart_port *port)
        if (sirfport->rx_dma_chan)
                sirfsoc_uart_start_next_rx_dma(port);
        else {
-               if (!sirfport->is_marco)
+               if (!sirfport->is_atlas7)
                        wr_regl(port, ureg->sirfsoc_int_en_reg,
                                rd_regl(port, ureg->sirfsoc_int_en_reg) |
                                SIRFUART_RX_IO_INT_EN(port, uint_en));
@@ -1124,7 +1124,7 @@ static void sirfsoc_uart_shutdown(struct uart_port *port)
 {
        struct sirfsoc_uart_port *sirfport = to_sirfport(port);
        struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
-       if (!sirfport->is_marco)
+       if (!sirfport->is_atlas7)
                wr_regl(port, ureg->sirfsoc_int_en_reg, 0);
        else
                wr_regl(port, SIRFUART_INT_EN_CLR, ~0UL);
@@ -1271,7 +1271,7 @@ static struct uart_driver sirfsoc_uart_drv = {
 
 static struct of_device_id sirfsoc_uart_ids[] = {
        { .compatible = "sirf,prima2-uart", .data = &sirfsoc_uart,},
-       { .compatible = "sirf,marco-uart", .data = &sirfsoc_uart},
+       { .compatible = "sirf,atlas7-uart", .data = &sirfsoc_uart},
        { .compatible = "sirf,prima2-usp-uart", .data = &sirfsoc_usp},
        {}
 };
@@ -1350,8 +1350,8 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
                gpio_direction_output(sirfport->rts_gpio, 1);
        }
 usp_no_flow_control:
-       if (of_device_is_compatible(pdev->dev.of_node, "sirf,marco-uart"))
-               sirfport->is_marco = true;
+       if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart"))
+               sirfport->is_atlas7 = true;
 
        if (of_property_read_u32(pdev->dev.of_node,
                        "fifosize",
@@ -1393,7 +1393,7 @@ usp_no_flow_control:
                goto err;
        }
        port->uartclk = clk_get_rate(sirfport->clk);
-       if (of_device_is_compatible(pdev->dev.of_node, "sirf,marco-bt-uart")) {
+       if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-bt-uart")) {
                sirfport->clk_general = devm_clk_get(&pdev->dev, "general");
                if (IS_ERR(sirfport->clk_general)) {
                        ret = PTR_ERR(sirfport->clk_general);
index 275d038939901d7d95fe84da938f1c4a1b896b54..727eb6b88fff0f28e57d44dc789223f2855231b3 100644 (file)
@@ -421,8 +421,8 @@ struct sirfsoc_uart_port {
        bool                            is_bt_uart;
        struct clk                      *clk_general;
        struct clk                      *clk_noc;
-       /* for SiRFmarco, there are SET/CLR for UART_INT_EN */
-       bool                            is_marco;
+       /* for SiRFatlas7, there are SET/CLR for UART_INT_EN */
+       bool                            is_atlas7;
        struct sirfsoc_uart_register    *uart_reg;
        struct dma_chan                 *rx_dma_chan;
        struct dma_chan                 *tx_dma_chan;
index 4486741190c47d52d8079f360081d99085ce82c4..a872389dc0bcd8309c6138057c90c9c0abf1f089 100644 (file)
@@ -46,12 +46,8 @@ EXPORT_SYMBOL(tty_unlock);
 
 void __lockfunc tty_lock_slave(struct tty_struct *tty)
 {
-       if (tty && tty != tty->link) {
-               WARN_ON(!mutex_is_locked(&tty->link->legacy_mutex) ||
-                       !tty->driver->type == TTY_DRIVER_TYPE_PTY ||
-                       !tty->driver->type == PTY_TYPE_SLAVE);
+       if (tty && tty != tty->link)
                tty_lock(tty);
-       }
 }
 
 void __lockfunc tty_unlock_slave(struct tty_struct *tty)
index f3fbbbca9bde1ba4d9a9a5ccda71f96b2d464eac..5d36c2358b4761adcc7acf5fb6e66ac309a8542a 100644 (file)
@@ -3318,11 +3318,8 @@ static int vt_bind(struct con_driver *con)
                if (first == 0 && last == MAX_NR_CONSOLES -1)
                        deflt = 1;
 
-               if (first != -1) {
-                       console_lock();
+               if (first != -1)
                        do_bind_con_driver(csw, first, last, deflt);
-                       console_unlock();
-               }
 
                first = -1;
                last = -1;
@@ -3362,9 +3359,7 @@ static int vt_unbind(struct con_driver *con)
                        deflt = 1;
 
                if (first != -1) {
-                       console_lock();
                        ret = do_unbind_con_driver(csw, first, last, deflt);
-                       console_unlock();
                        if (ret != 0)
                                return ret;
                }
@@ -3394,11 +3389,15 @@ static ssize_t store_bind(struct device *dev, struct device_attribute *attr,
        struct con_driver *con = dev_get_drvdata(dev);
        int bind = simple_strtoul(buf, NULL, 0);
 
+       console_lock();
+
        if (bind)
                vt_bind(con);
        else
                vt_unbind(con);
 
+       console_unlock();
+
        return count;
 }
 
@@ -3665,8 +3664,7 @@ int do_unregister_con_driver(const struct consw *csw)
        for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
                struct con_driver *con_driver = &registered_con_driver[i];
 
-               if (con_driver->con == csw &&
-                   con_driver->flag & CON_DRIVER_FLAG_INIT) {
+               if (con_driver->con == csw) {
                        vtconsole_deinit_device(con_driver);
                        device_destroy(vtconsole_class,
                                       MKDEV(0, con_driver->node));
index e02acf0a0ec995f6b2751f40b1e6c82c5f776bd0..245b959f1ff6eea60c7a03914dc63c1c31eb6c5b 100644 (file)
@@ -126,6 +126,7 @@ extern int serial8250_do_startup(struct uart_port *port);
 extern void serial8250_do_shutdown(struct uart_port *port);
 extern void serial8250_do_pm(struct uart_port *port, unsigned int state,
                             unsigned int oldstate);
+extern void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl);
 extern int fsl8250_handle_irq(struct uart_port *port);
 int serial8250_handle_irq(struct uart_port *port, unsigned int iir);
 unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr);
index 057038cf27880d34a17e428fb51baccf563692c2..a0c7033d5f91dd190756ec6b2209d7e6e9aeaf88 100644 (file)
@@ -123,6 +123,7 @@ struct uart_port {
        void                    (*set_termios)(struct uart_port *,
                                               struct ktermios *new,
                                               struct ktermios *old);
+       void                    (*set_mctrl)(struct uart_port *, unsigned int);
        int                     (*startup)(struct uart_port *port);
        void                    (*shutdown)(struct uart_port *port);
        void                    (*throttle)(struct uart_port *port);
index e6fc9567690bc6d5fe59ac0dfcc88cbeaac01fc8..a7f004a3c177b143a18eb17d2fdbd41c17aa0268 100644 (file)
                                   S3C2410_UCON_RXIRQMODE | \
                                   S3C2410_UCON_RXFIFO_TOI)
 
+#define S3C64XX_UCON_TXBURST_1          (0<<20)
+#define S3C64XX_UCON_TXBURST_4          (1<<20)
+#define S3C64XX_UCON_TXBURST_8          (2<<20)
+#define S3C64XX_UCON_TXBURST_16         (3<<20)
+#define S3C64XX_UCON_TXBURST_MASK       (0xf<<20)
+#define S3C64XX_UCON_RXBURST_1          (0<<16)
+#define S3C64XX_UCON_RXBURST_4          (1<<16)
+#define S3C64XX_UCON_RXBURST_8          (2<<16)
+#define S3C64XX_UCON_RXBURST_16         (3<<16)
+#define S3C64XX_UCON_RXBURST_MASK       (0xf<<16)
+#define S3C64XX_UCON_TIMEOUT_SHIFT      (12)
+#define S3C64XX_UCON_TIMEOUT_MASK       (0xf<<12)
+#define S3C64XX_UCON_EMPTYINT_EN        (1<<11)
+#define S3C64XX_UCON_DMASUS_EN          (1<<10)
+#define S3C64XX_UCON_TXINT_LEVEL        (1<<9)
+#define S3C64XX_UCON_RXINT_LEVEL        (1<<8)
+#define S3C64XX_UCON_TIMEOUT_EN         (1<<7)
+#define S3C64XX_UCON_ERRINT_EN          (1<<6)
+#define S3C64XX_UCON_TXMODE_DMA         (2<<2)
+#define S3C64XX_UCON_TXMODE_CPU         (1<<2)
+#define S3C64XX_UCON_TXMODE_MASK        (3<<2)
+#define S3C64XX_UCON_RXMODE_DMA         (2<<0)
+#define S3C64XX_UCON_RXMODE_CPU         (1<<0)
+#define S3C64XX_UCON_RXMODE_MASK        (3<<0)
+
 #define S3C2410_UFCON_FIFOMODE   (1<<0)
 #define S3C2410_UFCON_TXTRIG0    (0<<6)
 #define S3C2410_UFCON_RXTRIG8    (1<<4)
 #define S3C2440_UFSTAT_TXMASK    (63<<8)
 #define S3C2440_UFSTAT_RXMASK    (63)
 
+#define S3C2410_UTRSTAT_TIMEOUT   (1<<3)
 #define S3C2410_UTRSTAT_TXE      (1<<2)
 #define S3C2410_UTRSTAT_TXFE     (1<<1)
 #define S3C2410_UTRSTAT_RXDR     (1<<0)
 #define S3C64XX_UINTM          0x38
 
 #define S3C64XX_UINTM_RXD      (0)
+#define S3C64XX_UINTM_ERROR     (1)
 #define S3C64XX_UINTM_TXD      (2)
 #define S3C64XX_UINTM_RXD_MSK  (1 << S3C64XX_UINTM_RXD)
+#define S3C64XX_UINTM_ERR_MSK   (1 << S3C64XX_UINTM_ERROR)
 #define S3C64XX_UINTM_TXD_MSK  (1 << S3C64XX_UINTM_TXD)
 
 /* Following are specific to S5PV210 */
index c17218094f187511710d4f25f341216c531ca111..ee628c489e47f79a8a2b33ef1f4f6ac58fab662f 100644 (file)
@@ -55,7 +55,8 @@
 #define PORT_ALTR_16550_F64 27 /* Altera 16550 UART with 64 FIFOs */
 #define PORT_ALTR_16550_F128 28 /* Altera 16550 UART with 128 FIFOs */
 #define PORT_RT2880    29      /* Ralink RT2880 internal UART */
-#define PORT_MAX_8250  29      /* max port ID */
+#define PORT_16550A_FSL64 30   /* Freescale 16550 UART with 64 FIFOs */
+#define PORT_MAX_8250  30      /* max port ID */
 
 /*
  * ARM specific type numbers.  These are not currently guaranteed
 /* MESON */
 #define PORT_MESON     109
 
+/* Conexant Digicolor */
+#define PORT_DIGICOLOR 110
+
 #endif /* _UAPILINUX_SERIAL_CORE_H */
index 53af3b790129ee61d195288be4d278f67ca738e7..00adb01fa5f38f53858ea2bb265f2b040948f4cf 100644 (file)
@@ -86,7 +86,8 @@
 #define UART_FCR6_T_TRIGGER_8  0x10 /* Mask for transmit trigger set at 8 */
 #define UART_FCR6_T_TRIGGER_24  0x20 /* Mask for transmit trigger set at 24 */
 #define UART_FCR6_T_TRIGGER_30 0x30 /* Mask for transmit trigger set at 30 */
-#define UART_FCR7_64BYTE       0x20 /* Go into 64 byte mode (TI16C750) */
+#define UART_FCR7_64BYTE       0x20 /* Go into 64 byte mode (TI16C750 and
+                                       some Freescale UARTs) */
 
 #define UART_FCR_R_TRIG_SHIFT          6
 #define UART_FCR_R_TRIG_BITS(x)                \
This page took 0.072737 seconds and 5 git commands to generate.