]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'tty/tty-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Thu, 5 Nov 2015 03:46:44 +0000 (14:46 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Thu, 5 Nov 2015 03:46:44 +0000 (14:46 +1100)
81 files changed:
Documentation/devicetree/bindings/serial/ingenic,uart.txt
Documentation/devicetree/bindings/serial/qcom,msm-uartdm.txt
Documentation/devicetree/bindings/serial/renesas,sci-serial.txt
Documentation/devicetree/bindings/serial/snps-dw-apb-uart.txt
Documentation/kernel-parameters.txt
Documentation/serial/driver
Documentation/serial/tty.txt
arch/arm64/include/asm/dcc.h [new file with mode: 0644]
drivers/char/pcmcia/synclink_cs.c
drivers/dma/hsu/Kconfig
drivers/dma/hsu/hsu.c
drivers/dma/hsu/hsu.h
drivers/dma/hsu/pci.c
drivers/isdn/i4l/isdn_tty.c
drivers/tty/cyclades.c
drivers/tty/hvc/Kconfig
drivers/tty/hvc/hvc_console.c
drivers/tty/hvc/hvc_dcc.c
drivers/tty/hvc/hvcs.c
drivers/tty/mips_ejtag_fdc.c
drivers/tty/n_r3964.c
drivers/tty/n_tty.c
drivers/tty/pty.c
drivers/tty/rocket.c
drivers/tty/serial/68328serial.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_ingenic.c
drivers/tty/serial/8250/8250_mid.c [new file with mode: 0644]
drivers/tty/serial/8250/8250_omap.c
drivers/tty/serial/8250/8250_pci.c
drivers/tty/serial/8250/8250_port.c
drivers/tty/serial/8250/Kconfig
drivers/tty/serial/8250/Makefile
drivers/tty/serial/Kconfig
drivers/tty/serial/altera_uart.c
drivers/tty/serial/amba-pl011.c
drivers/tty/serial/apbuart.c
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/clps711x.c
drivers/tty/serial/cpm_uart/cpm_uart_core.c
drivers/tty/serial/crisv10.c
drivers/tty/serial/fsl_lpuart.c
drivers/tty/serial/imx.c
drivers/tty/serial/lpc32xx_hs.c
drivers/tty/serial/men_z135_uart.c
drivers/tty/serial/mpc52xx_uart.c
drivers/tty/serial/mpsc.c
drivers/tty/serial/msm_serial.c
drivers/tty/serial/msm_serial.h
drivers/tty/serial/mxs-auart.c
drivers/tty/serial/of_serial.c
drivers/tty/serial/omap-serial.c
drivers/tty/serial/samsung.c
drivers/tty/serial/sc16is7xx.c
drivers/tty/serial/serial-tegra.c
drivers/tty/serial/serial_core.c
drivers/tty/serial/serial_mctrl_gpio.c
drivers/tty/serial/serial_mctrl_gpio.h
drivers/tty/serial/sh-sci.c
drivers/tty/serial/sh-sci.h
drivers/tty/serial/sprd_serial.c
drivers/tty/serial/st-asc.c
drivers/tty/serial/stm32-usart.c
drivers/tty/synclink.c
drivers/tty/synclink_gt.c
drivers/tty/synclinkmp.c
drivers/tty/sysrq.c
drivers/tty/tty_buffer.c
drivers/tty/tty_io.c
drivers/tty/tty_ldisc.c
drivers/tty/tty_port.c
drivers/usb/gadget/function/u_serial.c
include/linux/dma/hsu.h
include/linux/n_r3964.h
include/linux/platform_data/atmel.h
include/linux/platform_data/dma-hsu.h
include/linux/tty.h
net/irda/ircomm/ircomm_tty.c

index c2d3b3abe7d9ab17db07c9a60dc9f6318d651e61..02cb7fe59cb776281ec2cdf150ff661fcab9b4ce 100644 (file)
@@ -1,7 +1,8 @@
 * Ingenic SoC UART
 
 Required properties:
-- compatible : "ingenic,jz4740-uart" or "ingenic,jz4780-uart"
+- compatible : "ingenic,jz4740-uart", "ingenic,jz4760-uart",
+       "ingenic,jz4775-uart" or "ingenic,jz4780-uart"
 - reg : offset and length of the register set for the device.
 - interrupts : should contain uart interrupt.
 - clocks : phandles to the module & baud clocks.
index a2114c217376a5dbf17a6fecd448da307516fee2..182777fac9a24dfa9f52e7b5c8774d0ed4715f51 100644 (file)
@@ -26,6 +26,12 @@ Required properties:
 Optional properties:
 - dmas: Should contain dma specifiers for transmit and receive channels
 - dma-names: Should contain "tx" for transmit and "rx" for receive channels
+- qcom,tx-crci: Identificator <u32> for Client Rate Control Interface to be
+           used with TX DMA channel. Required when using DMA for transmission
+           with UARTDM v1.3 and bellow.
+- qcom,rx-crci: Identificator <u32> for Client Rate Control Interface to be
+           used with RX DMA channel. Required when using DMA for reception
+           with UARTDM v1.3 and bellow.
 
 Note: Aliases may be defined to ensure the correct ordering of the UARTs.
 The alias serialN will result in the UART being assigned port N.  If any
index e84b13a8eda34a151edcd9107aaa7b1510a20d8c..73f825e5e64488151b8a7b49c0f99f06f0edb73c 100644 (file)
@@ -23,6 +23,8 @@ Required properties:
     - "renesas,scifa-r8a7794" for R8A7794 (R-Car E2) SCIFA compatible UART.
     - "renesas,scifb-r8a7794" for R8A7794 (R-Car E2) SCIFB compatible UART.
     - "renesas,hscif-r8a7794" for R8A7794 (R-Car E2) HSCIF compatible UART.
+    - "renesas,scif-r8a7795" for R8A7795 (R-Car H3) SCIF compatible UART.
+    - "renesas,hscif-r8a7795" for R8A7795 (R-Car H3) HSCIF compatible UART.
     - "renesas,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART.
     - "renesas,scifb-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFB compatible UART.
     - "renesas,scif" for generic SCIF compatible UART.
index 289c40ed747042a70b13f9912dc0b5c443f7827e..12bbe9f22560c59d29ac8bd45bdbe5ad9be8bf2a 100644 (file)
@@ -15,6 +15,9 @@ The supplying peripheral clock can also be handled, needing a second property
        Required elements: "baudclk", "apb_pclk"
 
 Optional properties:
+- snps,uart-16550-compatible : reflects the value of UART_16550_COMPATIBLE
+  configuration parameter. Define this if your UART does not implement the busy
+  functionality.
 - resets : phandle to the parent reset controller.
 - reg-shift : quantity to shift the register offsets by.  If this property is
   not present then the register offsets are not shifted.
index 3262b0d62ef87ac5d1018dad00a1380dd1a07f4d..101573c07788945b4423e3d29dbbed9275ab5cda 100644 (file)
@@ -1033,6 +1033,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        serial port must already be setup and configured.
                        Options are not yet supported.
 
+               lpuart,<addr>
+               lpuart32,<addr>
+                       Use early console provided by Freescale LP UART driver
+                       found on Freescale Vybrid and QorIQ LS1021A processors.
+                       A valid base address must be provided, and the serial
+                       port must already be setup and configured.
+
        earlyprintk=    [X86,SH,BLACKFIN,ARM,M68k]
                        earlyprintk=vga
                        earlyprintk=efi
index c415b0ef449378db4698ca9552c54bdfb387a9d0..379468e12680dbfb1d4a3dd222fb617681ae1df7 100644 (file)
@@ -439,11 +439,13 @@ Modem control lines via GPIO
 
 Some helpers are provided in order to set/get modem control lines via GPIO.
 
-mctrl_gpio_init(dev, idx):
+mctrl_gpio_init(port, idx):
        This will get the {cts,rts,...}-gpios from device tree if they are
        present and request them, set direction etc, and return an
        allocated structure. devm_* functions are used, so there's no need
        to call mctrl_gpio_free().
+       As this sets up the irq handling make sure to not handle changes to the
+       gpio input lines in your driver, too.
 
 mctrl_gpio_free(dev, gpios):
        This will free the requested gpios in mctrl_gpio_init().
@@ -458,3 +460,9 @@ mctrl_gpio_set(gpios, mctrl):
 
 mctrl_gpio_get(gpios, mctrl):
        This will update mctrl with the gpios values.
+
+mctrl_gpio_enable_ms(gpios):
+       Enables irqs and handling of changes to the ms lines.
+
+mctrl_gpio_disable_ms(gpios):
+       Disables irqs and handling of changes to the ms lines.
index 973c8ad3f959fba7f722aafa6c89c5b29c40aaa9..bc3842dc323a629fae6ec4cf5de0f6d1d6d6f37d 100644 (file)
@@ -39,8 +39,13 @@ TTY side interfaces:
 open()         -       Called when the line discipline is attached to
                        the terminal. No other call into the line
                        discipline for this tty will occur until it
-                       completes successfully. Returning an error will
-                       prevent the ldisc from being attached. Can sleep.
+                       completes successfully. Should initialize any
+                       state needed by the ldisc, and set receive_room
+                       in the tty_struct to the maximum amount of data
+                       the line discipline is willing to accept from the
+                       driver with a single call to receive_buf().
+                       Returning an error will prevent the ldisc from
+                       being attached. Can sleep.
 
 close()                -       This is called on a terminal when the line
                        discipline is being unplugged. At the point of
@@ -52,9 +57,16 @@ hangup()     -       Called when the tty line is hung up.
                        No further calls into the ldisc code will occur.
                        The return value is ignored. Can sleep.
 
-write()                -       A process is writing data through the line
-                       discipline.  Multiple write calls are serialized
-                       by the tty layer for the ldisc.  May sleep. 
+read()         -       (optional) A process requests reading data from
+                       the line. Multiple read calls may occur in parallel
+                       and the ldisc must deal with serialization issues.
+                       If not defined, the process will receive an EIO
+                       error. May sleep.
+
+write()                -       (optional) A process requests writing data to the
+                       line. Multiple write calls are serialized by the
+                       tty layer for the ldisc. If not defined, the
+                       process will receive an EIO error. May sleep.
 
 flush_buffer() -       (optional) May be called at any point between
                        open and close, and instructs the line discipline
@@ -69,27 +81,33 @@ set_termios()       -       (optional) Called on termios structure changes.
                        termios semaphore so allowed to sleep. Serialized
                        against itself only.
 
-read()         -       Move data from the line discipline to the user.
-                       Multiple read calls may occur in parallel and the
-                       ldisc must deal with serialization issues. May 
-                       sleep.
-
-poll()         -       Check the status for the poll/select calls. Multiple
-                       poll calls may occur in parallel. May sleep.
+poll()         -       (optional) Check the status for the poll/select
+                       calls. Multiple poll calls may occur in parallel.
+                       May sleep.
 
-ioctl()                -       Called when an ioctl is handed to the tty layer
-                       that might be for the ldisc. Multiple ioctl calls
-                       may occur in parallel. May sleep. 
+ioctl()                -       (optional) Called when an ioctl is handed to the
+                       tty layer that might be for the ldisc. Multiple
+                       ioctl calls may occur in parallel. May sleep.
 
-compat_ioctl() -       Called when a 32 bit ioctl is handed to the tty layer
-                       that might be for the ldisc. Multiple ioctl calls
-                       may occur in parallel. May sleep.
+compat_ioctl() -       (optional) Called when a 32 bit ioctl is handed
+                       to the tty layer that might be for the ldisc.
+                       Multiple ioctl calls may occur in parallel.
+                       May sleep.
 
 Driver Side Interfaces:
 
-receive_buf()  -       Hand buffers of bytes from the driver to the ldisc
-                       for processing. Semantics currently rather
-                       mysterious 8(
+receive_buf()  -       (optional) Called by the low-level driver to hand
+                       a buffer of received bytes to the ldisc for
+                       processing. The number of bytes is guaranteed not
+                       to exceed the current value of tty->receive_room.
+                       All bytes must be processed.
+
+receive_buf2() -       (optional) Called by the low-level driver to hand
+                       a buffer of received bytes to the ldisc for
+                       processing. Returns the number of bytes processed.
+
+                       If both receive_buf() and receive_buf2() are
+                       defined, receive_buf2() should be preferred.
 
 write_wakeup() -       May be called at any point between open and close.
                        The TTY_DO_WRITE_WAKEUP flag indicates if a call
diff --git a/arch/arm64/include/asm/dcc.h b/arch/arm64/include/asm/dcc.h
new file mode 100644 (file)
index 0000000..65e0190
--- /dev/null
@@ -0,0 +1,55 @@
+/* Copyright (c) 2014-2015 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * A call to __dcc_getchar() or __dcc_putchar() is typically followed by
+ * a call to __dcc_getstatus().  We want to make sure that the CPU does
+ * not speculative read the DCC status before executing the read or write
+ * instruction.  That's what the ISBs are for.
+ *
+ * The 'volatile' ensures that the compiler does not cache the status bits,
+ * and instead reads the DCC register every time.
+ */
+#ifndef __ASM_DCC_H
+#define __ASM_DCC_H
+
+#include <asm/barrier.h>
+
+static inline u32 __dcc_getstatus(void)
+{
+       u32 ret;
+
+       asm volatile("mrs %0, mdccsr_el0" : "=r" (ret));
+
+       return ret;
+}
+
+static inline char __dcc_getchar(void)
+{
+       char c;
+
+       asm volatile("mrs %0, dbgdtrrx_el0" : "=r" (c));
+       isb();
+
+       return c;
+}
+
+static inline void __dcc_putchar(char c)
+{
+       /*
+        * The typecast is to make absolutely certain that 'c' is
+        * zero-extended.
+        */
+       asm volatile("msr dbgdtrtx_el0, %0"
+                       : : "r" ((unsigned long)(unsigned char)c));
+       isb();
+}
+
+#endif
index 7680d5213ff840a095e94b1ce666b41a266617c1..45df4bf914f89fc6ec1fb2398c272f1b6f0444b9 100644 (file)
@@ -2507,15 +2507,6 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp)
                printk("%s(%d):mgslpc_open(%s), old ref count = %d\n",
                         __FILE__, __LINE__, tty->driver->name, port->count);
 
-       /* If port is closing, signal caller to try again */
-       if (port->flags & ASYNC_CLOSING){
-               wait_event_interruptible_tty(tty, port->close_wait,
-                                            !(port->flags & ASYNC_CLOSING));
-               retval = ((port->flags & ASYNC_HUP_NOTIFY) ?
-                       -EAGAIN : -ERESTARTSYS);
-               goto cleanup;
-       }
-
        port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
        spin_lock_irqsave(&info->netlock, flags);
index 2810dca7061203e63f26ca47a488e776d10ebd89..c70841731a80ac95c3acc8f62acbfddfdac212a1 100644 (file)
@@ -5,10 +5,5 @@ config HSU_DMA
        select DMA_VIRTUAL_CHANNELS
 
 config HSU_DMA_PCI
-       tristate "High Speed UART DMA PCI driver"
-       depends on PCI
-       select HSU_DMA
-       help
-         Support the High Speed UART DMA on the platfroms that
-         enumerate it as a PCI device. For example, Intel Medfield
-         has integrated this HSU DMA controller.
+       tristate
+       depends on HSU_DMA && PCI
index 7669c7dd1e344c1347f6a4c4ac8e0f319d0e2f27..823ad728aecff9b0e2b9810a6aad297bb1bb7d54 100644 (file)
@@ -146,7 +146,7 @@ irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr)
        u32 sr;
 
        /* Sanity check */
-       if (nr >= chip->pdata->nr_channels)
+       if (nr >= chip->hsu->nr_channels)
                return IRQ_NONE;
 
        hsuc = &chip->hsu->chan[nr];
@@ -375,7 +375,6 @@ static void hsu_dma_free_chan_resources(struct dma_chan *chan)
 int hsu_dma_probe(struct hsu_dma_chip *chip)
 {
        struct hsu_dma *hsu;
-       struct hsu_dma_platform_data *pdata = chip->pdata;
        void __iomem *addr = chip->regs + chip->offset;
        unsigned short i;
        int ret;
@@ -386,25 +385,16 @@ int hsu_dma_probe(struct hsu_dma_chip *chip)
 
        chip->hsu = hsu;
 
-       if (!pdata) {
-               pdata = devm_kzalloc(chip->dev, sizeof(*pdata), GFP_KERNEL);
-               if (!pdata)
-                       return -ENOMEM;
+       /* Calculate nr_channels from the IO space length */
+       hsu->nr_channels = (chip->length - chip->offset) / HSU_DMA_CHAN_LENGTH;
 
-               chip->pdata = pdata;
-
-               /* Guess nr_channels from the IO space length */
-               pdata->nr_channels = (chip->length - chip->offset) /
-                                    HSU_DMA_CHAN_LENGTH;
-       }
-
-       hsu->chan = devm_kcalloc(chip->dev, pdata->nr_channels,
+       hsu->chan = devm_kcalloc(chip->dev, hsu->nr_channels,
                                 sizeof(*hsu->chan), GFP_KERNEL);
        if (!hsu->chan)
                return -ENOMEM;
 
        INIT_LIST_HEAD(&hsu->dma.channels);
-       for (i = 0; i < pdata->nr_channels; i++) {
+       for (i = 0; i < hsu->nr_channels; i++) {
                struct hsu_dma_chan *hsuc = &hsu->chan[i];
 
                hsuc->vchan.desc_free = hsu_dma_desc_free;
@@ -440,7 +430,7 @@ int hsu_dma_probe(struct hsu_dma_chip *chip)
        if (ret)
                return ret;
 
-       dev_info(chip->dev, "Found HSU DMA, %d channels\n", pdata->nr_channels);
+       dev_info(chip->dev, "Found HSU DMA, %d channels\n", hsu->nr_channels);
        return 0;
 }
 EXPORT_SYMBOL_GPL(hsu_dma_probe);
@@ -452,7 +442,7 @@ int hsu_dma_remove(struct hsu_dma_chip *chip)
 
        dma_async_device_unregister(&hsu->dma);
 
-       for (i = 0; i < chip->pdata->nr_channels; i++) {
+       for (i = 0; i < hsu->nr_channels; i++) {
                struct hsu_dma_chan *hsuc = &hsu->chan[i];
 
                tasklet_kill(&hsuc->vchan.task);
index eeb9fff66967215b1d3277cf02aff2809a7fc649..f06579c6d548d0b11b83204d0f04494d001db2d3 100644 (file)
@@ -107,6 +107,7 @@ struct hsu_dma {
 
        /* channels */
        struct hsu_dma_chan             *chan;
+       unsigned short                  nr_channels;
 };
 
 static inline struct hsu_dma *to_hsu_dma(struct dma_device *ddev)
index 77879e6ddc4c211a0deacb7c019cf73a2b714222..e2db76bd56d89e9118308cb2dfb5d03b64811c0a 100644 (file)
@@ -31,7 +31,7 @@ static irqreturn_t hsu_pci_irq(int irq, void *dev)
        irqreturn_t ret = IRQ_NONE;
 
        dmaisr = readl(chip->regs + HSU_PCI_DMAISR);
-       for (i = 0; i < chip->pdata->nr_channels; i++) {
+       for (i = 0; i < chip->hsu->nr_channels; i++) {
                if (dmaisr & 0x1)
                        ret |= hsu_dma_irq(chip, i);
                dmaisr >>= 1;
index bc912611fe0974d7cb3c6759158210aafbf9ec02..2175225af74214c925ae1202a5c3771bf0608b7c 100644 (file)
@@ -1582,7 +1582,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
         * line status register.
         */
        if (port->flags & ASYNC_INITIALIZED) {
-               tty_wait_until_sent_from_close(tty, 3000);      /* 30 seconds timeout */
+               tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
                /*
                 * Before we drop DTR, make sure the UART transmitter
                 * has completely drained; this is especially
index 87f6578c6f4a389fbad842aebe9077d1577bab3a..d4a1331675ed5d69a3be971f91ceb59f27e0dbee 100644 (file)
@@ -1576,15 +1576,6 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
                current->pid, info->port.count);
 #endif
 
-       /*
-        * If the port is the middle of closing, bail out now
-        */
-       if (info->port.flags & ASYNC_CLOSING) {
-               wait_event_interruptible_tty(tty, info->port.close_wait,
-                               !(info->port.flags & ASYNC_CLOSING));
-               return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
-       }
-
        /*
         * Start up serial port
         */
index 2509d057b99c32bf96b5ad35058b714cff326788..574da15fe618ed57837ffa7f9ccfdeef03e89cc9 100644 (file)
@@ -81,7 +81,7 @@ config HVC_UDBG
 
 config HVC_DCC
        bool "ARM JTAG DCC console"
-       depends on ARM
+       depends on ARM || ARM64
        select HVC_DRIVER
        help
          This console uses the JTAG DCC on ARM to create a console under the HVC
index 4e9c4cc9e1b52a5b6a91f2881a0f4495743997d9..e46d628998f5cffb9b4be2366c635f0d9ced1b77 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/kernel.h>
 #include <linux/kthread.h>
 #include <linux/list.h>
-#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/major.h>
 #include <linux/atomic.h>
 #include <linux/sysrq.h>
@@ -418,7 +418,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
                 * there is no buffered data otherwise sleeps on a wait queue
                 * waking periodically to check chars_in_buffer().
                 */
-               tty_wait_until_sent_from_close(tty, HVC_CLOSE_WAIT);
+               tty_wait_until_sent(tty, HVC_CLOSE_WAIT);
        } else {
                if (hp->port.count < 0)
                        printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
@@ -1005,19 +1005,3 @@ put_tty:
 out:
        return err;
 }
-
-/* This isn't particularly necessary due to this being a console driver
- * but it is nice to be thorough.
- */
-static void __exit hvc_exit(void)
-{
-       if (hvc_driver) {
-               kthread_stop(hvc_task);
-
-               tty_unregister_driver(hvc_driver);
-               /* return tty_struct instances allocated in hvc_init(). */
-               put_tty_driver(hvc_driver);
-               unregister_console(&hvc_console);
-       }
-}
-module_exit(hvc_exit);
index 809920d80a66da7c08f8cd653451fa2fdcec636e..82f240fb98f00e8493c68cd331fa95a2d9be57da 100644 (file)
@@ -70,20 +70,27 @@ static const struct hv_ops hvc_dcc_get_put_ops = {
 
 static int __init hvc_dcc_console_init(void)
 {
+       int ret;
+
        if (!hvc_dcc_check())
                return -ENODEV;
 
-       hvc_instantiate(0, 0, &hvc_dcc_get_put_ops);
-       return 0;
+       /* Returns -1 if error */
+       ret = hvc_instantiate(0, 0, &hvc_dcc_get_put_ops);
+
+       return ret < 0 ? -ENODEV : 0;
 }
 console_initcall(hvc_dcc_console_init);
 
 static int __init hvc_dcc_init(void)
 {
+       struct hvc_struct *p;
+
        if (!hvc_dcc_check())
                return -ENODEV;
 
-       hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128);
-       return 0;
+       p = hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128);
+
+       return PTR_ERR_OR_ZERO(p);
 }
 device_initcall(hvc_dcc_init);
index f7ff97c0ad3499677578b7d1b68ff65c11ab74ec..5997b17311113150b93167aaaa4b1e37bb160cb3 100644 (file)
@@ -1230,7 +1230,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
                irq = hvcsd->vdev->irq;
                spin_unlock_irqrestore(&hvcsd->lock, flags);
 
-               tty_wait_until_sent_from_close(tty, HVCS_CLOSE_WAIT);
+               tty_wait_until_sent(tty, HVCS_CLOSE_WAIT);
 
                /*
                 * This line is important because it tells hvcs_open that this
index a8c8cfd52a23b862561b1211fe5f4330da909723..a119176a18551a19c59a0ee1750d89c67818ce05 100644 (file)
@@ -977,7 +977,7 @@ static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev)
        /* Try requesting the IRQ */
        if (priv->irq >= 0) {
                /*
-                * IRQF_SHARED, IRQF_NO_SUSPEND: The FDC IRQ may be shared with
+                * IRQF_SHARED, IRQF_COND_SUSPEND: The FDC IRQ may be shared with
                 * other local interrupts such as the timer which sets
                 * IRQF_TIMER (including IRQF_NO_SUSPEND).
                 *
@@ -987,7 +987,7 @@ static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev)
                 */
                ret = devm_request_irq(priv->dev, priv->irq, mips_ejtag_fdc_isr,
                                       IRQF_PERCPU | IRQF_SHARED |
-                                      IRQF_NO_THREAD | IRQF_NO_SUSPEND,
+                                      IRQF_NO_THREAD | IRQF_COND_SUSPEND,
                                       priv->fdc_name, priv);
                if (ret)
                        priv->irq = -1;
@@ -1048,38 +1048,6 @@ err_destroy_ports:
        return ret;
 }
 
-static int mips_ejtag_fdc_tty_remove(struct mips_cdmm_device *dev)
-{
-       struct mips_ejtag_fdc_tty *priv = mips_cdmm_get_drvdata(dev);
-       struct mips_ejtag_fdc_tty_port *dport;
-       int nport;
-       unsigned int cfg;
-
-       if (priv->irq >= 0) {
-               raw_spin_lock_irq(&priv->lock);
-               cfg = mips_ejtag_fdc_read(priv, REG_FDCFG);
-               /* Disable interrupts */
-               cfg &= ~(REG_FDCFG_TXINTTHRES | REG_FDCFG_RXINTTHRES);
-               cfg |= REG_FDCFG_TXINTTHRES_DISABLED;
-               cfg |= REG_FDCFG_RXINTTHRES_DISABLED;
-               mips_ejtag_fdc_write(priv, REG_FDCFG, cfg);
-               raw_spin_unlock_irq(&priv->lock);
-       } else {
-               priv->removing = true;
-               del_timer_sync(&priv->poll_timer);
-       }
-       kthread_stop(priv->thread);
-       if (dev->cpu == 0)
-               mips_ejtag_fdc_con.tty_drv = NULL;
-       tty_unregister_driver(priv->driver);
-       for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) {
-               dport = &priv->ports[nport];
-               tty_port_destroy(&dport->port);
-       }
-       put_tty_driver(priv->driver);
-       return 0;
-}
-
 static int mips_ejtag_fdc_tty_cpu_down(struct mips_cdmm_device *dev)
 {
        struct mips_ejtag_fdc_tty *priv = mips_cdmm_get_drvdata(dev);
@@ -1152,12 +1120,11 @@ static struct mips_cdmm_driver mips_ejtag_fdc_tty_driver = {
                .name   = "mips_ejtag_fdc",
        },
        .probe          = mips_ejtag_fdc_tty_probe,
-       .remove         = mips_ejtag_fdc_tty_remove,
        .cpu_down       = mips_ejtag_fdc_tty_cpu_down,
        .cpu_up         = mips_ejtag_fdc_tty_cpu_up,
        .id_table       = mips_ejtag_fdc_tty_ids,
 };
-module_mips_cdmm_driver(mips_ejtag_fdc_tty_driver);
+builtin_mips_cdmm_driver(mips_ejtag_fdc_tty_driver);
 
 static int __init mips_ejtag_fdc_init_console(void)
 {
index 8b157d68a03e97aa2089d9b3c4d98fdb0b109719..345111467b85026ead297b67f27a70cbf67a867d 100644 (file)
@@ -276,7 +276,7 @@ static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code)
                        add_msg(pHeader->owner, R3964_MSG_ACK, pHeader->length,
                                error_code, NULL);
                }
-               wake_up_interruptible(&pInfo->read_wait);
+               wake_up_interruptible(&pInfo->tty->read_wait);
        }
 
        spin_lock_irqsave(&pInfo->lock, flags);
@@ -542,7 +542,7 @@ static void on_receive_block(struct r3964_info *pInfo)
                                pBlock);
                }
        }
-       wake_up_interruptible(&pInfo->read_wait);
+       wake_up_interruptible(&pInfo->tty->read_wait);
 
        pInfo->state = R3964_IDLE;
 
@@ -978,8 +978,8 @@ static int r3964_open(struct tty_struct *tty)
        }
 
        spin_lock_init(&pInfo->lock);
+       mutex_init(&pInfo->read_lock);
        pInfo->tty = tty;
-       init_waitqueue_head(&pInfo->read_wait);
        pInfo->priority = R3964_MASTER;
        pInfo->rx_first = pInfo->rx_last = NULL;
        pInfo->tx_first = pInfo->tx_last = NULL;
@@ -1045,7 +1045,6 @@ static void r3964_close(struct tty_struct *tty)
        }
 
        /* Free buffers: */
-       wake_up_interruptible(&pInfo->read_wait);
        kfree(pInfo->rx_buf);
        TRACE_M("r3964_close - rx_buf kfree %p", pInfo->rx_buf);
        kfree(pInfo->tx_buf);
@@ -1065,7 +1064,16 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
 
        TRACE_L("read()");
 
-       tty_lock(tty);
+       /*
+        *      Internal serialization of reads.
+        */
+       if (file->f_flags & O_NONBLOCK) {
+               if (!mutex_trylock(&pInfo->read_lock))
+                       return -EAGAIN;
+       } else {
+               if (mutex_lock_interruptible(&pInfo->read_lock))
+                       return -ERESTARTSYS;
+       }
 
        pClient = findClient(pInfo, task_pid(current));
        if (pClient) {
@@ -1077,7 +1085,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
                                goto unlock;
                        }
                        /* block until there is a message: */
-                       wait_event_interruptible_tty(tty, pInfo->read_wait,
+                       wait_event_interruptible(tty->read_wait,
                                        (pMsg = remove_msg(pInfo, pClient)));
                }
 
@@ -1107,7 +1115,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
        }
        ret = -EPERM;
 unlock:
-       tty_unlock(tty);
+       mutex_unlock(&pInfo->read_lock);
        return ret;
 }
 
@@ -1156,8 +1164,6 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
        pHeader->locks = 0;
        pHeader->owner = NULL;
 
-       tty_lock(tty);
-
        pClient = findClient(pInfo, task_pid(current));
        if (pClient) {
                pHeader->owner = pClient;
@@ -1175,8 +1181,6 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
        add_tx_queue(pInfo, pHeader);
        trigger_transmit(pInfo);
 
-       tty_unlock(tty);
-
        return 0;
 }
 
@@ -1227,7 +1231,7 @@ static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
 
        pClient = findClient(pInfo, task_pid(current));
        if (pClient) {
-               poll_wait(file, &pInfo->read_wait, wait);
+               poll_wait(file, &tty->read_wait, wait);
                spin_lock_irqsave(&pInfo->lock, flags);
                pMsg = pClient->first_msg;
                spin_unlock_irqrestore(&pInfo->lock, flags);
index b09023b071696c2a5d25e003dcff798b42235602..13844261cd5f3cdad44131a3e215f97d2ecae2f4 100644 (file)
@@ -201,7 +201,7 @@ static void n_tty_kick_worker(struct tty_struct *tty)
                 */
                WARN_RATELIMIT(test_bit(TTY_LDISC_HALTED, &tty->flags),
                               "scheduling buffer work for halted ldisc\n");
-               queue_work(system_unbound_wq, &tty->port->buf.work);
+               tty_buffer_restart_work(tty->port);
        }
 }
 
@@ -1179,8 +1179,6 @@ static void n_tty_receive_break(struct tty_struct *tty)
                put_tty_queue('\0', ldata);
        }
        put_tty_queue('\0', ldata);
-       if (waitqueue_active(&tty->read_wait))
-               wake_up_interruptible_poll(&tty->read_wait, POLLIN);
 }
 
 /**
@@ -1237,8 +1235,6 @@ static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c)
                        put_tty_queue('\0', ldata);
        } else
                put_tty_queue(c, ldata);
-       if (waitqueue_active(&tty->read_wait))
-               wake_up_interruptible_poll(&tty->read_wait, POLLIN);
 }
 
 static void
@@ -2142,37 +2138,15 @@ extern ssize_t redirected_tty_write(struct file *, const char __user *,
 
 static int job_control(struct tty_struct *tty, struct file *file)
 {
-       struct pid *pgrp;
-
        /* Job control check -- must be done at start and after
           every sleep (POSIX.1 7.1.1.4). */
        /* NOTE: not yet done after every sleep pending a thorough
           check of the logic of this change. -- jlc */
        /* don't stop on /dev/console */
-       if (file->f_op->write == redirected_tty_write ||
-           current->signal->tty != tty)
+       if (file->f_op->write == redirected_tty_write)
                return 0;
 
-       rcu_read_lock();
-       pgrp = task_pgrp(current);
-
-       spin_lock_irq(&tty->ctrl_lock);
-       if (!tty->pgrp)
-               printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
-       else if (pgrp != tty->pgrp) {
-               spin_unlock_irq(&tty->ctrl_lock);
-               if (is_ignored(SIGTTIN) || is_current_pgrp_orphaned()) {
-                       rcu_read_unlock();
-                       return -EIO;
-               }
-               kill_pgrp(pgrp, SIGTTIN, 1);
-               rcu_read_unlock();
-               set_thread_flag(TIF_SIGPENDING);
-               return -ERESTARTSYS;
-       }
-       spin_unlock_irq(&tty->ctrl_lock);
-       rcu_read_unlock();
-       return 0;
+       return __tty_check_change(tty, SIGTTIN);
 }
 
 
index 4d5937c185c17bda6d506f00232b3f3598f28b95..a45660f62db54e37c47e0a04f5101d4adfb3463f 100644 (file)
@@ -7,7 +7,6 @@
  */
 
 #include <linux/module.h>
-
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/tty.h>
@@ -501,6 +500,10 @@ static int pty_bsd_ioctl(struct tty_struct *tty,
 }
 
 static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
+/*
+ * not really modular, but the easiest way to keep compat with existing
+ * bootargs behaviour is to continue using module_param here.
+ */
 module_param(legacy_count, int, 0);
 
 /*
@@ -877,4 +880,4 @@ static int __init pty_init(void)
        unix98_pty_init();
        return 0;
 }
-module_init(pty_init);
+device_initcall(pty_init);
index c8dd8dc31086ee5d373427dc5a7f04bee7cce1bb..802eac7e561b85f1aa43601a7a9eb94b05d3cb62 100644 (file)
@@ -895,14 +895,6 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
        if (!page)
                return -ENOMEM;
 
-       if (port->flags & ASYNC_CLOSING) {
-               retval = wait_for_completion_interruptible(&info->close_wait);
-               free_page(page);
-               if (retval)
-                       return retval;
-               return ((port->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);
-       }
-
        /*
         * We must not sleep from here until the port is marked fully in use.
         */
@@ -1057,7 +1049,6 @@ static void rp_close(struct tty_struct *tty, struct file *filp)
        mutex_unlock(&port->mutex);
        tty_port_tty_set(port, NULL);
 
-       wake_up_interruptible(&port->close_wait);
        complete_all(&info->close_wait);
        atomic_dec(&rp_num_ports_open);
 
@@ -1511,10 +1502,6 @@ static void rp_hangup(struct tty_struct *tty)
 #endif
        rp_flush_buffer(tty);
        spin_lock_irqsave(&info->port.lock, flags);
-       if (info->port.flags & ASYNC_CLOSING) {
-               spin_unlock_irqrestore(&info->port.lock, flags);
-               return;
-       }
        if (info->port.count)
                atomic_dec(&rp_num_ports_open);
        clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
index 748c18f8c8cdcbf417899e59b7ba60a35443607b..0140ba4aacded5ce8adf16cc7e8bfffb0fc7abd5 100644 (file)
@@ -560,8 +560,8 @@ static void rs_fair_output(void)
        struct m68k_serial *info = &m68k_soft[0];
        char c;
 
-       if (info == 0) return;
-       if (info->xmit_buf == 0) return;
+       if (info == NULL) return;
+       if (info->xmit_buf == NULL) return;
 
        local_irq_save(flags);
        left = info->xmit_cnt;
@@ -1071,7 +1071,6 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
                wake_up_interruptible(&port->open_wait);
        }
        port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-       wake_up_interruptible(&port->close_wait);
        local_irq_restore(flags);
 }
 
index 271d121376490042e87bda6eeb06d26833d6c0d6..39126460c1f59097ad164bfee65579e8ce54085a 100644 (file)
@@ -569,6 +569,9 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
        for (i = 0; i < nr_uarts; i++) {
                struct uart_8250_port *up = &serial8250_ports[i];
 
+               if (up->port.type == PORT_8250_CIR)
+                       continue;
+
                if (up->port.dev)
                        continue;
 
@@ -1027,13 +1030,24 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
                if (up->dl_write)
                        uart->dl_write = up->dl_write;
 
-               if (serial8250_isa_config != NULL)
-                       serial8250_isa_config(0, &uart->port,
-                                       &uart->capabilities);
+               if (uart->port.type != PORT_8250_CIR) {
+                       if (serial8250_isa_config != NULL)
+                               serial8250_isa_config(0, &uart->port,
+                                               &uart->capabilities);
+
+                       ret = uart_add_one_port(&serial8250_reg,
+                                               &uart->port);
+                       if (ret == 0)
+                               ret = uart->port.line;
+               } else {
+                       dev_info(uart->port.dev,
+                               "skipping CIR port at 0x%lx / 0x%llx, IRQ %d\n",
+                               uart->port.iobase,
+                               (unsigned long long)uart->port.mapbase,
+                               uart->port.irq);
 
-               ret = uart_add_one_port(&serial8250_reg, &uart->port);
-               if (ret == 0)
-                       ret = uart->port.line;
+                       ret = 0;
+               }
        }
        mutex_unlock(&serial_mutex);
 
index e508939daea3f3128a2ada1e696a5f751d212077..78259d3c6a55592281a5c6aaad88c5ae727d9615 100644 (file)
@@ -54,9 +54,6 @@ static void __dma_rx_complete(void *param)
        struct dma_tx_state     state;
        int                     count;
 
-       dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
-                               dma->rx_size, DMA_FROM_DEVICE);
-
        dma->rx_running = 0;
        dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
 
@@ -152,9 +149,6 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
 
        dma->rx_cookie = dmaengine_submit(desc);
 
-       dma_sync_single_for_device(dma->rxchan->device->dev, dma->rx_addr,
-                                  dma->rx_size, DMA_FROM_DEVICE);
-
        dma_async_issue_pending(dma->rxchan);
 
        return 0;
index 06324f17a0cb1de308128573330373d073e78db3..a0cdbf35dcb19bd637632f55d514ad16d1588036 100644 (file)
@@ -63,6 +63,9 @@ struct dw8250_data {
        struct clk              *pclk;
        struct reset_control    *rst;
        struct uart_8250_dma    dma;
+
+       unsigned int            skip_autocfg:1;
+       unsigned int            uart_16550_compatible:1;
 };
 
 #define BYT_PRV_CLK                    0x800
@@ -244,24 +247,77 @@ out:
        serial8250_do_set_termios(p, termios, old);
 }
 
-static bool dw8250_dma_filter(struct dma_chan *chan, void *param)
+/*
+ * dw8250_fallback_dma_filter will prevent the UART from getting just any free
+ * channel on platforms that have DMA engines, but don't have any channels
+ * assigned to the UART.
+ *
+ * REVISIT: This is a work around for limitation in the DMA Engine API. Once the
+ * core problem is fixed, this function is no longer needed.
+ */
+static bool dw8250_fallback_dma_filter(struct dma_chan *chan, void *param)
 {
        return false;
 }
 
-static void dw8250_setup_port(struct uart_8250_port *up)
+static bool dw8250_idma_filter(struct dma_chan *chan, void *param)
+{
+       return param == chan->device->dev->parent;
+}
+
+static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
 {
-       struct uart_port        *p = &up->port;
-       u32                     reg = readl(p->membase + DW_UART_UCV);
+       if (p->dev->of_node) {
+               struct device_node *np = p->dev->of_node;
+               int id;
+
+               /* get index of serial line, if found in DT aliases */
+               id = of_alias_get_id(np, "serial");
+               if (id >= 0)
+                       p->line = id;
+#ifdef CONFIG_64BIT
+               if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) {
+                       p->serial_in = dw8250_serial_inq;
+                       p->serial_out = dw8250_serial_outq;
+                       p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
+                       p->type = PORT_OCTEON;
+                       data->usr_reg = 0x27;
+                       data->skip_autocfg = true;
+               }
+#endif
+       } else if (has_acpi_companion(p->dev)) {
+               p->iotype = UPIO_MEM32;
+               p->regshift = 2;
+               p->serial_in = dw8250_serial_in32;
+               p->set_termios = dw8250_set_termios;
+               /* So far none of there implement the Busy Functionality */
+               data->uart_16550_compatible = true;
+       }
+
+       /* Platforms with iDMA */
+       if (platform_get_resource_byname(to_platform_device(p->dev),
+                                        IORESOURCE_MEM, "lpss_priv")) {
+               p->set_termios = dw8250_set_termios;
+               data->dma.rx_param = p->dev->parent;
+               data->dma.tx_param = p->dev->parent;
+               data->dma.fn = dw8250_idma_filter;
+       }
+}
+
+static void dw8250_setup_port(struct uart_port *p)
+{
+       struct uart_8250_port *up = up_to_u8250p(p);
+       u32 reg;
 
        /*
         * If the Component Version Register returns zero, we know that
         * ADDITIONAL_FEATURES are not enabled. No need to go any further.
         */
+       reg = readl(p->membase + DW_UART_UCV);
        if (!reg)
                return;
 
-       dev_dbg_ratelimited(p->dev, "Designware UART version %c.%c%c\n",
+       dev_dbg(p->dev, "Designware UART version %c.%c%c\n",
                (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
 
        reg = readl(p->membase + DW_UART_CPR);
@@ -273,7 +329,6 @@ static void dw8250_setup_port(struct uart_8250_port *up)
                p->type = PORT_16550A;
                p->flags |= UPF_FIXED_TYPE;
                p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);
-               up->tx_loadsz = p->fifosize;
                up->capabilities = UART_CAP_FIFO;
        }
 
@@ -281,166 +336,91 @@ static void dw8250_setup_port(struct uart_8250_port *up)
                up->capabilities |= UART_CAP_AFE;
 }
 
-static int dw8250_probe_of(struct uart_port *p,
-                          struct dw8250_data *data)
+static int dw8250_probe(struct platform_device *pdev)
 {
-       struct device_node      *np = p->dev->of_node;
-       struct uart_8250_port *up = up_to_u8250p(p);
-       u32                     val;
-       bool has_ucv = true;
-       int id;
+       struct uart_8250_port uart = {};
+       struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       int irq = platform_get_irq(pdev, 0);
+       struct uart_port *p = &uart.port;
+       struct dw8250_data *data;
+       int err;
+       u32 val;
 
-#ifdef CONFIG_64BIT
-       if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) {
-               p->serial_in = dw8250_serial_inq;
-               p->serial_out = dw8250_serial_outq;
-               p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
-               p->type = PORT_OCTEON;
-               data->usr_reg = 0x27;
-               has_ucv = false;
-       } else
-#endif
-       if (!of_property_read_u32(np, "reg-io-width", &val)) {
-               switch (val) {
-               case 1:
-                       break;
-               case 4:
-                       p->iotype = UPIO_MEM32;
-                       p->serial_in = dw8250_serial_in32;
-                       p->serial_out = dw8250_serial_out32;
-                       break;
-               default:
-                       dev_err(p->dev, "unsupported reg-io-width (%u)\n", val);
-                       return -EINVAL;
-               }
+       if (!regs) {
+               dev_err(&pdev->dev, "no registers defined\n");
+               return -EINVAL;
        }
-       if (has_ucv)
-               dw8250_setup_port(up);
 
-       /* if we have a valid fifosize, try hooking up DMA here */
-       if (p->fifosize) {
-               up->dma = &data->dma;
-
-               up->dma->rxconf.src_maxburst = p->fifosize / 4;
-               up->dma->txconf.dst_maxburst = p->fifosize / 4;
+       if (irq < 0) {
+               if (irq != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "cannot get irq\n");
+               return irq;
        }
 
-       if (!of_property_read_u32(np, "reg-shift", &val))
+       spin_lock_init(&p->lock);
+       p->mapbase      = regs->start;
+       p->irq          = irq;
+       p->handle_irq   = dw8250_handle_irq;
+       p->pm           = dw8250_do_pm;
+       p->type         = PORT_8250;
+       p->flags        = UPF_SHARE_IRQ | UPF_FIXED_PORT;
+       p->dev          = &pdev->dev;
+       p->iotype       = UPIO_MEM;
+       p->serial_in    = dw8250_serial_in;
+       p->serial_out   = dw8250_serial_out;
+
+       p->membase = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));
+       if (!p->membase)
+               return -ENOMEM;
+
+       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->dma.fn = dw8250_fallback_dma_filter;
+       data->usr_reg = DW_UART_USR;
+       p->private_data = data;
+
+       data->uart_16550_compatible = device_property_read_bool(p->dev,
+                                               "snps,uart-16550-compatible");
+
+       err = device_property_read_u32(p->dev, "reg-shift", &val);
+       if (!err)
                p->regshift = val;
 
-       /* get index of serial line, if found in DT aliases */
-       id = of_alias_get_id(np, "serial");
-       if (id >= 0)
-               p->line = id;
+       err = device_property_read_u32(p->dev, "reg-io-width", &val);
+       if (!err && val == 4) {
+               p->iotype = UPIO_MEM32;
+               p->serial_in = dw8250_serial_in32;
+               p->serial_out = dw8250_serial_out32;
+       }
 
-       if (of_property_read_bool(np, "dcd-override")) {
+       if (device_property_read_bool(p->dev, "dcd-override")) {
                /* Always report DCD as active */
                data->msr_mask_on |= UART_MSR_DCD;
                data->msr_mask_off |= UART_MSR_DDCD;
        }
 
-       if (of_property_read_bool(np, "dsr-override")) {
+       if (device_property_read_bool(p->dev, "dsr-override")) {
                /* Always report DSR as active */
                data->msr_mask_on |= UART_MSR_DSR;
                data->msr_mask_off |= UART_MSR_DDSR;
        }
 
-       if (of_property_read_bool(np, "cts-override")) {
+       if (device_property_read_bool(p->dev, "cts-override")) {
                /* Always report CTS as active */
                data->msr_mask_on |= UART_MSR_CTS;
                data->msr_mask_off |= UART_MSR_DCTS;
        }
 
-       if (of_property_read_bool(np, "ri-override")) {
+       if (device_property_read_bool(p->dev, "ri-override")) {
                /* Always report Ring indicator as inactive */
                data->msr_mask_off |= UART_MSR_RI;
                data->msr_mask_off |= UART_MSR_TERI;
        }
 
-       return 0;
-}
-
-static bool dw8250_idma_filter(struct dma_chan *chan, void *param)
-{
-       struct device *dev = param;
-
-       if (dev != chan->device->dev->parent)
-               return false;
-
-       return true;
-}
-
-static int dw8250_probe_acpi(struct uart_8250_port *up,
-                            struct dw8250_data *data)
-{
-       struct uart_port *p = &up->port;
-
-       dw8250_setup_port(up);
-
-       p->iotype = UPIO_MEM32;
-       p->serial_in = dw8250_serial_in32;
-       p->serial_out = dw8250_serial_out32;
-       p->regshift = 2;
-
-       /* Platforms with iDMA */
-       if (platform_get_resource_byname(to_platform_device(up->port.dev),
-                                        IORESOURCE_MEM, "lpss_priv")) {
-               data->dma.rx_param = up->port.dev->parent;
-               data->dma.tx_param = up->port.dev->parent;
-               data->dma.fn = dw8250_idma_filter;
-       }
-
-       up->dma = &data->dma;
-       up->dma->rxconf.src_maxburst = p->fifosize / 4;
-       up->dma->txconf.dst_maxburst = p->fifosize / 4;
-
-       up->port.set_termios = dw8250_set_termios;
-
-       return 0;
-}
-
-static int dw8250_probe(struct platform_device *pdev)
-{
-       struct uart_8250_port uart = {};
-       struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       int irq = platform_get_irq(pdev, 0);
-       struct dw8250_data *data;
-       int err;
-
-       if (!regs) {
-               dev_err(&pdev->dev, "no registers defined\n");
-               return -EINVAL;
-       }
-
-       if (irq < 0) {
-               if (irq != -EPROBE_DEFER)
-                       dev_err(&pdev->dev, "cannot get irq\n");
-               return irq;
-       }
-
-       spin_lock_init(&uart.port.lock);
-       uart.port.mapbase = regs->start;
-       uart.port.irq = irq;
-       uart.port.handle_irq = dw8250_handle_irq;
-       uart.port.pm = dw8250_do_pm;
-       uart.port.type = PORT_8250;
-       uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
-       uart.port.dev = &pdev->dev;
-
-       uart.port.membase = devm_ioremap(&pdev->dev, regs->start,
-                                        resource_size(regs));
-       if (!uart.port.membase)
-               return -ENOMEM;
-
-       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-
-       data->usr_reg = DW_UART_USR;
-
        /* Always ask for fixed clock rate from a property. */
-       device_property_read_u32(&pdev->dev, "clock-frequency",
-                                &uart.port.uartclk);
+       device_property_read_u32(p->dev, "clock-frequency", &p->uartclk);
 
        /* If there is separate baudclk, get the rate from it. */
        data->clk = devm_clk_get(&pdev->dev, "baudclk");
@@ -454,11 +434,11 @@ static int dw8250_probe(struct platform_device *pdev)
                        dev_warn(&pdev->dev, "could not enable optional baudclk: %d\n",
                                 err);
                else
-                       uart.port.uartclk = clk_get_rate(data->clk);
+                       p->uartclk = clk_get_rate(data->clk);
        }
 
        /* If no clock rate is defined, fail. */
-       if (!uart.port.uartclk) {
+       if (!p->uartclk) {
                dev_err(&pdev->dev, "clock rate not defined\n");
                return -EINVAL;
        }
@@ -484,26 +464,22 @@ static int dw8250_probe(struct platform_device *pdev)
        if (!IS_ERR(data->rst))
                reset_control_deassert(data->rst);
 
-       data->dma.rx_param = data;
-       data->dma.tx_param = data;
-       data->dma.fn = dw8250_dma_filter;
+       dw8250_quirks(p, data);
 
-       uart.port.iotype = UPIO_MEM;
-       uart.port.serial_in = dw8250_serial_in;
-       uart.port.serial_out = dw8250_serial_out;
-       uart.port.private_data = data;
+       /* If the Busy Functionality is not implemented, don't handle it */
+       if (data->uart_16550_compatible) {
+               p->serial_out = NULL;
+               p->handle_irq = NULL;
+       }
 
-       if (pdev->dev.of_node) {
-               err = dw8250_probe_of(&uart.port, data);
-               if (err)
-                       goto err_reset;
-       } else if (ACPI_HANDLE(&pdev->dev)) {
-               err = dw8250_probe_acpi(&uart, data);
-               if (err)
-                       goto err_reset;
-       } else {
-               err = -ENODEV;
-               goto err_reset;
+       if (!data->skip_autocfg)
+               dw8250_setup_port(p);
+
+       /* If we have a valid fifosize, try hooking up DMA */
+       if (p->fifosize) {
+               data->dma.rxconf.src_maxburst = p->fifosize / 4;
+               data->dma.txconf.dst_maxburst = p->fifosize / 4;
+               uart.dma = &data->dma;
        }
 
        data->line = serial8250_register_8250_port(&uart);
index faed05f25bc2e148837518ad34958924c06eb90e..ceb85792a5cf26e8865b317d82426ded50bf37b8 100644 (file)
@@ -29,6 +29,8 @@
 #include <linux/tty.h>
 #include <linux/init.h>
 #include <linux/console.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/serial_reg.h>
 #include <linux/serial.h>
 #include <linux/serial_8250.h>
@@ -152,3 +154,5 @@ int __init early_serial8250_setup(struct earlycon_device *device,
 }
 EARLYCON_DECLARE(uart8250, early_serial8250_setup);
 EARLYCON_DECLARE(uart, early_serial8250_setup);
+OF_EARLYCON_DECLARE(ns16550, "ns16550", early_serial8250_setup);
+OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup);
index 7c1e4be48e7b3b96b975b29ba4d2053083bd9700..49394b4c5cfdc947dd2763dcb368bea49e6cf3e0 100644 (file)
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_fdt.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
 #include <linux/serial_core.h>
 #include <linux/serial_reg.h>
 
+#include "8250.h"
+
+/** ingenic_uart_config: SOC specific config data. */
+struct ingenic_uart_config {
+       int tx_loadsz;
+       int fifosize;
+};
+
 struct ingenic_uart_data {
        struct clk      *clk_module;
        struct clk      *clk_baud;
        int             line;
 };
 
+static const struct of_device_id of_match[];
+
 #define UART_FCR_UME   BIT(4)
 
+#define UART_MCR_MDCE  BIT(7)
+#define UART_MCR_FCM   BIT(6)
+
 static struct earlycon_device *early_device;
 
 static uint8_t __init early_in(struct uart_port *port, int offset)
@@ -129,6 +143,8 @@ OF_EARLYCON_DECLARE(jz4780_uart, "ingenic,jz4780-uart",
 
 static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
 {
+       int ier;
+
        switch (offset) {
        case UART_FCR:
                /* UART module enable */
@@ -136,9 +152,22 @@ static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
                break;
 
        case UART_IER:
+               /* Enable receive timeout interrupt with the
+                * receive line status interrupt */
                value |= (value & 0x4) << 2;
                break;
 
+       case UART_MCR:
+               /* If we have enabled modem status IRQs we should enable modem
+                * mode. */
+               ier = p->serial_in(p, UART_IER);
+
+               if (ier & UART_IER_MSI)
+                       value |= UART_MCR_MDCE | UART_MCR_FCM;
+               else
+                       value &= ~(UART_MCR_MDCE | UART_MCR_FCM);
+               break;
+
        default:
                break;
        }
@@ -146,14 +175,45 @@ static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value)
        writeb(value, p->membase + (offset << p->regshift));
 }
 
+static unsigned int ingenic_uart_serial_in(struct uart_port *p, int offset)
+{
+       unsigned int value;
+
+       value = readb(p->membase + (offset << p->regshift));
+
+       /* Hide non-16550 compliant bits from higher levels */
+       switch (offset) {
+       case UART_FCR:
+               value &= ~UART_FCR_UME;
+               break;
+
+       case UART_MCR:
+               value &= ~(UART_MCR_MDCE | UART_MCR_FCM);
+               break;
+
+       default:
+               break;
+       }
+       return value;
+}
+
 static int ingenic_uart_probe(struct platform_device *pdev)
 {
        struct uart_8250_port uart = {};
        struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        struct ingenic_uart_data *data;
+       const struct ingenic_uart_config *cdata;
+       const struct of_device_id *match;
        int err, line;
 
+       match = of_match_device(of_match, &pdev->dev);
+       if (!match) {
+               dev_err(&pdev->dev, "Error: No device match found\n");
+               return -ENODEV;
+       }
+       cdata = match->data;
+
        if (!regs || !irq) {
                dev_err(&pdev->dev, "no registers/irq defined\n");
                return -EINVAL;
@@ -164,14 +224,18 @@ static int ingenic_uart_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        spin_lock_init(&uart.port.lock);
-       uart.port.type = PORT_16550;
+       uart.port.type = PORT_16550A;
        uart.port.flags = UPF_SKIP_TEST | UPF_IOREMAP | UPF_FIXED_TYPE;
        uart.port.iotype = UPIO_MEM;
        uart.port.mapbase = regs->start;
        uart.port.regshift = 2;
        uart.port.serial_out = ingenic_uart_serial_out;
+       uart.port.serial_in = ingenic_uart_serial_in;
        uart.port.irq = irq->start;
        uart.port.dev = &pdev->dev;
+       uart.port.fifosize = cdata->fifosize;
+       uart.tx_loadsz = cdata->tx_loadsz;
+       uart.capabilities = UART_CAP_FIFO | UART_CAP_RTOIE;
 
        /* Check for a fixed line number */
        line = of_alias_get_id(pdev->dev.of_node, "serial");
@@ -241,10 +305,26 @@ static int ingenic_uart_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct ingenic_uart_config jz4740_uart_config = {
+       .tx_loadsz = 8,
+       .fifosize = 16,
+};
+
+static const struct ingenic_uart_config jz4760_uart_config = {
+       .tx_loadsz = 16,
+       .fifosize = 32,
+};
+
+static const struct ingenic_uart_config jz4780_uart_config = {
+       .tx_loadsz = 32,
+       .fifosize = 64,
+};
+
 static const struct of_device_id of_match[] = {
-       { .compatible = "ingenic,jz4740-uart" },
-       { .compatible = "ingenic,jz4775-uart" },
-       { .compatible = "ingenic,jz4780-uart" },
+       { .compatible = "ingenic,jz4740-uart", .data = &jz4740_uart_config },
+       { .compatible = "ingenic,jz4760-uart", .data = &jz4760_uart_config },
+       { .compatible = "ingenic,jz4775-uart", .data = &jz4760_uart_config },
+       { .compatible = "ingenic,jz4780-uart", .data = &jz4780_uart_config },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, of_match);
diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c
new file mode 100644 (file)
index 0000000..88531a3
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * 8250_mid.c - Driver for UART on Intel Penwell and various other Intel SOCs
+ *
+ * Copyright (C) 2015 Intel Corporation
+ * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/rational.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include <linux/dma/hsu.h>
+
+#include "8250.h"
+
+#define PCI_DEVICE_ID_INTEL_PNW_UART1  0x081b
+#define PCI_DEVICE_ID_INTEL_PNW_UART2  0x081c
+#define PCI_DEVICE_ID_INTEL_PNW_UART3  0x081d
+#define PCI_DEVICE_ID_INTEL_TNG_UART   0x1191
+#define PCI_DEVICE_ID_INTEL_DNV_UART   0x19d8
+
+/* Intel MID Specific registers */
+#define INTEL_MID_UART_PS              0x30
+#define INTEL_MID_UART_MUL             0x34
+#define INTEL_MID_UART_DIV             0x38
+
+struct mid8250;
+
+struct mid8250_board {
+       unsigned long freq;
+       unsigned int base_baud;
+       int (*setup)(struct mid8250 *, struct uart_port *p);
+       void (*exit)(struct mid8250 *);
+};
+
+struct mid8250 {
+       int line;
+       int dma_index;
+       struct pci_dev *dma_dev;
+       struct uart_8250_dma dma;
+       struct mid8250_board *board;
+       struct hsu_dma_chip dma_chip;
+};
+
+/*****************************************************************************/
+
+static int pnw_setup(struct mid8250 *mid, struct uart_port *p)
+{
+       struct pci_dev *pdev = to_pci_dev(p->dev);
+
+       switch (pdev->device) {
+       case PCI_DEVICE_ID_INTEL_PNW_UART1:
+               mid->dma_index = 0;
+               break;
+       case PCI_DEVICE_ID_INTEL_PNW_UART2:
+               mid->dma_index = 1;
+               break;
+       case PCI_DEVICE_ID_INTEL_PNW_UART3:
+               mid->dma_index = 2;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       mid->dma_dev = pci_get_slot(pdev->bus,
+                                   PCI_DEVFN(PCI_SLOT(pdev->devfn), 3));
+       return 0;
+}
+
+static int tng_setup(struct mid8250 *mid, struct uart_port *p)
+{
+       struct pci_dev *pdev = to_pci_dev(p->dev);
+       int index = PCI_FUNC(pdev->devfn);
+
+       /* Currently no support for HSU port0 */
+       if (index-- == 0)
+               return -ENODEV;
+
+       mid->dma_index = index;
+       mid->dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(5, 0));
+       return 0;
+}
+
+static int dnv_handle_irq(struct uart_port *p)
+{
+       struct mid8250 *mid = p->private_data;
+       int ret;
+
+       ret = hsu_dma_irq(&mid->dma_chip, 0);
+       ret |= hsu_dma_irq(&mid->dma_chip, 1);
+
+       /* For now, letting the HW generate separate interrupt for the UART */
+       if (ret)
+               return ret;
+
+       return serial8250_handle_irq(p, serial_port_in(p, UART_IIR));
+}
+
+#define DNV_DMA_CHAN_OFFSET 0x80
+
+static int dnv_setup(struct mid8250 *mid, struct uart_port *p)
+{
+       struct hsu_dma_chip *chip = &mid->dma_chip;
+       struct pci_dev *pdev = to_pci_dev(p->dev);
+       int ret;
+
+       chip->dev = &pdev->dev;
+       chip->irq = pdev->irq;
+       chip->regs = p->membase;
+       chip->length = pci_resource_len(pdev, 0);
+       chip->offset = DNV_DMA_CHAN_OFFSET;
+
+       /* Falling back to PIO mode if DMA probing fails */
+       ret = hsu_dma_probe(chip);
+       if (ret)
+               return 0;
+
+       mid->dma_dev = pdev;
+
+       p->handle_irq = dnv_handle_irq;
+       return 0;
+}
+
+static void dnv_exit(struct mid8250 *mid)
+{
+       if (!mid->dma_dev)
+               return;
+       hsu_dma_remove(&mid->dma_chip);
+}
+
+/*****************************************************************************/
+
+static void mid8250_set_termios(struct uart_port *p,
+                               struct ktermios *termios,
+                               struct ktermios *old)
+{
+       unsigned int baud = tty_termios_baud_rate(termios);
+       struct mid8250 *mid = p->private_data;
+       unsigned short ps = 16;
+       unsigned long fuart = baud * ps;
+       unsigned long w = BIT(24) - 1;
+       unsigned long mul, div;
+
+       if (mid->board->freq < fuart) {
+               /* Find prescaler value that satisfies Fuart < Fref */
+               if (mid->board->freq > baud)
+                       ps = mid->board->freq / baud;   /* baud rate too high */
+               else
+                       ps = 1;                         /* PLL case */
+               fuart = baud * ps;
+       } else {
+               /* Get Fuart closer to Fref */
+               fuart *= rounddown_pow_of_two(mid->board->freq / fuart);
+       }
+
+       rational_best_approximation(fuart, mid->board->freq, w, w, &mul, &div);
+       p->uartclk = fuart * 16 / ps;           /* core uses ps = 16 always */
+
+       writel(ps, p->membase + INTEL_MID_UART_PS);             /* set PS */
+       writel(mul, p->membase + INTEL_MID_UART_MUL);           /* set MUL */
+       writel(div, p->membase + INTEL_MID_UART_DIV);
+
+       serial8250_do_set_termios(p, termios, old);
+}
+
+static bool mid8250_dma_filter(struct dma_chan *chan, void *param)
+{
+       struct hsu_dma_slave *s = param;
+
+       if (s->dma_dev != chan->device->dev || s->chan_id != chan->chan_id)
+               return false;
+
+       chan->private = s;
+       return true;
+}
+
+static int mid8250_dma_setup(struct mid8250 *mid, struct uart_8250_port *port)
+{
+       struct uart_8250_dma *dma = &mid->dma;
+       struct device *dev = port->port.dev;
+       struct hsu_dma_slave *rx_param;
+       struct hsu_dma_slave *tx_param;
+
+       if (!mid->dma_dev)
+               return 0;
+
+       rx_param = devm_kzalloc(dev, sizeof(*rx_param), GFP_KERNEL);
+       if (!rx_param)
+               return -ENOMEM;
+
+       tx_param = devm_kzalloc(dev, sizeof(*tx_param), GFP_KERNEL);
+       if (!tx_param)
+               return -ENOMEM;
+
+       rx_param->chan_id = mid->dma_index * 2 + 1;
+       tx_param->chan_id = mid->dma_index * 2;
+
+       dma->rxconf.src_maxburst = 64;
+       dma->txconf.dst_maxburst = 64;
+
+       rx_param->dma_dev = &mid->dma_dev->dev;
+       tx_param->dma_dev = &mid->dma_dev->dev;
+
+       dma->fn = mid8250_dma_filter;
+       dma->rx_param = rx_param;
+       dma->tx_param = tx_param;
+
+       port->dma = dma;
+       return 0;
+}
+
+static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+       struct uart_8250_port uart;
+       struct mid8250 *mid;
+       int ret;
+
+       ret = pcim_enable_device(pdev);
+       if (ret)
+               return ret;
+
+       pci_set_master(pdev);
+
+       mid = devm_kzalloc(&pdev->dev, sizeof(*mid), GFP_KERNEL);
+       if (!mid)
+               return -ENOMEM;
+
+       mid->board = (struct mid8250_board *)id->driver_data;
+
+       memset(&uart, 0, sizeof(struct uart_8250_port));
+
+       uart.port.dev = &pdev->dev;
+       uart.port.irq = pdev->irq;
+       uart.port.private_data = mid;
+       uart.port.type = PORT_16750;
+       uart.port.iotype = UPIO_MEM;
+       uart.port.uartclk = mid->board->base_baud * 16;
+       uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE;
+       uart.port.set_termios = mid8250_set_termios;
+
+       uart.port.mapbase = pci_resource_start(pdev, 0);
+       uart.port.membase = pcim_iomap(pdev, 0, 0);
+       if (!uart.port.membase)
+               return -ENOMEM;
+
+       if (mid->board->setup) {
+               ret = mid->board->setup(mid, &uart.port);
+               if (ret)
+                       return ret;
+       }
+
+       ret = mid8250_dma_setup(mid, &uart);
+       if (ret)
+               goto err;
+
+       ret = serial8250_register_8250_port(&uart);
+       if (ret < 0)
+               goto err;
+
+       mid->line = ret;
+
+       pci_set_drvdata(pdev, mid);
+       return 0;
+err:
+       if (mid->board->exit)
+               mid->board->exit(mid);
+       return ret;
+}
+
+static void mid8250_remove(struct pci_dev *pdev)
+{
+       struct mid8250 *mid = pci_get_drvdata(pdev);
+
+       if (mid->board->exit)
+               mid->board->exit(mid);
+
+       serial8250_unregister_port(mid->line);
+}
+
+static const struct mid8250_board pnw_board = {
+       .freq = 50000000,
+       .base_baud = 115200,
+       .setup = pnw_setup,
+};
+
+static const struct mid8250_board tng_board = {
+       .freq = 38400000,
+       .base_baud = 1843200,
+       .setup = tng_setup,
+};
+
+static const struct mid8250_board dnv_board = {
+       .freq = 133333333,
+       .base_baud = 115200,
+       .setup = dnv_setup,
+       .exit = dnv_exit,
+};
+
+#define MID_DEVICE(id, board) { PCI_VDEVICE(INTEL, id), (kernel_ulong_t)&board }
+
+static const struct pci_device_id pci_ids[] = {
+       MID_DEVICE(PCI_DEVICE_ID_INTEL_PNW_UART1, pnw_board),
+       MID_DEVICE(PCI_DEVICE_ID_INTEL_PNW_UART2, pnw_board),
+       MID_DEVICE(PCI_DEVICE_ID_INTEL_PNW_UART3, pnw_board),
+       MID_DEVICE(PCI_DEVICE_ID_INTEL_TNG_UART, tng_board),
+       MID_DEVICE(PCI_DEVICE_ID_INTEL_DNV_UART, dnv_board),
+       { },
+};
+MODULE_DEVICE_TABLE(pci, pci_ids);
+
+static struct pci_driver mid8250_pci_driver = {
+       .name           = "8250_mid",
+       .id_table       = pci_ids,
+       .probe          = mid8250_probe,
+       .remove         = mid8250_remove,
+};
+
+module_pci_driver(mid8250_pci_driver);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel MID UART driver");
index 826c5c4a2103be3ac9c5065eeb8274fd8ce8c75f..a2c0734c76e2eb47eab5d7b294b3071a99efcf0e 100644 (file)
@@ -439,7 +439,6 @@ static void omap_8250_set_termios(struct uart_port *port,
        priv->xoff = termios->c_cc[VSTOP];
 
        priv->efr = 0;
-       up->mcr &= ~(UART_MCR_RTS | UART_MCR_XONANY);
        up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF);
 
        if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
@@ -726,6 +725,7 @@ static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
        struct dma_tx_state     state;
        int                     count;
        unsigned long           flags;
+       int                     ret;
 
        dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
                                dma->rx_size, DMA_FROM_DEVICE);
@@ -741,8 +741,10 @@ static void __dma_rx_do_complete(struct uart_8250_port *p, bool error)
 
        count = dma->rx_size - state.residue;
 
-       tty_insert_flip_string(tty_port, dma->rx_buf, count);
-       p->port.icount.rx += count;
+       ret = tty_insert_flip_string(tty_port, dma->rx_buf, count);
+
+       p->port.icount.rx += ret;
+       p->port.icount.buf_overrun += count - ret;
 unlock:
        spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
 
index 68042dd1c525ee01519ca51701192ba840b6e55b..4097f3f65b3bb1bfc3e3d4d6a40f05fb46c70618 100644 (file)
@@ -28,7 +28,6 @@
 
 #include <linux/dmaengine.h>
 #include <linux/platform_data/dma-dw.h>
-#include <linux/platform_data/dma-hsu.h>
 
 #include "8250.h"
 
@@ -1508,167 +1507,6 @@ byt_serial_setup(struct serial_private *priv,
        return ret;
 }
 
-#define INTEL_MID_UART_PS              0x30
-#define INTEL_MID_UART_MUL             0x34
-#define INTEL_MID_UART_DIV             0x38
-
-static void intel_mid_set_termios(struct uart_port *p,
-                                 struct ktermios *termios,
-                                 struct ktermios *old,
-                                 unsigned long fref)
-{
-       unsigned int baud = tty_termios_baud_rate(termios);
-       unsigned short ps = 16;
-       unsigned long fuart = baud * ps;
-       unsigned long w = BIT(24) - 1;
-       unsigned long mul, div;
-
-       if (fref < fuart) {
-               /* Find prescaler value that satisfies Fuart < Fref */
-               if (fref > baud)
-                       ps = fref / baud;       /* baud rate too high */
-               else
-                       ps = 1;                 /* PLL case */
-               fuart = baud * ps;
-       } else {
-               /* Get Fuart closer to Fref */
-               fuart *= rounddown_pow_of_two(fref / fuart);
-       }
-
-       rational_best_approximation(fuart, fref, w, w, &mul, &div);
-       p->uartclk = fuart * 16 / ps;           /* core uses ps = 16 always */
-
-       writel(ps, p->membase + INTEL_MID_UART_PS);             /* set PS */
-       writel(mul, p->membase + INTEL_MID_UART_MUL);           /* set MUL */
-       writel(div, p->membase + INTEL_MID_UART_DIV);
-
-       serial8250_do_set_termios(p, termios, old);
-}
-
-static void intel_mid_set_termios_38_4M(struct uart_port *p,
-                                       struct ktermios *termios,
-                                       struct ktermios *old)
-{
-       intel_mid_set_termios(p, termios, old, 38400000);
-}
-
-static void intel_mid_set_termios_50M(struct uart_port *p,
-                                     struct ktermios *termios,
-                                     struct ktermios *old)
-{
-       /*
-        * The uart clk is 50Mhz, and the baud rate come from:
-        *      baud = 50M * MUL / (DIV * PS * DLAB)
-        */
-       intel_mid_set_termios(p, termios, old, 50000000);
-}
-
-static bool intel_mid_dma_filter(struct dma_chan *chan, void *param)
-{
-       struct hsu_dma_slave *s = param;
-
-       if (s->dma_dev != chan->device->dev || s->chan_id != chan->chan_id)
-               return false;
-
-       chan->private = s;
-       return true;
-}
-
-static int intel_mid_serial_setup(struct serial_private *priv,
-                                 const struct pciserial_board *board,
-                                 struct uart_8250_port *port, int idx,
-                                 int index, struct pci_dev *dma_dev)
-{
-       struct device *dev = port->port.dev;
-       struct uart_8250_dma *dma;
-       struct hsu_dma_slave *tx_param, *rx_param;
-
-       dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
-       if (!dma)
-               return -ENOMEM;
-
-       tx_param = devm_kzalloc(dev, sizeof(*tx_param), GFP_KERNEL);
-       if (!tx_param)
-               return -ENOMEM;
-
-       rx_param = devm_kzalloc(dev, sizeof(*rx_param), GFP_KERNEL);
-       if (!rx_param)
-               return -ENOMEM;
-
-       rx_param->chan_id = index * 2 + 1;
-       tx_param->chan_id = index * 2;
-
-       dma->rxconf.src_maxburst = 64;
-       dma->txconf.dst_maxburst = 64;
-
-       rx_param->dma_dev = &dma_dev->dev;
-       tx_param->dma_dev = &dma_dev->dev;
-
-       dma->fn = intel_mid_dma_filter;
-       dma->rx_param = rx_param;
-       dma->tx_param = tx_param;
-
-       port->port.type = PORT_16750;
-       port->port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE;
-       port->dma = dma;
-
-       return pci_default_setup(priv, board, port, idx);
-}
-
-#define PCI_DEVICE_ID_INTEL_PNW_UART1  0x081b
-#define PCI_DEVICE_ID_INTEL_PNW_UART2  0x081c
-#define PCI_DEVICE_ID_INTEL_PNW_UART3  0x081d
-
-static int pnw_serial_setup(struct serial_private *priv,
-                           const struct pciserial_board *board,
-                           struct uart_8250_port *port, int idx)
-{
-       struct pci_dev *pdev = priv->dev;
-       struct pci_dev *dma_dev;
-       int index;
-
-       switch (pdev->device) {
-       case PCI_DEVICE_ID_INTEL_PNW_UART1:
-               index = 0;
-               break;
-       case PCI_DEVICE_ID_INTEL_PNW_UART2:
-               index = 1;
-               break;
-       case PCI_DEVICE_ID_INTEL_PNW_UART3:
-               index = 2;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(PCI_SLOT(pdev->devfn), 3));
-
-       port->port.set_termios = intel_mid_set_termios_50M;
-
-       return intel_mid_serial_setup(priv, board, port, idx, index, dma_dev);
-}
-
-#define PCI_DEVICE_ID_INTEL_TNG_UART   0x1191
-
-static int tng_serial_setup(struct serial_private *priv,
-                           const struct pciserial_board *board,
-                           struct uart_8250_port *port, int idx)
-{
-       struct pci_dev *pdev = priv->dev;
-       struct pci_dev *dma_dev;
-       int index = PCI_FUNC(pdev->devfn);
-
-       /* Currently no support for HSU port0 */
-       if (index-- == 0)
-               return -ENODEV;
-
-       dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(5, 0));
-
-       port->port.set_termios = intel_mid_set_termios_38_4M;
-
-       return intel_mid_serial_setup(priv, board, port, idx, index, dma_dev);
-}
-
 static int
 pci_omegapci_setup(struct serial_private *priv,
                      const struct pciserial_board *board,
@@ -2210,34 +2048,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
                .subdevice      = PCI_ANY_ID,
                .setup          = byt_serial_setup,
        },
-       {
-               .vendor         = PCI_VENDOR_ID_INTEL,
-               .device         = PCI_DEVICE_ID_INTEL_PNW_UART1,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = pnw_serial_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_INTEL,
-               .device         = PCI_DEVICE_ID_INTEL_PNW_UART2,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = pnw_serial_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_INTEL,
-               .device         = PCI_DEVICE_ID_INTEL_PNW_UART3,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = pnw_serial_setup,
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_INTEL,
-               .device         = PCI_DEVICE_ID_INTEL_TNG_UART,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .setup          = tng_serial_setup,
-       },
        {
                .vendor         = PCI_VENDOR_ID_INTEL,
                .device         = PCI_DEVICE_ID_INTEL_BSW_UART1,
@@ -3119,8 +2929,6 @@ enum pci_board_num_t {
        pbn_ADDIDATA_PCIe_8_3906250,
        pbn_ce4100_1_115200,
        pbn_byt,
-       pbn_pnw,
-       pbn_tng,
        pbn_qrk,
        pbn_omegapci,
        pbn_NETMOS9900_2s_115200,
@@ -3907,16 +3715,6 @@ static struct pciserial_board pci_boards[] = {
                .uart_offset    = 0x80,
                .reg_shift      = 2,
        },
-       [pbn_pnw] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 1,
-               .base_baud      = 115200,
-       },
-       [pbn_tng] = {
-               .flags          = FL_BASE0,
-               .num_ports      = 1,
-               .base_baud      = 1843200,
-       },
        [pbn_qrk] = {
                .flags          = FL_BASE0,
                .num_ports      = 1,
@@ -4005,6 +3803,13 @@ static const struct pci_device_id blacklist[] = {
        { PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */
        { PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */
        { PCI_DEVICE(0x1c00, 0x3470), }, /* WCH CH384 4S */
+
+       /* Intel platforms with MID UART */
+       { PCI_VDEVICE(INTEL, 0x081b), },
+       { PCI_VDEVICE(INTEL, 0x081c), },
+       { PCI_VDEVICE(INTEL, 0x081d), },
+       { PCI_VDEVICE(INTEL, 0x1191), },
+       { PCI_VDEVICE(INTEL, 0x19d8), },
 };
 
 /*
@@ -5701,26 +5506,6 @@ static struct pci_device_id serial_pci_tbl[] = {
                PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000,
                pbn_byt },
 
-       /*
-        * Intel Penwell
-        */
-       {       PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART1,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_pnw},
-       {       PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART2,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_pnw},
-       {       PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART3,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_pnw},
-
-       /*
-        * Intel Tangier
-        */
-       {       PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TNG_UART,
-               PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-               pbn_tng},
-
        /*
         * Intel Quark x1000
         */
index 0bbf34035d6a51edb267d2f53c66fc13d7b54260..52d82d2ac726be56d5838b872b9049b3c7729188 100644 (file)
@@ -284,7 +284,7 @@ static void default_serial_dl_write(struct uart_8250_port *up, int value)
        serial_out(up, UART_DLM, value >> 8 & 0xff);
 }
 
-#if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X)
+#ifdef CONFIG_SERIAL_8250_RT288X
 
 /* Au1x00/RT288x UART hardware has a weird register layout */
 static const s8 au_io_in_map[8] = {
@@ -435,7 +435,7 @@ static void set_io_from_upio(struct uart_port *p)
                p->serial_out = mem32be_serial_out;
                break;
 
-#if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X)
+#ifdef CONFIG_SERIAL_8250_RT288X
        case UPIO_AU:
                p->serial_in = au_serial_in;
                p->serial_out = au_serial_out;
@@ -1246,6 +1246,9 @@ static void autoconfig_irq(struct uart_8250_port *up)
                inb_p(ICP);
        }
 
+       if (uart_console(port))
+               console_lock();
+
        /* forget possible initially masked and pending IRQ */
        probe_irq_off(probe_irq_on());
        save_mcr = serial_in(up, UART_MCR);
@@ -1277,6 +1280,9 @@ static void autoconfig_irq(struct uart_8250_port *up)
        if (port->flags & UPF_FOURPORT)
                outb_p(save_ICP, ICP);
 
+       if (uart_console(port))
+               console_unlock();
+
        port->irq = (irq > 0) ? irq : 0;
 }
 
@@ -1807,9 +1813,6 @@ int serial8250_do_startup(struct uart_port *port)
        unsigned char lsr, iir;
        int retval;
 
-       if (port->type == PORT_8250_CIR)
-               return -ENODEV;
-
        if (!port->fifosize)
                port->fifosize = uart_config[port->type].fifo_size;
        if (!up->tx_loadsz)
@@ -2230,6 +2233,23 @@ static void serial8250_set_divisor(struct uart_port *port, unsigned int baud,
                serial_port_out(port, 0x2, quot_frac);
 }
 
+static unsigned int
+serial8250_get_baud_rate(struct uart_port *port, struct ktermios *termios,
+                        struct ktermios *old)
+{
+       unsigned int tolerance = port->uartclk / 100;
+
+       /*
+        * Ask the core to calculate the divisor for us.
+        * Allow 1% tolerance at the upper limit so uart clks marginally
+        * slower than nominal still match standard baud rates without
+        * causing transmission errors.
+        */
+       return uart_get_baud_rate(port, termios, old,
+                                 port->uartclk / 16 / 0xffff,
+                                 (port->uartclk + tolerance) / 16);
+}
+
 void
 serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
                          struct ktermios *old)
@@ -2241,12 +2261,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
 
        cval = serial8250_compute_lcr(up, termios->c_cflag);
 
-       /*
-        * Ask the core to calculate the divisor for us.
-        */
-       baud = uart_get_baud_rate(port, termios, old,
-                                 port->uartclk / 16 / 0xffff,
-                                 port->uartclk / 16);
+       baud = serial8250_get_baud_rate(port, termios, old);
        quot = serial8250_get_divisor(up, baud, &frac);
 
        /*
@@ -2513,14 +2528,8 @@ static void serial8250_release_port(struct uart_port *port)
 static int serial8250_request_port(struct uart_port *port)
 {
        struct uart_8250_port *up = up_to_u8250p(port);
-       int ret;
-
-       if (port->type == PORT_8250_CIR)
-               return -ENODEV;
-
-       ret = serial8250_request_std_resource(up);
 
-       return ret;
+       return serial8250_request_std_resource(up);
 }
 
 static int fcr_get_rxtrig_bytes(struct uart_8250_port *up)
@@ -2668,9 +2677,6 @@ static void serial8250_config_port(struct uart_port *port, int flags)
        struct uart_8250_port *up = up_to_u8250p(port);
        int ret;
 
-       if (port->type == PORT_8250_CIR)
-               return;
-
        /*
         * Find the region that we can probe for.  This in turn
         * tells us whether we can probe for the type of port.
@@ -2804,6 +2810,27 @@ static void serial8250_console_putchar(struct uart_port *port, int ch)
        serial_port_out(port, UART_TX, ch);
 }
 
+/*
+ *     Restore serial console when h/w power-off detected
+ */
+static void serial8250_console_restore(struct uart_8250_port *up)
+{
+       struct uart_port *port = &up->port;
+       struct ktermios termios;
+       unsigned int baud, quot, frac = 0;
+
+       termios.c_cflag = port->cons->cflag;
+       if (port->state->port.tty && termios.c_cflag == 0)
+               termios.c_cflag = port->state->port.tty->termios.c_cflag;
+
+       baud = serial8250_get_baud_rate(port, &termios, NULL);
+       quot = serial8250_get_divisor(up, baud, &frac);
+
+       serial8250_set_divisor(port, baud, quot, frac);
+       serial_port_out(port, UART_LCR, up->lcr);
+       serial_port_out(port, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
+}
+
 /*
  *     Print a string to the serial port trying not to disturb
  *     any possible real use of the port...
@@ -2841,22 +2868,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
 
        /* check scratch reg to see if port powered off during system sleep */
        if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) {
-               struct ktermios termios;
-               unsigned int baud, quot, frac = 0;
-
-               termios.c_cflag = port->cons->cflag;
-               if (port->state->port.tty && termios.c_cflag == 0)
-                       termios.c_cflag = port->state->port.tty->termios.c_cflag;
-
-               baud = uart_get_baud_rate(port, &termios, NULL,
-                                         port->uartclk / 16 / 0xffff,
-                                         port->uartclk / 16);
-               quot = serial8250_get_divisor(up, baud, &frac);
-
-               serial8250_set_divisor(port, baud, quot, frac);
-               serial_port_out(port, UART_LCR, up->lcr);
-               serial_port_out(port, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
-
+               serial8250_console_restore(up);
                up->canary = 0;
        }
 
index e1de1181b322d6c4d40f689e99501915f2e63b8e..e6f5e12a2d83bcc5c03b3e2b81caf50f70721467 100644 (file)
@@ -274,8 +274,8 @@ config SERIAL_8250_ACORN
 
 config SERIAL_8250_FSL
        bool
-       depends on SERIAL_8250_CONSOLE && PPC_UDBG_16550
-       default PPC
+       depends on SERIAL_8250_CONSOLE
+       default PPC || ARM || ARM64
 
 config SERIAL_8250_DW
        tristate "Support for Synopsys DesignWare 8250 quirks"
@@ -294,11 +294,12 @@ config SERIAL_8250_EM
 
 config SERIAL_8250_RT288X
        bool "Ralink RT288x/RT305x/RT3662/RT3883 serial port support"
-       depends on SERIAL_8250 && (SOC_RT288X || SOC_RT305X || SOC_RT3883 || SOC_MT7620)
+       depends on SERIAL_8250
+       default y if MIPS_ALCHEMY || SOC_RT288X || SOC_RT305X || SOC_RT3883 || SOC_MT7620
        help
-         If you have a Ralink RT288x/RT305x SoC based board and want to use the
-         serial port, say Y to this option. The driver can handle up to 2 serial
-         ports. If unsure, say N.
+         Selecting this option will add support for the alternate register
+         layout used by Ralink RT288x/RT305x, Alchemy Au1xxx, and some others.
+         If unsure, say N.
 
 config SERIAL_8250_OMAP
        tristate "Support for OMAP internal UART (8250 based driver)"
@@ -337,7 +338,7 @@ config SERIAL_8250_FINTEK
          through the PNP driver. If unsure, say N.
 
 config SERIAL_8250_LPC18XX
-       bool "NXP LPC18xx/43xx serial port support"
+       tristate "NXP LPC18xx/43xx serial port support"
        depends on SERIAL_8250 && OF && (ARCH_LPC18XX || COMPILE_TEST)
        default ARCH_LPC18XX
        help
@@ -366,3 +367,13 @@ config SERIAL_8250_INGENIC
        help
          If you have a system using an Ingenic SoC and wish to make use of
          its UARTs, say Y to this option. If unsure, say N.
+
+config SERIAL_8250_MID
+       tristate "Support for serial ports on Intel MID platforms"
+       depends on SERIAL_8250 && PCI
+       select HSU_DMA if SERIAL_8250_DMA
+       select HSU_DMA_PCI if X86_INTEL_MID
+       help
+         Selecting this option will enable handling of the extra features
+         present on the UART found on Intel Medfield SOC and various other
+         Intel platforms.
index 39c6d2277570bcacef38c09fd8203ae8b6793ccd..e177f8681adad8831a1bf7e6935664d28e9b001e 100644 (file)
@@ -27,5 +27,6 @@ obj-$(CONFIG_SERIAL_8250_LPC18XX)     += 8250_lpc18xx.o
 obj-$(CONFIG_SERIAL_8250_MT6577)       += 8250_mtk.o
 obj-$(CONFIG_SERIAL_8250_UNIPHIER)     += 8250_uniphier.o
 obj-$(CONFIG_SERIAL_8250_INGENIC)      += 8250_ingenic.o
+obj-$(CONFIG_SERIAL_8250_MID)          += 8250_mid.o
 
 CFLAGS_8250_ingenic.o += -I$(srctree)/scripts/dtc/libfdt
index 687b1ea294b79bbf999c4c86747ee2df7ba30df5..1aec4404062d8f1995e8da8da821a1b176cb0e7a 100644 (file)
@@ -115,9 +115,9 @@ config SERIAL_SB1250_DUART_CONSOLE
 
 config SERIAL_ATMEL
        bool "AT91 / AT32 on-chip serial port support"
-       depends on ARCH_AT91 || AVR32
+       depends on ARCH_AT91 || AVR32 || COMPILE_TEST
        select SERIAL_CORE
-       select SERIAL_MCTRL_GPIO
+       select SERIAL_MCTRL_GPIO if GPIOLIB
        help
          This enables the driver for the on-chip UARTs of the Atmel
          AT91 and AT32 processors.
@@ -571,7 +571,7 @@ config BFIN_UART3_CTSRTS
 
 config SERIAL_IMX
        tristate "IMX serial port support"
-       depends on ARCH_MXC
+       depends on ARCH_MXC || COMPILE_TEST
        select SERIAL_CORE
        select RATIONAL
        help
@@ -582,6 +582,7 @@ config SERIAL_IMX_CONSOLE
        bool "Console on IMX serial port"
        depends on SERIAL_IMX=y
        select SERIAL_CORE_CONSOLE
+       select SERIAL_EARLYCON if OF
        help
          If you have enabled the serial port on the Freescale IMX
          CPU you can make it the console by answering Y to this option.
@@ -743,7 +744,7 @@ config SERIAL_SH_SCI_CONSOLE
 
 config SERIAL_SH_SCI_DMA
        bool "DMA support"
-       depends on SERIAL_SH_SCI && SH_DMAE
+       depends on SERIAL_SH_SCI && DMA_ENGINE
 
 config SERIAL_PNX8XXX
        bool "Enable PNX8XXX SoCs' UART Support"
@@ -1408,7 +1409,7 @@ config SERIAL_PCH_UART_CONSOLE
          warnings and which allows logins in single user mode).
 
 config SERIAL_MXS_AUART
-       depends on ARCH_MXS
+       depends on ARCH_MXS || COMPILE_TEST
        tristate "MXS AUART support"
        select SERIAL_CORE
        select SERIAL_MCTRL_GPIO if GPIOLIB
@@ -1538,6 +1539,7 @@ config SERIAL_FSL_LPUART
        tristate "Freescale lpuart serial port support"
        depends on HAS_DMA
        select SERIAL_CORE
+       select SERIAL_EARLYCON
        help
          Support for the on-chip lpuart on some Freescale SOCs.
 
index fd87a6f574e3b32e370ce27244960c37c5f36576..61b607f2488e36761069e0e58a9bd2cf74661100 100644 (file)
@@ -508,29 +508,6 @@ static struct uart_driver altera_uart_driver = {
        .cons           = ALTERA_UART_CONSOLE,
 };
 
-#ifdef CONFIG_OF
-static int altera_uart_get_of_uartclk(struct platform_device *pdev,
-                                     struct uart_port *port)
-{
-       int len;
-       const __be32 *clk;
-
-       clk = of_get_property(pdev->dev.of_node, "clock-frequency", &len);
-       if (!clk || len < sizeof(__be32))
-               return -ENODEV;
-
-       port->uartclk = be32_to_cpup(clk);
-
-       return 0;
-}
-#else
-static int altera_uart_get_of_uartclk(struct platform_device *pdev,
-                                     struct uart_port *port)
-{
-       return -ENODEV;
-}
-#endif /* CONFIG_OF */
-
 static int altera_uart_probe(struct platform_device *pdev)
 {
        struct altera_uart_platform_uart *platp = dev_get_platdata(&pdev->dev);
@@ -570,7 +547,8 @@ static int altera_uart_probe(struct platform_device *pdev)
        if (platp)
                port->uartclk = platp->uartclk;
        else {
-               ret = altera_uart_get_of_uartclk(pdev, port);
+               ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+                                          &port->uartclk);
                if (ret)
                        return ret;
        }
index fd27e986b1dd3437dfd2560ec11efd8def7bf254..899a77187bdead871b2e1f22ed4f320486e5288b 100644 (file)
@@ -191,8 +191,8 @@ struct uart_amba_port {
  */
 static int pl011_fifo_to_tty(struct uart_amba_port *uap)
 {
-       u16 status, ch;
-       unsigned int flag, max_count = 256;
+       u16 status;
+       unsigned int ch, flag, max_count = 256;
        int fifotaken = 0;
 
        while (max_count--) {
index f3af317131acb022616739800cca755c29ebf404..75eb083b3361c8fc47c910eecc316152e4e34e84 100644 (file)
@@ -581,6 +581,7 @@ static const struct of_device_id apbuart_match[] = {
         },
        {},
 };
+MODULE_DEVICE_TABLE(of, apbuart_match);
 
 static struct platform_driver grlib_apbuart_of_driver = {
        .probe = apbuart_probe,
index 538ea03bc101a2994324d2ce33b8f7b237c12c78..94294558943cba662d03f019b30659d9cd008870 100644 (file)
@@ -111,6 +111,12 @@ struct atmel_uart_char {
 
 #define ATMEL_SERIAL_RINGSIZE 1024
 
+/*
+ * at91: 6 USARTs and one DBGU port (SAM9260)
+ * avr32: 4
+ */
+#define ATMEL_MAX_UART         7
+
 /*
  * We wrap our port structure around the generic uart_port.
  */
@@ -921,7 +927,7 @@ static int atmel_prepare_tx_dma(struct uart_port *port)
        sg_set_page(&atmel_port->sg_tx,
                        virt_to_page(port->state->xmit.buf),
                        UART_XMIT_SIZE,
-                       (int)port->state->xmit.buf & ~PAGE_MASK);
+                       (unsigned long)port->state->xmit.buf & ~PAGE_MASK);
        nent = dma_map_sg(port->dev,
                                &atmel_port->sg_tx,
                                1,
@@ -931,10 +937,10 @@ static int atmel_prepare_tx_dma(struct uart_port *port)
                dev_dbg(port->dev, "need to release resource of dma\n");
                goto chan_err;
        } else {
-               dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__,
+               dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", __func__,
                        sg_dma_len(&atmel_port->sg_tx),
                        port->state->xmit.buf,
-                       sg_dma_address(&atmel_port->sg_tx));
+                       &sg_dma_address(&atmel_port->sg_tx));
        }
 
        /* Configure the slave DMA */
@@ -1103,7 +1109,7 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
        sg_set_page(&atmel_port->sg_rx,
                    virt_to_page(ring->buf),
                    sizeof(struct atmel_uart_char) * ATMEL_SERIAL_RINGSIZE,
-                   (int)ring->buf & ~PAGE_MASK);
+                   (unsigned long)ring->buf & ~PAGE_MASK);
        nent = dma_map_sg(port->dev,
                          &atmel_port->sg_rx,
                          1,
@@ -1113,10 +1119,10 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
                dev_dbg(port->dev, "need to release resource of dma\n");
                goto chan_err;
        } else {
-               dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__,
+               dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", __func__,
                        sg_dma_len(&atmel_port->sg_rx),
                        ring->buf,
-                       sg_dma_address(&atmel_port->sg_rx));
+                       &sg_dma_address(&atmel_port->sg_rx));
        }
 
        /* Configure the slave DMA */
@@ -1676,15 +1682,15 @@ static void atmel_init_rs485(struct uart_port *port,
        struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev);
 
        if (np) {
+               struct serial_rs485 *rs485conf = &port->rs485;
                u32 rs485_delay[2];
                /* rs485 properties */
                if (of_property_read_u32_array(np, "rs485-rts-delay",
                                        rs485_delay, 2) == 0) {
-                       struct serial_rs485 *rs485conf = &port->rs485;
-
                        rs485conf->delay_rts_before_send = rs485_delay[0];
                        rs485conf->delay_rts_after_send = rs485_delay[1];
                        rs485conf->flags = 0;
+               }
 
                if (of_get_property(np, "rs485-rx-during-tx", NULL))
                        rs485conf->flags |= SER_RS485_RX_DURING_TX;
@@ -1692,7 +1698,6 @@ static void atmel_init_rs485(struct uart_port *port,
                if (of_get_property(np, "linux,rs485-enabled-at-boot-time",
                                                                NULL))
                        rs485conf->flags |= SER_RS485_ENABLED;
-               }
        } else {
                port->rs485       = pdata->rs485;
        }
@@ -2296,7 +2301,7 @@ static int atmel_verify_port(struct uart_port *port, struct serial_struct *ser)
                ret = -EINVAL;
        if (port->uartclk / 16 != ser->baud_base)
                ret = -EINVAL;
-       if ((void *)port->mapbase != ser->iomem_base)
+       if (port->mapbase != (unsigned long)ser->iomem_base)
                ret = -EINVAL;
        if (port->iobase != ser->port)
                ret = -EINVAL;
@@ -2686,7 +2691,7 @@ static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev)
        enum mctrl_gpio_idx i;
        struct gpio_desc *gpiod;
 
-       p->gpios = mctrl_gpio_init(dev, 0);
+       p->gpios = mctrl_gpio_init_noauto(dev, 0);
        if (IS_ERR(p->gpios))
                return PTR_ERR(p->gpios);
 
index d5d2dd7c79174820432363d4a7076566eafc2204..b3a4e0cdddaab29b0b86e42738a763e279411354 100644 (file)
@@ -500,7 +500,7 @@ static int uart_clps711x_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, s);
 
-       s->gpios = mctrl_gpio_init(&pdev->dev, 0);
+       s->gpios = mctrl_gpio_init_noauto(&pdev->dev, 0);
        if (IS_ERR(s->gpios))
            return PTR_ERR(s->gpios);
 
index 08431adeacd5dcd4f24e4ba395a228eab1060457..d3e3d42c0c129035c96ca9ee7578d1195fd7db56 100644 (file)
@@ -1450,6 +1450,7 @@ static const struct of_device_id cpm_uart_match[] = {
        },
        {}
 };
+MODULE_DEVICE_TABLE(of, cpm_uart_match);
 
 static struct platform_driver cpm_uart_driver = {
        .driver = {
index 3e4470af5c50d56f8484273af1c61f864d8d2d03..f13f2ebd215bc9afe2ad64ae9070b8c069967d18 100644 (file)
@@ -3655,7 +3655,6 @@ rs_close(struct tty_struct *tty, struct file * filp)
                wake_up_interruptible(&info->port.open_wait);
        }
        info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-       wake_up_interruptible(&info->port.close_wait);
        local_irq_restore(flags);
 
        /* port closed */
@@ -3758,23 +3757,6 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
        int             retval;
        int             do_clocal = 0;
 
-       /*
-        * If the device is in the middle of being closed, then block
-        * until it's done, and then try again.
-        */
-       if (info->port.flags & ASYNC_CLOSING) {
-               wait_event_interruptible_tty(tty, info->port.close_wait,
-                       !(info->port.flags & ASYNC_CLOSING));
-#ifdef SERIAL_DO_RESTART
-               if (info->port.flags & ASYNC_HUP_NOTIFY)
-                       return -EAGAIN;
-               else
-                       return -ERESTARTSYS;
-#else
-               return -EAGAIN;
-#endif
-       }
-
        /*
         * If non-blocking mode is set, or the port is not enabled,
         * then make the check up front and then exit.
@@ -3825,7 +3807,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
 #endif
                        break;
                }
-               if (!(info->port.flags & ASYNC_CLOSING) && do_clocal)
+               if (do_clocal)
                        /* && (do_clocal || DCD_IS_ASSERTED) */
                        break;
                if (signal_pending(current)) {
@@ -3894,20 +3876,6 @@ rs_open(struct tty_struct *tty, struct file * filp)
 
        info->port.low_latency = !!(info->port.flags & ASYNC_LOW_LATENCY);
 
-       /*
-        * If the port is in the middle of closing, bail out now
-        */
-       if (info->port.flags & ASYNC_CLOSING) {
-               wait_event_interruptible_tty(tty, info->port.close_wait,
-                       !(info->port.flags & ASYNC_CLOSING));
-#ifdef SERIAL_DO_RESTART
-               return ((info->port.flags & ASYNC_HUP_NOTIFY) ?
-                       -EAGAIN : -ERESTARTSYS);
-#else
-               return -EAGAIN;
-#endif
-       }
-
        /*
         * If DMA is enabled try to allocate the irq's.
         */
index 08ce76f4f261043c20d843c88c8d4dfe8167ce64..3d790033744efd060bf42dad1f494a5ee4da0155 100644 (file)
@@ -1746,6 +1746,45 @@ static struct console lpuart32_console = {
        .data           = &lpuart_reg,
 };
 
+static void lpuart_early_write(struct console *con, const char *s, unsigned n)
+{
+       struct earlycon_device *dev = con->data;
+
+       uart_console_write(&dev->port, s, n, lpuart_console_putchar);
+}
+
+static void lpuart32_early_write(struct console *con, const char *s, unsigned n)
+{
+       struct earlycon_device *dev = con->data;
+
+       uart_console_write(&dev->port, s, n, lpuart32_console_putchar);
+}
+
+static int __init lpuart_early_console_setup(struct earlycon_device *device,
+                                         const char *opt)
+{
+       if (!device->port.membase)
+               return -ENODEV;
+
+       device->con->write = lpuart_early_write;
+       return 0;
+}
+
+static int __init lpuart32_early_console_setup(struct earlycon_device *device,
+                                         const char *opt)
+{
+       if (!device->port.membase)
+               return -ENODEV;
+
+       device->con->write = lpuart32_early_write;
+       return 0;
+}
+
+OF_EARLYCON_DECLARE(lpuart, "fsl,vf610-lpuart", lpuart_early_console_setup);
+OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1021a-lpuart", lpuart32_early_console_setup);
+EARLYCON_DECLARE(lpuart, lpuart_early_console_setup);
+EARLYCON_DECLARE(lpuart32, lpuart32_early_console_setup);
+
 #define LPUART_CONSOLE (&lpuart_console)
 #define LPUART32_CONSOLE       (&lpuart32_console)
 #else
index d0388a071ba1d474025a74fec8cfb80f5a1ed4a0..016e4be05cec3e60141f0497dd643d9ad0c7ee98 100644 (file)
 #define USR1_ESCF      (1<<11) /* Escape seq interrupt flag */
 #define USR1_FRAMERR   (1<<10) /* Frame error interrupt flag */
 #define USR1_RRDY      (1<<9)   /* Receiver ready interrupt/dma flag */
+#define USR1_AGTIM     (1<<8)   /* Ageing timer interrupt flag */
 #define USR1_TIMEOUT   (1<<7)   /* Receive timeout interrupt status */
 #define USR1_RXDS       (1<<6)  /* Receiver idle interrupt flag */
 #define USR1_AIRINT     (1<<5)  /* Async IR wake interrupt flag */
@@ -728,11 +729,15 @@ static void imx_dma_rxint(struct imx_port *sport)
        if ((temp & USR2_RDR) && !sport->dma_is_rxing) {
                sport->dma_is_rxing = 1;
 
-               /* disable the `Recerver Ready Interrrupt` */
+               /* disable the receiver ready and aging timer interrupts */
                temp = readl(sport->port.membase + UCR1);
                temp &= ~(UCR1_RRDYEN);
                writel(temp, sport->port.membase + UCR1);
 
+               temp = readl(sport->port.membase + UCR2);
+               temp &= ~(UCR2_ATEN);
+               writel(temp, sport->port.membase + UCR2);
+
                /* tell the DMA to receive the data. */
                start_rx_dma(sport);
        }
@@ -749,7 +754,7 @@ static irqreturn_t imx_int(int irq, void *dev_id)
        sts = readl(sport->port.membase + USR1);
        sts2 = readl(sport->port.membase + USR2);
 
-       if (sts & USR1_RRDY) {
+       if (sts & (USR1_RRDY | USR1_AGTIM)) {
                if (sport->dma_is_enabled)
                        imx_dma_rxint(sport);
                else
@@ -852,19 +857,6 @@ static void imx_break_ctl(struct uart_port *port, int break_state)
        spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
-#define TXTL 2 /* reset default */
-#define RXTL 1 /* reset default */
-
-static void imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
-{
-       unsigned int val;
-
-       /* set receiver / transmitter trigger level */
-       val = readl(sport->port.membase + UFCR) & (UFCR_RFDIV | UFCR_DCEDTE);
-       val |= TXTL << UFCR_TXTL_SHF | RXTL;
-       writel(val, sport->port.membase + UFCR);
-}
-
 #define RX_BUF_SIZE    (PAGE_SIZE)
 static void imx_rx_dma_done(struct imx_port *sport)
 {
@@ -873,11 +865,15 @@ static void imx_rx_dma_done(struct imx_port *sport)
 
        spin_lock_irqsave(&sport->port.lock, flags);
 
-       /* Enable this interrupt when the RXFIFO is empty. */
+       /* re-enable interrupts to get notified when new symbols are incoming */
        temp = readl(sport->port.membase + UCR1);
        temp |= UCR1_RRDYEN;
        writel(temp, sport->port.membase + UCR1);
 
+       temp = readl(sport->port.membase + UCR2);
+       temp |= UCR2_ATEN;
+       writel(temp, sport->port.membase + UCR2);
+
        sport->dma_is_rxing = 0;
 
        /* Is the shutdown waiting for us? */
@@ -888,14 +884,12 @@ static void imx_rx_dma_done(struct imx_port *sport)
 }
 
 /*
- * There are three kinds of RX DMA interrupts(such as in the MX6Q):
+ * There are two kinds of RX DMA interrupts(such as in the MX6Q):
  *   [1] the RX DMA buffer is full.
- *   [2] the Aging timer expires(wait for 8 bytes long)
- *   [3] the Idle Condition Detect(enabled the UCR4_IDDMAEN).
+ *   [2] the aging timer expires
  *
- * The [2] is trigger when a character was been sitting in the FIFO
- * meanwhile [3] can wait for 32 bytes long when the RX line is
- * on IDLE state and RxFIFO is empty.
+ * Condition [2] is triggered when a character has been sitting in the FIFO
+ * for at least 8 byte durations.
  */
 static void dma_rx_callback(void *data)
 {
@@ -913,13 +907,6 @@ static void dma_rx_callback(void *data)
        status = dmaengine_tx_status(chan, (dma_cookie_t)0, &state);
        count = RX_BUF_SIZE - state.residue;
 
-       if (readl(sport->port.membase + USR2) & USR2_IDLE) {
-               /* In condition [3] the SDMA counted up too early */
-               count--;
-
-               writel(USR2_IDLE, sport->port.membase + USR2);
-       }
-
        dev_dbg(sport->port.dev, "We get %d bytes.\n", count);
 
        if (count) {
@@ -931,23 +918,21 @@ static void dma_rx_callback(void *data)
                                sport->port.icount.buf_overrun++;
                }
                tty_flip_buffer_push(port);
+               sport->port.icount.rx += count;
+       }
 
+       /*
+        * Restart RX DMA directly if more data is available in order to skip
+        * the roundtrip through the IRQ handler. If there is some data already
+        * in the FIFO, DMA needs to be restarted soon anyways.
+        *
+        * Otherwise stop the DMA and reactivate FIFO IRQs to restart DMA once
+        * data starts to arrive again.
+        */
+       if (readl(sport->port.membase + USR2) & USR2_RDR)
                start_rx_dma(sport);
-       } 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
-                */
+       else
                imx_rx_dma_done(sport);
-       }
 }
 
 static int start_rx_dma(struct imx_port *sport)
@@ -980,6 +965,22 @@ static int start_rx_dma(struct imx_port *sport)
        return 0;
 }
 
+#define TXTL_DEFAULT 2 /* reset default */
+#define RXTL_DEFAULT 1 /* reset default */
+#define TXTL_DMA 8 /* DMA burst setting */
+#define RXTL_DMA 9 /* DMA burst setting */
+
+static void imx_setup_ufcr(struct imx_port *sport,
+                         unsigned char txwl, unsigned char rxwl)
+{
+       unsigned int val;
+
+       /* set receiver / transmitter trigger level */
+       val = readl(sport->port.membase + UFCR) & (UFCR_RFDIV | UFCR_DCEDTE);
+       val |= txwl << UFCR_TXTL_SHF | rxwl;
+       writel(val, sport->port.membase + UFCR);
+}
+
 static void imx_uart_dma_exit(struct imx_port *sport)
 {
        if (sport->dma_chan_rx) {
@@ -1015,7 +1016,8 @@ static int imx_uart_dma_init(struct imx_port *sport)
        slave_config.direction = DMA_DEV_TO_MEM;
        slave_config.src_addr = sport->port.mapbase + URXD0;
        slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
-       slave_config.src_maxburst = RXTL;
+       /* one byte less than the watermark level to enable the aging timer */
+       slave_config.src_maxburst = RXTL_DMA - 1;
        ret = dmaengine_slave_config(sport->dma_chan_rx, &slave_config);
        if (ret) {
                dev_err(dev, "error in RX dma configuration.\n");
@@ -1039,7 +1041,7 @@ static int imx_uart_dma_init(struct imx_port *sport)
        slave_config.direction = DMA_MEM_TO_DEV;
        slave_config.dst_addr = sport->port.mapbase + URTX0;
        slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
-       slave_config.dst_maxburst = TXTL;
+       slave_config.dst_maxburst = TXTL_DMA;
        ret = dmaengine_slave_config(sport->dma_chan_tx, &slave_config);
        if (ret) {
                dev_err(dev, "error in TX dma configuration.");
@@ -1062,15 +1064,14 @@ static void imx_enable_dma(struct imx_port *sport)
 
        /* set UCR1 */
        temp = readl(sport->port.membase + UCR1);
-       temp |= UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN |
-               /* wait for 32 idle frames for IDDMA interrupt */
-               UCR1_ICD_REG(3);
+       temp |= UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN;
        writel(temp, sport->port.membase + UCR1);
 
-       /* set UCR4 */
-       temp = readl(sport->port.membase + UCR4);
-       temp |= UCR4_IDDMAEN;
-       writel(temp, sport->port.membase + UCR4);
+       temp = readl(sport->port.membase + UCR2);
+       temp |= UCR2_ATEN;
+       writel(temp, sport->port.membase + UCR2);
+
+       imx_setup_ufcr(sport, TXTL_DMA, RXTL_DMA);
 
        sport->dma_is_enabled = 1;
 }
@@ -1086,13 +1087,10 @@ static void imx_disable_dma(struct imx_port *sport)
 
        /* clear UCR2 */
        temp = readl(sport->port.membase + UCR2);
-       temp &= ~(UCR2_CTSC | UCR2_CTS);
+       temp &= ~(UCR2_CTSC | UCR2_CTS | UCR2_ATEN);
        writel(temp, sport->port.membase + UCR2);
 
-       /* clear UCR4 */
-       temp = readl(sport->port.membase + UCR4);
-       temp &= ~UCR4_IDDMAEN;
-       writel(temp, sport->port.membase + UCR4);
+       imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
 
        sport->dma_is_enabled = 0;
 }
@@ -1115,7 +1113,7 @@ static int imx_startup(struct uart_port *port)
                return retval;
        }
 
-       imx_setup_ufcr(sport, 0);
+       imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
 
        /* disable the DREN bit (Data Ready interrupt enable) before
         * requesting IRQs
@@ -1128,6 +1126,11 @@ static int imx_startup(struct uart_port *port)
 
        writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
 
+       /* 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);
        /* Reset fifo's and state machines */
        i = 100;
@@ -1145,6 +1148,9 @@ static int imx_startup(struct uart_port *port)
        writel(USR1_RTSD, sport->port.membase + USR1);
        writel(USR2_ORE, sport->port.membase + USR2);
 
+       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;
 
@@ -1278,7 +1284,7 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
 {
        struct imx_port *sport = (struct imx_port *)port;
        unsigned long flags;
-       unsigned int ucr2, old_ucr1, old_txrxen, baud, quot;
+       unsigned int ucr2, old_ucr1, old_ucr2, baud, quot;
        unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
        unsigned int div, ufcr;
        unsigned long num, denom;
@@ -1315,11 +1321,6 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
                        } else {
                                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;
                }
@@ -1387,10 +1388,10 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
                barrier();
 
        /* then, disable everything */
-       old_txrxen = readl(sport->port.membase + UCR2);
-       writel(old_txrxen & ~(UCR2_TXEN | UCR2_RXEN),
+       old_ucr2 = readl(sport->port.membase + UCR2);
+       writel(old_ucr2 & ~(UCR2_TXEN | UCR2_RXEN),
                        sport->port.membase + UCR2);
-       old_txrxen &= (UCR2_TXEN | UCR2_RXEN);
+       old_ucr2 &= (UCR2_TXEN | UCR2_RXEN | UCR2_ATEN);
 
        /* custom-baudrate handling */
        div = sport->port.uartclk / (baud * 16);
@@ -1431,13 +1432,11 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
        writel(old_ucr1, sport->port.membase + UCR1);
 
        /* set the parity, stop bits and data size */
-       writel(ucr2 | old_txrxen, sport->port.membase + UCR2);
+       writel(ucr2 | old_ucr2, sport->port.membase + UCR2);
 
        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);
 }
 
@@ -1503,7 +1502,7 @@ static int imx_poll_init(struct uart_port *port)
        if (retval)
                clk_disable_unprepare(sport->clk_ipg);
 
-       imx_setup_ufcr(sport, 0);
+       imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
 
        spin_lock_irqsave(&sport->port.lock, flags);
 
@@ -1773,7 +1772,7 @@ imx_console_setup(struct console *co, char *options)
        else
                imx_console_get_options(sport, &baud, &parity, &bits);
 
-       imx_setup_ufcr(sport, 0);
+       imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
 
        retval = uart_set_options(&sport->port, co, baud, parity, bits, flow);
 
@@ -1803,6 +1802,38 @@ static struct console imx_console = {
 };
 
 #define IMX_CONSOLE    &imx_console
+
+#ifdef CONFIG_OF
+static void imx_console_early_putchar(struct uart_port *port, int ch)
+{
+       while (readl_relaxed(port->membase + IMX21_UTS) & UTS_TXFULL)
+               cpu_relax();
+
+       writel_relaxed(ch, port->membase + URTX0);
+}
+
+static void imx_console_early_write(struct console *con, const char *s,
+                                   unsigned count)
+{
+       struct earlycon_device *dev = con->data;
+
+       uart_console_write(&dev->port, s, count, imx_console_early_putchar);
+}
+
+static int __init
+imx_console_early_setup(struct earlycon_device *dev, const char *opt)
+{
+       if (!dev->port.membase)
+               return -ENODEV;
+
+       dev->con->write = imx_console_early_write;
+
+       return 0;
+}
+OF_EARLYCON_DECLARE(ec_imx6q, "fsl,imx6q-uart", imx_console_early_setup);
+OF_EARLYCON_DECLARE(ec_imx21, "fsl,imx21-uart", imx_console_early_setup);
+#endif
+
 #else
 #define IMX_CONSOLE    NULL
 #endif
index e92d7ebe9e77e545dae5de45db8857535de123a6..7eb04ae71cc876c2fcd3f4826feb29f6d01b11cc 100644 (file)
@@ -691,12 +691,13 @@ static int serial_hs_lpc32xx_probe(struct platform_device *pdev)
        p->port.mapbase = res->start;
        p->port.membase = NULL;
 
-       p->port.irq = platform_get_irq(pdev, 0);
-       if (p->port.irq < 0) {
+       ret = platform_get_irq(pdev, 0);
+       if (ret < 0) {
                dev_err(&pdev->dev, "Error getting irq for HS UART port %d\n",
                        uarts_registered);
-               return p->port.irq;
+               return ret;
        }
+       p->port.irq = ret;
 
        p->port.iotype = UPIO_MEM32;
        p->port.uartclk = LPC32XX_MAIN_OSC_FREQ;
index b90e7b30468b3c885b84b379e1cfa98993993f73..3141aa20843d7d92867389711f8925e4606091df 100644 (file)
@@ -35,8 +35,6 @@
 #define MEN_Z135_BAUD_REG              0x810
 #define MEN_Z135_TIMEOUT               0x814
 
-#define MEN_Z135_MEM_SIZE              0x818
-
 #define IRQ_ID(x) ((x) & 0x1f)
 
 #define MEN_Z135_IER_RXCIEN BIT(0)             /* RX Space IRQ */
@@ -124,6 +122,7 @@ MODULE_PARM_DESC(rx_timeout, "RX timeout. "
 struct men_z135_port {
        struct uart_port port;
        struct mcb_device *mdev;
+       struct resource *mem;
        unsigned char *rxbuf;
        u32 stat_reg;
        spinlock_t lock;
@@ -734,22 +733,30 @@ static const char *men_z135_type(struct uart_port *port)
 
 static void men_z135_release_port(struct uart_port *port)
 {
+       struct men_z135_port *uart = to_men_z135(port);
+
        iounmap(port->membase);
        port->membase = NULL;
 
-       release_mem_region(port->mapbase, MEN_Z135_MEM_SIZE);
+       mcb_release_mem(uart->mem);
 }
 
 static int men_z135_request_port(struct uart_port *port)
 {
-       int size = MEN_Z135_MEM_SIZE;
+       struct men_z135_port *uart = to_men_z135(port);
+       struct mcb_device *mdev = uart->mdev;
+       struct resource *mem;
+
+       mem = mcb_request_mem(uart->mdev, dev_name(&mdev->dev));
+       if (IS_ERR(mem))
+               return PTR_ERR(mem);
 
-       if (!request_mem_region(port->mapbase, size, "men_z135_port"))
-               return -EBUSY;
+       port->mapbase = mem->start;
+       uart->mem = mem;
 
-       port->membase = ioremap(port->mapbase, MEN_Z135_MEM_SIZE);
+       port->membase = ioremap(mem->start, resource_size(mem));
        if (port->membase == NULL) {
-               release_mem_region(port->mapbase, MEN_Z135_MEM_SIZE);
+               mcb_release_mem(mem);
                return -ENOMEM;
        }
 
index 41de374d9784384ece372732e972a3de7c52e84f..8c3e5131447027104f4497f177faec3e4df68ade 100644 (file)
@@ -1135,6 +1135,13 @@ mpc52xx_uart_startup(struct uart_port *port)
        psc_ops->command(port, MPC52xx_PSC_RST_RX);
        psc_ops->command(port, MPC52xx_PSC_RST_TX);
 
+       /*
+        * According to Freescale's support the RST_TX command can produce a
+        * spike on the TX pin. So they recommend to delay "for one character".
+        * One millisecond should be enough for everyone.
+        */
+       msleep(1);
+
        psc_ops->set_sicr(port, 0);     /* UART mode DCD ignored */
 
        psc_ops->fifo_init(port);
index 82bb6d1fe23b416f05ac5bee9879ae299ed1b185..cadfd1cfae2b9dde93f3d0d08e0d49f5edc4b708 100644 (file)
@@ -55,8 +55,6 @@
 #define SUPPORT_SYSRQ
 #endif
 
-#include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/ioport.h>
@@ -755,7 +753,7 @@ static int mpsc_alloc_ring_mem(struct mpsc_port_info *pi)
                pi->port.line);
 
        if (!pi->dma_region) {
-               if (!dma_supported(pi->port.dev, 0xffffffff)) {
+               if (!dma_set_mask(pi->port.dev, 0xffffffff)) {
                        printk(KERN_ERR "MPSC: Inadequate DMA support\n");
                        rc = -ENXIO;
                } else if ((pi->dma_region = dma_alloc_noncoherent(pi->port.dev,
@@ -2108,26 +2106,11 @@ static int mpsc_drv_probe(struct platform_device *dev)
        return rc;
 }
 
-static int mpsc_drv_remove(struct platform_device *dev)
-{
-       pr_debug("mpsc_drv_exit: Removing MPSC %d\n", dev->id);
-
-       if (dev->id < MPSC_NUM_CTLRS) {
-               uart_remove_one_port(&mpsc_reg, &mpsc_ports[dev->id].port);
-               mpsc_release_port((struct uart_port *)
-                               &mpsc_ports[dev->id].port);
-               mpsc_drv_unmap_regs(&mpsc_ports[dev->id]);
-               return 0;
-       } else {
-               return -ENODEV;
-       }
-}
-
 static struct platform_driver mpsc_driver = {
        .probe  = mpsc_drv_probe,
-       .remove = mpsc_drv_remove,
        .driver = {
-               .name   = MPSC_CTLR_NAME,
+               .name                   = MPSC_CTLR_NAME,
+               .suppress_bind_attrs    = true,
        },
 };
 
@@ -2156,22 +2139,10 @@ static int __init mpsc_drv_init(void)
 
        return rc;
 }
+device_initcall(mpsc_drv_init);
 
-static void __exit mpsc_drv_exit(void)
-{
-       platform_driver_unregister(&mpsc_driver);
-       platform_driver_unregister(&mpsc_shared_driver);
-       uart_unregister_driver(&mpsc_reg);
-       memset(mpsc_ports, 0, sizeof(mpsc_ports));
-       memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));
-}
-
-module_init(mpsc_drv_init);
-module_exit(mpsc_drv_exit);
-
+/*
 MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>");
 MODULE_DESCRIPTION("Generic Marvell MPSC serial/UART driver");
-MODULE_VERSION(MPSC_VERSION);
 MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV_MAJOR(MPSC_MAJOR);
-MODULE_ALIAS("platform:" MPSC_CTLR_NAME);
+*/
index b73889c8ed4b91242be90295d225aaa93b0adaa2..dcde955475dc9b11029c614d0d137d582d04e77c 100644 (file)
@@ -20,6 +20,8 @@
 #endif
 
 #include <linux/atomic.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
 #include <linux/hrtimer.h>
 #include <linux/module.h>
 #include <linux/io.h>
@@ -31,6 +33,7 @@
 #include <linux/tty_flip.h>
 #include <linux/serial_core.h>
 #include <linux/serial.h>
+#include <linux/slab.h>
 #include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 
 #include "msm_serial.h"
 
+#define UARTDM_BURST_SIZE      16   /* in bytes */
+#define UARTDM_TX_AIGN(x)      ((x) & ~0x3) /* valid for > 1p3 */
+#define UARTDM_TX_MAX          256   /* in bytes, valid for <= 1p3 */
+#define UARTDM_RX_SIZE         (UART_XMIT_SIZE / 4)
+
 enum {
        UARTDM_1P1 = 1,
        UARTDM_1P2,
@@ -46,6 +54,17 @@ enum {
        UARTDM_1P4,
 };
 
+struct msm_dma {
+       struct dma_chan         *chan;
+       enum dma_data_direction dir;
+       dma_addr_t              phys;
+       unsigned char           *virt;
+       dma_cookie_t            cookie;
+       u32                     enable_bit;
+       unsigned int            count;
+       struct dma_async_tx_descriptor  *desc;
+};
+
 struct msm_port {
        struct uart_port        uart;
        char                    name[16];
@@ -55,9 +74,153 @@ struct msm_port {
        int                     is_uartdm;
        unsigned int            old_snap_state;
        bool                    break_detected;
+       struct msm_dma          tx_dma;
+       struct msm_dma          rx_dma;
 };
 
-static inline void wait_for_xmitr(struct uart_port *port)
+static void msm_handle_tx(struct uart_port *port);
+static void msm_start_rx_dma(struct msm_port *msm_port);
+
+void msm_stop_dma(struct uart_port *port, struct msm_dma *dma)
+{
+       struct device *dev = port->dev;
+       unsigned int mapped;
+       u32 val;
+
+       mapped = dma->count;
+       dma->count = 0;
+
+       dmaengine_terminate_all(dma->chan);
+
+       /*
+        * DMA Stall happens if enqueue and flush command happens concurrently.
+        * For example before changing the baud rate/protocol configuration and
+        * sending flush command to ADM, disable the channel of UARTDM.
+        * Note: should not reset the receiver here immediately as it is not
+        * suggested to do disable/reset or reset/disable at the same time.
+        */
+       val = msm_read(port, UARTDM_DMEN);
+       val &= ~dma->enable_bit;
+       msm_write(port, val, UARTDM_DMEN);
+
+       if (mapped)
+               dma_unmap_single(dev, dma->phys, mapped, dma->dir);
+}
+
+static void msm_release_dma(struct msm_port *msm_port)
+{
+       struct msm_dma *dma;
+
+       dma = &msm_port->tx_dma;
+       if (dma->chan) {
+               msm_stop_dma(&msm_port->uart, dma);
+               dma_release_channel(dma->chan);
+       }
+
+       memset(dma, 0, sizeof(*dma));
+
+       dma = &msm_port->rx_dma;
+       if (dma->chan) {
+               msm_stop_dma(&msm_port->uart, dma);
+               dma_release_channel(dma->chan);
+               kfree(dma->virt);
+       }
+
+       memset(dma, 0, sizeof(*dma));
+}
+
+static void msm_request_tx_dma(struct msm_port *msm_port, resource_size_t base)
+{
+       struct device *dev = msm_port->uart.dev;
+       struct dma_slave_config conf;
+       struct msm_dma *dma;
+       u32 crci = 0;
+       int ret;
+
+       dma = &msm_port->tx_dma;
+
+       /* allocate DMA resources, if available */
+       dma->chan = dma_request_slave_channel_reason(dev, "tx");
+       if (IS_ERR(dma->chan))
+               goto no_tx;
+
+       of_property_read_u32(dev->of_node, "qcom,tx-crci", &crci);
+
+       memset(&conf, 0, sizeof(conf));
+       conf.direction = DMA_MEM_TO_DEV;
+       conf.device_fc = true;
+       conf.dst_addr = base + UARTDM_TF;
+       conf.dst_maxburst = UARTDM_BURST_SIZE;
+       conf.slave_id = crci;
+
+       ret = dmaengine_slave_config(dma->chan, &conf);
+       if (ret)
+               goto rel_tx;
+
+       dma->dir = DMA_TO_DEVICE;
+
+       if (msm_port->is_uartdm < UARTDM_1P4)
+               dma->enable_bit = UARTDM_DMEN_TX_DM_ENABLE;
+       else
+               dma->enable_bit = UARTDM_DMEN_TX_BAM_ENABLE;
+
+       return;
+
+rel_tx:
+       dma_release_channel(dma->chan);
+no_tx:
+       memset(dma, 0, sizeof(*dma));
+}
+
+static void msm_request_rx_dma(struct msm_port *msm_port, resource_size_t base)
+{
+       struct device *dev = msm_port->uart.dev;
+       struct dma_slave_config conf;
+       struct msm_dma *dma;
+       u32 crci = 0;
+       int ret;
+
+       dma = &msm_port->rx_dma;
+
+       /* allocate DMA resources, if available */
+       dma->chan = dma_request_slave_channel_reason(dev, "rx");
+       if (IS_ERR(dma->chan))
+               goto no_rx;
+
+       of_property_read_u32(dev->of_node, "qcom,rx-crci", &crci);
+
+       dma->virt = kzalloc(UARTDM_RX_SIZE, GFP_KERNEL);
+       if (!dma->virt)
+               goto rel_rx;
+
+       memset(&conf, 0, sizeof(conf));
+       conf.direction = DMA_DEV_TO_MEM;
+       conf.device_fc = true;
+       conf.src_addr = base + UARTDM_RF;
+       conf.src_maxburst = UARTDM_BURST_SIZE;
+       conf.slave_id = crci;
+
+       ret = dmaengine_slave_config(dma->chan, &conf);
+       if (ret)
+               goto err;
+
+       dma->dir = DMA_FROM_DEVICE;
+
+       if (msm_port->is_uartdm < UARTDM_1P4)
+               dma->enable_bit = UARTDM_DMEN_RX_DM_ENABLE;
+       else
+               dma->enable_bit = UARTDM_DMEN_RX_BAM_ENABLE;
+
+       return;
+err:
+       kfree(dma->virt);
+rel_rx:
+       dma_release_channel(dma->chan);
+no_rx:
+       memset(dma, 0, sizeof(*dma));
+}
+
+static inline void msm_wait_for_xmitr(struct uart_port *port)
 {
        while (!(msm_read(port, UART_SR) & UART_SR_TX_EMPTY)) {
                if (msm_read(port, UART_ISR) & UART_ISR_TX_READY)
@@ -78,17 +241,277 @@ static void msm_stop_tx(struct uart_port *port)
 static void msm_start_tx(struct uart_port *port)
 {
        struct msm_port *msm_port = UART_TO_MSM(port);
+       struct msm_dma *dma = &msm_port->tx_dma;
+
+       /* Already started in DMA mode */
+       if (dma->count)
+               return;
+
+       msm_port->imr |= UART_IMR_TXLEV;
+       msm_write(port, msm_port->imr, UART_IMR);
+}
+
+static void msm_reset_dm_count(struct uart_port *port, int count)
+{
+       msm_wait_for_xmitr(port);
+       msm_write(port, count, UARTDM_NCF_TX);
+       msm_read(port, UARTDM_NCF_TX);
+}
+
+static void msm_complete_tx_dma(void *args)
+{
+       struct msm_port *msm_port = args;
+       struct uart_port *port = &msm_port->uart;
+       struct circ_buf *xmit = &port->state->xmit;
+       struct msm_dma *dma = &msm_port->tx_dma;
+       struct dma_tx_state state;
+       enum dma_status status;
+       unsigned long flags;
+       unsigned int count;
+       u32 val;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Already stopped */
+       if (!dma->count)
+               goto done;
+
+       status = dmaengine_tx_status(dma->chan, dma->cookie, &state);
+
+       dma_unmap_single(port->dev, dma->phys, dma->count, dma->dir);
 
+       val = msm_read(port, UARTDM_DMEN);
+       val &= ~dma->enable_bit;
+       msm_write(port, val, UARTDM_DMEN);
+
+       if (msm_port->is_uartdm > UARTDM_1P3) {
+               msm_write(port, UART_CR_CMD_RESET_TX, UART_CR);
+               msm_write(port, UART_CR_TX_ENABLE, UART_CR);
+       }
+
+       count = dma->count - state.residue;
+       port->icount.tx += count;
+       dma->count = 0;
+
+       xmit->tail += count;
+       xmit->tail &= UART_XMIT_SIZE - 1;
+
+       /* Restore "Tx FIFO below watermark" interrupt */
        msm_port->imr |= UART_IMR_TXLEV;
        msm_write(port, msm_port->imr, UART_IMR);
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       msm_handle_tx(port);
+done:
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count)
+{
+       struct circ_buf *xmit = &msm_port->uart.state->xmit;
+       struct uart_port *port = &msm_port->uart;
+       struct msm_dma *dma = &msm_port->tx_dma;
+       void *cpu_addr;
+       int ret;
+       u32 val;
+
+       cpu_addr = &xmit->buf[xmit->tail];
+
+       dma->phys = dma_map_single(port->dev, cpu_addr, count, dma->dir);
+       ret = dma_mapping_error(port->dev, dma->phys);
+       if (ret)
+               return ret;
+
+       dma->desc = dmaengine_prep_slave_single(dma->chan, dma->phys,
+                                               count, DMA_MEM_TO_DEV,
+                                               DMA_PREP_INTERRUPT |
+                                               DMA_PREP_FENCE);
+       if (!dma->desc) {
+               ret = -EIO;
+               goto unmap;
+       }
+
+       dma->desc->callback = msm_complete_tx_dma;
+       dma->desc->callback_param = msm_port;
+
+       dma->cookie = dmaengine_submit(dma->desc);
+       ret = dma_submit_error(dma->cookie);
+       if (ret)
+               goto unmap;
+
+       /*
+        * Using DMA complete for Tx FIFO reload, no need for
+        * "Tx FIFO below watermark" one, disable it
+        */
+       msm_port->imr &= ~UART_IMR_TXLEV;
+       msm_write(port, msm_port->imr, UART_IMR);
+
+       dma->count = count;
+
+       val = msm_read(port, UARTDM_DMEN);
+       val |= dma->enable_bit;
+
+       if (msm_port->is_uartdm < UARTDM_1P4)
+               msm_write(port, val, UARTDM_DMEN);
+
+       msm_reset_dm_count(port, count);
+
+       if (msm_port->is_uartdm > UARTDM_1P3)
+               msm_write(port, val, UARTDM_DMEN);
+
+       dma_async_issue_pending(dma->chan);
+       return 0;
+unmap:
+       dma_unmap_single(port->dev, dma->phys, count, dma->dir);
+       return ret;
+}
+
+static void msm_complete_rx_dma(void *args)
+{
+       struct msm_port *msm_port = args;
+       struct uart_port *port = &msm_port->uart;
+       struct tty_port *tport = &port->state->port;
+       struct msm_dma *dma = &msm_port->rx_dma;
+       int count = 0, i, sysrq;
+       unsigned long flags;
+       u32 val;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Already stopped */
+       if (!dma->count)
+               goto done;
+
+       val = msm_read(port, UARTDM_DMEN);
+       val &= ~dma->enable_bit;
+       msm_write(port, val, UARTDM_DMEN);
+
+       /* Restore interrupts */
+       msm_port->imr |= UART_IMR_RXLEV | UART_IMR_RXSTALE;
+       msm_write(port, msm_port->imr, UART_IMR);
+
+       if (msm_read(port, UART_SR) & UART_SR_OVERRUN) {
+               port->icount.overrun++;
+               tty_insert_flip_char(tport, 0, TTY_OVERRUN);
+               msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
+       }
+
+       count = msm_read(port, UARTDM_RX_TOTAL_SNAP);
+
+       port->icount.rx += count;
+
+       dma->count = 0;
+
+       dma_unmap_single(port->dev, dma->phys, UARTDM_RX_SIZE, dma->dir);
+
+       for (i = 0; i < count; i++) {
+               char flag = TTY_NORMAL;
+
+               if (msm_port->break_detected && dma->virt[i] == 0) {
+                       port->icount.brk++;
+                       flag = TTY_BREAK;
+                       msm_port->break_detected = false;
+                       if (uart_handle_break(port))
+                               continue;
+               }
+
+               if (!(port->read_status_mask & UART_SR_RX_BREAK))
+                       flag = TTY_NORMAL;
+
+               spin_unlock_irqrestore(&port->lock, flags);
+               sysrq = uart_handle_sysrq_char(port, dma->virt[i]);
+               spin_lock_irqsave(&port->lock, flags);
+               if (!sysrq)
+                       tty_insert_flip_char(tport, dma->virt[i], flag);
+       }
+
+       msm_start_rx_dma(msm_port);
+done:
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       if (count)
+               tty_flip_buffer_push(tport);
+}
+
+static void msm_start_rx_dma(struct msm_port *msm_port)
+{
+       struct msm_dma *dma = &msm_port->rx_dma;
+       struct uart_port *uart = &msm_port->uart;
+       u32 val;
+       int ret;
+
+       if (!dma->chan)
+               return;
+
+       dma->phys = dma_map_single(uart->dev, dma->virt,
+                                  UARTDM_RX_SIZE, dma->dir);
+       ret = dma_mapping_error(uart->dev, dma->phys);
+       if (ret)
+               return;
+
+       dma->desc = dmaengine_prep_slave_single(dma->chan, dma->phys,
+                                               UARTDM_RX_SIZE, DMA_DEV_TO_MEM,
+                                               DMA_PREP_INTERRUPT);
+       if (!dma->desc)
+               goto unmap;
+
+       dma->desc->callback = msm_complete_rx_dma;
+       dma->desc->callback_param = msm_port;
+
+       dma->cookie = dmaengine_submit(dma->desc);
+       ret = dma_submit_error(dma->cookie);
+       if (ret)
+               goto unmap;
+       /*
+        * Using DMA for FIFO off-load, no need for "Rx FIFO over
+        * watermark" or "stale" interrupts, disable them
+        */
+       msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE);
+
+       /*
+        * Well, when DMA is ADM3 engine(implied by <= UARTDM v1.3),
+        * we need RXSTALE to flush input DMA fifo to memory
+        */
+       if (msm_port->is_uartdm < UARTDM_1P4)
+               msm_port->imr |= UART_IMR_RXSTALE;
+
+       msm_write(uart, msm_port->imr, UART_IMR);
+
+       dma->count = UARTDM_RX_SIZE;
+
+       dma_async_issue_pending(dma->chan);
+
+       msm_write(uart, UART_CR_CMD_RESET_STALE_INT, UART_CR);
+       msm_write(uart, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR);
+
+       val = msm_read(uart, UARTDM_DMEN);
+       val |= dma->enable_bit;
+
+       if (msm_port->is_uartdm < UARTDM_1P4)
+               msm_write(uart, val, UARTDM_DMEN);
+
+       msm_write(uart, UARTDM_RX_SIZE, UARTDM_DMRX);
+
+       if (msm_port->is_uartdm > UARTDM_1P3)
+               msm_write(uart, val, UARTDM_DMEN);
+
+       return;
+unmap:
+       dma_unmap_single(uart->dev, dma->phys, UARTDM_RX_SIZE, dma->dir);
 }
 
 static void msm_stop_rx(struct uart_port *port)
 {
        struct msm_port *msm_port = UART_TO_MSM(port);
+       struct msm_dma *dma = &msm_port->rx_dma;
 
        msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE);
        msm_write(port, msm_port->imr, UART_IMR);
+
+       if (dma->chan)
+               msm_stop_dma(port, dma);
 }
 
 static void msm_enable_ms(struct uart_port *port)
@@ -99,7 +522,7 @@ static void msm_enable_ms(struct uart_port *port)
        msm_write(port, msm_port->imr, UART_IMR);
 }
 
-static void handle_rx_dm(struct uart_port *port, unsigned int misr)
+static void msm_handle_rx_dm(struct uart_port *port, unsigned int misr)
 {
        struct tty_port *tport = &port->state->port;
        unsigned int sr;
@@ -169,9 +592,12 @@ static void handle_rx_dm(struct uart_port *port, unsigned int misr)
                msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR);
        msm_write(port, 0xFFFFFF, UARTDM_DMRX);
        msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR);
+
+       /* Try to use DMA */
+       msm_start_rx_dma(msm_port);
 }
 
-static void handle_rx(struct uart_port *port)
+static void msm_handle_rx(struct uart_port *port)
 {
        struct tty_port *tport = &port->state->port;
        unsigned int sr;
@@ -224,18 +650,11 @@ static void handle_rx(struct uart_port *port)
        spin_lock(&port->lock);
 }
 
-static void reset_dm_count(struct uart_port *port, int count)
-{
-       wait_for_xmitr(port);
-       msm_write(port, count, UARTDM_NCF_TX);
-       msm_read(port, UARTDM_NCF_TX);
-}
-
-static void handle_tx(struct uart_port *port)
+static void msm_handle_tx_pio(struct uart_port *port, unsigned int tx_count)
 {
        struct circ_buf *xmit = &port->state->xmit;
        struct msm_port *msm_port = UART_TO_MSM(port);
-       unsigned int tx_count, num_chars;
+       unsigned int num_chars;
        unsigned int tf_pointer = 0;
        void __iomem *tf;
 
@@ -244,20 +663,8 @@ static void handle_tx(struct uart_port *port)
        else
                tf = port->membase + UART_TF;
 
-       tx_count = uart_circ_chars_pending(xmit);
-       tx_count = min3(tx_count, (unsigned int)UART_XMIT_SIZE - xmit->tail,
-                       port->fifosize);
-
-       if (port->x_char) {
-               if (msm_port->is_uartdm)
-                       reset_dm_count(port, tx_count + 1);
-
-               iowrite8_rep(tf, &port->x_char, 1);
-               port->icount.tx++;
-               port->x_char = 0;
-       } else if (tx_count && msm_port->is_uartdm) {
-               reset_dm_count(port, tx_count);
-       }
+       if (tx_count && msm_port->is_uartdm)
+               msm_reset_dm_count(port, tx_count);
 
        while (tf_pointer < tx_count) {
                int i;
@@ -290,20 +697,76 @@ static void handle_tx(struct uart_port *port)
                uart_write_wakeup(port);
 }
 
-static void handle_delta_cts(struct uart_port *port)
+static void msm_handle_tx(struct uart_port *port)
+{
+       struct msm_port *msm_port = UART_TO_MSM(port);
+       struct circ_buf *xmit = &msm_port->uart.state->xmit;
+       struct msm_dma *dma = &msm_port->tx_dma;
+       unsigned int pio_count, dma_count, dma_min;
+       void __iomem *tf;
+       int err = 0;
+
+       if (port->x_char) {
+               if (msm_port->is_uartdm)
+                       tf = port->membase + UARTDM_TF;
+               else
+                       tf = port->membase + UART_TF;
+
+               if (msm_port->is_uartdm)
+                       msm_reset_dm_count(port, 1);
+
+               iowrite8_rep(tf, &port->x_char, 1);
+               port->icount.tx++;
+               port->x_char = 0;
+               return;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               msm_stop_tx(port);
+               return;
+       }
+
+       pio_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);
+       dma_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+
+       dma_min = 1;    /* Always DMA */
+       if (msm_port->is_uartdm > UARTDM_1P3) {
+               dma_count = UARTDM_TX_AIGN(dma_count);
+               dma_min = UARTDM_BURST_SIZE;
+       } else {
+               if (dma_count > UARTDM_TX_MAX)
+                       dma_count = UARTDM_TX_MAX;
+       }
+
+       if (pio_count > port->fifosize)
+               pio_count = port->fifosize;
+
+       if (!dma->chan || dma_count < dma_min)
+               msm_handle_tx_pio(port, pio_count);
+       else
+               err = msm_handle_tx_dma(msm_port, dma_count);
+
+       if (err)        /* fall back to PIO mode */
+               msm_handle_tx_pio(port, pio_count);
+}
+
+static void msm_handle_delta_cts(struct uart_port *port)
 {
        msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR);
        port->icount.cts++;
        wake_up_interruptible(&port->state->port.delta_msr_wait);
 }
 
-static irqreturn_t msm_irq(int irq, void *dev_id)
+static irqreturn_t msm_uart_irq(int irq, void *dev_id)
 {
        struct uart_port *port = dev_id;
        struct msm_port *msm_port = UART_TO_MSM(port);
+       struct msm_dma *dma = &msm_port->rx_dma;
+       unsigned long flags;
        unsigned int misr;
+       u32 val;
 
-       spin_lock(&port->lock);
+       spin_lock_irqsave(&port->lock, flags);
        misr = msm_read(port, UART_MISR);
        msm_write(port, 0, UART_IMR); /* disable interrupt */
 
@@ -313,18 +776,29 @@ static irqreturn_t msm_irq(int irq, void *dev_id)
        }
 
        if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE)) {
-               if (msm_port->is_uartdm)
-                       handle_rx_dm(port, misr);
-               else
-                       handle_rx(port);
+               if (dma->count) {
+                       val = UART_CR_CMD_STALE_EVENT_DISABLE;
+                       msm_write(port, val, UART_CR);
+                       val = UART_CR_CMD_RESET_STALE_INT;
+                       msm_write(port, val, UART_CR);
+                       /*
+                        * Flush DMA input fifo to memory, this will also
+                        * trigger DMA RX completion
+                        */
+                       dmaengine_terminate_all(dma->chan);
+               } else if (msm_port->is_uartdm) {
+                       msm_handle_rx_dm(port, misr);
+               } else {
+                       msm_handle_rx(port);
+               }
        }
        if (misr & UART_IMR_TXLEV)
-               handle_tx(port);
+               msm_handle_tx(port);
        if (misr & UART_IMR_DELTA_CTS)
-               handle_delta_cts(port);
+               msm_handle_delta_cts(port);
 
        msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */
-       spin_unlock(&port->lock);
+       spin_unlock_irqrestore(&port->lock, flags);
 
        return IRQ_HANDLED;
 }
@@ -408,6 +882,7 @@ msm_find_best_baud(struct uart_port *port, unsigned int baud)
                {    3, 0xdd,  8 },
                {    2, 0xee, 16 },
                {    1, 0xff, 31 },
+               {    0, 0xff, 31 },
        };
 
        divisor = uart_get_divisor(port, baud);
@@ -419,21 +894,41 @@ msm_find_best_baud(struct uart_port *port, unsigned int baud)
        return entry; /* Default to smallest divider */
 }
 
-static int msm_set_baud_rate(struct uart_port *port, unsigned int baud)
+static int msm_set_baud_rate(struct uart_port *port, unsigned int baud,
+                            unsigned long *saved_flags)
 {
-       unsigned int rxstale, watermark;
+       unsigned int rxstale, watermark, mask;
        struct msm_port *msm_port = UART_TO_MSM(port);
        const struct msm_baud_map *entry;
+       unsigned long flags;
 
        entry = msm_find_best_baud(port, baud);
 
        msm_write(port, entry->code, UART_CSR);
 
+       if (baud > 460800)
+               port->uartclk = baud * 16;
+
+       flags = *saved_flags;
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       clk_set_rate(msm_port->clk, port->uartclk);
+
+       spin_lock_irqsave(&port->lock, flags);
+       *saved_flags = flags;
+
        /* RX stale watermark */
        rxstale = entry->rxstale;
        watermark = UART_IPR_STALE_LSB & rxstale;
-       watermark |= UART_IPR_RXSTALE_LAST;
-       watermark |= UART_IPR_STALE_TIMEOUT_MSB & (rxstale << 2);
+       if (msm_port->is_uartdm) {
+               mask = UART_DM_IPR_STALE_TIMEOUT_MSB;
+       } else {
+               watermark |= UART_IPR_RXSTALE_LAST;
+               mask = UART_IPR_STALE_TIMEOUT_MSB;
+       }
+
+       watermark |= mask & (rxstale << 2);
+
        msm_write(port, watermark, UART_IPR);
 
        /* set RX watermark */
@@ -476,13 +971,13 @@ static void msm_init_clock(struct uart_port *port)
 static int msm_startup(struct uart_port *port)
 {
        struct msm_port *msm_port = UART_TO_MSM(port);
-       unsigned int data, rfr_level;
+       unsigned int data, rfr_level, mask;
        int ret;
 
        snprintf(msm_port->name, sizeof(msm_port->name),
                 "msm_serial%d", port->line);
 
-       ret = request_irq(port->irq, msm_irq, IRQF_TRIGGER_HIGH,
+       ret = request_irq(port->irq, msm_uart_irq, IRQF_TRIGGER_HIGH,
                          msm_port->name, port);
        if (unlikely(ret))
                return ret;
@@ -496,11 +991,23 @@ static int msm_startup(struct uart_port *port)
 
        /* set automatic RFR level */
        data = msm_read(port, UART_MR1);
-       data &= ~UART_MR1_AUTO_RFR_LEVEL1;
+
+       if (msm_port->is_uartdm)
+               mask = UART_DM_MR1_AUTO_RFR_LEVEL1;
+       else
+               mask = UART_MR1_AUTO_RFR_LEVEL1;
+
+       data &= ~mask;
        data &= ~UART_MR1_AUTO_RFR_LEVEL0;
-       data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2);
+       data |= mask & (rfr_level << 2);
        data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level;
        msm_write(port, data, UART_MR1);
+
+       if (msm_port->is_uartdm) {
+               msm_request_tx_dma(msm_port, msm_port->uart.mapbase);
+               msm_request_rx_dma(msm_port, msm_port->uart.mapbase);
+       }
+
        return 0;
 }
 
@@ -511,6 +1018,9 @@ static void msm_shutdown(struct uart_port *port)
        msm_port->imr = 0;
        msm_write(port, 0, UART_IMR); /* disable interrupts */
 
+       if (msm_port->is_uartdm)
+               msm_release_dma(msm_port);
+
        clk_disable_unprepare(msm_port->clk);
 
        free_irq(port->irq, port);
@@ -519,14 +1029,19 @@ static void msm_shutdown(struct uart_port *port)
 static void msm_set_termios(struct uart_port *port, struct ktermios *termios,
                            struct ktermios *old)
 {
+       struct msm_port *msm_port = UART_TO_MSM(port);
+       struct msm_dma *dma = &msm_port->rx_dma;
        unsigned long flags;
        unsigned int baud, mr;
 
        spin_lock_irqsave(&port->lock, flags);
 
+       if (dma->chan) /* Terminate if any */
+               msm_stop_dma(port, dma);
+
        /* calculate and set baud rate */
-       baud = uart_get_baud_rate(port, termios, old, 300, 115200);
-       baud = msm_set_baud_rate(port, baud);
+       baud = uart_get_baud_rate(port, termios, old, 300, 4000000);
+       baud = msm_set_baud_rate(port, baud, &flags);
        if (tty_termios_baud_rate(termios))
                tty_termios_encode_baud_rate(termios, baud, baud);
 
@@ -588,6 +1103,9 @@ static void msm_set_termios(struct uart_port *port, struct ktermios *termios,
 
        uart_update_timeout(port, termios->c_cflag, baud);
 
+       /* Try to use DMA */
+       msm_start_rx_dma(msm_port);
+
        spin_unlock_irqrestore(&port->lock, flags);
 }
 
@@ -765,7 +1283,7 @@ static void msm_poll_put_char(struct uart_port *port, unsigned char c)
        msm_write(port, 0, UART_IMR);
 
        if (msm_port->is_uartdm)
-               reset_dm_count(port, 1);
+               msm_reset_dm_count(port, 1);
 
        /* Wait until FIFO is empty */
        while (!(msm_read(port, UART_SR) & UART_SR_TX_READY))
@@ -839,7 +1357,7 @@ static struct msm_port msm_uart_ports[] = {
 
 #define UART_NR        ARRAY_SIZE(msm_uart_ports)
 
-static inline struct uart_port *get_port_from_line(unsigned int line)
+static inline struct uart_port *msm_get_port_from_line(unsigned int line)
 {
        return &msm_uart_ports[line].uart;
 }
@@ -866,7 +1384,7 @@ static void __msm_console_write(struct uart_port *port, const char *s,
 
        spin_lock(&port->lock);
        if (is_uartdm)
-               reset_dm_count(port, count);
+               msm_reset_dm_count(port, count);
 
        i = 0;
        while (i < count) {
@@ -911,7 +1429,7 @@ static void msm_console_write(struct console *co, const char *s,
 
        BUG_ON(co->index < 0 || co->index >= UART_NR);
 
-       port = get_port_from_line(co->index);
+       port = msm_get_port_from_line(co->index);
        msm_port = UART_TO_MSM(port);
 
        __msm_console_write(port, s, count, msm_port->is_uartdm);
@@ -928,7 +1446,7 @@ static int __init msm_console_setup(struct console *co, char *options)
        if (unlikely(co->index >= UART_NR || co->index < 0))
                return -ENXIO;
 
-       port = get_port_from_line(co->index);
+       port = msm_get_port_from_line(co->index);
 
        if (unlikely(!port->membase))
                return -ENXIO;
@@ -1043,7 +1561,7 @@ static int msm_serial_probe(struct platform_device *pdev)
 
        dev_info(&pdev->dev, "msm_serial: detected port #%d\n", line);
 
-       port = get_port_from_line(line);
+       port = msm_get_port_from_line(line);
        port->dev = &pdev->dev;
        msm_port = UART_TO_MSM(port);
 
index 737f69fe7113a93410652cd84030a08bc6697335..178645826f1696bb0537f525443b022ae35cff12 100644 (file)
 
 #define UART_MR1_AUTO_RFR_LEVEL0       0x3F
 #define UART_MR1_AUTO_RFR_LEVEL1       0x3FF00
-#define UART_MR1_RX_RDY_CTL                    (1 << 7)
-#define UART_MR1_CTS_CTL                       (1 << 6)
+#define UART_DM_MR1_AUTO_RFR_LEVEL1    0xFFFFFF00
+#define UART_MR1_RX_RDY_CTL            BIT(7)
+#define UART_MR1_CTS_CTL               BIT(6)
 
 #define UART_MR2                       0x0004
-#define UART_MR2_ERROR_MODE            (1 << 6)
+#define UART_MR2_ERROR_MODE            BIT(6)
 #define UART_MR2_BITS_PER_CHAR         0x30
 #define UART_MR2_BITS_PER_CHAR_5       (0x0 << 4)
 #define UART_MR2_BITS_PER_CHAR_6       (0x1 << 4)
 #define UART_CR_CMD_SET_RFR            (13 << 4)
 #define UART_CR_CMD_RESET_RFR          (14 << 4)
 #define UART_CR_CMD_PROTECTION_EN      (16 << 4)
+#define UART_CR_CMD_STALE_EVENT_DISABLE        (6 << 8)
 #define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4)
 #define UART_CR_CMD_FORCE_STALE                (4 << 8)
 #define UART_CR_CMD_RESET_TX_READY     (3 << 8)
-#define UART_CR_TX_DISABLE             (1 << 3)
-#define UART_CR_TX_ENABLE              (1 << 2)
-#define UART_CR_RX_DISABLE             (1 << 1)
-#define UART_CR_RX_ENABLE              (1 << 0)
+#define UART_CR_TX_DISABLE             BIT(3)
+#define UART_CR_TX_ENABLE              BIT(2)
+#define UART_CR_RX_DISABLE             BIT(1)
+#define UART_CR_RX_ENABLE              BIT(0)
 #define UART_CR_CMD_RESET_RXBREAK_START        ((1 << 11) | (2 << 4))
 
 #define UART_IMR               0x0014
-#define UART_IMR_TXLEV         (1 << 0)
-#define UART_IMR_RXSTALE       (1 << 3)
-#define UART_IMR_RXLEV         (1 << 4)
-#define UART_IMR_DELTA_CTS     (1 << 5)
-#define UART_IMR_CURRENT_CTS   (1 << 6)
-#define UART_IMR_RXBREAK_START (1 << 10)
+#define UART_IMR_TXLEV                 BIT(0)
+#define UART_IMR_RXSTALE               BIT(3)
+#define UART_IMR_RXLEV                 BIT(4)
+#define UART_IMR_DELTA_CTS             BIT(5)
+#define UART_IMR_CURRENT_CTS           BIT(6)
+#define UART_IMR_RXBREAK_START         BIT(10)
 
 #define UART_IPR_RXSTALE_LAST          0x20
 #define UART_IPR_STALE_LSB             0x1F
 #define UART_IPR_STALE_TIMEOUT_MSB     0x3FF80
+#define UART_DM_IPR_STALE_TIMEOUT_MSB  0xFFFFFF80
 
 #define UART_IPR       0x0018
 #define UART_TFWR      0x001C
 #define UART_TEST_CTRL         0x0050
 
 #define UART_SR                        0x0008
-#define UART_SR_HUNT_CHAR      (1 << 7)
-#define UART_SR_RX_BREAK       (1 << 6)
-#define UART_SR_PAR_FRAME_ERR  (1 << 5)
-#define UART_SR_OVERRUN                (1 << 4)
-#define UART_SR_TX_EMPTY       (1 << 3)
-#define UART_SR_TX_READY       (1 << 2)
-#define UART_SR_RX_FULL                (1 << 1)
-#define UART_SR_RX_READY       (1 << 0)
+#define UART_SR_HUNT_CHAR      BIT(7)
+#define UART_SR_RX_BREAK       BIT(6)
+#define UART_SR_PAR_FRAME_ERR  BIT(5)
+#define UART_SR_OVERRUN                BIT(4)
+#define UART_SR_TX_EMPTY       BIT(3)
+#define UART_SR_TX_READY       BIT(2)
+#define UART_SR_RX_FULL                BIT(1)
+#define UART_SR_RX_READY       BIT(0)
 
 #define UART_RF                        0x000C
 #define UARTDM_RF              0x0070
 #define UART_MISR              0x0010
 #define UART_ISR               0x0014
-#define UART_ISR_TX_READY      (1 << 7)
+#define UART_ISR_TX_READY      BIT(7)
 
 #define UARTDM_RXFS            0x50
 #define UARTDM_RXFS_BUF_SHIFT  0x7
 #define UARTDM_DMEN_RX_SC_ENABLE BIT(5)
 #define UARTDM_DMEN_TX_SC_ENABLE BIT(4)
 
+#define UARTDM_DMEN_TX_BAM_ENABLE BIT(2)       /* UARTDM_1P4 */
+#define UARTDM_DMEN_TX_DM_ENABLE  BIT(0)       /* < UARTDM_1P4 */
+
+#define UARTDM_DMEN_RX_BAM_ENABLE BIT(3)       /* UARTDM_1P4 */
+#define UARTDM_DMEN_RX_DM_ENABLE  BIT(1)       /* < UARTDM_1P4 */
+
 #define UARTDM_DMRX            0x34
 #define UARTDM_NCF_TX          0x40
 #define UARTDM_RX_TOTAL_SNAP   0x38
index 7c7f30809849d24d337f8f2eedf4a83ed23907f1..cd0414bbe094898ed3fdeca0a941549312472581 100644 (file)
@@ -1196,7 +1196,7 @@ static int mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev)
        enum mctrl_gpio_idx i;
        struct gpio_desc *gpiod;
 
-       s->gpios = mctrl_gpio_init(dev, 0);
+       s->gpios = mctrl_gpio_init_noauto(dev, 0);
        if (IS_ERR(s->gpios))
                return PTR_ERR(s->gpios);
 
index 6823df99bd7685db295b94599e6bd1b7f7a78057..de50296497955c0387f4865ce582d3ce024e6470 100644 (file)
 #include <linux/nwpserial.h>
 #include <linux/clk.h>
 
+#ifdef CONFIG_SERIAL_8250_MODULE
+#define CONFIG_SERIAL_8250 CONFIG_SERIAL_8250_MODULE
+#endif
+
 #include "8250/8250.h"
 
 struct of_serial_info {
@@ -150,6 +154,11 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
                break;
        }
 
+       if (IS_ENABLED(CONFIG_SERIAL_8250_FSL) &&
+           (of_device_is_compatible(np, "fsl,ns16550") ||
+            of_device_is_compatible(np, "fsl,16550-FIFO64")))
+               port->handle_irq = fsl8250_handle_irq;
+
        return 0;
 out:
        if (info->clk)
@@ -350,6 +359,7 @@ static const struct of_device_id of_platform_serial_table[] = {
 #endif
        { /* end of list */ },
 };
+MODULE_DEVICE_TABLE(of, of_platform_serial_table);
 
 static struct platform_driver of_platform_serial_driver = {
        .driver = {
index 7a2172b5e93cd296674c9b78a5fd31594db0f492..9d4c84f7485f6412231fdad9703202cfae0a4393 100644 (file)
@@ -199,6 +199,7 @@ static inline void serial_omap_clear_fifos(struct uart_omap_port *up)
        serial_out(up, UART_FCR, 0);
 }
 
+#ifdef CONFIG_PM
 static int serial_omap_get_context_loss_count(struct uart_omap_port *up)
 {
        struct omap_uart_port_info *pdata = dev_get_platdata(up->dev);
@@ -219,6 +220,7 @@ static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable)
 
        pdata->enable_wakeup(up->dev, enable);
 }
+#endif /* CONFIG_PM */
 
 /*
  * Calculate the absolute difference between the desired and actual baud
index 856686d6dcdbc61adbadc5ae6c0d86dbdf2c18d9..d72cd736bdc6ec9d28277616ca6231885089dc56 100644 (file)
@@ -385,32 +385,6 @@ static void s3c24xx_uart_copy_rx_to_tty(struct s3c24xx_uart_port *ourport,
        }
 }
 
-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);
@@ -573,7 +547,9 @@ static void enable_rx_pio(struct s3c24xx_uart_port *ourport)
        ourport->rx_mode = S3C24XX_RX_PIO;
 }
 
-static irqreturn_t s3c24xx_serial_rx_chars_dma(int irq, void *dev_id)
+static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport);
+
+static irqreturn_t s3c24xx_serial_rx_chars_dma(void *dev_id)
 {
        unsigned int utrstat, ufstat, received;
        struct s3c24xx_uart_port *ourport = dev_id;
@@ -606,7 +582,7 @@ static irqreturn_t s3c24xx_serial_rx_chars_dma(int irq, void *dev_id)
                enable_rx_pio(ourport);
        }
 
-       uart_rx_drain_fifo(ourport);
+       s3c24xx_serial_rx_drain_fifo(ourport);
 
        if (tty) {
                tty_flip_buffer_push(t);
@@ -621,16 +597,12 @@ finish:
        return IRQ_HANDLED;
 }
 
-static irqreturn_t s3c24xx_serial_rx_chars_pio(int irq, void *dev_id)
+static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
 {
-       struct s3c24xx_uart_port *ourport = dev_id;
        struct uart_port *port = &ourport->port;
        unsigned int ufcon, ch, flag, ufstat, uerstat;
-       unsigned long flags;
        int max_count = port->fifosize;
 
-       spin_lock_irqsave(&port->lock, flags);
-
        while (max_count-- > 0) {
                ufcon = rd_regl(port, S3C2410_UFCON);
                ufstat = rd_regl(port, S3C2410_UFSTAT);
@@ -654,9 +626,7 @@ static irqreturn_t s3c24xx_serial_rx_chars_pio(int irq, void *dev_id)
                                        ufcon |= S3C2410_UFCON_RESETRX;
                                        wr_regl(port, S3C2410_UFCON, ufcon);
                                        rx_enabled(port) = 1;
-                                       spin_unlock_irqrestore(&port->lock,
-                                                       flags);
-                                       goto out;
+                                       return;
                                }
                                continue;
                        }
@@ -676,7 +646,7 @@ static irqreturn_t s3c24xx_serial_rx_chars_pio(int irq, void *dev_id)
                                dbg("break!\n");
                                port->icount.brk++;
                                if (uart_handle_break(port))
-                                       goto ignore_char;
+                                       continue; /* Ignore character */
                        }
 
                        if (uerstat & S3C2410_UERSTAT_FRAME)
@@ -696,19 +666,25 @@ static irqreturn_t s3c24xx_serial_rx_chars_pio(int irq, void *dev_id)
                }
 
                if (uart_handle_sysrq_char(port, ch))
-                       goto ignore_char;
+                       continue; /* Ignore character */
 
                uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN,
                                 ch, flag);
-
-ignore_char:
-               continue;
        }
 
-       spin_unlock_irqrestore(&port->lock, flags);
        tty_flip_buffer_push(&port->state->port);
+}
+
+static irqreturn_t s3c24xx_serial_rx_chars_pio(void *dev_id)
+{
+       struct s3c24xx_uart_port *ourport = dev_id;
+       struct uart_port *port = &ourport->port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       s3c24xx_serial_rx_drain_fifo(ourport);
+       spin_unlock_irqrestore(&port->lock, flags);
 
-out:
        return IRQ_HANDLED;
 }
 
@@ -718,8 +694,8 @@ 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);
+               return s3c24xx_serial_rx_chars_dma(dev_id);
+       return s3c24xx_serial_rx_chars_pio(dev_id);
 }
 
 static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
index 55b61d79e75770ada22902588106beee0411720b..edb5305b9d4da72e388452f66db9e65e40d15f18 100644 (file)
@@ -1321,6 +1321,9 @@ static int sc16is7xx_spi_probe(struct spi_device *spi)
                const struct of_device_id *of_id =
                        of_match_device(sc16is7xx_dt_ids, &spi->dev);
 
+               if (!of_id)
+                       return -ENODEV;
+
                devtype = (struct sc16is7xx_devtype *)of_id->data;
        } else {
                const struct spi_device_id *id_entry = spi_get_device_id(spi);
@@ -1379,6 +1382,9 @@ static int sc16is7xx_i2c_probe(struct i2c_client *i2c,
                const struct of_device_id *of_id =
                                of_match_device(sc16is7xx_dt_ids, &i2c->dev);
 
+               if (!of_id)
+                       return -ENODEV;
+
                devtype = (struct sc16is7xx_devtype *)of_id->data;
        } else {
                devtype = (struct sc16is7xx_devtype *)id->driver_data;
@@ -1419,7 +1425,6 @@ static struct i2c_driver sc16is7xx_i2c_uart_driver = {
        .id_table       = sc16is7xx_i2c_id_table,
 };
 
-MODULE_ALIAS("i2c:sc16is7xx");
 #endif
 
 static int __init sc16is7xx_init(void)
index cf0133ae762dcd68d05fb834a2f481891b06e3dc..1d6fc60ed01332da1dfebfade8065e57565d124a 100644 (file)
@@ -186,7 +186,6 @@ static void set_rts(struct tegra_uart_port *tup, bool active)
                tegra_uart_write(tup, mcr, UART_MCR);
                tup->mcr_shadow = mcr;
        }
-       return;
 }
 
 static void set_dtr(struct tegra_uart_port *tup, bool active)
@@ -202,7 +201,6 @@ static void set_dtr(struct tegra_uart_port *tup, bool active)
                tegra_uart_write(tup, mcr, UART_MCR);
                tup->mcr_shadow = mcr;
        }
-       return;
 }
 
 static void tegra_uart_set_mctrl(struct uart_port *u, unsigned int mctrl)
@@ -217,7 +215,6 @@ static void tegra_uart_set_mctrl(struct uart_port *u, unsigned int mctrl)
 
        dtr_enable = !!(mctrl & TIOCM_DTR);
        set_dtr(tup, dtr_enable);
-       return;
 }
 
 static void tegra_uart_break_ctl(struct uart_port *u, int break_ctl)
@@ -511,7 +508,6 @@ static void tegra_uart_stop_tx(struct uart_port *u)
        async_tx_ack(tup->tx_dma_desc);
        xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
        tup->tx_in_progress = 0;
-       return;
 }
 
 static void tegra_uart_handle_tx_pio(struct tegra_uart_port *tup)
@@ -523,7 +519,6 @@ static void tegra_uart_handle_tx_pio(struct tegra_uart_port *tup)
        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
                uart_write_wakeup(&tup->uport);
        tegra_uart_start_next_tx(tup);
-       return;
 }
 
 static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup,
@@ -545,8 +540,6 @@ static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup,
                if (!uart_handle_sysrq_char(&tup->uport, ch) && tty)
                        tty_insert_flip_char(tty, ch, flag);
        } while (1);
-
-       return;
 }
 
 static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup,
@@ -576,13 +569,30 @@ static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup,
                                TEGRA_UART_RX_DMA_BUFFER_SIZE, DMA_TO_DEVICE);
 }
 
+static void tegra_uart_rx_buffer_push(struct tegra_uart_port *tup,
+                                     unsigned int residue)
+{
+       struct tty_port *port = &tup->uport.state->port;
+       struct tty_struct *tty = tty_port_tty_get(port);
+       unsigned int count;
+
+       async_tx_ack(tup->rx_dma_desc);
+       count = tup->rx_bytes_requested - residue;
+
+       /* If we are here, DMA is stopped */
+       tegra_uart_copy_rx_to_tty(tup, port, count);
+
+       tegra_uart_handle_rx_pio(tup, port);
+       if (tty) {
+               tty_flip_buffer_push(port);
+               tty_kref_put(tty);
+       }
+}
+
 static void tegra_uart_rx_dma_complete(void *args)
 {
        struct tegra_uart_port *tup = args;
        struct uart_port *u = &tup->uport;
-       unsigned int count = tup->rx_bytes_requested;
-       struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port);
-       struct tty_port *port = &u->state->port;
        unsigned long flags;
        struct dma_tx_state state;
        enum dma_status status;
@@ -596,22 +606,11 @@ static void tegra_uart_rx_dma_complete(void *args)
                goto done;
        }
 
-       async_tx_ack(tup->rx_dma_desc);
-
        /* Deactivate flow control to stop sender */
        if (tup->rts_active)
                set_rts(tup, false);
 
-       /* If we are here, DMA is stopped */
-       tegra_uart_copy_rx_to_tty(tup, port, count);
-
-       tegra_uart_handle_rx_pio(tup, port);
-       if (tty) {
-               spin_unlock_irqrestore(&u->lock, flags);
-               tty_flip_buffer_push(port);
-               spin_lock_irqsave(&u->lock, flags);
-               tty_kref_put(tty);
-       }
+       tegra_uart_rx_buffer_push(tup, 0);
        tegra_uart_start_rx_dma(tup);
 
        /* Activate flow control to start transfer */
@@ -622,34 +621,17 @@ done:
        spin_unlock_irqrestore(&u->lock, flags);
 }
 
-static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup,
-               unsigned long *flags)
+static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup)
 {
        struct dma_tx_state state;
-       struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port);
-       struct tty_port *port = &tup->uport.state->port;
-       struct uart_port *u = &tup->uport;
-       unsigned int count;
 
        /* Deactivate flow control to stop sender */
        if (tup->rts_active)
                set_rts(tup, false);
 
        dmaengine_terminate_all(tup->rx_dma_chan);
-       dmaengine_tx_status(tup->rx_dma_chan,  tup->rx_cookie, &state);
-       async_tx_ack(tup->rx_dma_desc);
-       count = tup->rx_bytes_requested - state.residue;
-
-       /* If we are here, DMA is stopped */
-       tegra_uart_copy_rx_to_tty(tup, port, count);
-
-       tegra_uart_handle_rx_pio(tup, port);
-       if (tty) {
-               spin_unlock_irqrestore(&u->lock, *flags);
-               tty_flip_buffer_push(port);
-               spin_lock_irqsave(&u->lock, *flags);
-               tty_kref_put(tty);
-       }
+       dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state);
+       tegra_uart_rx_buffer_push(tup, state.residue);
        tegra_uart_start_rx_dma(tup);
 
        if (tup->rts_active)
@@ -697,7 +679,6 @@ static void tegra_uart_handle_modem_signal_change(struct uart_port *u)
        /* Will start/stop_tx accordingly */
        if (msr & UART_MSR_DCTS)
                uart_handle_cts_change(&tup->uport, msr & UART_MSR_CTS);
-       return;
 }
 
 static irqreturn_t tegra_uart_isr(int irq, void *data)
@@ -714,7 +695,7 @@ static irqreturn_t tegra_uart_isr(int irq, void *data)
                iir = tegra_uart_read(tup, UART_IIR);
                if (iir & UART_IIR_NO_INT) {
                        if (is_rx_int) {
-                               tegra_uart_handle_rx_dma(tup, &flags);
+                               tegra_uart_handle_rx_dma(tup);
                                if (tup->rx_in_progress) {
                                        ier = tup->ier_shadow;
                                        ier |= (UART_IER_RLSI | UART_IER_RTOIE |
@@ -769,11 +750,8 @@ static irqreturn_t tegra_uart_isr(int irq, void *data)
 static void tegra_uart_stop_rx(struct uart_port *u)
 {
        struct tegra_uart_port *tup = to_tegra_uport(u);
-       struct tty_struct *tty;
-       struct tty_port *port = &u->state->port;
        struct dma_tx_state state;
        unsigned long ier;
-       int count;
 
        if (tup->rts_active)
                set_rts(tup, false);
@@ -781,8 +759,6 @@ static void tegra_uart_stop_rx(struct uart_port *u)
        if (!tup->rx_in_progress)
                return;
 
-       tty = tty_port_tty_get(&tup->uport.state->port);
-
        tegra_uart_wait_sym_time(tup, 1); /* wait a character interval */
 
        ier = tup->ier_shadow;
@@ -791,21 +767,9 @@ static void tegra_uart_stop_rx(struct uart_port *u)
        tup->ier_shadow = ier;
        tegra_uart_write(tup, ier, UART_IER);
        tup->rx_in_progress = 0;
-       if (tup->rx_dma_chan) {
-               dmaengine_terminate_all(tup->rx_dma_chan);
-               dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state);
-               async_tx_ack(tup->rx_dma_desc);
-               count = tup->rx_bytes_requested - state.residue;
-               tegra_uart_copy_rx_to_tty(tup, port, count);
-               tegra_uart_handle_rx_pio(tup, port);
-       } else {
-               tegra_uart_handle_rx_pio(tup, port);
-       }
-       if (tty) {
-               tty_flip_buffer_push(port);
-               tty_kref_put(tty);
-       }
-       return;
+       dmaengine_terminate_all(tup->rx_dma_chan);
+       dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state);
+       tegra_uart_rx_buffer_push(tup, state.residue);
 }
 
 static void tegra_uart_hw_deinit(struct tegra_uart_port *tup)
@@ -1083,7 +1047,6 @@ static void tegra_uart_flush_buffer(struct uart_port *u)
        tup->tx_bytes = 0;
        if (tup->tx_dma_chan)
                dmaengine_terminate_all(tup->tx_dma_chan);
-       return;
 }
 
 static void tegra_uart_shutdown(struct uart_port *u)
@@ -1223,7 +1186,6 @@ static void tegra_uart_set_termios(struct uart_port *u,
        tegra_uart_read(tup, UART_IER);
 
        spin_unlock_irqrestore(&u->lock, flags);
-       return;
 }
 
 static const char *tegra_uart_type(struct uart_port *u)
index 603d2cc3f424f691c53f2ccb7c91efd4cf8ae9a5..def5199ca004d1f3b7fa70057b465871a8ef5bb5 100644 (file)
@@ -1437,7 +1437,6 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
        clear_bit(ASYNCB_CLOSING, &port->flags);
        spin_unlock_irq(&port->lock);
        wake_up_interruptible(&port->open_wait);
-       wake_up_interruptible(&port->close_wait);
 
        mutex_unlock(&port->mutex);
 
@@ -1819,8 +1818,8 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co)
  *     @options: ptr for <options> field; NULL if not present (out)
  *
  *     Decodes earlycon kernel command line parameters of the form
- *        earlycon=<name>,io|mmio|mmio32|mmio32be,<addr>,<options>
- *        console=<name>,io|mmio|mmio32|mmio32be,<addr>,<options>
+ *        earlycon=<name>,io|mmio|mmio32|mmio32be|mmio32native,<addr>,<options>
+ *        console=<name>,io|mmio|mmio32|mmio32be|mmio32native,<addr>,<options>
  *
  *     The optional form
  *        earlycon=<name>,0x<addr>,<options>
@@ -1841,6 +1840,10 @@ int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr,
        } else if (strncmp(p, "mmio32be,", 9) == 0) {
                *iotype = UPIO_MEM32BE;
                p += 9;
+       } else if (strncmp(p, "mmio32native,", 13) == 0) {
+               *iotype = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) ?
+                       UPIO_MEM32BE : UPIO_MEM32;
+               p += 13;
        } else if (strncmp(p, "io,", 3) == 0) {
                *iotype = UPIO_PORT;
                p += 3;
index 402f7fb541333a67a0383a4ac2fb3754ed2f395d..3eb57eb532f18a6af5fc169b044699a453e59975 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
  */
 
 #include <linux/err.h>
 #include <linux/device.h>
+#include <linux/irq.h>
 #include <linux/gpio/consumer.h>
 #include <linux/termios.h>
+#include <linux/serial_core.h>
 
 #include "serial_mctrl_gpio.h"
 
 struct mctrl_gpios {
+       struct uart_port *port;
        struct gpio_desc *gpio[UART_GPIO_MAX];
+       int irq[UART_GPIO_MAX];
+       unsigned int mctrl_prev;
+       bool mctrl_on;
 };
 
 static const struct {
@@ -82,7 +87,7 @@ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
 }
 EXPORT_SYMBOL_GPL(mctrl_gpio_get);
 
-struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx)
+struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx)
 {
        struct mctrl_gpios *gpios;
        enum mctrl_gpio_idx i;
@@ -110,15 +115,135 @@ struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx)
 
        return gpios;
 }
-EXPORT_SYMBOL_GPL(mctrl_gpio_init);
+EXPORT_SYMBOL_GPL(mctrl_gpio_init_noauto);
+
+#define MCTRL_ANY_DELTA (TIOCM_RI | TIOCM_DSR | TIOCM_CD | TIOCM_CTS)
+static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context)
+{
+       struct mctrl_gpios *gpios = context;
+       struct uart_port *port = gpios->port;
+       u32 mctrl = gpios->mctrl_prev;
+       u32 mctrl_diff;
+
+       mctrl_gpio_get(gpios, &mctrl);
+
+       mctrl_diff = mctrl ^ gpios->mctrl_prev;
+       gpios->mctrl_prev = mctrl;
+
+       if (mctrl_diff & MCTRL_ANY_DELTA && port->state != NULL) {
+               if ((mctrl_diff & mctrl) & TIOCM_RI)
+                       port->icount.rng++;
+
+               if ((mctrl_diff & mctrl) & TIOCM_DSR)
+                       port->icount.dsr++;
+
+               if (mctrl_diff & TIOCM_CD)
+                       uart_handle_dcd_change(port, mctrl & TIOCM_CD);
+
+               if (mctrl_diff & TIOCM_CTS)
+                       uart_handle_cts_change(port, mctrl & TIOCM_CTS);
+
+               wake_up_interruptible(&port->state->port.delta_msr_wait);
+       }
+
+       return IRQ_HANDLED;
+}
+
+struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx)
+{
+       struct mctrl_gpios *gpios;
+       enum mctrl_gpio_idx i;
+
+       gpios = mctrl_gpio_init_noauto(port->dev, idx);
+       if (IS_ERR(gpios))
+               return gpios;
+
+       gpios->port = port;
+
+       for (i = 0; i < UART_GPIO_MAX; ++i) {
+               int ret;
+
+               if (!gpios->gpio[i] || mctrl_gpios_desc[i].dir_out)
+                       continue;
+
+               ret = gpiod_to_irq(gpios->gpio[i]);
+               if (ret <= 0) {
+                       dev_err(port->dev,
+                               "failed to find corresponding irq for %s (idx=%d, err=%d)\n",
+                               mctrl_gpios_desc[i].name, idx, ret);
+                       return ERR_PTR(ret);
+               }
+               gpios->irq[i] = ret;
+
+               /* irqs should only be enabled in .enable_ms */
+               irq_set_status_flags(gpios->irq[i], IRQ_NOAUTOEN);
+
+               ret = devm_request_irq(port->dev, gpios->irq[i],
+                                      mctrl_gpio_irq_handle,
+                                      IRQ_TYPE_EDGE_BOTH, dev_name(port->dev),
+                                      gpios);
+               if (ret) {
+                       /* alternatively implement polling */
+                       dev_err(port->dev,
+                               "failed to request irq for %s (idx=%d, err=%d)\n",
+                               mctrl_gpios_desc[i].name, idx, ret);
+                       return ERR_PTR(ret);
+               }
+       }
+
+       return gpios;
+}
 
 void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
 {
        enum mctrl_gpio_idx i;
 
-       for (i = 0; i < UART_GPIO_MAX; i++)
+       for (i = 0; i < UART_GPIO_MAX; i++) {
+               if (gpios->irq[i])
+                       devm_free_irq(gpios->port->dev, gpios->irq[i], gpios);
+
                if (gpios->gpio[i])
                        devm_gpiod_put(dev, gpios->gpio[i]);
+       }
        devm_kfree(dev, gpios);
 }
 EXPORT_SYMBOL_GPL(mctrl_gpio_free);
+
+void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
+{
+       enum mctrl_gpio_idx i;
+
+       /* .enable_ms may be called multiple times */
+       if (gpios->mctrl_on)
+               return;
+
+       gpios->mctrl_on = true;
+
+       /* get initial status of modem lines GPIOs */
+       mctrl_gpio_get(gpios, &gpios->mctrl_prev);
+
+       for (i = 0; i < UART_GPIO_MAX; ++i) {
+               if (!gpios->irq[i])
+                       continue;
+
+               enable_irq(gpios->irq[i]);
+       }
+}
+EXPORT_SYMBOL_GPL(mctrl_gpio_enable_ms);
+
+void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
+{
+       enum mctrl_gpio_idx i;
+
+       if (!gpios->mctrl_on)
+               return;
+
+       gpios->mctrl_on = false;
+
+       for (i = 0; i < UART_GPIO_MAX; ++i) {
+               if (!gpios->irq[i])
+                       continue;
+
+               disable_irq(gpios->irq[i]);
+       }
+}
index 400ba0494a1798ed4304c5b07da2b68e03234a4a..9716db283290697165002860430ab77bdb2ace00 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/device.h>
 #include <linux/gpio/consumer.h>
 
+struct uart_port;
+
 enum mctrl_gpio_idx {
        UART_GPIO_CTS,
        UART_GPIO_DSR,
@@ -59,13 +61,23 @@ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl);
 struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
                                      enum mctrl_gpio_idx gidx);
 
+/*
+ * Request and set direction of modem control lines GPIOs and sets up irq
+ * handling.
+ * devm_* functions are used, so there's no need to call mctrl_gpio_free().
+ * Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on
+ * allocation error.
+ */
+struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx);
+
 /*
  * Request and set direction of modem control lines GPIOs.
  * devm_* functions are used, so there's no need to call mctrl_gpio_free().
  * Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on
  * allocation error.
  */
-struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx);
+struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev,
+                                          unsigned int idx);
 
 /*
  * Free the mctrl_gpios structure.
@@ -74,6 +86,16 @@ struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx);
  */
 void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios);
 
+/*
+ * Enable gpio interrupts to report status line changes.
+ */
+void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios);
+
+/*
+ * Disable gpio interrupts to report status line changes.
+ */
+void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios);
+
 #else /* GPIOLIB */
 
 static inline
@@ -95,7 +117,13 @@ struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
 }
 
 static inline
-struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx)
+struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx)
+{
+       return ERR_PTR(-ENOSYS);
+}
+
+static inline
+struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx)
 {
        return ERR_PTR(-ENOSYS);
 }
@@ -105,6 +133,14 @@ void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
 {
 }
 
+static inline void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
+{
+}
+
+static inline void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
+{
+}
+
 #endif /* GPIOLIB */
 
 #endif
index 1b2f894bdc9e0e6ed15cf93feb405337b1d0d07b..960e50a97558cff52a1fb9eb8ed8879a5238991c 100644 (file)
@@ -84,6 +84,7 @@ struct sci_port {
        unsigned int            overrun_reg;
        unsigned int            overrun_mask;
        unsigned int            error_mask;
+       unsigned int            error_clear;
        unsigned int            sampling_rate;
        resource_size_t         reg_size;
 
@@ -103,19 +104,15 @@ struct sci_port {
        struct dma_chan                 *chan_rx;
 
 #ifdef CONFIG_SERIAL_SH_SCI_DMA
-       struct dma_async_tx_descriptor  *desc_tx;
-       struct dma_async_tx_descriptor  *desc_rx[2];
        dma_cookie_t                    cookie_tx;
        dma_cookie_t                    cookie_rx[2];
        dma_cookie_t                    active_rx;
-       struct scatterlist              sg_tx;
-       unsigned int                    sg_len_tx;
+       dma_addr_t                      tx_dma_addr;
+       unsigned int                    tx_dma_len;
        struct scatterlist              sg_rx[2];
+       void                            *rx_buf[2];
        size_t                          buf_len_rx;
-       struct sh_dmae_slave            param_tx;
-       struct sh_dmae_slave            param_rx;
        struct work_struct              work_tx;
-       struct work_struct              work_rx;
        struct timer_list               rx_timer;
        unsigned int                    rx_timeout;
 #endif
@@ -123,11 +120,6 @@ struct sci_port {
        struct notifier_block           freq_transition;
 };
 
-/* Function prototypes */
-static void sci_start_tx(struct uart_port *port);
-static void sci_stop_tx(struct uart_port *port);
-static void sci_start_rx(struct uart_port *port);
-
 #define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
 
 static struct sci_port sci_ports[SCI_NPORTS];
@@ -146,7 +138,7 @@ struct plat_sci_reg {
 /* Helper for invalidating specific entries of an inherited map. */
 #define sci_reg_invalid        { .offset = 0, .size = 0 }
 
-static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
+static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
        [SCIx_PROBE_REGTYPE] = {
                [0 ... SCIx_NR_REGS - 1] = sci_reg_invalid,
        },
@@ -399,7 +391,7 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = {
  */
 static unsigned int sci_serial_in(struct uart_port *p, int offset)
 {
-       struct plat_sci_reg *reg = sci_getreg(p, offset);
+       const struct plat_sci_reg *reg = sci_getreg(p, offset);
 
        if (reg->size == 8)
                return ioread8(p->membase + (reg->offset << p->regshift));
@@ -413,7 +405,7 @@ static unsigned int sci_serial_in(struct uart_port *p, int offset)
 
 static void sci_serial_out(struct uart_port *p, int offset, int value)
 {
-       struct plat_sci_reg *reg = sci_getreg(p, offset);
+       const struct plat_sci_reg *reg = sci_getreg(p, offset);
 
        if (reg->size == 8)
                iowrite8(value, p->membase + (reg->offset << p->regshift));
@@ -489,6 +481,105 @@ static void sci_port_disable(struct sci_port *sci_port)
        pm_runtime_put_sync(sci_port->port.dev);
 }
 
+static inline unsigned long port_rx_irq_mask(struct uart_port *port)
+{
+       /*
+        * Not all ports (such as SCIFA) will support REIE. Rather than
+        * special-casing the port type, we check the port initialization
+        * IRQ enable mask to see whether the IRQ is desired at all. If
+        * it's unset, it's logically inferred that there's no point in
+        * testing for it.
+        */
+       return SCSCR_RIE | (to_sci_port(port)->cfg->scscr & SCSCR_REIE);
+}
+
+static void sci_start_tx(struct uart_port *port)
+{
+       struct sci_port *s = to_sci_port(port);
+       unsigned short ctrl;
+
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+               u16 new, scr = serial_port_in(port, SCSCR);
+               if (s->chan_tx)
+                       new = scr | SCSCR_TDRQE;
+               else
+                       new = scr & ~SCSCR_TDRQE;
+               if (new != scr)
+                       serial_port_out(port, SCSCR, new);
+       }
+
+       if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) &&
+           dma_submit_error(s->cookie_tx)) {
+               s->cookie_tx = 0;
+               schedule_work(&s->work_tx);
+       }
+#endif
+
+       if (!s->chan_tx || port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+               /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
+               ctrl = serial_port_in(port, SCSCR);
+               serial_port_out(port, SCSCR, ctrl | SCSCR_TIE);
+       }
+}
+
+static void sci_stop_tx(struct uart_port *port)
+{
+       unsigned short ctrl;
+
+       /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */
+       ctrl = serial_port_in(port, SCSCR);
+
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+               ctrl &= ~SCSCR_TDRQE;
+
+       ctrl &= ~SCSCR_TIE;
+
+       serial_port_out(port, SCSCR, ctrl);
+}
+
+static void sci_start_rx(struct uart_port *port)
+{
+       unsigned short ctrl;
+
+       ctrl = serial_port_in(port, SCSCR) | port_rx_irq_mask(port);
+
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+               ctrl &= ~SCSCR_RDRQE;
+
+       serial_port_out(port, SCSCR, ctrl);
+}
+
+static void sci_stop_rx(struct uart_port *port)
+{
+       unsigned short ctrl;
+
+       ctrl = serial_port_in(port, SCSCR);
+
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+               ctrl &= ~SCSCR_RDRQE;
+
+       ctrl &= ~port_rx_irq_mask(port);
+
+       serial_port_out(port, SCSCR, ctrl);
+}
+
+static void sci_clear_SCxSR(struct uart_port *port, unsigned int mask)
+{
+       if (port->type == PORT_SCI) {
+               /* Just store the mask */
+               serial_port_out(port, SCxSR, mask);
+       } else if (to_sci_port(port)->overrun_mask == SCIFA_ORER) {
+               /* SCIFA/SCIFB and SCIF on SH7705/SH7720/SH7721 */
+               /* Only clear the status bits we want to clear */
+               serial_port_out(port, SCxSR,
+                               serial_port_in(port, SCxSR) & mask);
+       } else {
+               /* Store the mask, clear parity/framing errors */
+               serial_port_out(port, SCxSR, mask & ~(SCIF_FERC | SCIF_PERC));
+       }
+}
+
 #if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
 
 #ifdef CONFIG_CONSOLE_POLL
@@ -500,7 +591,7 @@ static int sci_poll_get_char(struct uart_port *port)
        do {
                status = serial_port_in(port, SCxSR);
                if (status & SCxSR_ERRORS(port)) {
-                       serial_port_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
+                       sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
                        continue;
                }
                break;
@@ -513,7 +604,7 @@ static int sci_poll_get_char(struct uart_port *port)
 
        /* Dummy read */
        serial_port_in(port, SCxSR);
-       serial_port_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+       sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
 
        return c;
 }
@@ -528,14 +619,14 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c)
        } while (!(status & SCxSR_TDxE(port)));
 
        serial_port_out(port, SCxTDR, c);
-       serial_port_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
+       sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
 }
 #endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */
 
 static void sci_init_pins(struct uart_port *port, unsigned int cflag)
 {
        struct sci_port *s = to_sci_port(port);
-       struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR;
+       const struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR;
 
        /*
         * Use port-specific handler if provided.
@@ -565,7 +656,7 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag)
 
 static int sci_txfill(struct uart_port *port)
 {
-       struct plat_sci_reg *reg;
+       const struct plat_sci_reg *reg;
 
        reg = sci_getreg(port, SCTFDR);
        if (reg->size)
@@ -585,7 +676,7 @@ static int sci_txroom(struct uart_port *port)
 
 static int sci_rxfill(struct uart_port *port)
 {
-       struct plat_sci_reg *reg;
+       const struct plat_sci_reg *reg;
 
        reg = sci_getreg(port, SCRFDR);
        if (reg->size)
@@ -655,7 +746,7 @@ static void sci_transmit_chars(struct uart_port *port)
                port->icount.tx++;
        } while (--count > 0);
 
-       serial_port_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
+       sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port));
 
        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
                uart_write_wakeup(port);
@@ -666,7 +757,7 @@ static void sci_transmit_chars(struct uart_port *port)
 
                if (port->type != PORT_SCI) {
                        serial_port_in(port, SCxSR); /* Dummy read */
-                       serial_port_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
+                       sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port));
                }
 
                ctrl |= SCSCR_TIE;
@@ -750,7 +841,7 @@ static void sci_receive_chars(struct uart_port *port)
                }
 
                serial_port_in(port, SCxSR); /* dummy read */
-               serial_port_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+               sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
 
                copied += count;
                port->icount.rx += count;
@@ -761,7 +852,7 @@ static void sci_receive_chars(struct uart_port *port)
                tty_flip_buffer_push(tport);
        } else {
                serial_port_in(port, SCxSR); /* dummy read */
-               serial_port_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+               sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
        }
 }
 
@@ -866,7 +957,7 @@ static int sci_handle_fifo_overrun(struct uart_port *port)
 {
        struct tty_port *tport = &port->state->port;
        struct sci_port *s = to_sci_port(port);
-       struct plat_sci_reg *reg;
+       const struct plat_sci_reg *reg;
        int copied = 0;
        u16 status;
 
@@ -924,686 +1015,783 @@ static int sci_handle_breaks(struct uart_port *port)
        return copied;
 }
 
-static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
-{
 #ifdef CONFIG_SERIAL_SH_SCI_DMA
-       struct uart_port *port = ptr;
-       struct sci_port *s = to_sci_port(port);
+static void sci_dma_tx_complete(void *arg)
+{
+       struct sci_port *s = arg;
+       struct uart_port *port = &s->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       unsigned long flags;
 
-       if (s->chan_rx) {
-               u16 scr = serial_port_in(port, SCSCR);
-               u16 ssr = serial_port_in(port, SCxSR);
+       dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
 
-               /* Disable future Rx interrupts */
-               if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
-                       disable_irq_nosync(irq);
-                       scr |= SCSCR_RDRQE;
-               } else {
-                       scr &= ~SCSCR_RIE;
-               }
-               serial_port_out(port, SCSCR, scr);
-               /* Clear current interrupt */
-               serial_port_out(port, SCxSR, ssr & ~(1 | SCxSR_RDxF(port)));
-               dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u jiffies\n",
-                       jiffies, s->rx_timeout);
-               mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
+       spin_lock_irqsave(&port->lock, flags);
 
-               return IRQ_HANDLED;
-       }
-#endif
+       xmit->tail += s->tx_dma_len;
+       xmit->tail &= UART_XMIT_SIZE - 1;
 
-       /* I think sci_receive_chars has to be called irrespective
-        * of whether the I_IXOFF is set, otherwise, how is the interrupt
-        * to be disabled?
-        */
-       sci_receive_chars(ptr);
+       port->icount.tx += s->tx_dma_len;
 
-       return IRQ_HANDLED;
-}
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
 
-static irqreturn_t sci_tx_interrupt(int irq, void *ptr)
-{
-       struct uart_port *port = ptr;
-       unsigned long flags;
+       if (!uart_circ_empty(xmit)) {
+               s->cookie_tx = 0;
+               schedule_work(&s->work_tx);
+       } else {
+               s->cookie_tx = -EINVAL;
+               if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+                       u16 ctrl = serial_port_in(port, SCSCR);
+                       serial_port_out(port, SCSCR, ctrl & ~SCSCR_TIE);
+               }
+       }
 
-       spin_lock_irqsave(&port->lock, flags);
-       sci_transmit_chars(port);
        spin_unlock_irqrestore(&port->lock, flags);
-
-       return IRQ_HANDLED;
 }
 
-static irqreturn_t sci_er_interrupt(int irq, void *ptr)
+/* Locking: called with port lock held */
+static int sci_dma_rx_push(struct sci_port *s, void *buf, size_t count)
 {
-       struct uart_port *port = ptr;
+       struct uart_port *port = &s->port;
+       struct tty_port *tport = &port->state->port;
+       int copied;
 
-       /* Handle errors */
-       if (port->type == PORT_SCI) {
-               if (sci_handle_errors(port)) {
-                       /* discard character in rx buffer */
-                       serial_port_in(port, SCxSR);
-                       serial_port_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
-               }
-       } else {
-               sci_handle_fifo_overrun(port);
-               sci_rx_interrupt(irq, ptr);
+       copied = tty_insert_flip_string(tport, buf, count);
+       if (copied < count) {
+               dev_warn(port->dev, "Rx overrun: dropping %zu bytes\n",
+                        count - copied);
+               port->icount.buf_overrun++;
        }
 
-       serial_port_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
-
-       /* Kick the transmission */
-       sci_tx_interrupt(irq, ptr);
+       port->icount.rx += copied;
 
-       return IRQ_HANDLED;
+       return copied;
 }
 
-static irqreturn_t sci_br_interrupt(int irq, void *ptr)
+static int sci_dma_rx_find_active(struct sci_port *s)
 {
-       struct uart_port *port = ptr;
+       unsigned int i;
 
-       /* Handle BREAKs */
-       sci_handle_breaks(port);
-       serial_port_out(port, SCxSR, SCxSR_BREAK_CLEAR(port));
+       for (i = 0; i < ARRAY_SIZE(s->cookie_rx); i++)
+               if (s->active_rx == s->cookie_rx[i])
+                       return i;
 
-       return IRQ_HANDLED;
+       dev_err(s->port.dev, "%s: Rx cookie %d not found!\n", __func__,
+               s->active_rx);
+       return -1;
 }
 
-static inline unsigned long port_rx_irq_mask(struct uart_port *port)
+static void sci_rx_dma_release(struct sci_port *s, bool enable_pio)
 {
-       /*
-        * Not all ports (such as SCIFA) will support REIE. Rather than
-        * special-casing the port type, we check the port initialization
-        * IRQ enable mask to see whether the IRQ is desired at all. If
-        * it's unset, it's logically inferred that there's no point in
-        * testing for it.
-        */
-       return SCSCR_RIE | (to_sci_port(port)->cfg->scscr & SCSCR_REIE);
+       struct dma_chan *chan = s->chan_rx;
+       struct uart_port *port = &s->port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       s->chan_rx = NULL;
+       s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL;
+       spin_unlock_irqrestore(&port->lock, flags);
+       dmaengine_terminate_all(chan);
+       dma_free_coherent(chan->device->dev, s->buf_len_rx * 2, s->rx_buf[0],
+                         sg_dma_address(&s->sg_rx[0]));
+       dma_release_channel(chan);
+       if (enable_pio)
+               sci_start_rx(port);
 }
 
-static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
+static void sci_dma_rx_complete(void *arg)
 {
-       unsigned short ssr_status, scr_status, err_enabled, orer_status = 0;
-       struct uart_port *port = ptr;
-       struct sci_port *s = to_sci_port(port);
-       irqreturn_t ret = IRQ_NONE;
+       struct sci_port *s = arg;
+       struct dma_chan *chan = s->chan_rx;
+       struct uart_port *port = &s->port;
+       struct dma_async_tx_descriptor *desc;
+       unsigned long flags;
+       int active, count = 0;
 
-       ssr_status = serial_port_in(port, SCxSR);
-       scr_status = serial_port_in(port, SCSCR);
-       if (s->overrun_reg == SCxSR)
-               orer_status = ssr_status;
-       else {
-               if (sci_getreg(port, s->overrun_reg)->size)
-                       orer_status = serial_port_in(port, s->overrun_reg);
-       }
+       dev_dbg(port->dev, "%s(%d) active cookie %d\n", __func__, port->line,
+               s->active_rx);
 
-       err_enabled = scr_status & port_rx_irq_mask(port);
+       spin_lock_irqsave(&port->lock, flags);
 
-       /* Tx Interrupt */
-       if ((ssr_status & SCxSR_TDxE(port)) && (scr_status & SCSCR_TIE) &&
-           !s->chan_tx)
-               ret = sci_tx_interrupt(irq, ptr);
+       active = sci_dma_rx_find_active(s);
+       if (active >= 0)
+               count = sci_dma_rx_push(s, s->rx_buf[active], s->buf_len_rx);
 
-       /*
-        * Rx Interrupt: if we're using DMA, the DMA controller clears RDF /
-        * DR flags
-        */
-       if (((ssr_status & SCxSR_RDxF(port)) || s->chan_rx) &&
-           (scr_status & SCSCR_RIE)) {
-               if (port->type == PORT_SCIF || port->type == PORT_HSCIF)
-                       sci_handle_fifo_overrun(port);
-               ret = sci_rx_interrupt(irq, ptr);
-       }
+       mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
 
-       /* Error Interrupt */
-       if ((ssr_status & SCxSR_ERRORS(port)) && err_enabled)
-               ret = sci_er_interrupt(irq, ptr);
+       if (count)
+               tty_flip_buffer_push(&port->state->port);
 
-       /* Break Interrupt */
-       if ((ssr_status & SCxSR_BRK(port)) && err_enabled)
-               ret = sci_br_interrupt(irq, ptr);
+       desc = dmaengine_prep_slave_sg(s->chan_rx, &s->sg_rx[active], 1,
+                                      DMA_DEV_TO_MEM,
+                                      DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!desc)
+               goto fail;
 
-       /* Overrun Interrupt */
-       if (orer_status & s->overrun_mask)
-               sci_handle_fifo_overrun(port);
+       desc->callback = sci_dma_rx_complete;
+       desc->callback_param = s;
+       s->cookie_rx[active] = dmaengine_submit(desc);
+       if (dma_submit_error(s->cookie_rx[active]))
+               goto fail;
 
-       return ret;
+       s->active_rx = s->cookie_rx[!active];
+
+       dma_async_issue_pending(chan);
+
+       dev_dbg(port->dev, "%s: cookie %d #%d, new active cookie %d\n",
+               __func__, s->cookie_rx[active], active, s->active_rx);
+       spin_unlock_irqrestore(&port->lock, flags);
+       return;
+
+fail:
+       spin_unlock_irqrestore(&port->lock, flags);
+       dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n");
+       sci_rx_dma_release(s, true);
 }
 
-/*
- * Here we define a transition notifier so that we can update all of our
- * ports' baud rate when the peripheral clock changes.
- */
-static int sci_notifier(struct notifier_block *self,
-                       unsigned long phase, void *p)
+static void sci_tx_dma_release(struct sci_port *s, bool enable_pio)
 {
-       struct sci_port *sci_port;
+       struct dma_chan *chan = s->chan_tx;
+       struct uart_port *port = &s->port;
        unsigned long flags;
 
-       sci_port = container_of(self, struct sci_port, freq_transition);
-
-       if (phase == CPUFREQ_POSTCHANGE) {
-               struct uart_port *port = &sci_port->port;
+       spin_lock_irqsave(&port->lock, flags);
+       s->chan_tx = NULL;
+       s->cookie_tx = -EINVAL;
+       spin_unlock_irqrestore(&port->lock, flags);
+       dmaengine_terminate_all(chan);
+       dma_unmap_single(chan->device->dev, s->tx_dma_addr, UART_XMIT_SIZE,
+                        DMA_TO_DEVICE);
+       dma_release_channel(chan);
+       if (enable_pio)
+               sci_start_tx(port);
+}
 
-               spin_lock_irqsave(&port->lock, flags);
-               port->uartclk = clk_get_rate(sci_port->iclk);
-               spin_unlock_irqrestore(&port->lock, flags);
+static void sci_submit_rx(struct sci_port *s)
+{
+       struct dma_chan *chan = s->chan_rx;
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               struct scatterlist *sg = &s->sg_rx[i];
+               struct dma_async_tx_descriptor *desc;
+
+               desc = dmaengine_prep_slave_sg(chan,
+                       sg, 1, DMA_DEV_TO_MEM,
+                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+               if (!desc)
+                       goto fail;
+
+               desc->callback = sci_dma_rx_complete;
+               desc->callback_param = s;
+               s->cookie_rx[i] = dmaengine_submit(desc);
+               if (dma_submit_error(s->cookie_rx[i]))
+                       goto fail;
+
+               dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", __func__,
+                       s->cookie_rx[i], i);
        }
 
-       return NOTIFY_OK;
+       s->active_rx = s->cookie_rx[0];
+
+       dma_async_issue_pending(chan);
+       return;
+
+fail:
+       if (i)
+               dmaengine_terminate_all(chan);
+       for (i = 0; i < 2; i++)
+               s->cookie_rx[i] = -EINVAL;
+       s->active_rx = -EINVAL;
+       dev_warn(s->port.dev, "Failed to re-start Rx DMA, using PIO\n");
+       sci_rx_dma_release(s, true);
 }
 
-static struct sci_irq_desc {
-       const char      *desc;
-       irq_handler_t   handler;
-} sci_irq_desc[] = {
+static void work_fn_tx(struct work_struct *work)
+{
+       struct sci_port *s = container_of(work, struct sci_port, work_tx);
+       struct dma_async_tx_descriptor *desc;
+       struct dma_chan *chan = s->chan_tx;
+       struct uart_port *port = &s->port;
+       struct circ_buf *xmit = &port->state->xmit;
+       dma_addr_t buf;
+
        /*
-        * Split out handlers, the default case.
+        * DMA is idle now.
+        * Port xmit buffer is already mapped, and it is one page... Just adjust
+        * offsets and lengths. Since it is a circular buffer, we have to
+        * transmit till the end, and then the rest. Take the port lock to get a
+        * consistent xmit buffer state.
         */
-       [SCIx_ERI_IRQ] = {
-               .desc = "rx err",
-               .handler = sci_er_interrupt,
-       },
+       spin_lock_irq(&port->lock);
+       buf = s->tx_dma_addr + (xmit->tail & (UART_XMIT_SIZE - 1));
+       s->tx_dma_len = min_t(unsigned int,
+               CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE),
+               CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE));
+       spin_unlock_irq(&port->lock);
 
-       [SCIx_RXI_IRQ] = {
-               .desc = "rx full",
-               .handler = sci_rx_interrupt,
-       },
+       desc = dmaengine_prep_slave_single(chan, buf, s->tx_dma_len,
+                                          DMA_MEM_TO_DEV,
+                                          DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!desc) {
+               dev_warn(port->dev, "Failed preparing Tx DMA descriptor\n");
+               /* switch to PIO */
+               sci_tx_dma_release(s, true);
+               return;
+       }
 
-       [SCIx_TXI_IRQ] = {
-               .desc = "tx empty",
-               .handler = sci_tx_interrupt,
-       },
+       dma_sync_single_for_device(chan->device->dev, buf, s->tx_dma_len,
+                                  DMA_TO_DEVICE);
 
-       [SCIx_BRI_IRQ] = {
-               .desc = "break",
-               .handler = sci_br_interrupt,
-       },
+       spin_lock_irq(&port->lock);
+       desc->callback = sci_dma_tx_complete;
+       desc->callback_param = s;
+       spin_unlock_irq(&port->lock);
+       s->cookie_tx = dmaengine_submit(desc);
+       if (dma_submit_error(s->cookie_tx)) {
+               dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n");
+               /* switch to PIO */
+               sci_tx_dma_release(s, true);
+               return;
+       }
 
-       /*
-        * Special muxed handler.
-        */
-       [SCIx_MUX_IRQ] = {
-               .desc = "mux",
-               .handler = sci_mpxed_interrupt,
-       },
-};
+       dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n",
+               __func__, xmit->buf, xmit->tail, xmit->head, s->cookie_tx);
 
-static int sci_request_irq(struct sci_port *port)
+       dma_async_issue_pending(chan);
+}
+
+static void rx_timer_fn(unsigned long arg)
 {
-       struct uart_port *up = &port->port;
-       int i, j, ret = 0;
+       struct sci_port *s = (struct sci_port *)arg;
+       struct dma_chan *chan = s->chan_rx;
+       struct uart_port *port = &s->port;
+       struct dma_tx_state state;
+       enum dma_status status;
+       unsigned long flags;
+       unsigned int read;
+       int active, count;
+       u16 scr;
 
-       for (i = j = 0; i < SCIx_NR_IRQS; i++, j++) {
-               struct sci_irq_desc *desc;
-               int irq;
+       spin_lock_irqsave(&port->lock, flags);
 
-               if (SCIx_IRQ_IS_MUXED(port)) {
-                       i = SCIx_MUX_IRQ;
-                       irq = up->irq;
-               } else {
-                       irq = port->irqs[i];
+       dev_dbg(port->dev, "DMA Rx timed out\n");
 
-                       /*
-                        * Certain port types won't support all of the
-                        * available interrupt sources.
-                        */
-                       if (unlikely(irq < 0))
-                               continue;
-               }
+       active = sci_dma_rx_find_active(s);
+       if (active < 0) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               return;
+       }
 
-               desc = sci_irq_desc + i;
-               port->irqstr[j] = kasprintf(GFP_KERNEL, "%s:%s",
-                                           dev_name(up->dev), desc->desc);
-               if (!port->irqstr[j]) {
-                       dev_err(up->dev, "Failed to allocate %s IRQ string\n",
-                               desc->desc);
-                       goto out_nomem;
-               }
+       status = dmaengine_tx_status(s->chan_rx, s->active_rx, &state);
+       if (status == DMA_COMPLETE) {
+               dev_dbg(port->dev, "Cookie %d #%d has already completed\n",
+                       s->active_rx, active);
+               spin_unlock_irqrestore(&port->lock, flags);
 
-               ret = request_irq(irq, desc->handler, up->irqflags,
-                                 port->irqstr[j], port);
-               if (unlikely(ret)) {
-                       dev_err(up->dev, "Can't allocate %s IRQ\n", desc->desc);
-                       goto out_noirq;
-               }
+               /* Let packet complete handler take care of the packet */
+               return;
        }
 
-       return 0;
+       dmaengine_pause(chan);
 
-out_noirq:
-       while (--i >= 0)
-               free_irq(port->irqs[i], port);
+       /*
+        * sometimes DMA transfer doesn't stop even if it is stopped and
+        * data keeps on coming until transaction is complete so check
+        * for DMA_COMPLETE again
+        * Let packet complete handler take care of the packet
+        */
+       status = dmaengine_tx_status(s->chan_rx, s->active_rx, &state);
+       if (status == DMA_COMPLETE) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               dev_dbg(port->dev, "Transaction complete after DMA engine was stopped");
+               return;
+       }
 
-out_nomem:
-       while (--j >= 0)
-               kfree(port->irqstr[j]);
+       /* Handle incomplete DMA receive */
+       dmaengine_terminate_all(s->chan_rx);
+       read = sg_dma_len(&s->sg_rx[active]) - state.residue;
+       dev_dbg(port->dev, "Read %u bytes with cookie %d\n", read,
+               s->active_rx);
 
-       return ret;
+       if (read) {
+               count = sci_dma_rx_push(s, s->rx_buf[active], read);
+               if (count)
+                       tty_flip_buffer_push(&port->state->port);
+       }
+
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+               sci_submit_rx(s);
+
+       /* Direct new serial port interrupts back to CPU */
+       scr = serial_port_in(port, SCSCR);
+       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+               scr &= ~SCSCR_RDRQE;
+               enable_irq(s->irqs[SCIx_RXI_IRQ]);
+       }
+       serial_port_out(port, SCSCR, scr | SCSCR_RIE);
+
+       spin_unlock_irqrestore(&port->lock, flags);
 }
 
-static void sci_free_irq(struct sci_port *port)
+static struct dma_chan *sci_request_dma_chan(struct uart_port *port,
+                                            enum dma_transfer_direction dir,
+                                            unsigned int id)
 {
-       int i;
+       dma_cap_mask_t mask;
+       struct dma_chan *chan;
+       struct dma_slave_config cfg;
+       int ret;
 
-       /*
-        * Intentionally in reverse order so we iterate over the muxed
-        * IRQ first.
-        */
-       for (i = 0; i < SCIx_NR_IRQS; i++) {
-               int irq = port->irqs[i];
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
 
-               /*
-                * Certain port types won't support all of the available
-                * interrupt sources.
-                */
-               if (unlikely(irq < 0))
-                       continue;
+       chan = dma_request_slave_channel_compat(mask, shdma_chan_filter,
+                                       (void *)(unsigned long)id, port->dev,
+                                       dir == DMA_MEM_TO_DEV ? "tx" : "rx");
+       if (!chan) {
+               dev_warn(port->dev,
+                        "dma_request_slave_channel_compat failed\n");
+               return NULL;
+       }
 
-               free_irq(port->irqs[i], port);
-               kfree(port->irqstr[i]);
+       memset(&cfg, 0, sizeof(cfg));
+       cfg.direction = dir;
+       if (dir == DMA_MEM_TO_DEV) {
+               cfg.dst_addr = port->mapbase +
+                       (sci_getreg(port, SCxTDR)->offset << port->regshift);
+               cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+       } else {
+               cfg.src_addr = port->mapbase +
+                       (sci_getreg(port, SCxRDR)->offset << port->regshift);
+               cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+       }
 
-               if (SCIx_IRQ_IS_MUXED(port)) {
-                       /* If there's only one IRQ, we're done. */
-                       return;
-               }
+       ret = dmaengine_slave_config(chan, &cfg);
+       if (ret) {
+               dev_warn(port->dev, "dmaengine_slave_config failed %d\n", ret);
+               dma_release_channel(chan);
+               return NULL;
        }
+
+       return chan;
 }
 
-static unsigned int sci_tx_empty(struct uart_port *port)
+static void sci_request_dma(struct uart_port *port)
 {
-       unsigned short status = serial_port_in(port, SCxSR);
-       unsigned short in_tx_fifo = sci_txfill(port);
+       struct sci_port *s = to_sci_port(port);
+       struct dma_chan *chan;
 
-       return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0;
-}
+       dev_dbg(port->dev, "%s: port %d\n", __func__, port->line);
 
-/*
- * Modem control is a bit of a mixed bag for SCI(F) ports. Generally
- * CTS/RTS is supported in hardware by at least one port and controlled
- * via SCSPTR (SCxPCR for SCIFA/B parts), or external pins (presently
- * handled via the ->init_pins() op, which is a bit of a one-way street,
- * lacking any ability to defer pin control -- this will later be
- * converted over to the GPIO framework).
- *
- * Other modes (such as loopback) are supported generically on certain
- * port types, but not others. For these it's sufficient to test for the
- * existence of the support register and simply ignore the port type.
- */
-static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       if (mctrl & TIOCM_LOOP) {
-               struct plat_sci_reg *reg;
+       if (!port->dev->of_node &&
+           (s->cfg->dma_slave_tx <= 0 || s->cfg->dma_slave_rx <= 0))
+               return;
 
-               /*
-                * Standard loopback mode for SCFCR ports.
-                */
-               reg = sci_getreg(port, SCFCR);
-               if (reg->size)
-                       serial_port_out(port, SCFCR,
-                                       serial_port_in(port, SCFCR) |
-                                       SCFCR_LOOP);
-       }
-}
+       s->cookie_tx = -EINVAL;
+       chan = sci_request_dma_chan(port, DMA_MEM_TO_DEV, s->cfg->dma_slave_tx);
+       dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan);
+       if (chan) {
+               s->chan_tx = chan;
+               /* UART circular tx buffer is an aligned page. */
+               s->tx_dma_addr = dma_map_single(chan->device->dev,
+                                               port->state->xmit.buf,
+                                               UART_XMIT_SIZE,
+                                               DMA_TO_DEVICE);
+               if (dma_mapping_error(chan->device->dev, s->tx_dma_addr)) {
+                       dev_warn(port->dev, "Failed mapping Tx DMA descriptor\n");
+                       dma_release_channel(chan);
+                       s->chan_tx = NULL;
+               } else {
+                       dev_dbg(port->dev, "%s: mapped %lu@%p to %pad\n",
+                               __func__, UART_XMIT_SIZE,
+                               port->state->xmit.buf, &s->tx_dma_addr);
+               }
 
-static unsigned int sci_get_mctrl(struct uart_port *port)
-{
-       /*
-        * CTS/RTS is handled in hardware when supported, while nothing
-        * else is wired up. Keep it simple and simply assert DSR/CAR.
-        */
-       return TIOCM_DSR | TIOCM_CAR;
-}
+               INIT_WORK(&s->work_tx, work_fn_tx);
+       }
 
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
-static void sci_dma_tx_complete(void *arg)
-{
-       struct sci_port *s = arg;
-       struct uart_port *port = &s->port;
-       struct circ_buf *xmit = &port->state->xmit;
-       unsigned long flags;
+       chan = sci_request_dma_chan(port, DMA_DEV_TO_MEM, s->cfg->dma_slave_rx);
+       dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan);
+       if (chan) {
+               unsigned int i;
+               dma_addr_t dma;
+               void *buf;
 
-       dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
+               s->chan_rx = chan;
 
-       spin_lock_irqsave(&port->lock, flags);
+               s->buf_len_rx = 2 * max_t(size_t, 16, port->fifosize);
+               buf = dma_alloc_coherent(chan->device->dev, s->buf_len_rx * 2,
+                                        &dma, GFP_KERNEL);
+               if (!buf) {
+                       dev_warn(port->dev,
+                                "Failed to allocate Rx dma buffer, using PIO\n");
+                       dma_release_channel(chan);
+                       s->chan_rx = NULL;
+                       return;
+               }
 
-       xmit->tail += sg_dma_len(&s->sg_tx);
-       xmit->tail &= UART_XMIT_SIZE - 1;
+               for (i = 0; i < 2; i++) {
+                       struct scatterlist *sg = &s->sg_rx[i];
 
-       port->icount.tx += sg_dma_len(&s->sg_tx);
+                       sg_init_table(sg, 1);
+                       s->rx_buf[i] = buf;
+                       sg_dma_address(sg) = dma;
+                       sg->length = s->buf_len_rx;
 
-       async_tx_ack(s->desc_tx);
-       s->desc_tx = NULL;
+                       buf += s->buf_len_rx;
+                       dma += s->buf_len_rx;
+               }
 
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(port);
+               setup_timer(&s->rx_timer, rx_timer_fn, (unsigned long)s);
 
-       if (!uart_circ_empty(xmit)) {
-               s->cookie_tx = 0;
-               schedule_work(&s->work_tx);
-       } else {
-               s->cookie_tx = -EINVAL;
-               if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
-                       u16 ctrl = serial_port_in(port, SCSCR);
-                       serial_port_out(port, SCSCR, ctrl & ~SCSCR_TIE);
-               }
+               if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
+                       sci_submit_rx(s);
        }
+}
 
-       spin_unlock_irqrestore(&port->lock, flags);
+static void sci_free_dma(struct uart_port *port)
+{
+       struct sci_port *s = to_sci_port(port);
+
+       if (s->chan_tx)
+               sci_tx_dma_release(s, false);
+       if (s->chan_rx)
+               sci_rx_dma_release(s, false);
+}
+#else
+static inline void sci_request_dma(struct uart_port *port)
+{
 }
 
-/* Locking: called with port lock held */
-static int sci_dma_rx_push(struct sci_port *s, size_t count)
+static inline void sci_free_dma(struct uart_port *port)
 {
-       struct uart_port *port = &s->port;
-       struct tty_port *tport = &port->state->port;
-       int i, active, room;
+}
+#endif
 
-       room = tty_buffer_request_room(tport, count);
+static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
+{
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+       struct uart_port *port = ptr;
+       struct sci_port *s = to_sci_port(port);
 
-       if (s->active_rx == s->cookie_rx[0]) {
-               active = 0;
-       } else if (s->active_rx == s->cookie_rx[1]) {
-               active = 1;
-       } else {
-               dev_err(port->dev, "cookie %d not found!\n", s->active_rx);
-               return 0;
-       }
+       if (s->chan_rx) {
+               u16 scr = serial_port_in(port, SCSCR);
+               u16 ssr = serial_port_in(port, SCxSR);
 
-       if (room < count)
-               dev_warn(port->dev, "Rx overrun: dropping %zu bytes\n",
-                        count - room);
-       if (!room)
-               return room;
+               /* Disable future Rx interrupts */
+               if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
+                       disable_irq_nosync(irq);
+                       scr |= SCSCR_RDRQE;
+               } else {
+                       scr &= ~SCSCR_RIE;
+                       sci_submit_rx(s);
+               }
+               serial_port_out(port, SCSCR, scr);
+               /* Clear current interrupt */
+               serial_port_out(port, SCxSR,
+                               ssr & ~(SCIF_DR | SCxSR_RDxF(port)));
+               dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u jiffies\n",
+                       jiffies, s->rx_timeout);
+               mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
 
-       for (i = 0; i < room; i++)
-               tty_insert_flip_char(tport, ((u8 *)sg_virt(&s->sg_rx[active]))[i],
-                                    TTY_NORMAL);
+               return IRQ_HANDLED;
+       }
+#endif
 
-       port->icount.rx += room;
+       /* I think sci_receive_chars has to be called irrespective
+        * of whether the I_IXOFF is set, otherwise, how is the interrupt
+        * to be disabled?
+        */
+       sci_receive_chars(ptr);
 
-       return room;
+       return IRQ_HANDLED;
 }
 
-static void sci_dma_rx_complete(void *arg)
+static irqreturn_t sci_tx_interrupt(int irq, void *ptr)
 {
-       struct sci_port *s = arg;
-       struct uart_port *port = &s->port;
+       struct uart_port *port = ptr;
        unsigned long flags;
-       int count;
-
-       dev_dbg(port->dev, "%s(%d) active #%d\n",
-               __func__, port->line, s->active_rx);
 
        spin_lock_irqsave(&port->lock, flags);
+       sci_transmit_chars(port);
+       spin_unlock_irqrestore(&port->lock, flags);
 
-       count = sci_dma_rx_push(s, s->buf_len_rx);
+       return IRQ_HANDLED;
+}
 
-       mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
+static irqreturn_t sci_er_interrupt(int irq, void *ptr)
+{
+       struct uart_port *port = ptr;
+       struct sci_port *s = to_sci_port(port);
 
-       spin_unlock_irqrestore(&port->lock, flags);
+       /* Handle errors */
+       if (port->type == PORT_SCI) {
+               if (sci_handle_errors(port)) {
+                       /* discard character in rx buffer */
+                       serial_port_in(port, SCxSR);
+                       sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
+               }
+       } else {
+               sci_handle_fifo_overrun(port);
+               if (!s->chan_rx)
+                       sci_receive_chars(ptr);
+       }
 
-       if (count)
-               tty_flip_buffer_push(&port->state->port);
+       sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
+
+       /* Kick the transmission */
+       if (!s->chan_tx)
+               sci_tx_interrupt(irq, ptr);
 
-       schedule_work(&s->work_rx);
+       return IRQ_HANDLED;
 }
 
-static void sci_rx_dma_release(struct sci_port *s, bool enable_pio)
+static irqreturn_t sci_br_interrupt(int irq, void *ptr)
 {
-       struct dma_chan *chan = s->chan_rx;
-       struct uart_port *port = &s->port;
+       struct uart_port *port = ptr;
 
-       s->chan_rx = NULL;
-       s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL;
-       dma_release_channel(chan);
-       if (sg_dma_address(&s->sg_rx[0]))
-               dma_free_coherent(port->dev, s->buf_len_rx * 2,
-                                 sg_virt(&s->sg_rx[0]), sg_dma_address(&s->sg_rx[0]));
-       if (enable_pio)
-               sci_start_rx(port);
+       /* Handle BREAKs */
+       sci_handle_breaks(port);
+       sci_clear_SCxSR(port, SCxSR_BREAK_CLEAR(port));
+
+       return IRQ_HANDLED;
 }
 
-static void sci_tx_dma_release(struct sci_port *s, bool enable_pio)
+static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
 {
-       struct dma_chan *chan = s->chan_tx;
-       struct uart_port *port = &s->port;
+       unsigned short ssr_status, scr_status, err_enabled, orer_status = 0;
+       struct uart_port *port = ptr;
+       struct sci_port *s = to_sci_port(port);
+       irqreturn_t ret = IRQ_NONE;
 
-       s->chan_tx = NULL;
-       s->cookie_tx = -EINVAL;
-       dma_release_channel(chan);
-       if (enable_pio)
-               sci_start_tx(port);
-}
+       ssr_status = serial_port_in(port, SCxSR);
+       scr_status = serial_port_in(port, SCSCR);
+       if (s->overrun_reg == SCxSR)
+               orer_status = ssr_status;
+       else {
+               if (sci_getreg(port, s->overrun_reg)->size)
+                       orer_status = serial_port_in(port, s->overrun_reg);
+       }
 
-static void sci_submit_rx(struct sci_port *s)
-{
-       struct dma_chan *chan = s->chan_rx;
-       int i;
+       err_enabled = scr_status & port_rx_irq_mask(port);
 
-       for (i = 0; i < 2; i++) {
-               struct scatterlist *sg = &s->sg_rx[i];
-               struct dma_async_tx_descriptor *desc;
+       /* Tx Interrupt */
+       if ((ssr_status & SCxSR_TDxE(port)) && (scr_status & SCSCR_TIE) &&
+           !s->chan_tx)
+               ret = sci_tx_interrupt(irq, ptr);
 
-               desc = dmaengine_prep_slave_sg(chan,
-                       sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
+       /*
+        * Rx Interrupt: if we're using DMA, the DMA controller clears RDF /
+        * DR flags
+        */
+       if (((ssr_status & SCxSR_RDxF(port)) || s->chan_rx) &&
+           (scr_status & SCSCR_RIE))
+               ret = sci_rx_interrupt(irq, ptr);
 
-               if (desc) {
-                       s->desc_rx[i] = desc;
-                       desc->callback = sci_dma_rx_complete;
-                       desc->callback_param = s;
-                       s->cookie_rx[i] = desc->tx_submit(desc);
-               }
+       /* Error Interrupt */
+       if ((ssr_status & SCxSR_ERRORS(port)) && err_enabled)
+               ret = sci_er_interrupt(irq, ptr);
 
-               if (!desc || s->cookie_rx[i] < 0) {
-                       if (i) {
-                               async_tx_ack(s->desc_rx[0]);
-                               s->cookie_rx[0] = -EINVAL;
-                       }
-                       if (desc) {
-                               async_tx_ack(desc);
-                               s->cookie_rx[i] = -EINVAL;
-                       }
-                       dev_warn(s->port.dev,
-                                "failed to re-start DMA, using PIO\n");
-                       sci_rx_dma_release(s, true);
-                       return;
-               }
-               dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n",
-                       __func__, s->cookie_rx[i], i);
-       }
+       /* Break Interrupt */
+       if ((ssr_status & SCxSR_BRK(port)) && err_enabled)
+               ret = sci_br_interrupt(irq, ptr);
 
-       s->active_rx = s->cookie_rx[0];
+       /* Overrun Interrupt */
+       if (orer_status & s->overrun_mask) {
+               sci_handle_fifo_overrun(port);
+               ret = IRQ_HANDLED;
+       }
 
-       dma_async_issue_pending(chan);
+       return ret;
 }
 
-static void work_fn_rx(struct work_struct *work)
+/*
+ * Here we define a transition notifier so that we can update all of our
+ * ports' baud rate when the peripheral clock changes.
+ */
+static int sci_notifier(struct notifier_block *self,
+                       unsigned long phase, void *p)
 {
-       struct sci_port *s = container_of(work, struct sci_port, work_rx);
-       struct uart_port *port = &s->port;
-       struct dma_async_tx_descriptor *desc;
-       int new;
-
-       if (s->active_rx == s->cookie_rx[0]) {
-               new = 0;
-       } else if (s->active_rx == s->cookie_rx[1]) {
-               new = 1;
-       } else {
-               dev_err(port->dev, "cookie %d not found!\n", s->active_rx);
-               return;
-       }
-       desc = s->desc_rx[new];
+       struct sci_port *sci_port;
+       unsigned long flags;
 
-       if (dma_async_is_tx_complete(s->chan_rx, s->active_rx, NULL, NULL) !=
-           DMA_COMPLETE) {
-               /* Handle incomplete DMA receive */
-               struct dma_chan *chan = s->chan_rx;
-               struct shdma_desc *sh_desc = container_of(desc,
-                                       struct shdma_desc, async_tx);
-               unsigned long flags;
-               int count;
+       sci_port = container_of(self, struct sci_port, freq_transition);
 
-               dmaengine_terminate_all(chan);
-               dev_dbg(port->dev, "Read %zu bytes with cookie %d\n",
-                       sh_desc->partial, sh_desc->cookie);
+       if (phase == CPUFREQ_POSTCHANGE) {
+               struct uart_port *port = &sci_port->port;
 
                spin_lock_irqsave(&port->lock, flags);
-               count = sci_dma_rx_push(s, sh_desc->partial);
+               port->uartclk = clk_get_rate(sci_port->iclk);
                spin_unlock_irqrestore(&port->lock, flags);
-
-               if (count)
-                       tty_flip_buffer_push(&port->state->port);
-
-               sci_submit_rx(s);
-
-               return;
-       }
-
-       s->cookie_rx[new] = desc->tx_submit(desc);
-       if (s->cookie_rx[new] < 0) {
-               dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n");
-               sci_rx_dma_release(s, true);
-               return;
        }
 
-       s->active_rx = s->cookie_rx[!new];
-
-       dev_dbg(port->dev, "%s: cookie %d #%d, new active #%d\n",
-               __func__, s->cookie_rx[new], new, s->active_rx);
+       return NOTIFY_OK;
 }
 
-static void work_fn_tx(struct work_struct *work)
-{
-       struct sci_port *s = container_of(work, struct sci_port, work_tx);
-       struct dma_async_tx_descriptor *desc;
-       struct dma_chan *chan = s->chan_tx;
-       struct uart_port *port = &s->port;
-       struct circ_buf *xmit = &port->state->xmit;
-       struct scatterlist *sg = &s->sg_tx;
-
+static const struct sci_irq_desc {
+       const char      *desc;
+       irq_handler_t   handler;
+} sci_irq_desc[] = {
        /*
-        * DMA is idle now.
-        * Port xmit buffer is already mapped, and it is one page... Just adjust
-        * offsets and lengths. Since it is a circular buffer, we have to
-        * transmit till the end, and then the rest. Take the port lock to get a
-        * consistent xmit buffer state.
+        * Split out handlers, the default case.
         */
-       spin_lock_irq(&port->lock);
-       sg->offset = xmit->tail & (UART_XMIT_SIZE - 1);
-       sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) +
-               sg->offset;
-       sg_dma_len(sg) = min((int)CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE),
-               CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE));
-       spin_unlock_irq(&port->lock);
+       [SCIx_ERI_IRQ] = {
+               .desc = "rx err",
+               .handler = sci_er_interrupt,
+       },
 
-       BUG_ON(!sg_dma_len(sg));
+       [SCIx_RXI_IRQ] = {
+               .desc = "rx full",
+               .handler = sci_rx_interrupt,
+       },
 
-       desc = dmaengine_prep_slave_sg(chan,
-                       sg, s->sg_len_tx, DMA_MEM_TO_DEV,
-                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-       if (!desc) {
-               /* switch to PIO */
-               sci_tx_dma_release(s, true);
-               return;
-       }
+       [SCIx_TXI_IRQ] = {
+               .desc = "tx empty",
+               .handler = sci_tx_interrupt,
+       },
+
+       [SCIx_BRI_IRQ] = {
+               .desc = "break",
+               .handler = sci_br_interrupt,
+       },
+
+       /*
+        * Special muxed handler.
+        */
+       [SCIx_MUX_IRQ] = {
+               .desc = "mux",
+               .handler = sci_mpxed_interrupt,
+       },
+};
 
-       dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE);
+static int sci_request_irq(struct sci_port *port)
+{
+       struct uart_port *up = &port->port;
+       int i, j, ret = 0;
 
-       spin_lock_irq(&port->lock);
-       s->desc_tx = desc;
-       desc->callback = sci_dma_tx_complete;
-       desc->callback_param = s;
-       spin_unlock_irq(&port->lock);
-       s->cookie_tx = desc->tx_submit(desc);
-       if (s->cookie_tx < 0) {
-               dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n");
-               /* switch to PIO */
-               sci_tx_dma_release(s, true);
-               return;
-       }
+       for (i = j = 0; i < SCIx_NR_IRQS; i++, j++) {
+               const struct sci_irq_desc *desc;
+               int irq;
 
-       dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n",
-               __func__, xmit->buf, xmit->tail, xmit->head, s->cookie_tx);
+               if (SCIx_IRQ_IS_MUXED(port)) {
+                       i = SCIx_MUX_IRQ;
+                       irq = up->irq;
+               } else {
+                       irq = port->irqs[i];
 
-       dma_async_issue_pending(chan);
-}
-#endif
+                       /*
+                        * Certain port types won't support all of the
+                        * available interrupt sources.
+                        */
+                       if (unlikely(irq < 0))
+                               continue;
+               }
 
-static void sci_start_tx(struct uart_port *port)
-{
-       struct sci_port *s = to_sci_port(port);
-       unsigned short ctrl;
+               desc = sci_irq_desc + i;
+               port->irqstr[j] = kasprintf(GFP_KERNEL, "%s:%s",
+                                           dev_name(up->dev), desc->desc);
+               if (!port->irqstr[j])
+                       goto out_nomem;
 
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
-       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
-               u16 new, scr = serial_port_in(port, SCSCR);
-               if (s->chan_tx)
-                       new = scr | SCSCR_TDRQE;
-               else
-                       new = scr & ~SCSCR_TDRQE;
-               if (new != scr)
-                       serial_port_out(port, SCSCR, new);
+               ret = request_irq(irq, desc->handler, up->irqflags,
+                                 port->irqstr[j], port);
+               if (unlikely(ret)) {
+                       dev_err(up->dev, "Can't allocate %s IRQ\n", desc->desc);
+                       goto out_noirq;
+               }
        }
 
-       if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) &&
-           s->cookie_tx < 0) {
-               s->cookie_tx = 0;
-               schedule_work(&s->work_tx);
-       }
-#endif
+       return 0;
 
-       if (!s->chan_tx || port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
-               /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
-               ctrl = serial_port_in(port, SCSCR);
-               serial_port_out(port, SCSCR, ctrl | SCSCR_TIE);
-       }
+out_noirq:
+       while (--i >= 0)
+               free_irq(port->irqs[i], port);
+
+out_nomem:
+       while (--j >= 0)
+               kfree(port->irqstr[j]);
+
+       return ret;
 }
 
-static void sci_stop_tx(struct uart_port *port)
+static void sci_free_irq(struct sci_port *port)
 {
-       unsigned short ctrl;
+       int i;
 
-       /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */
-       ctrl = serial_port_in(port, SCSCR);
+       /*
+        * Intentionally in reverse order so we iterate over the muxed
+        * IRQ first.
+        */
+       for (i = 0; i < SCIx_NR_IRQS; i++) {
+               int irq = port->irqs[i];
 
-       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
-               ctrl &= ~SCSCR_TDRQE;
+               /*
+                * Certain port types won't support all of the available
+                * interrupt sources.
+                */
+               if (unlikely(irq < 0))
+                       continue;
 
-       ctrl &= ~SCSCR_TIE;
+               free_irq(port->irqs[i], port);
+               kfree(port->irqstr[i]);
 
-       serial_port_out(port, SCSCR, ctrl);
+               if (SCIx_IRQ_IS_MUXED(port)) {
+                       /* If there's only one IRQ, we're done. */
+                       return;
+               }
+       }
 }
 
-static void sci_start_rx(struct uart_port *port)
+static unsigned int sci_tx_empty(struct uart_port *port)
 {
-       unsigned short ctrl;
-
-       ctrl = serial_port_in(port, SCSCR) | port_rx_irq_mask(port);
-
-       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
-               ctrl &= ~SCSCR_RDRQE;
+       unsigned short status = serial_port_in(port, SCxSR);
+       unsigned short in_tx_fifo = sci_txfill(port);
 
-       serial_port_out(port, SCSCR, ctrl);
+       return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0;
 }
 
-static void sci_stop_rx(struct uart_port *port)
+/*
+ * Modem control is a bit of a mixed bag for SCI(F) ports. Generally
+ * CTS/RTS is supported in hardware by at least one port and controlled
+ * via SCSPTR (SCxPCR for SCIFA/B parts), or external pins (presently
+ * handled via the ->init_pins() op, which is a bit of a one-way street,
+ * lacking any ability to defer pin control -- this will later be
+ * converted over to the GPIO framework).
+ *
+ * Other modes (such as loopback) are supported generically on certain
+ * port types, but not others. For these it's sufficient to test for the
+ * existence of the support register and simply ignore the port type.
+ */
+static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
-       unsigned short ctrl;
-
-       ctrl = serial_port_in(port, SCSCR);
-
-       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
-               ctrl &= ~SCSCR_RDRQE;
+       if (mctrl & TIOCM_LOOP) {
+               const struct plat_sci_reg *reg;
 
-       ctrl &= ~port_rx_irq_mask(port);
+               /*
+                * Standard loopback mode for SCFCR ports.
+                */
+               reg = sci_getreg(port, SCFCR);
+               if (reg->size)
+                       serial_port_out(port, SCFCR,
+                                       serial_port_in(port, SCFCR) |
+                                       SCFCR_LOOP);
+       }
+}
 
-       serial_port_out(port, SCSCR, ctrl);
+static unsigned int sci_get_mctrl(struct uart_port *port)
+{
+       /*
+        * CTS/RTS is handled in hardware when supported, while nothing
+        * else is wired up. Keep it simple and simply assert DSR/CAR.
+        */
+       return TIOCM_DSR | TIOCM_CAR;
 }
 
 static void sci_break_ctl(struct uart_port *port, int break_state)
 {
        struct sci_port *s = to_sci_port(port);
-       struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR;
+       const struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR;
        unsigned short scscr, scsptr;
 
        /* check wheter the port has SCSPTR */
@@ -1630,142 +1818,6 @@ static void sci_break_ctl(struct uart_port *port, int break_state)
        serial_port_out(port, SCSCR, scscr);
 }
 
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
-static bool filter(struct dma_chan *chan, void *slave)
-{
-       struct sh_dmae_slave *param = slave;
-
-       dev_dbg(chan->device->dev, "%s: slave ID %d\n",
-               __func__, param->shdma_slave.slave_id);
-
-       chan->private = &param->shdma_slave;
-       return true;
-}
-
-static void rx_timer_fn(unsigned long arg)
-{
-       struct sci_port *s = (struct sci_port *)arg;
-       struct uart_port *port = &s->port;
-       u16 scr = serial_port_in(port, SCSCR);
-
-       if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
-               scr &= ~SCSCR_RDRQE;
-               enable_irq(s->irqs[SCIx_RXI_IRQ]);
-       }
-       serial_port_out(port, SCSCR, scr | SCSCR_RIE);
-       dev_dbg(port->dev, "DMA Rx timed out\n");
-       schedule_work(&s->work_rx);
-}
-
-static void sci_request_dma(struct uart_port *port)
-{
-       struct sci_port *s = to_sci_port(port);
-       struct sh_dmae_slave *param;
-       struct dma_chan *chan;
-       dma_cap_mask_t mask;
-       int nent;
-
-       dev_dbg(port->dev, "%s: port %d\n", __func__, port->line);
-
-       if (s->cfg->dma_slave_tx <= 0 || s->cfg->dma_slave_rx <= 0)
-               return;
-
-       dma_cap_zero(mask);
-       dma_cap_set(DMA_SLAVE, mask);
-
-       param = &s->param_tx;
-
-       /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_TX */
-       param->shdma_slave.slave_id = s->cfg->dma_slave_tx;
-
-       s->cookie_tx = -EINVAL;
-       chan = dma_request_channel(mask, filter, param);
-       dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan);
-       if (chan) {
-               s->chan_tx = chan;
-               sg_init_table(&s->sg_tx, 1);
-               /* UART circular tx buffer is an aligned page. */
-               BUG_ON((uintptr_t)port->state->xmit.buf & ~PAGE_MASK);
-               sg_set_page(&s->sg_tx, virt_to_page(port->state->xmit.buf),
-                           UART_XMIT_SIZE,
-                           (uintptr_t)port->state->xmit.buf & ~PAGE_MASK);
-               nent = dma_map_sg(port->dev, &s->sg_tx, 1, DMA_TO_DEVICE);
-               if (!nent)
-                       sci_tx_dma_release(s, false);
-               else
-                       dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n",
-                               __func__,
-                               sg_dma_len(&s->sg_tx), port->state->xmit.buf,
-                               &sg_dma_address(&s->sg_tx));
-
-               s->sg_len_tx = nent;
-
-               INIT_WORK(&s->work_tx, work_fn_tx);
-       }
-
-       param = &s->param_rx;
-
-       /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_RX */
-       param->shdma_slave.slave_id = s->cfg->dma_slave_rx;
-
-       chan = dma_request_channel(mask, filter, param);
-       dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan);
-       if (chan) {
-               dma_addr_t dma[2];
-               void *buf[2];
-               int i;
-
-               s->chan_rx = chan;
-
-               s->buf_len_rx = 2 * max(16, (int)port->fifosize);
-               buf[0] = dma_alloc_coherent(port->dev, s->buf_len_rx * 2,
-                                           &dma[0], GFP_KERNEL);
-
-               if (!buf[0]) {
-                       dev_warn(port->dev,
-                                "failed to allocate dma buffer, using PIO\n");
-                       sci_rx_dma_release(s, true);
-                       return;
-               }
-
-               buf[1] = buf[0] + s->buf_len_rx;
-               dma[1] = dma[0] + s->buf_len_rx;
-
-               for (i = 0; i < 2; i++) {
-                       struct scatterlist *sg = &s->sg_rx[i];
-
-                       sg_init_table(sg, 1);
-                       sg_set_page(sg, virt_to_page(buf[i]), s->buf_len_rx,
-                                   (uintptr_t)buf[i] & ~PAGE_MASK);
-                       sg_dma_address(sg) = dma[i];
-               }
-
-               INIT_WORK(&s->work_rx, work_fn_rx);
-               setup_timer(&s->rx_timer, rx_timer_fn, (unsigned long)s);
-
-               sci_submit_rx(s);
-       }
-}
-
-static void sci_free_dma(struct uart_port *port)
-{
-       struct sci_port *s = to_sci_port(port);
-
-       if (s->chan_tx)
-               sci_tx_dma_release(s, false);
-       if (s->chan_rx)
-               sci_rx_dma_release(s, false);
-}
-#else
-static inline void sci_request_dma(struct uart_port *port)
-{
-}
-
-static inline void sci_free_dma(struct uart_port *port)
-{
-}
-#endif
-
 static int sci_startup(struct uart_port *port)
 {
        struct sci_port *s = to_sci_port(port);
@@ -1800,6 +1852,14 @@ static void sci_shutdown(struct uart_port *port)
        sci_stop_tx(port);
        spin_unlock_irqrestore(&port->lock, flags);
 
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+       if (s->chan_rx) {
+               dev_dbg(port->dev, "%s(%d) deleting rx_timer\n", __func__,
+                       port->line);
+               del_timer_sync(&s->rx_timer);
+       }
+#endif
+
        sci_free_dma(port);
        sci_free_irq(s);
 }
@@ -1892,7 +1952,7 @@ static void sci_baud_calc_hscif(unsigned int bps, unsigned long freq,
 
 static void sci_reset(struct uart_port *port)
 {
-       struct plat_sci_reg *reg;
+       const struct plat_sci_reg *reg;
        unsigned int status;
 
        do {
@@ -1910,7 +1970,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
                            struct ktermios *old)
 {
        struct sci_port *s = to_sci_port(port);
-       struct plat_sci_reg *reg;
+       const struct plat_sci_reg *reg;
        unsigned int baud, smr_val = 0, max_baud, cks = 0;
        int t = -1;
        unsigned int srr = 15;
@@ -1951,7 +2011,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
 
        sci_reset(port);
 
-       smr_val |= serial_port_in(port, SCSMR) & 3;
+       smr_val |= serial_port_in(port, SCSMR) & SCSMR_CKS;
 
        uart_update_timeout(port, termios->c_cflag, baud);
 
@@ -1996,13 +2056,13 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
 #ifdef CONFIG_SERIAL_SH_SCI_DMA
        /*
         * Calculate delay for 2 DMA buffers (4 FIFO).
-        * See drivers/serial/serial_core.c::uart_update_timeout(). With 10
-        * bits (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above function
-        * calculates 1 jiffie for the data plus 5 jiffies for the "slop(e)."
-        * Then below we calculate 5 jiffies (20ms) for 2 DMA buffers (4 FIFO
-        * sizes), but when performing a faster transfer, value obtained by
-        * this formula is may not enough. Therefore, if value is smaller than
-        * 20msec, this sets 20msec as timeout of DMA.
+        * See serial_core.c::uart_update_timeout().
+        * With 10 bits (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above
+        * function calculates 1 jiffie for the data plus 5 jiffies for the
+        * "slop(e)." Then below we calculate 5 jiffies (20ms) for 2 DMA
+        * buffers (4 FIFO sizes), but when performing a faster transfer, the
+        * value obtained by this formula is too small. Therefore, if the value
+        * is smaller than 20ms, use 20ms as the timeout value for DMA.
         */
        if (s->chan_rx) {
                unsigned int bits;
@@ -2187,7 +2247,6 @@ static int sci_init_single(struct platform_device *dev,
 {
        struct uart_port *port = &sci_port->port;
        const struct resource *res;
-       unsigned int sampling_rate;
        unsigned int i;
        int ret;
 
@@ -2232,37 +2291,37 @@ static int sci_init_single(struct platform_device *dev,
                port->fifosize = 256;
                sci_port->overrun_reg = SCxSR;
                sci_port->overrun_mask = SCIFA_ORER;
-               sampling_rate = 16;
+               sci_port->sampling_rate = 16;
                break;
        case PORT_HSCIF:
                port->fifosize = 128;
-               sampling_rate = 0;
                sci_port->overrun_reg = SCLSR;
                sci_port->overrun_mask = SCLSR_ORER;
+               sci_port->sampling_rate = 0;
                break;
        case PORT_SCIFA:
                port->fifosize = 64;
                sci_port->overrun_reg = SCxSR;
                sci_port->overrun_mask = SCIFA_ORER;
-               sampling_rate = 16;
+               sci_port->sampling_rate = 16;
                break;
        case PORT_SCIF:
                port->fifosize = 16;
                if (p->regtype == SCIx_SH7705_SCIF_REGTYPE) {
                        sci_port->overrun_reg = SCxSR;
                        sci_port->overrun_mask = SCIFA_ORER;
-                       sampling_rate = 16;
+                       sci_port->sampling_rate = 16;
                } else {
                        sci_port->overrun_reg = SCLSR;
                        sci_port->overrun_mask = SCLSR_ORER;
-                       sampling_rate = 32;
+                       sci_port->sampling_rate = 32;
                }
                break;
        default:
                port->fifosize = 1;
                sci_port->overrun_reg = SCxSR;
                sci_port->overrun_mask = SCI_ORER;
-               sampling_rate = 32;
+               sci_port->sampling_rate = 32;
                break;
        }
 
@@ -2270,8 +2329,8 @@ static int sci_init_single(struct platform_device *dev,
         * match the SoC datasheet, this should be investigated. Let platform
         * data override the sampling rate for now.
         */
-       sci_port->sampling_rate = p->sampling_rate ? p->sampling_rate
-                               : sampling_rate;
+       if (p->sampling_rate)
+               sci_port->sampling_rate = p->sampling_rate;
 
        if (!early) {
                sci_port->iclk = clk_get(&dev->dev, "sci_ick");
@@ -2303,15 +2362,22 @@ static int sci_init_single(struct platform_device *dev,
        /*
         * Establish some sensible defaults for the error detection.
         */
-       sci_port->error_mask = (p->type == PORT_SCI) ?
-                       SCI_DEFAULT_ERROR_MASK : SCIF_DEFAULT_ERROR_MASK;
+       if (p->type == PORT_SCI) {
+               sci_port->error_mask = SCI_DEFAULT_ERROR_MASK;
+               sci_port->error_clear = SCI_ERROR_CLEAR;
+       } else {
+               sci_port->error_mask = SCIF_DEFAULT_ERROR_MASK;
+               sci_port->error_clear = SCIF_ERROR_CLEAR;
+       }
 
        /*
         * Make the error mask inclusive of overrun detection, if
         * supported.
         */
-       if (sci_port->overrun_reg == SCxSR)
+       if (sci_port->overrun_reg == SCxSR) {
                sci_port->error_mask |= sci_port->overrun_mask;
+               sci_port->error_clear &= ~sci_port->overrun_mask;
+       }
 
        port->type              = p->type;
        port->flags             = UPF_FIXED_PORT | p->flags;
@@ -2564,10 +2630,8 @@ sci_parse_dt(struct platform_device *pdev, unsigned int *dev_id)
        info = match->data;
 
        p = devm_kzalloc(&pdev->dev, sizeof(struct plat_sci_port), GFP_KERNEL);
-       if (!p) {
-               dev_err(&pdev->dev, "failed to allocate DT config data\n");
+       if (!p)
                return NULL;
-       }
 
        /* Get the line number for the aliases node. */
        id = of_alias_get_id(np, "serial");
index 3393f67b4e84357890747bd79cd8002fdf33843f..bf69bbdcc1f9aa3975a7847ec323d23fa50a73ce 100644 (file)
@@ -54,10 +54,10 @@ enum {
 
 #define SCI_DEFAULT_ERROR_MASK (SCI_PER | SCI_FER)
 
-#define SCI_RDxF_CLEAR ~(SCI_RESERVED | SCI_RDRF)
-#define SCI_ERROR_CLEAR        ~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER)
-#define SCI_TDxE_CLEAR ~(SCI_RESERVED | SCI_TEND | SCI_TDRE)
-#define SCI_BREAK_CLEAR        ~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER)
+#define SCI_RDxF_CLEAR (u32)(~(SCI_RESERVED | SCI_RDRF))
+#define SCI_ERROR_CLEAR        (u32)(~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER))
+#define SCI_TDxE_CLEAR (u32)(~(SCI_RESERVED | SCI_TEND | SCI_TDRE))
+#define SCI_BREAK_CLEAR        (u32)(~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER))
 
 /* SCxSR (Serial Status Register) on SCIF, SCIFA, SCIFB, HSCIF */
 #define SCIF_ER                BIT(7)  /* Receive Error */
@@ -76,10 +76,10 @@ enum {
 
 #define SCIF_DEFAULT_ERROR_MASK (SCIF_PER | SCIF_FER | SCIF_BRK | SCIF_ER)
 
-#define SCIF_RDxF_CLEAR                ~(SCIF_DR | SCIF_RDF)
-#define SCIF_ERROR_CLEAR       ~(SCIFA_ORER | SCIF_PER | SCIF_FER | SCIF_ER)
-#define SCIF_TDxE_CLEAR                ~(SCIF_TDFE)
-#define SCIF_BREAK_CLEAR       ~(SCIF_PER | SCIF_FER | SCIF_BRK)
+#define SCIF_RDxF_CLEAR                (u32)(~(SCIF_DR | SCIF_RDF))
+#define SCIF_ERROR_CLEAR       (u32)(~(SCIF_PER | SCIF_FER | SCIF_ER))
+#define SCIF_TDxE_CLEAR                (u32)(~(SCIF_TDFE))
+#define SCIF_BREAK_CLEAR       (u32)(~(SCIF_PER | SCIF_FER | SCIF_BRK))
 
 /* SCFCR (FIFO Control Register) */
 #define SCFCR_MCE      BIT(3)  /* Modem Control Enable */
@@ -119,28 +119,11 @@ enum {
 
 #define SCxSR_ERRORS(port)     (to_sci_port(port)->error_mask)
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7721) || \
-    defined(CONFIG_ARCH_SH73A0) || \
-    defined(CONFIG_ARCH_R8A7740)
-
-# define SCxSR_RDxF_CLEAR(port) \
-       (serial_port_in(port, SCxSR) & SCIF_RDxF_CLEAR)
-# define SCxSR_ERROR_CLEAR(port) \
-       (serial_port_in(port, SCxSR) & SCIF_ERROR_CLEAR)
-# define SCxSR_TDxE_CLEAR(port) \
-       (serial_port_in(port, SCxSR) & SCIF_TDxE_CLEAR)
-# define SCxSR_BREAK_CLEAR(port) \
-       (serial_port_in(port, SCxSR) & SCIF_BREAK_CLEAR)
-#else
-# define SCxSR_RDxF_CLEAR(port) \
-       ((((port)->type == PORT_SCI) ? SCI_RDxF_CLEAR : SCIF_RDxF_CLEAR) & 0xff)
-# define SCxSR_ERROR_CLEAR(port) \
-       ((((port)->type == PORT_SCI) ? SCI_ERROR_CLEAR : SCIF_ERROR_CLEAR) & 0xff)
-# define SCxSR_TDxE_CLEAR(port) \
-       ((((port)->type == PORT_SCI) ? SCI_TDxE_CLEAR : SCIF_TDxE_CLEAR) & 0xff)
-# define SCxSR_BREAK_CLEAR(port) \
-       ((((port)->type == PORT_SCI) ? SCI_BREAK_CLEAR : SCIF_BREAK_CLEAR) & 0xff)
-#endif
-
+#define SCxSR_RDxF_CLEAR(port) \
+       (((port)->type == PORT_SCI) ? SCI_RDxF_CLEAR : SCIF_RDxF_CLEAR)
+#define SCxSR_ERROR_CLEAR(port) \
+       (to_sci_port(port)->error_clear)
+#define SCxSR_TDxE_CLEAR(port) \
+       (((port)->type == PORT_SCI) ? SCI_TDxE_CLEAR : SCIF_TDxE_CLEAR)
+#define SCxSR_BREAK_CLEAR(port) \
+       (((port)->type == PORT_SCI) ? SCI_BREAK_CLEAR : SCIF_BREAK_CLEAR)
index 3866516c2926a32c5f63600b7dbee05497af99bf..9dbae01d41cef75186932201674ef937168279e6 100644 (file)
@@ -782,6 +782,7 @@ static const struct of_device_id serial_ids[] = {
        {.compatible = "sprd,sc9836-uart",},
        {}
 };
+MODULE_DEVICE_TABLE(of, serial_ids);
 
 static struct platform_driver sprd_platform_driver = {
        .probe          = sprd_probe,
index d625664ce1b51eea836775d800eded58140fb5ee..2d78cb3627aef9da5e0593d0da38810fc09977c5 100644 (file)
@@ -430,7 +430,7 @@ static void asc_break_ctl(struct uart_port *port, int break_state)
  */
 static int asc_startup(struct uart_port *port)
 {
-       if (request_irq(port->irq, asc_interrupt, IRQF_NO_SUSPEND,
+       if (request_irq(port->irq, asc_interrupt, 0,
                        asc_port_name(port), port)) {
                dev_err(port->dev, "cannot allocate irq.\n");
                return -ENODEV;
index e3de9c6d22265746ea1b34ffa822b0a381898b19..f89d1f79be18fffd199f902d5cc8fa3936d0b815 100644 (file)
@@ -322,8 +322,7 @@ static int stm32_startup(struct uart_port *port)
        u32 val;
        int ret;
 
-       ret = request_irq(port->irq, stm32_interrupt, IRQF_NO_SUSPEND,
-                         name, port);
+       ret = request_irq(port->irq, stm32_interrupt, 0, name, port);
        if (ret)
                return ret;
 
index 2fac7123b27419c16a53c7e01b6d08743b959cee..6188059fd523991c4a5072c0b8350f4d31b00dfd 100644 (file)
@@ -3314,12 +3314,11 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
                                        -EAGAIN : -ERESTARTSYS;
                        break;
                }
-               
+
                dcd = tty_port_carrier_raised(&info->port);
-               
-               if (!(port->flags & ASYNC_CLOSING) && (do_clocal || dcd))
-                       break;
-                       
+               if (do_clocal || dcd)
+                       break;
+
                if (signal_pending(current)) {
                        retval = -ERESTARTSYS;
                        break;
@@ -3398,15 +3397,6 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp)
                printk("%s(%d):mgsl_open(%s), old ref count = %d\n",
                         __FILE__,__LINE__,tty->driver->name, info->port.count);
 
-       /* If port is closing, signal caller to try again */
-       if (info->port.flags & ASYNC_CLOSING){
-               wait_event_interruptible_tty(tty, info->port.close_wait,
-                                    !(info->port.flags & ASYNC_CLOSING));
-               retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?
-                       -EAGAIN : -ERESTARTSYS);
-               goto cleanup;
-       }
-       
        info->port.low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
        spin_lock_irqsave(&info->netlock, flags);
@@ -6635,7 +6625,7 @@ static bool mgsl_get_rx_frame(struct mgsl_struct *info)
                        unsigned char *ptmp = info->intermediate_rxbuffer;
 
                        if ( !(status & RXSTATUS_CRC_ERROR))
-                       info->icount.rxok++;
+                               info->icount.rxok++;
                        
                        while(copy_count) {
                                int partial_count;
index 0ea8eee0017865af58c528c551b137711ea22ec2..6fc39fbfc27556088e0aa1e6744996497bcb06ea 100644 (file)
@@ -672,15 +672,6 @@ static int open(struct tty_struct *tty, struct file *filp)
 
        DBGINFO(("%s open, old ref count = %d\n", info->device_name, info->port.count));
 
-       /* If port is closing, signal caller to try again */
-       if (info->port.flags & ASYNC_CLOSING){
-               wait_event_interruptible_tty(tty, info->port.close_wait,
-                                            !(info->port.flags & ASYNC_CLOSING));
-               retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?
-                       -EAGAIN : -ERESTARTSYS);
-               goto cleanup;
-       }
-
        mutex_lock(&info->port.mutex);
        info->port.low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
@@ -3320,9 +3311,8 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
                }
 
                cd = tty_port_carrier_raised(port);
-
-               if (!(port->flags & ASYNC_CLOSING) && (do_clocal || cd ))
-                       break;
+               if (do_clocal || cd)
+                       break;
 
                if (signal_pending(current)) {
                        retval = -ERESTARTSYS;
index 08633a8139ffa072cc600d71ebc9ff023ff4b671..fb00a06dfa4bba12e41f4dd42bd38e2c95d16ee4 100644 (file)
@@ -752,15 +752,6 @@ static int open(struct tty_struct *tty, struct file *filp)
                printk("%s(%d):%s open(), old ref count = %d\n",
                         __FILE__,__LINE__,tty->driver->name, info->port.count);
 
-       /* If port is closing, signal caller to try again */
-       if (info->port.flags & ASYNC_CLOSING){
-               wait_event_interruptible_tty(tty, info->port.close_wait,
-                                            !(info->port.flags & ASYNC_CLOSING));
-               retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?
-                       -EAGAIN : -ERESTARTSYS);
-               goto cleanup;
-       }
-
        info->port.low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
        spin_lock_irqsave(&info->netlock, flags);
@@ -3341,9 +3332,8 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
                }
 
                cd = tty_port_carrier_raised(port);
-
-               if (!(port->flags & ASYNC_CLOSING) && (do_clocal || cd))
-                       break;
+               if (do_clocal || cd)
+                       break;
 
                if (signal_pending(current)) {
                        retval = -ERESTARTSYS;
index 95b330a9ea983dcafae63956cefd03ddefe9379b..5381a728d23e773af0e1ebe2869e01bf98757244 100644 (file)
@@ -1003,6 +1003,10 @@ static const struct kernel_param_ops param_ops_sysrq_reset_seq = {
 #define param_check_sysrq_reset_seq(name, p)   \
        __param_check(name, p, unsigned short)
 
+/*
+ * not really modular, but the easiest way to keep compat with existing
+ * bootargs behaviour is to continue using module_param here.
+ */
 module_param_array_named(reset_seq, sysrq_reset_seq, sysrq_reset_seq,
                         &sysrq_reset_seq_len, 0644);
 
@@ -1119,4 +1123,4 @@ static int __init sysrq_init(void)
 
        return 0;
 }
-module_init(sysrq_init);
+device_initcall(sysrq_init);
index a660ab181cca7357c59c7256303628eb8bb929a9..9a479e61791a2a80cd0ae3fd5c93c6d0873d6998 100644 (file)
@@ -403,7 +403,7 @@ void tty_schedule_flip(struct tty_port *port)
         * flush_to_ldisc() sees buffer data.
         */
        smp_store_release(&buf->tail->commit, buf->tail->used);
-       schedule_work(&buf->work);
+       queue_work(system_unbound_wq, &buf->work);
 }
 EXPORT_SYMBOL(tty_schedule_flip);
 
@@ -587,3 +587,13 @@ void tty_buffer_set_lock_subclass(struct tty_port *port)
 {
        lockdep_set_subclass(&port->buf.lock, TTY_LOCK_SLAVE);
 }
+
+bool tty_buffer_restart_work(struct tty_port *port)
+{
+       return queue_work(system_unbound_wq, &port->buf.work);
+}
+
+bool tty_buffer_cancel_work(struct tty_port *port)
+{
+       return cancel_work_sync(&port->buf.work);
+}
index 2eefaa6e3e3a4af9a5ab2b03cf03f9e75a04ca1d..0c41dbcb90b8bc7d8ab430d562206e7c2469411f 100644 (file)
@@ -390,10 +390,10 @@ EXPORT_SYMBOL_GPL(tty_find_polling_driver);
  *     Locking: ctrl_lock
  */
 
-int tty_check_change(struct tty_struct *tty)
+int __tty_check_change(struct tty_struct *tty, int sig)
 {
        unsigned long flags;
-       struct pid *pgrp;
+       struct pid *pgrp, *tty_pgrp;
        int ret = 0;
 
        if (current->signal->tty != tty)
@@ -403,33 +403,35 @@ int tty_check_change(struct tty_struct *tty)
        pgrp = task_pgrp(current);
 
        spin_lock_irqsave(&tty->ctrl_lock, flags);
-
-       if (!tty->pgrp) {
-               printk(KERN_WARNING "tty_check_change: tty->pgrp == NULL!\n");
-               goto out_unlock;
-       }
-       if (pgrp == tty->pgrp)
-               goto out_unlock;
+       tty_pgrp = tty->pgrp;
        spin_unlock_irqrestore(&tty->ctrl_lock, flags);
 
-       if (is_ignored(SIGTTOU))
-               goto out_rcuunlock;
-       if (is_current_pgrp_orphaned()) {
-               ret = -EIO;
-               goto out_rcuunlock;
+       if (tty_pgrp && pgrp != tty->pgrp) {
+               if (is_ignored(sig)) {
+                       if (sig == SIGTTIN)
+                               ret = -EIO;
+               } else if (is_current_pgrp_orphaned())
+                       ret = -EIO;
+               else {
+                       kill_pgrp(pgrp, sig, 1);
+                       set_thread_flag(TIF_SIGPENDING);
+                       ret = -ERESTARTSYS;
+               }
        }
-       kill_pgrp(pgrp, SIGTTOU, 1);
-       rcu_read_unlock();
-       set_thread_flag(TIF_SIGPENDING);
-       ret = -ERESTARTSYS;
-       return ret;
-out_unlock:
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-out_rcuunlock:
        rcu_read_unlock();
+
+       if (!tty_pgrp) {
+               pr_warn("%s: tty_check_change: sig=%d, tty->pgrp == NULL!\n",
+                       tty_name(tty), sig);
+       }
+
        return ret;
 }
 
+int tty_check_change(struct tty_struct *tty)
+{
+       return __tty_check_change(tty, SIGTTOU);
+}
 EXPORT_SYMBOL(tty_check_change);
 
 static ssize_t hung_up_tty_read(struct file *file, char __user *buf,
@@ -1198,11 +1200,9 @@ void tty_write_message(struct tty_struct *tty, char *msg)
        if (tty) {
                mutex_lock(&tty->atomic_write_lock);
                tty_lock(tty);
-               if (tty->ops->write && tty->count > 0) {
-                       tty_unlock(tty);
+               if (tty->ops->write && tty->count > 0)
                        tty->ops->write(tty, msg, strlen(msg));
-               } else
-                       tty_unlock(tty);
+               tty_unlock(tty);
                tty_write_unlock(tty);
        }
        return;
@@ -1689,7 +1689,7 @@ static void release_tty(struct tty_struct *tty, int idx)
        tty->port->itty = NULL;
        if (tty->link)
                tty->link->port->itty = NULL;
-       cancel_work_sync(&tty->port->buf.work);
+       tty_buffer_cancel_work(tty->port);
 
        tty_kref_put(tty->link);
        tty_kref_put(tty);
@@ -2569,7 +2569,6 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
        struct pid *pgrp;
        pid_t pgrp_nr;
        int retval = tty_check_change(real_tty);
-       unsigned long flags;
 
        if (retval == -EIO)
                return -ENOTTY;
@@ -2592,10 +2591,10 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
        if (session_of_pgrp(pgrp) != task_session(current))
                goto out_unlock;
        retval = 0;
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       spin_lock_irq(&tty->ctrl_lock);
        put_pid(real_tty->pgrp);
        real_tty->pgrp = get_pid(pgrp);
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+       spin_unlock_irq(&tty->ctrl_lock);
 out_unlock:
        rcu_read_unlock();
        return retval;
index 71750cbac31f745a6a899bc598cf0af1b84556b2..5af8f1874c1aab02fc16dbb0950d7264caa282ca 100644 (file)
@@ -319,7 +319,7 @@ __tty_ldisc_lock_nested(struct tty_struct *tty, unsigned long timeout)
 
 static inline void __tty_ldisc_unlock(struct tty_struct *tty)
 {
-       return ldsem_up_write(&tty->ldisc_sem);
+       ldsem_up_write(&tty->ldisc_sem);
 }
 
 static int __lockfunc
index 40b31835f80bc0d8634960a33cc5c3b1ec6d6064..482f33f2004336abd3c99686600cf9bc2382f2ad 100644 (file)
@@ -22,7 +22,6 @@ void tty_port_init(struct tty_port *port)
        memset(port, 0, sizeof(*port));
        tty_buffer_init(port);
        init_waitqueue_head(&port->open_wait);
-       init_waitqueue_head(&port->close_wait);
        init_waitqueue_head(&port->delta_msr_wait);
        mutex_init(&port->mutex);
        mutex_init(&port->buf_mutex);
@@ -131,7 +130,7 @@ EXPORT_SYMBOL(tty_port_free_xmit_buf);
  */
 void tty_port_destroy(struct tty_port *port)
 {
-       cancel_work_sync(&port->buf.work);
+       tty_buffer_cancel_work(port);
        tty_buffer_free_all(port);
 }
 EXPORT_SYMBOL(tty_port_destroy);
@@ -363,16 +362,6 @@ int tty_port_block_til_ready(struct tty_port *port,
        unsigned long flags;
        DEFINE_WAIT(wait);
 
-       /* block if port is in the process of being closed */
-       if (port->flags & ASYNC_CLOSING) {
-               wait_event_interruptible_tty(tty, port->close_wait,
-                               !(port->flags & ASYNC_CLOSING));
-               if (port->flags & ASYNC_HUP_NOTIFY)
-                       return -EAGAIN;
-               else
-                       return -ERESTARTSYS;
-       }
-
        /* if non-blocking mode is set we can pass directly to open unless
           the port has just hung up or is in another error state */
        if (tty->flags & (1 << TTY_IO_ERROR)) {
@@ -423,8 +412,7 @@ int tty_port_block_til_ready(struct tty_port *port,
                 * Never ask drivers if CLOCAL is set, this causes troubles
                 * on some hardware.
                 */
-               if (!(port->flags & ASYNC_CLOSING) &&
-                               (do_clocal || tty_port_carrier_raised(port)))
+               if (do_clocal || tty_port_carrier_raised(port))
                        break;
                if (signal_pending(current)) {
                        retval = -ERESTARTSYS;
@@ -463,10 +451,7 @@ static void tty_port_drain_delay(struct tty_port *port, struct tty_struct *tty)
        schedule_timeout_interruptible(timeout);
 }
 
-/* Caller holds tty lock.
- * NB: may drop and reacquire tty lock (in tty_wait_until_sent_from_close())
- * so tty and tty port may have changed state (but not hung up or reopened).
- */
+/* Caller holds tty lock. */
 int tty_port_close_start(struct tty_port *port,
                                struct tty_struct *tty, struct file *filp)
 {
@@ -502,7 +487,7 @@ int tty_port_close_start(struct tty_port *port,
                if (tty->flow_stopped)
                        tty_driver_flush_buffer(tty);
                if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-                       tty_wait_until_sent_from_close(tty, port->closing_wait);
+                       tty_wait_until_sent(tty, port->closing_wait);
                if (port->drain_delay)
                        tty_port_drain_delay(port, tty);
        }
@@ -534,7 +519,6 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
                wake_up_interruptible(&port->open_wait);
        }
        port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
-       wake_up_interruptible(&port->close_wait);
        spin_unlock_irqrestore(&port->lock, flags);
 }
 EXPORT_SYMBOL(tty_port_close_end);
@@ -543,10 +527,6 @@ EXPORT_SYMBOL(tty_port_close_end);
  * tty_port_close
  *
  * Caller holds tty lock
- *
- * NB: may drop and reacquire tty lock (in tty_port_close_start()->
- * tty_wait_until_sent_from_close()) so tty and tty_port may have changed
- * state (but not hung up or reopened).
  */
 void tty_port_close(struct tty_port *port, struct tty_struct *tty,
                                                        struct file *filp)
index 7ee057930ae71793bcbd2777cb275572af21c295..42894f58016eab5fae91534cdefec3fc3bb77e3e 100644 (file)
@@ -114,6 +114,7 @@ struct gs_port {
        struct gs_buf           port_write_buf;
        wait_queue_head_t       drain_wait;     /* wait while writes drain */
        bool                    write_busy;
+       wait_queue_head_t       close_wait;
 
        /* REVISIT this state ... */
        struct usb_cdc_line_coding port_line_coding;    /* 8-N-1 etc */
@@ -884,7 +885,7 @@ static void gs_close(struct tty_struct *tty, struct file *file)
        pr_debug("gs_close: ttyGS%d (%p,%p) done!\n",
                        port->port_num, tty, file);
 
-       wake_up(&port->port.close_wait);
+       wake_up(&port->close_wait);
 exit:
        spin_unlock_irq(&port->port_lock);
 }
@@ -1044,6 +1045,7 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding)
        tty_port_init(&port->port);
        spin_lock_init(&port->port_lock);
        init_waitqueue_head(&port->drain_wait);
+       init_waitqueue_head(&port->close_wait);
 
        tasklet_init(&port->push, gs_rx_push, (unsigned long) port);
 
@@ -1074,7 +1076,7 @@ static void gserial_free_port(struct gs_port *port)
 {
        tasklet_kill(&port->push);
        /* wait for old opens to finish */
-       wait_event(port->port.close_wait, gs_closed(port));
+       wait_event(port->close_wait, gs_closed(port));
        WARN_ON(port->port_usb != NULL);
        tty_port_destroy(&port->port);
        kfree(port);
index 234393a6997bbdf22ecb270b672b9d0c49a01c5c..79df69dc629cd61a918ffe185f2fccf9e56ea393 100644 (file)
@@ -35,14 +35,23 @@ struct hsu_dma_chip {
        unsigned int                    length;
        unsigned int                    offset;
        struct hsu_dma                  *hsu;
-       struct hsu_dma_platform_data    *pdata;
 };
 
+#if IS_ENABLED(CONFIG_HSU_DMA)
 /* Export to the internal users */
 irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip, unsigned short nr);
 
 /* Export to the platform drivers */
 int hsu_dma_probe(struct hsu_dma_chip *chip);
 int hsu_dma_remove(struct hsu_dma_chip *chip);
+#else
+static inline irqreturn_t hsu_dma_irq(struct hsu_dma_chip *chip,
+                                     unsigned short nr)
+{
+       return IRQ_NONE;
+}
+static inline int hsu_dma_probe(struct hsu_dma_chip *chip) { return -ENODEV; }
+static inline int hsu_dma_remove(struct hsu_dma_chip *chip) { return 0; }
+#endif /* CONFIG_HSU_DMA */
 
 #endif /* _DMA_HSU_H */
index 5d0b2a1dee69c9814fe218407aa3bf381d577e23..90a803aa42e8cc1075e63dfc0bc17967d318f40f 100644 (file)
@@ -152,9 +152,6 @@ struct r3964_info {
        unsigned char *rx_buf;            /* ring buffer */
        unsigned char *tx_buf;
 
-       wait_queue_head_t read_wait;
-       //struct wait_queue *read_wait;
-
        struct r3964_block_header *rx_first;
        struct r3964_block_header *rx_last;
        struct r3964_block_header *tx_first;
@@ -164,8 +161,9 @@ struct r3964_info {
        unsigned char last_rx;
        unsigned char bcc;
         unsigned int  blocks_in_rx_queue;
-         
-       
+
+       struct mutex read_lock;         /* serialize r3964_read */
+
        struct r3964_client_info *firstClient;
        unsigned int state;
        unsigned int flags;
index c841e7e349729adf3a4bab9f0b47aaca8d7b6643..e649d8d370f8954435b79728e95db462795add5f 100644 (file)
 #include <linux/mtd/partitions.h>
 #include <linux/serial.h>
 
-/*
- * at91: 6 USARTs and one DBGU port (SAM9260)
- * avr32: 4
- */
-#define ATMEL_MAX_UART 7
-
  /* USB Device */
 struct at91_udc_data {
        int     vbus_pin;               /* high == host powering us */
index 8a1f6a4920b2e0c49bbdec12da5c3d169049f747..3453fa65550224311bea2f706e9b83c6880ed8bc 100644 (file)
@@ -18,8 +18,4 @@ struct hsu_dma_slave {
        int             chan_id;
 };
 
-struct hsu_dma_platform_data {
-       unsigned short  nr_channels;
-};
-
 #endif /* _PLATFORM_DATA_DMA_HSU_H */
index d072ded416786631838ec0aefaf6428362b0f291..5b04b0a5375b338dabbfa4a68b8482e04ffbbbc9 100644 (file)
@@ -227,7 +227,6 @@ struct tty_port {
        int                     blocked_open;   /* Waiting to open */
        int                     count;          /* Usage count */
        wait_queue_head_t       open_wait;      /* Open waiters */
-       wait_queue_head_t       close_wait;     /* Close waiters */
        wait_queue_head_t       delta_msr_wait; /* Modem status change */
        unsigned long           flags;          /* TTY flags ASY_*/
        unsigned char           console:1,      /* port is a console */
@@ -424,6 +423,7 @@ extern int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
                              const char *routine);
 extern const char *tty_name(const struct tty_struct *tty);
 extern void tty_wait_until_sent(struct tty_struct *tty, long timeout);
+extern int __tty_check_change(struct tty_struct *tty, int sig);
 extern int tty_check_change(struct tty_struct *tty);
 extern void __stop_tty(struct tty_struct *tty);
 extern void stop_tty(struct tty_struct *tty);
@@ -467,6 +467,8 @@ extern void tty_buffer_free_all(struct tty_port *port);
 extern void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld);
 extern void tty_buffer_init(struct tty_port *port);
 extern void tty_buffer_set_lock_subclass(struct tty_port *port);
+extern bool tty_buffer_restart_work(struct tty_port *port);
+extern bool tty_buffer_cancel_work(struct tty_port *port);
 extern speed_t tty_termios_baud_rate(struct ktermios *termios);
 extern speed_t tty_termios_input_baud_rate(struct ktermios *termios);
 extern void tty_termios_encode_baud_rate(struct ktermios *termios,
@@ -656,50 +658,6 @@ extern void __lockfunc tty_unlock(struct tty_struct *tty);
 extern void __lockfunc tty_lock_slave(struct tty_struct *tty);
 extern void __lockfunc tty_unlock_slave(struct tty_struct *tty);
 extern void tty_set_lock_subclass(struct tty_struct *tty);
-/*
- * this shall be called only from where BTM is held (like close)
- *
- * We need this to ensure nobody waits for us to finish while we are waiting.
- * Without this we were encountering system stalls.
- *
- * This should be indeed removed with BTM removal later.
- *
- * Locking: BTM required. Nobody is allowed to hold port->mutex.
- */
-static inline void tty_wait_until_sent_from_close(struct tty_struct *tty,
-               long timeout)
-{
-       tty_unlock(tty); /* tty->ops->close holds the BTM, drop it while waiting */
-       tty_wait_until_sent(tty, timeout);
-       tty_lock(tty);
-}
-
-/*
- * wait_event_interruptible_tty -- wait for a condition with the tty lock held
- *
- * The condition we are waiting for might take a long time to
- * become true, or might depend on another thread taking the
- * BTM. In either case, we need to drop the BTM to guarantee
- * forward progress. This is a leftover from the conversion
- * from the BKL and should eventually get removed as the BTM
- * falls out of use.
- *
- * Do not use in new code.
- */
-#define wait_event_interruptible_tty(tty, wq, condition)               \
-({                                                                     \
-       int __ret = 0;                                                  \
-       if (!(condition))                                               \
-               __ret = __wait_event_interruptible_tty(tty, wq,         \
-                                                      condition);      \
-       __ret;                                                          \
-})
-
-#define __wait_event_interruptible_tty(tty, wq, condition)             \
-       ___wait_event(wq, condition, TASK_INTERRUPTIBLE, 0, 0,          \
-                       tty_unlock(tty);                                \
-                       schedule();                                     \
-                       tty_lock(tty))
 
 #ifdef CONFIG_PROC_FS
 extern void proc_tty_register_driver(struct tty_driver *);
index 683346d2d633b4b2ac839e975e2c21d687242075..a4237707f79d56097099c2fe8704d686670cc9fe 100644 (file)
@@ -335,8 +335,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
                 * specified, we cannot return before the IrCOMM link is
                 * ready
                 */
-               if (!test_bit(ASYNCB_CLOSING, &port->flags) &&
-                   (do_clocal || tty_port_carrier_raised(port)) &&
+               if ((do_clocal || tty_port_carrier_raised(port)) &&
                    self->state == IRCOMM_TTY_READY)
                {
                        break;
@@ -443,34 +442,6 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
        /* Not really used by us, but lets do it anyway */
        self->port.low_latency = (self->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
-       /*
-        * If the port is the middle of closing, bail out now
-        */
-       if (test_bit(ASYNCB_CLOSING, &self->port.flags)) {
-
-               /* Hm, why are we blocking on ASYNC_CLOSING if we
-                * do return -EAGAIN/-ERESTARTSYS below anyway?
-                * IMHO it's either not needed in the first place
-                * or for some reason we need to make sure the async
-                * closing has been finished - if so, wouldn't we
-                * probably better sleep uninterruptible?
-                */
-
-               if (wait_event_interruptible(self->port.close_wait,
-                               !test_bit(ASYNCB_CLOSING, &self->port.flags))) {
-                       net_warn_ratelimited("%s - got signal while blocking on ASYNC_CLOSING!\n",
-                                            __func__);
-                       return -ERESTARTSYS;
-               }
-
-#ifdef SERIAL_DO_RESTART
-               return (self->port.flags & ASYNC_HUP_NOTIFY) ?
-                       -EAGAIN : -ERESTARTSYS;
-#else
-               return -EAGAIN;
-#endif
-       }
-
        /* Check if this is a "normal" ircomm device, or an irlpt device */
        if (self->line < 0x10) {
                self->service_type = IRCOMM_3_WIRE | IRCOMM_9_WIRE;