Merge tag 'tty-4.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 29 Oct 2018 17:42:20 +0000 (10:42 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 29 Oct 2018 17:42:20 +0000 (10:42 -0700)
Pull tty/serial updates from Greg KH:
 "Here is the big tty and serial pull request for 4.20-rc1

  Lots of little things here, including a merge from the SPI tree in
  order to keep things simpler for everyone to sync around for one
  platform.

  Major stuff is:

   - tty buffer clearing after use

   - atmel_serial fixes and additions

   - xilinx uart driver updates

  and of course, lots of tiny fixes and additions to individual serial
  drivers.

  All of these have been in linux-next with no reported issues for a
  while"

* tag 'tty-4.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (66 commits)
  of: base: Change logic in of_alias_get_alias_list()
  of: base: Fix english spelling in of_alias_get_alias_list()
  serial: sh-sci: do not warn if DMA transfers are not supported
  serial: uartps: Do not allow use aliases >= MAX_UART_INSTANCES
  tty: check name length in tty_find_polling_driver()
  serial: sh-sci: Add r8a77990 support
  tty: wipe buffer if not echoing data
  tty: wipe buffer.
  serial: fsl_lpuart: Remove the alias node dependence
  TTY: sn_console: Replace spin_is_locked() with spin_trylock()
  Revert "serial:serial_core: Allow use of CTS for PPS line discipline"
  serial: 8250_uniphier: add auto-flow-control support
  serial: 8250_uniphier: flatten probe function
  serial: 8250_uniphier: remove unused "fifo-size" property
  dt-bindings: serial: sh-sci: Document r8a7744 bindings
  serial: uartps: Fix missing unlock on error in cdns_get_id()
  tty/serial: atmel: add ISO7816 support
  tty/serial_core: add ISO7816 infrastructure
  serial:serial_core: Allow use of CTS for PPS line discipline
  serial: docs: Fix filename for serial reference implementation
  ...

43 files changed:
Documentation/devicetree/bindings/serial/renesas,sci-serial.txt
Documentation/devicetree/bindings/serial/uniphier-uart.txt
Documentation/serial/driver
Documentation/serial/serial-iso7816.txt [new file with mode: 0644]
arch/alpha/include/uapi/asm/ioctls.h
arch/mips/include/uapi/asm/ioctls.h
arch/parisc/include/uapi/asm/ioctls.h
arch/powerpc/include/uapi/asm/ioctls.h
arch/sh/include/uapi/asm/ioctls.h
arch/sparc/include/uapi/asm/ioctls.h
arch/xtensa/include/uapi/asm/ioctls.h
drivers/of/base.c
drivers/tty/ehv_bytechan.c
drivers/tty/n_tty.c
drivers/tty/serial/8250/8250_core.c
drivers/tty/serial/8250/8250_of.c
drivers/tty/serial/8250/8250_port.c
drivers/tty/serial/8250/8250_uniphier.c
drivers/tty/serial/8250/Kconfig
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/atmel_serial.h
drivers/tty/serial/cpm_uart/cpm_uart_core.c
drivers/tty/serial/fsl_lpuart.c
drivers/tty/serial/imx.c
drivers/tty/serial/kgdboc.c
drivers/tty/serial/mxs-auart.c
drivers/tty/serial/pmac_zilog.c
drivers/tty/serial/qcom_geni_serial.c
drivers/tty/serial/samsung.c
drivers/tty/serial/sc16is7xx.c
drivers/tty/serial/serial_core.c
drivers/tty/serial/sh-sci.c
drivers/tty/serial/sn_console.c
drivers/tty/serial/sprd_serial.c
drivers/tty/serial/uartlite.c
drivers/tty/serial/xilinx_uartps.c
drivers/tty/tty_buffer.c
drivers/tty/tty_io.c
drivers/tty/tty_port.c
include/linux/of.h
include/linux/serial_core.h
include/uapi/asm-generic/ioctls.h
include/uapi/linux/serial.h

index eaca9da79d83af982a79abe8e1b911f944a64ed1..e52e16c6bc57af9b1f6ce9b36d1630e69443f755 100644 (file)
@@ -14,6 +14,10 @@ Required properties:
     - "renesas,scifa-r8a7743" for R8A7743 (RZ/G1M) SCIFA compatible UART.
     - "renesas,scifb-r8a7743" for R8A7743 (RZ/G1M) SCIFB compatible UART.
     - "renesas,hscif-r8a7743" for R8A7743 (RZ/G1M) HSCIF compatible UART.
+    - "renesas,scif-r8a7744" for R8A7744 (RZ/G1N) SCIF compatible UART.
+    - "renesas,scifa-r8a7744" for R8A7744 (RZ/G1N) SCIFA compatible UART.
+    - "renesas,scifb-r8a7744" for R8A7744 (RZ/G1N) SCIFB compatible UART.
+    - "renesas,hscif-r8a7744" for R8A7744 (RZ/G1N) HSCIF compatible UART.
     - "renesas,scif-r8a7745" for R8A7745 (RZ/G1E) SCIF compatible UART.
     - "renesas,scifa-r8a7745" for R8A7745 (RZ/G1E) SCIFA compatible UART.
     - "renesas,scifb-r8a7745" for R8A7745 (RZ/G1E) SCIFB compatible UART.
@@ -50,6 +54,8 @@ Required properties:
     - "renesas,hscif-r8a77970" for R8A77970 (R-Car V3M) HSCIF compatible UART.
     - "renesas,scif-r8a77980" for R8A77980 (R-Car V3H) SCIF compatible UART.
     - "renesas,hscif-r8a77980" for R8A77980 (R-Car V3H) HSCIF compatible UART.
+    - "renesas,scif-r8a77990" for R8A77990 (R-Car E3) SCIF compatible UART.
+    - "renesas,hscif-r8a77990" for R8A77990 (R-Car E3) HSCIF compatible UART.
     - "renesas,scif-r8a77995" for R8A77995 (R-Car D3) SCIF compatible UART.
     - "renesas,hscif-r8a77995" for R8A77995 (R-Car D3) HSCIF compatible UART.
     - "renesas,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART.
index 0b3892a7a528ce34b9f4e4626e19c6a388a6573b..7a1bf02bb86984eb54d2a679641ebc25243f5f8d 100644 (file)
@@ -7,7 +7,7 @@ Required properties:
 - clocks: phandle to the input clock.
 
 Optional properties:
-- fifo-size: the RX/TX FIFO size.  Defaults to 64 if not specified.
+-auto-flow-control: enable automatic flow control support.
 
 Example:
        aliases {
@@ -19,5 +19,4 @@ Example:
                reg = <0x54006800 0x40>;
                interrupts = <0 33 4>;
                clocks = <&uart_clk>;
-               fifo-size = <64>;
        };
index da193e092fc3d5314164cf0dc0aae075addcd0d8..86e47c19a9240524e9f06bc4e135824ac43e5f0e 100644 (file)
@@ -7,7 +7,7 @@ This document is meant as a brief overview of some aspects of the new serial
 driver.  It is not complete, any questions you have should be directed to
 <rmk@arm.linux.org.uk>
 
-The reference implementation is contained within amba_pl011.c.
+The reference implementation is contained within amba-pl011.c.
 
 
 
diff --git a/Documentation/serial/serial-iso7816.txt b/Documentation/serial/serial-iso7816.txt
new file mode 100644 (file)
index 0000000..3193d24
--- /dev/null
@@ -0,0 +1,83 @@
+                        ISO7816 SERIAL COMMUNICATIONS
+
+1. INTRODUCTION
+
+  ISO/IEC7816 is a series of standards specifying integrated circuit cards (ICC)
+  also known as smart cards.
+
+2. HARDWARE-RELATED CONSIDERATIONS
+
+  Some CPUs/UARTs (e.g., Microchip AT91) contain a built-in mode capable of
+  handling communication with a smart card.
+
+  For these microcontrollers, the Linux driver should be made capable of
+  working in both modes, and proper ioctls (see later) should be made
+  available at user-level to allow switching from one mode to the other, and
+  vice versa.
+
+3. DATA STRUCTURES ALREADY AVAILABLE IN THE KERNEL
+
+  The Linux kernel provides the serial_iso7816 structure (see [1]) to handle
+  ISO7816 communications. This data structure is used to set and configure
+  ISO7816 parameters in ioctls.
+
+  Any driver for devices capable of working both as RS232 and ISO7816 should
+  implement the iso7816_config callback in the uart_port structure. The
+  serial_core calls iso7816_config to do the device specific part in response
+  to TIOCGISO7816 and TIOCSISO7816 ioctls (see below). The iso7816_config
+  callback receives a pointer to struct serial_iso7816.
+
+4. USAGE FROM USER-LEVEL
+
+  From user-level, ISO7816 configuration can be get/set using the previous
+  ioctls. For instance, to set ISO7816 you can use the following code:
+
+       #include <linux/serial.h>
+
+       /* Include definition for ISO7816 ioctls: TIOCSISO7816 and TIOCGISO7816 */
+       #include <sys/ioctl.h>
+
+       /* Open your specific device (e.g., /dev/mydevice): */
+       int fd = open ("/dev/mydevice", O_RDWR);
+       if (fd < 0) {
+               /* Error handling. See errno. */
+       }
+
+       struct serial_iso7816 iso7816conf;
+
+       /* Reserved fields as to be zeroed */
+       memset(&iso7816conf, 0, sizeof(iso7816conf));
+
+       /* Enable ISO7816 mode: */
+       iso7816conf.flags |= SER_ISO7816_ENABLED;
+
+       /* Select the protocol: */
+       /* T=0 */
+       iso7816conf.flags |= SER_ISO7816_T(0);
+       /* or T=1 */
+       iso7816conf.flags |= SER_ISO7816_T(1);
+
+       /* Set the guard time: */
+       iso7816conf.tg = 2;
+
+       /* Set the clock frequency*/
+       iso7816conf.clk = 3571200;
+
+       /* Set transmission factors: */
+       iso7816conf.sc_fi = 372;
+       iso7816conf.sc_di = 1;
+
+       if (ioctl(fd_usart, TIOCSISO7816, &iso7816conf) < 0) {
+               /* Error handling. See errno. */
+       }
+
+       /* Use read() and write() syscalls here... */
+
+       /* Close the device when finished: */
+       if (close (fd) < 0) {
+               /* Error handling. See errno. */
+       }
+
+5. REFERENCES
+
+ [1]    include/uapi/linux/serial.h
index 3729d92d3fa854599a99ba57c56aa33b40b4e0c8..1e9121c9b3c74c16d129ce6fac97f614080dca94 100644 (file)
 #define TIOCGPTLCK     _IOR('T', 0x39, int) /* Get Pty lock state */
 #define TIOCGEXCL      _IOR('T', 0x40, int) /* Get exclusive mode state */
 #define TIOCGPTPEER    _IO('T', 0x41) /* Safely open the slave */
+#define TIOCGISO7816   _IOR('T', 0x42, struct serial_iso7816)
+#define TIOCSISO7816   _IOWR('T', 0x43, struct serial_iso7816)
 
 #define TIOCSERCONFIG  0x5453
 #define TIOCSERGWILD   0x5454
index 890245a9f0c4d4064588596ea86c76219f5d2e1b..16aa8a766aec229839602893e245ee020b3c19c2 100644 (file)
@@ -93,6 +93,8 @@
 #define TIOCGPTLCK     _IOR('T', 0x39, int) /* Get Pty lock state */
 #define TIOCGEXCL      _IOR('T', 0x40, int) /* Get exclusive mode state */
 #define TIOCGPTPEER    _IO('T', 0x41) /* Safely open the slave */
+#define TIOCGISO7816   _IOR('T', 0x42, struct serial_iso7816)
+#define TIOCSISO7816   _IOWR('T', 0x43, struct serial_iso7816)
 
 /* I hope the range from 0x5480 on is free ... */
 #define TIOCSCTTY      0x5480          /* become controlling tty */
index aafb1c0ca0af63e4aefcc35687a9dfff78370b1e..82d1148c6379a50f0eae5622d7ab8fd71ffb80c1 100644 (file)
@@ -62,6 +62,8 @@
 #define TIOCGPTLCK     _IOR('T', 0x39, int) /* Get Pty lock state */
 #define TIOCGEXCL      _IOR('T', 0x40, int) /* Get exclusive mode state */
 #define TIOCGPTPEER    _IO('T', 0x41) /* Safely open the slave */
+#define TIOCGISO7816   _IOR('T', 0x42, struct serial_iso7816)
+#define TIOCSISO7816   _IOWR('T', 0x43, struct serial_iso7816)
 
 #define FIONCLEX       0x5450  /* these numbers need to be adjusted. */
 #define FIOCLEX                0x5451
index 41b1a5c1573403b7c0ceea122a37f018eab74f9d..2c145da3b774a136044e9106e96e38559c9e5832 100644 (file)
 #define TIOCGPTLCK     _IOR('T', 0x39, int) /* Get Pty lock state */
 #define TIOCGEXCL      _IOR('T', 0x40, int) /* Get exclusive mode state */
 #define TIOCGPTPEER    _IO('T', 0x41) /* Safely open the slave */
+#define TIOCGISO7816   _IOR('T', 0x42, struct serial_iso7816)
+#define TIOCSISO7816   _IOWR('T', 0x43, struct serial_iso7816)
 
 #define TIOCSERCONFIG  0x5453
 #define TIOCSERGWILD   0x5454
index cc62f6f981036b539387abf9205cc8c43e5f18ec..11866d4f60e1679f4b4836276a20a858c7365563 100644 (file)
@@ -95,6 +95,8 @@
 #define TIOCGPTLCK     _IOR('T', 0x39, int) /* Get Pty lock state */
 #define TIOCGEXCL      _IOR('T', 0x40, int) /* Get exclusive mode state */
 #define TIOCGPTPEER    _IO('T', 0x41) /* Safely open the slave */
+#define TIOCGISO7816   _IOR('T', 0x42, struct serial_iso7816)
+#define TIOCSISO7816   _IOWR('T', 0x43, struct serial_iso7816)
 
 #define TIOCSERCONFIG  _IO('T', 83) /* 0x5453 */
 #define TIOCSERGWILD   _IOR('T', 84,  int) /* 0x5454 */
index 2df52711e17033f5f725b682d9719306c7f35ec7..7fd2f5873c9e7a9f5878f20be1e47a68666759a3 100644 (file)
@@ -27,6 +27,8 @@
 #define TIOCGEXCL      _IOR('T', 0x40, int) /* Get exclusive mode state */
 #define TIOCGRS485     _IOR('T', 0x41, struct serial_rs485)
 #define TIOCSRS485     _IOWR('T', 0x42, struct serial_rs485)
+#define TIOCGISO7816   _IOR('T', 0x43, struct serial_iso7816)
+#define TIOCSISO7816   _IOWR('T', 0x44, struct serial_iso7816)
 
 /* Note that all the ioctls that are not available in Linux have a
  * double underscore on the front to: a) avoid some programs to
index ec43609cbfc533c411e6ddb1bbcda8a3089ebf43..6d4a87296c95cc51636f3109bd213732dde5c6d4 100644 (file)
 #define TIOCGPTLCK     _IOR('T', 0x39, int) /* Get Pty lock state */
 #define TIOCGEXCL      _IOR('T', 0x40, int) /* Get exclusive mode state */
 #define TIOCGPTPEER    _IO('T', 0x41) /* Safely open the slave */
+#define TIOCGISO7816   _IOR('T', 0x42, struct serial_iso7816)
+#define TIOCSISO7816   _IOWR('T', 0x43, struct serial_iso7816)
 
 #define TIOCSERCONFIG  _IO('T', 83)
 #define TIOCSERGWILD   _IOR('T', 84,  int)
index 13ebb16be64e7bfe16669b0a9701f9e424914af3..d023cf303d56c3a557881a55818b9ee424e74162 100644 (file)
@@ -16,6 +16,7 @@
 
 #define pr_fmt(fmt)    "OF: " fmt
 
+#include <linux/bitmap.h>
 #include <linux/console.h>
 #include <linux/ctype.h>
 #include <linux/cpu.h>
@@ -1985,6 +1986,59 @@ int of_alias_get_id(struct device_node *np, const char *stem)
 }
 EXPORT_SYMBOL_GPL(of_alias_get_id);
 
+/**
+ * of_alias_get_alias_list - Get alias list for the given device driver
+ * @matches:   Array of OF device match structures to search in
+ * @stem:      Alias stem of the given device_node
+ * @bitmap:    Bitmap field pointer
+ * @nbits:     Maximum number of alias IDs which can be recorded in bitmap
+ *
+ * The function travels the lookup table to record alias ids for the given
+ * device match structures and alias stem.
+ *
+ * Return:     0 or -ENOSYS when !CONFIG_OF or
+ *             -EOVERFLOW if alias ID is greater then allocated nbits
+ */
+int of_alias_get_alias_list(const struct of_device_id *matches,
+                            const char *stem, unsigned long *bitmap,
+                            unsigned int nbits)
+{
+       struct alias_prop *app;
+       int ret = 0;
+
+       /* Zero bitmap field to make sure that all the time it is clean */
+       bitmap_zero(bitmap, nbits);
+
+       mutex_lock(&of_mutex);
+       pr_debug("%s: Looking for stem: %s\n", __func__, stem);
+       list_for_each_entry(app, &aliases_lookup, link) {
+               pr_debug("%s: stem: %s, id: %d\n",
+                        __func__, app->stem, app->id);
+
+               if (strcmp(app->stem, stem) != 0) {
+                       pr_debug("%s: stem comparison didn't pass %s\n",
+                                __func__, app->stem);
+                       continue;
+               }
+
+               if (of_match_node(matches, app->np)) {
+                       pr_debug("%s: Allocated ID %d\n", __func__, app->id);
+
+                       if (app->id >= nbits) {
+                               pr_warn("%s: ID %d >= than bitmap field %d\n",
+                                       __func__, app->id, nbits);
+                               ret = -EOVERFLOW;
+                       } else {
+                               set_bit(app->id, bitmap);
+                       }
+               }
+       }
+       mutex_unlock(&of_mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(of_alias_get_alias_list);
+
 /**
  * of_alias_get_highest_id - Get highest alias id for the given stem
  * @stem:      Alias stem to be examined
index eea4049b5dcc67836ec99f2f25faa8c4a24ccd4d..769e0a5d1dfccf346cc1c912d151b68ddc0ec6af 100644 (file)
@@ -128,8 +128,8 @@ static int find_console_handle(void)
         */
        iprop = of_get_property(np, "hv-handle", NULL);
        if (!iprop) {
-               pr_err("ehv-bc: no 'hv-handle' property in %s node\n",
-                      np->name);
+               pr_err("ehv-bc: no 'hv-handle' property in %pOFn node\n",
+                      np);
                return 0;
        }
        stdout_bc = be32_to_cpu(*iprop);
@@ -661,8 +661,8 @@ static int ehv_bc_tty_probe(struct platform_device *pdev)
 
        iprop = of_get_property(np, "hv-handle", NULL);
        if (!iprop) {
-               dev_err(&pdev->dev, "no 'hv-handle' property in %s node\n",
-                       np->name);
+               dev_err(&pdev->dev, "no 'hv-handle' property in %pOFn node\n",
+                       np);
                return -ENODEV;
        }
 
@@ -682,8 +682,8 @@ static int ehv_bc_tty_probe(struct platform_device *pdev)
        bc->rx_irq = irq_of_parse_and_map(np, 0);
        bc->tx_irq = irq_of_parse_and_map(np, 1);
        if ((bc->rx_irq == NO_IRQ) || (bc->tx_irq == NO_IRQ)) {
-               dev_err(&pdev->dev, "no 'interrupts' property in %s node\n",
-                       np->name);
+               dev_err(&pdev->dev, "no 'interrupts' property in %pOFn node\n",
+                       np);
                ret = -ENODEV;
                goto error;
        }
index 43174220170924e094567ad6271703bd881e2a6f..3ad460219fd62ea580bbdc7a9102ff22de881d14 100644 (file)
@@ -152,17 +152,28 @@ static inline unsigned char *echo_buf_addr(struct n_tty_data *ldata, size_t i)
        return &ldata->echo_buf[i & (N_TTY_BUF_SIZE - 1)];
 }
 
+/* If we are not echoing the data, perhaps this is a secret so erase it */
+static void zero_buffer(struct tty_struct *tty, u8 *buffer, int size)
+{
+       bool icanon = !!L_ICANON(tty);
+       bool no_echo = !L_ECHO(tty);
+
+       if (icanon && no_echo)
+               memset(buffer, 0x00, size);
+}
+
 static int tty_copy_to_user(struct tty_struct *tty, void __user *to,
                            size_t tail, size_t n)
 {
        struct n_tty_data *ldata = tty->disc_data;
        size_t size = N_TTY_BUF_SIZE - tail;
-       const void *from = read_buf_addr(ldata, tail);
+       void *from = read_buf_addr(ldata, tail);
        int uncopied;
 
        if (n > size) {
                tty_audit_add_data(tty, from, size);
                uncopied = copy_to_user(to, from, size);
+               zero_buffer(tty, from, size - uncopied);
                if (uncopied)
                        return uncopied;
                to += size;
@@ -171,7 +182,9 @@ static int tty_copy_to_user(struct tty_struct *tty, void __user *to,
        }
 
        tty_audit_add_data(tty, from, n);
-       return copy_to_user(to, from, n);
+       uncopied = copy_to_user(to, from, n);
+       zero_buffer(tty, from, n - uncopied);
+       return uncopied;
 }
 
 /**
@@ -1960,11 +1973,12 @@ static int copy_from_read_buf(struct tty_struct *tty,
        n = min(head - ldata->read_tail, N_TTY_BUF_SIZE - tail);
        n = min(*nr, n);
        if (n) {
-               const unsigned char *from = read_buf_addr(ldata, tail);
+               unsigned char *from = read_buf_addr(ldata, tail);
                retval = copy_to_user(*b, from, n);
                n -= retval;
                is_eof = n == 1 && *from == EOF_CHAR(tty);
                tty_audit_add_data(tty, from, n);
+               zero_buffer(tty, from, n);
                smp_store_release(&ldata->read_tail, ldata->read_tail + n);
                /* Turn single EOF into zero-length read */
                if (L_EXTPROC(tty) && ldata->icanon && is_eof &&
index 8fe3d0ed229ed27c9bdb53ade9c356aaed1abc85..94f3e1c6449094125da28780d211d1341d2e0d8f 100644 (file)
@@ -130,12 +130,8 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
 
                l = l->next;
 
-               if (l == i->head && pass_counter++ > PASS_LIMIT) {
-                       /* If we hit this, we're dead. */
-                       printk_ratelimited(KERN_ERR
-                               "serial8250: too much work for irq%d\n", irq);
+               if (l == i->head && pass_counter++ > PASS_LIMIT)
                        break;
-               }
        } while (l != end);
 
        spin_unlock(&i->lock);
index af8beefe9b5c30b1153ab3ac769e73faecb47ee3..877fd7f8a8ed14e708ec952afbf49790d6a4d09b 100644 (file)
@@ -58,7 +58,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
        struct resource resource;
        struct device_node *np = ofdev->dev.of_node;
        u32 clk, spd, prop;
-       int ret;
+       int ret, irq;
 
        memset(port, 0, sizeof *port);
 
@@ -143,21 +143,27 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
        if (ret >= 0)
                port->line = ret;
 
-       port->irq = irq_of_parse_and_map(np, 0);
-       if (!port->irq) {
-               ret = -EPROBE_DEFER;
-               goto err_unprepare;
+       irq = of_irq_get(np, 0);
+       if (irq < 0) {
+               if (irq == -EPROBE_DEFER) {
+                       ret = -EPROBE_DEFER;
+                       goto err_unprepare;
+               }
+               /* IRQ support not mandatory */
+               irq = 0;
        }
 
+       port->irq = irq;
+
        info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL);
        if (IS_ERR(info->rst)) {
                ret = PTR_ERR(info->rst);
-               goto err_dispose;
+               goto err_unprepare;
        }
 
        ret = reset_control_deassert(info->rst);
        if (ret)
-               goto err_dispose;
+               goto err_unprepare;
 
        port->type = type;
        port->uartclk = clk;
@@ -184,8 +190,6 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
                port->handle_irq = fsl8250_handle_irq;
 
        return 0;
-err_dispose:
-       irq_dispose_mapping(port->irq);
 err_unprepare:
        clk_disable_unprepare(info->clk);
 err_pmruntime:
index 3f779d25ec0cdfa10575b153b62dc34c0c5b218b..f776b3eafb9619578986f2c0a3b0234fc2842067 100644 (file)
@@ -552,11 +552,30 @@ static unsigned int serial_icr_read(struct uart_8250_port *up, int offset)
  */
 static void serial8250_clear_fifos(struct uart_8250_port *p)
 {
+       unsigned char fcr;
+       unsigned char clr_mask = UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT;
+
        if (p->capabilities & UART_CAP_FIFO) {
-               serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO);
-               serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO |
-                              UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
-               serial_out(p, UART_FCR, 0);
+               /*
+                * Make sure to avoid changing FCR[7:3] and ENABLE_FIFO bits.
+                * In case ENABLE_FIFO is not set, there is nothing to flush
+                * so just return. Furthermore, on certain implementations of
+                * the 8250 core, the FCR[7:3] bits may only be changed under
+                * specific conditions and changing them if those conditions
+                * are not met can have nasty side effects. One such core is
+                * the 8250-omap present in TI AM335x.
+                */
+               fcr = serial_in(p, UART_FCR);
+
+               /* FIFO is not enabled, there's nothing to clear. */
+               if (!(fcr & UART_FCR_ENABLE_FIFO))
+                       return;
+
+               fcr |= clr_mask;
+               serial_out(p, UART_FCR, fcr);
+
+               fcr &= ~clr_mask;
+               serial_out(p, UART_FCR, fcr);
        }
 }
 
@@ -1448,7 +1467,7 @@ static void __do_stop_tx_rs485(struct uart_8250_port *p)
         * Enable previously disabled RX interrupts.
         */
        if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
-               serial8250_clear_and_reinit_fifos(p);
+               serial8250_clear_fifos(p);
 
                p->ier |= UART_IER_RLSI | UART_IER_RDI;
                serial_port_out(&p->port, UART_IER, p->ier);
index 28d88ccf5a0c2da6c399141de475f8c741960e60..164ba133437af69176ce0ca8316c7d572a0ff99a 100644 (file)
@@ -12,9 +12,6 @@
 
 #include "8250.h"
 
-/* Most (but not all) of UniPhier UART devices have 64-depth FIFO. */
-#define UNIPHIER_UART_DEFAULT_FIFO_SIZE        64
-
 /*
  * This hardware is similar to 8250, but its register map is a bit different:
  *   - MMIO32 (regshift = 2)
@@ -158,42 +155,6 @@ static void uniphier_serial_dl_write(struct uart_8250_port *up, int value)
        writel(value, up->port.membase + UNIPHIER_UART_DLR);
 }
 
-static int uniphier_of_serial_setup(struct device *dev, struct uart_port *port,
-                                   struct uniphier8250_priv *priv)
-{
-       int ret;
-       u32 prop;
-       struct device_node *np = dev->of_node;
-
-       ret = of_alias_get_id(np, "serial");
-       if (ret < 0) {
-               dev_err(dev, "failed to get alias id\n");
-               return ret;
-       }
-       port->line = ret;
-
-       /* Get clk rate through clk driver */
-       priv->clk = devm_clk_get(dev, NULL);
-       if (IS_ERR(priv->clk)) {
-               dev_err(dev, "failed to get clock\n");
-               return PTR_ERR(priv->clk);
-       }
-
-       ret = clk_prepare_enable(priv->clk);
-       if (ret < 0)
-               return ret;
-
-       port->uartclk = clk_get_rate(priv->clk);
-
-       /* Check for fifo size */
-       if (of_property_read_u32(np, "fifo-size", &prop) == 0)
-               port->fifosize = prop;
-       else
-               port->fifosize = UNIPHIER_UART_DEFAULT_FIFO_SIZE;
-
-       return 0;
-}
-
 static int uniphier_uart_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -226,10 +187,25 @@ static int uniphier_uart_probe(struct platform_device *pdev)
 
        memset(&up, 0, sizeof(up));
 
-       ret = uniphier_of_serial_setup(dev, &up.port, priv);
-       if (ret < 0)
+       ret = of_alias_get_id(dev->of_node, "serial");
+       if (ret < 0) {
+               dev_err(dev, "failed to get alias id\n");
+               return ret;
+       }
+       up.port.line = ret;
+
+       priv->clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(priv->clk)) {
+               dev_err(dev, "failed to get clock\n");
+               return PTR_ERR(priv->clk);
+       }
+
+       ret = clk_prepare_enable(priv->clk);
+       if (ret)
                return ret;
 
+       up.port.uartclk = clk_get_rate(priv->clk);
+
        spin_lock_init(&priv->atomic_write_lock);
 
        up.port.dev = dev;
@@ -241,10 +217,14 @@ static int uniphier_uart_probe(struct platform_device *pdev)
 
        up.port.type = PORT_16550A;
        up.port.iotype = UPIO_MEM32;
+       up.port.fifosize = 64;
        up.port.regshift = UNIPHIER_UART_REGSHIFT;
        up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE;
        up.capabilities = UART_CAP_FIFO;
 
+       if (of_property_read_bool(dev->of_node, "auto-flow-control"))
+               up.capabilities |= UART_CAP_AFE;
+
        up.port.serial_in = uniphier_serial_in;
        up.port.serial_out = uniphier_serial_out;
        up.dl_read = uniphier_serial_dl_read;
index f005eaf8bc57aab704adffc21258f8ee5e8cabbf..15c2c54638354744beb9a7031ce4f98344e9be1e 100644 (file)
@@ -375,7 +375,7 @@ config SERIAL_8250_RT288X
 
 config SERIAL_8250_OMAP
        tristate "Support for OMAP internal UART (8250 based driver)"
-       depends on SERIAL_8250 && ARCH_OMAP2PLUS
+       depends on SERIAL_8250 && (ARCH_OMAP2PLUS || ARCH_K3)
        help
          If you have a machine based on an Texas Instruments OMAP CPU you
          can enable its onboard serial ports by enabling this option.
index 267d4d1de3f877f0bb8d5060bf43921222f23f2a..05147fe243434a52e4ca827227d95dc1f6a0f2e6 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/suspend.h>
 #include <linux/mm.h>
 
+#include <asm/div64.h>
 #include <asm/io.h>
 #include <asm/ioctls.h>
 
@@ -147,6 +148,8 @@ struct atmel_uart_port {
        struct circ_buf         rx_ring;
 
        struct mctrl_gpios      *gpios;
+       u32                     backup_mode;    /* MR saved during iso7816 operations */
+       u32                     backup_brgr;    /* BRGR saved during iso7816 operations */
        unsigned int            tx_done_mask;
        u32                     fifo_size;
        u32                     rts_high;
@@ -163,6 +166,10 @@ struct atmel_uart_port {
        unsigned int            pending_status;
        spinlock_t              lock_suspended;
 
+       /* ISO7816 */
+       unsigned int            fidi_min;
+       unsigned int            fidi_max;
+
 #ifdef CONFIG_PM
        struct {
                u32             cr;
@@ -361,6 +368,127 @@ static int atmel_config_rs485(struct uart_port *port,
        return 0;
 }
 
+static unsigned int atmel_calc_cd(struct uart_port *port,
+                                 struct serial_iso7816 *iso7816conf)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       unsigned int cd;
+       u64 mck_rate;
+
+       mck_rate = (u64)clk_get_rate(atmel_port->clk);
+       do_div(mck_rate, iso7816conf->clk);
+       cd = mck_rate;
+       return cd;
+}
+
+static unsigned int atmel_calc_fidi(struct uart_port *port,
+                                   struct serial_iso7816 *iso7816conf)
+{
+       u64 fidi = 0;
+
+       if (iso7816conf->sc_fi && iso7816conf->sc_di) {
+               fidi = (u64)iso7816conf->sc_fi;
+               do_div(fidi, iso7816conf->sc_di);
+       }
+       return (u32)fidi;
+}
+
+/* Enable or disable the iso7816 support */
+/* Called with interrupts disabled */
+static int atmel_config_iso7816(struct uart_port *port,
+                               struct serial_iso7816 *iso7816conf)
+{
+       struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+       unsigned int mode;
+       unsigned int cd, fidi;
+       int ret = 0;
+
+       /* Disable interrupts */
+       atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
+
+       mode = atmel_uart_readl(port, ATMEL_US_MR);
+
+       if (iso7816conf->flags & SER_ISO7816_ENABLED) {
+               mode &= ~ATMEL_US_USMODE;
+
+               if (iso7816conf->tg > 255) {
+                       dev_err(port->dev, "ISO7816: Timeguard exceeding 255\n");
+                       memset(iso7816conf, 0, sizeof(struct serial_iso7816));
+                       ret = -EINVAL;
+                       goto err_out;
+               }
+
+               if ((iso7816conf->flags & SER_ISO7816_T_PARAM)
+                   == SER_ISO7816_T(0)) {
+                       mode |= ATMEL_US_USMODE_ISO7816_T0 | ATMEL_US_DSNACK;
+               } else if ((iso7816conf->flags & SER_ISO7816_T_PARAM)
+                          == SER_ISO7816_T(1)) {
+                       mode |= ATMEL_US_USMODE_ISO7816_T1 | ATMEL_US_INACK;
+               } else {
+                       dev_err(port->dev, "ISO7816: Type not supported\n");
+                       memset(iso7816conf, 0, sizeof(struct serial_iso7816));
+                       ret = -EINVAL;
+                       goto err_out;
+               }
+
+               mode &= ~(ATMEL_US_USCLKS | ATMEL_US_NBSTOP | ATMEL_US_PAR);
+
+               /* select mck clock, and output  */
+               mode |= ATMEL_US_USCLKS_MCK | ATMEL_US_CLKO;
+               /* set parity for normal/inverse mode + max iterations */
+               mode |= ATMEL_US_PAR_EVEN | ATMEL_US_NBSTOP_1 | ATMEL_US_MAX_ITER(3);
+
+               cd = atmel_calc_cd(port, iso7816conf);
+               fidi = atmel_calc_fidi(port, iso7816conf);
+               if (fidi == 0) {
+                       dev_warn(port->dev, "ISO7816 fidi = 0, Generator generates no signal\n");
+               } else if (fidi < atmel_port->fidi_min
+                          || fidi > atmel_port->fidi_max) {
+                       dev_err(port->dev, "ISO7816 fidi = %u, value not supported\n", fidi);
+                       memset(iso7816conf, 0, sizeof(struct serial_iso7816));
+                       ret = -EINVAL;
+                       goto err_out;
+               }
+
+               if (!(port->iso7816.flags & SER_ISO7816_ENABLED)) {
+                       /* port not yet in iso7816 mode: store configuration */
+                       atmel_port->backup_mode = atmel_uart_readl(port, ATMEL_US_MR);
+                       atmel_port->backup_brgr = atmel_uart_readl(port, ATMEL_US_BRGR);
+               }
+
+               atmel_uart_writel(port, ATMEL_US_TTGR, iso7816conf->tg);
+               atmel_uart_writel(port, ATMEL_US_BRGR, cd);
+               atmel_uart_writel(port, ATMEL_US_FIDI, fidi);
+
+               atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS | ATMEL_US_RXEN);
+               atmel_port->tx_done_mask = ATMEL_US_TXEMPTY | ATMEL_US_NACK | ATMEL_US_ITERATION;
+       } else {
+               dev_dbg(port->dev, "Setting UART back to RS232\n");
+               /* back to last RS232 settings */
+               mode = atmel_port->backup_mode;
+               memset(iso7816conf, 0, sizeof(struct serial_iso7816));
+               atmel_uart_writel(port, ATMEL_US_TTGR, 0);
+               atmel_uart_writel(port, ATMEL_US_BRGR, atmel_port->backup_brgr);
+               atmel_uart_writel(port, ATMEL_US_FIDI, 0x174);
+
+               if (atmel_use_pdc_tx(port))
+                       atmel_port->tx_done_mask = ATMEL_US_ENDTX |
+                                                  ATMEL_US_TXBUFE;
+               else
+                       atmel_port->tx_done_mask = ATMEL_US_TXRDY;
+       }
+
+       port->iso7816 = *iso7816conf;
+
+       atmel_uart_writel(port, ATMEL_US_MR, mode);
+
+err_out:
+       /* Enable interrupts */
+       atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask);
+
+       return ret;
+}
+
 /*
  * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
  */
@@ -480,8 +608,9 @@ static void atmel_stop_tx(struct uart_port *port)
        /* Disable interrupts */
        atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
 
-       if ((port->rs485.flags & SER_RS485_ENABLED) &&
-           !(port->rs485.flags & SER_RS485_RX_DURING_TX))
+       if (((port->rs485.flags & SER_RS485_ENABLED) &&
+            !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
+           port->iso7816.flags & SER_ISO7816_ENABLED)
                atmel_start_rx(port);
 }
 
@@ -499,8 +628,9 @@ static void atmel_start_tx(struct uart_port *port)
                return;
 
        if (atmel_use_pdc_tx(port) || atmel_use_dma_tx(port))
-               if ((port->rs485.flags & SER_RS485_ENABLED) &&
-                   !(port->rs485.flags & SER_RS485_RX_DURING_TX))
+               if (((port->rs485.flags & SER_RS485_ENABLED) &&
+                    !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
+                   port->iso7816.flags & SER_ISO7816_ENABLED)
                        atmel_stop_rx(port);
 
        if (atmel_use_pdc_tx(port))
@@ -798,8 +928,9 @@ static void atmel_complete_tx_dma(void *arg)
         */
        if (!uart_circ_empty(xmit))
                atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx);
-       else if ((port->rs485.flags & SER_RS485_ENABLED) &&
-                !(port->rs485.flags & SER_RS485_RX_DURING_TX)) {
+       else if (((port->rs485.flags & SER_RS485_ENABLED) &&
+                 !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
+                port->iso7816.flags & SER_ISO7816_ENABLED) {
                /* DMA done, stop TX, start RX for RS485 */
                atmel_start_rx(port);
        }
@@ -1282,6 +1413,9 @@ atmel_handle_status(struct uart_port *port, unsigned int pending,
                        wake_up_interruptible(&port->state->port.delta_msr_wait);
                }
        }
+
+       if (pending & (ATMEL_US_NACK | ATMEL_US_ITERATION))
+               dev_dbg(port->dev, "ISO7816 ERROR (0x%08x)\n", pending);
 }
 
 /*
@@ -1374,8 +1508,9 @@ static void atmel_tx_pdc(struct uart_port *port)
                atmel_uart_writel(port, ATMEL_US_IER,
                                  atmel_port->tx_done_mask);
        } else {
-               if ((port->rs485.flags & SER_RS485_ENABLED) &&
-                   !(port->rs485.flags & SER_RS485_RX_DURING_TX)) {
+               if (((port->rs485.flags & SER_RS485_ENABLED) &&
+                    !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
+                   port->iso7816.flags & SER_ISO7816_ENABLED) {
                        /* DMA done, stop TX, start RX for RS485 */
                        atmel_start_rx(port);
                }
@@ -1727,6 +1862,22 @@ static void atmel_get_ip_name(struct uart_port *port)
                atmel_port->has_frac_baudrate = true;
                atmel_port->has_hw_timer = true;
                atmel_port->rtor = ATMEL_US_RTOR;
+               version = atmel_uart_readl(port, ATMEL_US_VERSION);
+               switch (version) {
+               case 0x814:     /* sama5d2 */
+                       /* fall through */
+               case 0x701:     /* sama5d4 */
+                       atmel_port->fidi_min = 3;
+                       atmel_port->fidi_max = 65535;
+                       break;
+               case 0x502:     /* sam9x5, sama5d3 */
+                       atmel_port->fidi_min = 3;
+                       atmel_port->fidi_max = 2047;
+                       break;
+               default:
+                       atmel_port->fidi_min = 1;
+                       atmel_port->fidi_max = 2047;
+               }
        } else if (name == dbgu_uart) {
                dev_dbg(port->dev, "Dbgu or uart without hw timer\n");
        } else {
@@ -2100,6 +2251,17 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
                atmel_uart_writel(port, ATMEL_US_TTGR,
                                  port->rs485.delay_rts_after_send);
                mode |= ATMEL_US_USMODE_RS485;
+       } else if (port->iso7816.flags & SER_ISO7816_ENABLED) {
+               atmel_uart_writel(port, ATMEL_US_TTGR, port->iso7816.tg);
+               /* select mck clock, and output  */
+               mode |= ATMEL_US_USCLKS_MCK | ATMEL_US_CLKO;
+               /* set max iterations */
+               mode |= ATMEL_US_MAX_ITER(3);
+               if ((port->iso7816.flags & SER_ISO7816_T_PARAM)
+                               == SER_ISO7816_T(0))
+                       mode |= ATMEL_US_USMODE_ISO7816_T0;
+               else
+                       mode |= ATMEL_US_USMODE_ISO7816_T1;
        } else if (termios->c_cflag & CRTSCTS) {
                /* RS232 with hardware handshake (RTS/CTS) */
                if (atmel_use_fifo(port) &&
@@ -2176,7 +2338,8 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
        }
        quot = cd | fp << ATMEL_US_FP_OFFSET;
 
-       atmel_uart_writel(port, ATMEL_US_BRGR, quot);
+       if (!(port->iso7816.flags & SER_ISO7816_ENABLED))
+               atmel_uart_writel(port, ATMEL_US_BRGR, quot);
        atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
        atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN);
        atmel_port->tx_stopped = false;
@@ -2357,6 +2520,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
        port->mapbase           = mpdev->resource[0].start;
        port->irq               = mpdev->resource[1].start;
        port->rs485_config      = atmel_config_rs485;
+       port->iso7816_config    = atmel_config_iso7816;
        port->membase           = NULL;
 
        memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
@@ -2380,8 +2544,12 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
                /* only enable clock when USART is in use */
        }
 
-       /* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
-       if (port->rs485.flags & SER_RS485_ENABLED)
+       /*
+        * Use TXEMPTY for interrupt when rs485 or ISO7816 else TXRDY or
+        * ENDTX|TXBUFE
+        */
+       if (port->rs485.flags & SER_RS485_ENABLED ||
+           port->iso7816.flags & SER_ISO7816_ENABLED)
                atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
        else if (atmel_use_pdc_tx(port)) {
                port->fifosize = PDC_BUFFER_SIZE;
index ba3a2437cde4c68d99ff77d229f55fe75e1987e5..d811d4f2d0c06c8ffe0370093dc161651c222524 100644 (file)
@@ -78,7 +78,8 @@
 #define        ATMEL_US_OVER           BIT(19) /* Oversampling Mode */
 #define        ATMEL_US_INACK          BIT(20) /* Inhibit Non Acknowledge */
 #define        ATMEL_US_DSNACK         BIT(21) /* Disable Successive NACK */
-#define        ATMEL_US_MAX_ITER       GENMASK(26, 24) /* Max Iterations */
+#define        ATMEL_US_MAX_ITER_MASK  GENMASK(26, 24) /* Max Iterations */
+#define        ATMEL_US_MAX_ITER(n)    (((n) << 24) & ATMEL_US_MAX_ITER_MASK)
 #define        ATMEL_US_FILTER         BIT(28) /* Infrared Receive Line Filter */
 
 #define ATMEL_US_IER           0x08    /* Interrupt Enable Register */
index e5389591bb4f1f83a207ee5be7e3577648972599..79ad30d34949edfdbae4c2ca7c06a17649ec0c27 100644 (file)
@@ -1155,8 +1155,8 @@ static int cpm_uart_init_port(struct device_node *np,
        if (!pinfo->clk) {
                data = of_get_property(np, "fsl,cpm-brg", &len);
                if (!data || len != 4) {
-                       printk(KERN_ERR "CPM UART %s has no/invalid "
-                                       "fsl,cpm-brg property.\n", np->name);
+                       printk(KERN_ERR "CPM UART %pOFn has no/invalid "
+                                       "fsl,cpm-brg property.\n", np);
                        return -EINVAL;
                }
                pinfo->brg = *data;
@@ -1164,8 +1164,8 @@ static int cpm_uart_init_port(struct device_node *np,
 
        data = of_get_property(np, "fsl,cpm-command", &len);
        if (!data || len != 4) {
-               printk(KERN_ERR "CPM UART %s has no/invalid "
-                               "fsl,cpm-command property.\n", np->name);
+               printk(KERN_ERR "CPM UART %pOFn has no/invalid "
+                               "fsl,cpm-command property.\n", np);
                return -EINVAL;
        }
        pinfo->command = *data;
index 3f8d1274fc85c2ee0306d93db03042e55c7e193d..00c220e4f43c035ba470c3414f8e070e08845d98 100644 (file)
 /* IMX lpuart has four extra unused regs located at the beginning */
 #define IMX_REG_OFF    0x10
 
+static DEFINE_IDA(fsl_lpuart_ida);
+
 struct lpuart_port {
        struct uart_port        port;
        struct clk              *clk;
@@ -2143,8 +2145,11 @@ static int lpuart_probe(struct platform_device *pdev)
 
        ret = of_alias_get_id(np, "serial");
        if (ret < 0) {
-               dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
-               return ret;
+               ret = ida_simple_get(&fsl_lpuart_ida, 0, UART_NR, GFP_KERNEL);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "port line is full, add device failed\n");
+                       return ret;
+               }
        }
        if (ret >= ARRAY_SIZE(lpuart_ports)) {
                dev_err(&pdev->dev, "serial%d out of range\n", ret);
@@ -2246,6 +2251,8 @@ static int lpuart_remove(struct platform_device *pdev)
 
        uart_remove_one_port(&lpuart_reg, &sport->port);
 
+       ida_simple_remove(&fsl_lpuart_ida, sport->port.line);
+
        clk_disable_unprepare(sport->clk);
 
        if (sport->dma_tx_chan)
@@ -2384,6 +2391,7 @@ static int __init lpuart_serial_init(void)
 
 static void __exit lpuart_serial_exit(void)
 {
+       ida_destroy(&fsl_lpuart_ida);
        platform_driver_unregister(&lpuart_driver);
        uart_unregister_driver(&lpuart_reg);
 }
index 0f67197a3783ffdd62eccd3b41a813a80d66b6df..d4e051b578f6b941207176c471dc7645c33bef69 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/serial.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/rational.h>
 #include <linux/slab.h>
 #include <linux/of.h>
@@ -706,27 +707,25 @@ static irqreturn_t imx_uart_rtsint(int irq, void *dev_id)
 {
        struct imx_port *sport = dev_id;
        u32 usr1;
-       unsigned long flags;
 
-       spin_lock_irqsave(&sport->port.lock, flags);
+       spin_lock(&sport->port.lock);
 
        imx_uart_writel(sport, USR1_RTSD, USR1);
        usr1 = imx_uart_readl(sport, USR1) & USR1_RTSS;
        uart_handle_cts_change(&sport->port, !!usr1);
        wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
 
-       spin_unlock_irqrestore(&sport->port.lock, flags);
+       spin_unlock(&sport->port.lock);
        return IRQ_HANDLED;
 }
 
 static irqreturn_t imx_uart_txint(int irq, void *dev_id)
 {
        struct imx_port *sport = dev_id;
-       unsigned long flags;
 
-       spin_lock_irqsave(&sport->port.lock, flags);
+       spin_lock(&sport->port.lock);
        imx_uart_transmit_buffer(sport);
-       spin_unlock_irqrestore(&sport->port.lock, flags);
+       spin_unlock(&sport->port.lock);
        return IRQ_HANDLED;
 }
 
@@ -735,9 +734,8 @@ static irqreturn_t imx_uart_rxint(int irq, void *dev_id)
        struct imx_port *sport = dev_id;
        unsigned int rx, flg, ignored = 0;
        struct tty_port *port = &sport->port.state->port;
-       unsigned long flags;
 
-       spin_lock_irqsave(&sport->port.lock, flags);
+       spin_lock(&sport->port.lock);
 
        while (imx_uart_readl(sport, USR2) & USR2_RDR) {
                u32 usr2;
@@ -797,7 +795,7 @@ static irqreturn_t imx_uart_rxint(int irq, void *dev_id)
        }
 
 out:
-       spin_unlock_irqrestore(&sport->port.lock, flags);
+       spin_unlock(&sport->port.lock);
        tty_flip_buffer_push(port);
        return IRQ_HANDLED;
 }
@@ -903,13 +901,11 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id)
        }
 
        if (usr1 & USR1_DTRD) {
-               unsigned long flags;
-
                imx_uart_writel(sport, USR1_DTRD, USR1);
 
-               spin_lock_irqsave(&sport->port.lock, flags);
+               spin_lock(&sport->port.lock);
                imx_uart_mctrl_check(sport);
-               spin_unlock_irqrestore(&sport->port.lock, flags);
+               spin_unlock(&sport->port.lock);
 
                ret = IRQ_HANDLED;
        }
@@ -2384,8 +2380,13 @@ static int imx_uart_remove(struct platform_device *pdev)
 
 static void imx_uart_restore_context(struct imx_port *sport)
 {
-       if (!sport->context_saved)
+       unsigned long flags;
+
+       spin_lock_irqsave(&sport->port.lock, flags);
+       if (!sport->context_saved) {
+               spin_unlock_irqrestore(&sport->port.lock, flags);
                return;
+       }
 
        imx_uart_writel(sport, sport->saved_reg[4], UFCR);
        imx_uart_writel(sport, sport->saved_reg[5], UESC);
@@ -2398,11 +2399,15 @@ static void imx_uart_restore_context(struct imx_port *sport)
        imx_uart_writel(sport, sport->saved_reg[2], UCR3);
        imx_uart_writel(sport, sport->saved_reg[3], UCR4);
        sport->context_saved = false;
+       spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
 static void imx_uart_save_context(struct imx_port *sport)
 {
+       unsigned long flags;
+
        /* Save necessary regs */
+       spin_lock_irqsave(&sport->port.lock, flags);
        sport->saved_reg[0] = imx_uart_readl(sport, UCR1);
        sport->saved_reg[1] = imx_uart_readl(sport, UCR2);
        sport->saved_reg[2] = imx_uart_readl(sport, UCR3);
@@ -2414,6 +2419,7 @@ static void imx_uart_save_context(struct imx_port *sport)
        sport->saved_reg[8] = imx_uart_readl(sport, UBMR);
        sport->saved_reg[9] = imx_uart_readl(sport, IMX21_UTS);
        sport->context_saved = true;
+       spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
 static void imx_uart_enable_wakeup(struct imx_port *sport, bool on)
@@ -2447,6 +2453,8 @@ static int imx_uart_suspend_noirq(struct device *dev)
 
        clk_disable(sport->clk_ipg);
 
+       pinctrl_pm_select_sleep_state(dev);
+
        return 0;
 }
 
@@ -2455,6 +2463,8 @@ static int imx_uart_resume_noirq(struct device *dev)
        struct imx_port *sport = dev_get_drvdata(dev);
        int ret;
 
+       pinctrl_pm_select_default_state(dev);
+
        ret = clk_enable(sport->clk_ipg);
        if (ret)
                return ret;
index b4ba2b1dab767cac45a96dd6f0e2064ad138447c..baeeeaec3f030f94d7c0176647dff851e6647232 100644 (file)
@@ -8,6 +8,9 @@
  *
  * 2007-2008 (c) Jason Wessel - Wind River Systems, Inc.
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/ctype.h>
 #include <linux/kgdb.h>
@@ -128,19 +131,6 @@ static void kgdboc_unregister_kbd(void)
 #define kgdboc_restore_input()
 #endif /* ! CONFIG_KDB_KEYBOARD */
 
-static int kgdboc_option_setup(char *opt)
-{
-       if (strlen(opt) >= MAX_CONFIG_LEN) {
-               printk(KERN_ERR "kgdboc: config string too long\n");
-               return -ENOSPC;
-       }
-       strcpy(config, opt);
-
-       return 0;
-}
-
-__setup("kgdboc=", kgdboc_option_setup);
-
 static void cleanup_kgdboc(void)
 {
        if (kgdb_unregister_nmi_console())
@@ -154,15 +144,13 @@ static int configure_kgdboc(void)
 {
        struct tty_driver *p;
        int tty_line = 0;
-       int err;
+       int err = -ENODEV;
        char *cptr = config;
        struct console *cons;
 
-       err = kgdboc_option_setup(config);
-       if (err || !strlen(config) || isspace(config[0]))
+       if (!strlen(config) || isspace(config[0]))
                goto noconfig;
 
-       err = -ENODEV;
        kgdboc_io_ops.is_console = 0;
        kgdb_tty_driver = NULL;
 
@@ -248,7 +236,7 @@ static int param_set_kgdboc_var(const char *kmessage,
        int len = strlen(kmessage);
 
        if (len >= MAX_CONFIG_LEN) {
-               printk(KERN_ERR "kgdboc: config string too long\n");
+               pr_err("config string too long\n");
                return -ENOSPC;
        }
 
@@ -259,8 +247,7 @@ static int param_set_kgdboc_var(const char *kmessage,
        }
 
        if (kgdb_connected) {
-               printk(KERN_ERR
-                      "kgdboc: Cannot reconfigure while KGDB is connected.\n");
+               pr_err("Cannot reconfigure while KGDB is connected.\n");
 
                return -EBUSY;
        }
@@ -311,6 +298,25 @@ static struct kgdb_io kgdboc_io_ops = {
 };
 
 #ifdef CONFIG_KGDB_SERIAL_CONSOLE
+static int kgdboc_option_setup(char *opt)
+{
+       if (!opt) {
+               pr_err("config string not provided\n");
+               return -EINVAL;
+       }
+
+       if (strlen(opt) >= MAX_CONFIG_LEN) {
+               pr_err("config string too long\n");
+               return -ENOSPC;
+       }
+       strcpy(config, opt);
+
+       return 0;
+}
+
+__setup("kgdboc=", kgdboc_option_setup);
+
+
 /* This is only available if kgdboc is a built in for early debugging */
 static int __init kgdboc_early_init(char *opt)
 {
index 76aa289652f7ae20a532e9355affc501de8fe763..27235a526cce8c4b59aa14f6764e466b10988748 100644 (file)
@@ -1634,8 +1634,9 @@ static int mxs_auart_request_gpio_irq(struct mxs_auart_port *s)
 
        /*
         * If something went wrong, rollback.
+        * Be careful: i may be unsigned.
         */
-       while (err && (--i >= 0))
+       while (err && (i-- > 0))
                if (irq[i] >= 0)
                        free_irq(irq[i], s);
 
index 3d21790d961e3d03ce92c360408eff5b9ff974df..a9d40988e1c8d6dff1cc996d1b5f0c40b752060c 100644 (file)
@@ -219,7 +219,7 @@ static void pmz_interrupt_control(struct uart_pmac_port *uap, int enable)
 static bool pmz_receive_chars(struct uart_pmac_port *uap)
 {
        struct tty_port *port;
-       unsigned char ch, r1, drop, error, flag;
+       unsigned char ch, r1, drop, flag;
        int loops = 0;
 
        /* Sanity check, make sure the old bug is no longer happening */
@@ -231,7 +231,6 @@ static bool pmz_receive_chars(struct uart_pmac_port *uap)
        port = &uap->port.state->port;
 
        while (1) {
-               error = 0;
                drop = 0;
 
                r1 = read_zsreg(uap, R1);
@@ -273,7 +272,6 @@ static bool pmz_receive_chars(struct uart_pmac_port *uap)
                uap->port.icount.rx++;
 
                if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | BRK_ABRT)) {
-                       error = 1;
                        if (r1 & BRK_ABRT) {
                                pmz_debug("pmz: got break !\n");
                                r1 &= ~(PAR_ERR | CRC_ERR);
@@ -1566,9 +1564,9 @@ static int pmz_attach(struct macio_dev *mdev, const struct of_device_id *match)
         * to work around bugs in ancient Apple device-trees
         */
        if (macio_request_resources(uap->dev, "pmac_zilog"))
-               printk(KERN_WARNING "%s: Failed to request resource"
+               printk(KERN_WARNING "%pOFn: Failed to request resource"
                       ", port still active\n",
-                      uap->node->name);
+                      uap->node);
        else
                uap->flags |= PMACZILOG_FLAG_RSRC_REQUESTED;
 
index 1515074e18fb6d60a37de13daf6102b98712841f..d3b5261ee80af491ea8a0c6f365f0f83269eae6a 100644 (file)
@@ -851,6 +851,23 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport)
 {
        struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
        unsigned int rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT;
+       u32 proto;
+
+       if (uart_console(uport))
+               port->tx_bytes_pw = 1;
+       else
+               port->tx_bytes_pw = 4;
+       port->rx_bytes_pw = RX_BYTES_PW;
+
+       proto = geni_se_read_proto(&port->se);
+       if (proto != GENI_SE_UART) {
+               dev_err(uport->dev, "Invalid FW loaded, proto: %d\n", proto);
+               return -ENXIO;
+       }
+
+       qcom_geni_serial_stop_rx(uport);
+
+       get_tx_fifo_size(port);
 
        set_rfr_wm(port);
        writel_relaxed(rxstale, uport->membase + SE_UART_RX_STALE_CNT);
@@ -874,30 +891,19 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport)
                        return -ENOMEM;
        }
        port->setup = true;
+
        return 0;
 }
 
 static int qcom_geni_serial_startup(struct uart_port *uport)
 {
        int ret;
-       u32 proto;
        struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
 
        scnprintf(port->name, sizeof(port->name),
                  "qcom_serial_%s%d",
                (uart_console(uport) ? "console" : "uart"), uport->line);
 
-       if (!uart_console(uport)) {
-               port->tx_bytes_pw = 4;
-               port->rx_bytes_pw = RX_BYTES_PW;
-       }
-       proto = geni_se_read_proto(&port->se);
-       if (proto != GENI_SE_UART) {
-               dev_err(uport->dev, "Invalid FW loaded, proto: %d\n", proto);
-               return -ENXIO;
-       }
-
-       get_tx_fifo_size(port);
        if (!port->setup) {
                ret = qcom_geni_serial_port_setup(uport);
                if (ret)
@@ -1056,6 +1062,7 @@ static int __init qcom_geni_console_setup(struct console *co, char *options)
        int bits = 8;
        int parity = 'n';
        int flow = 'n';
+       int ret;
 
        if (co->index >= GENI_UART_CONS_PORTS  || co->index < 0)
                return -ENXIO;
@@ -1071,21 +1078,10 @@ static int __init qcom_geni_console_setup(struct console *co, char *options)
        if (unlikely(!uport->membase))
                return -ENXIO;
 
-       if (geni_se_resources_on(&port->se)) {
-               dev_err(port->se.dev, "Error turning on resources\n");
-               return -ENXIO;
-       }
-
-       if (unlikely(geni_se_read_proto(&port->se) != GENI_SE_UART)) {
-               geni_se_resources_off(&port->se);
-               return -ENXIO;
-       }
-
        if (!port->setup) {
-               port->tx_bytes_pw = 1;
-               port->rx_bytes_pw = RX_BYTES_PW;
-               qcom_geni_serial_stop_rx(uport);
-               qcom_geni_serial_port_setup(uport);
+               ret = qcom_geni_serial_port_setup(uport);
+               if (ret)
+                       return ret;
        }
 
        if (options)
@@ -1203,11 +1199,12 @@ static void qcom_geni_serial_pm(struct uart_port *uport,
 {
        struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
 
+       /* If we've never been called, treat it as off */
+       if (old_state == UART_PM_STATE_UNDEFINED)
+               old_state = UART_PM_STATE_OFF;
+
        if (new_state == UART_PM_STATE_ON && old_state == UART_PM_STATE_OFF)
                geni_se_resources_on(&port->se);
-       else if (!uart_console(uport) && (new_state == UART_PM_STATE_ON &&
-                               old_state == UART_PM_STATE_UNDEFINED))
-               geni_se_resources_on(&port->se);
        else if (new_state == UART_PM_STATE_OFF &&
                        old_state == UART_PM_STATE_ON)
                geni_se_resources_off(&port->se);
@@ -1263,14 +1260,12 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
        if (of_device_is_compatible(pdev->dev.of_node, "qcom,geni-debug-uart"))
                console = true;
 
-       if (pdev->dev.of_node) {
-               if (console) {
-                       drv = &qcom_geni_console_driver;
-                       line = of_alias_get_id(pdev->dev.of_node, "serial");
-               } else {
-                       drv = &qcom_geni_uart_driver;
-                       line = of_alias_get_id(pdev->dev.of_node, "hsuart");
-               }
+       if (console) {
+               drv = &qcom_geni_console_driver;
+               line = of_alias_get_id(pdev->dev.of_node, "serial");
+       } else {
+               drv = &qcom_geni_uart_driver;
+               line = of_alias_get_id(pdev->dev.of_node, "hsuart");
        }
 
        port = get_port_from_line(line, console);
index 2f8fa184aafaadbc9d796ec74588a19d3861caab..da1bd4bba8a9496962002b19252eed16468f7417 100644 (file)
@@ -1941,7 +1941,11 @@ static int s3c24xx_serial_resume(struct device *dev)
 
        if (port) {
                clk_prepare_enable(ourport->clk);
+               if (!IS_ERR(ourport->baudclk))
+                       clk_prepare_enable(ourport->baudclk);
                s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port));
+               if (!IS_ERR(ourport->baudclk))
+                       clk_disable_unprepare(ourport->baudclk);
                clk_disable_unprepare(ourport->clk);
 
                uart_resume_port(&s3c24xx_uart_drv, port);
@@ -1964,7 +1968,11 @@ static int s3c24xx_serial_resume_noirq(struct device *dev)
                        if (rx_enabled(port))
                                uintm &= ~S3C64XX_UINTM_RXD_MSK;
                        clk_prepare_enable(ourport->clk);
+                       if (!IS_ERR(ourport->baudclk))
+                               clk_prepare_enable(ourport->baudclk);
                        wr_regl(port, S3C64XX_UINTM, uintm);
+                       if (!IS_ERR(ourport->baudclk))
+                               clk_disable_unprepare(ourport->baudclk);
                        clk_disable_unprepare(ourport->clk);
                }
        }
index 243c9602505306c3d7581f7e58a5967b680df838..268098681856b4c06b82cb1189928915eb10259a 100644 (file)
@@ -328,6 +328,7 @@ struct sc16is7xx_port {
        struct kthread_worker           kworker;
        struct task_struct              *kworker_task;
        struct kthread_work             irq_work;
+       struct mutex                    efr_lock;
        struct sc16is7xx_one            p[0];
 };
 
@@ -499,6 +500,21 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)
                div /= 4;
        }
 
+       /* In an amazing feat of design, the Enhanced Features Register shares
+        * the address of the Interrupt Identification Register, and is
+        * switched in by writing a magic value (0xbf) to the Line Control
+        * Register. Any interrupt firing during this time will see the EFR
+        * where it expects the IIR to be, leading to "Unexpected interrupt"
+        * messages.
+        *
+        * Prevent this possibility by claiming a mutex while accessing the
+        * EFR, and claiming the same mutex from within the interrupt handler.
+        * This is similar to disabling the interrupt, but that doesn't work
+        * because the bulk of the interrupt processing is run as a workqueue
+        * job in thread context.
+        */
+       mutex_lock(&s->efr_lock);
+
        lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG);
 
        /* Open the LCR divisors for configuration */
@@ -514,6 +530,8 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)
        /* Put LCR back to the normal mode */
        sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
 
+       mutex_unlock(&s->efr_lock);
+
        sc16is7xx_port_update(port, SC16IS7XX_MCR_REG,
                              SC16IS7XX_MCR_CLKSEL_BIT,
                              prescaler);
@@ -657,7 +675,7 @@ static void sc16is7xx_handle_tx(struct uart_port *port)
                uart_write_wakeup(port);
 }
 
-static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
+static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
 {
        struct uart_port *port = &s->p[portno].port;
 
@@ -666,7 +684,7 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
 
                iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG);
                if (iir & SC16IS7XX_IIR_NO_INT_BIT)
-                       break;
+                       return false;
 
                iir &= SC16IS7XX_IIR_ID_MASK;
 
@@ -688,16 +706,27 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
                                            port->line, iir);
                        break;
                }
-       } while (1);
+       } while (0);
+       return true;
 }
 
 static void sc16is7xx_ist(struct kthread_work *ws)
 {
        struct sc16is7xx_port *s = to_sc16is7xx_port(ws, irq_work);
-       int i;
 
-       for (i = 0; i < s->devtype->nr_uart; ++i)
-               sc16is7xx_port_irq(s, i);
+       mutex_lock(&s->efr_lock);
+
+       while (1) {
+               bool keep_polling = false;
+               int i;
+
+               for (i = 0; i < s->devtype->nr_uart; ++i)
+                       keep_polling |= sc16is7xx_port_irq(s, i);
+               if (!keep_polling)
+                       break;
+       }
+
+       mutex_unlock(&s->efr_lock);
 }
 
 static irqreturn_t sc16is7xx_irq(int irq, void *dev_id)
@@ -892,6 +921,9 @@ static void sc16is7xx_set_termios(struct uart_port *port,
        if (!(termios->c_cflag & CREAD))
                port->ignore_status_mask |= SC16IS7XX_LSR_BRK_ERROR_MASK;
 
+       /* As above, claim the mutex while accessing the EFR. */
+       mutex_lock(&s->efr_lock);
+
        sc16is7xx_port_write(port, SC16IS7XX_LCR_REG,
                             SC16IS7XX_LCR_CONF_MODE_B);
 
@@ -913,6 +945,8 @@ static void sc16is7xx_set_termios(struct uart_port *port,
        /* Update LCR register */
        sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
 
+       mutex_unlock(&s->efr_lock);
+
        /* Get baud rate generator configuration */
        baud = uart_get_baud_rate(port, termios, old,
                                  port->uartclk / 16 / 4 / 0xffff,
@@ -1178,6 +1212,7 @@ static int sc16is7xx_probe(struct device *dev,
        s->regmap = regmap;
        s->devtype = devtype;
        dev_set_drvdata(dev, s);
+       mutex_init(&s->efr_lock);
 
        kthread_init_worker(&s->kworker);
        kthread_init_work(&s->irq_work, sc16is7xx_ist);
index 54726c3f74c6249b4fab889b1e6691b5add53560..c439a5a1e6c078e71bda4ea756480b1344507707 100644 (file)
@@ -1302,6 +1302,58 @@ static int uart_set_rs485_config(struct uart_port *port,
        return 0;
 }
 
+static int uart_get_iso7816_config(struct uart_port *port,
+                                  struct serial_iso7816 __user *iso7816)
+{
+       unsigned long flags;
+       struct serial_iso7816 aux;
+
+       if (!port->iso7816_config)
+               return -ENOIOCTLCMD;
+
+       spin_lock_irqsave(&port->lock, flags);
+       aux = port->iso7816;
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       if (copy_to_user(iso7816, &aux, sizeof(aux)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int uart_set_iso7816_config(struct uart_port *port,
+                                  struct serial_iso7816 __user *iso7816_user)
+{
+       struct serial_iso7816 iso7816;
+       int i, ret;
+       unsigned long flags;
+
+       if (!port->iso7816_config)
+               return -ENOIOCTLCMD;
+
+       if (copy_from_user(&iso7816, iso7816_user, sizeof(*iso7816_user)))
+               return -EFAULT;
+
+       /*
+        * There are 5 words reserved for future use. Check that userspace
+        * doesn't put stuff in there to prevent breakages in the future.
+        */
+       for (i = 0; i < 5; i++)
+               if (iso7816.reserved[i])
+                       return -EINVAL;
+
+       spin_lock_irqsave(&port->lock, flags);
+       ret = port->iso7816_config(port, &iso7816);
+       spin_unlock_irqrestore(&port->lock, flags);
+       if (ret)
+               return ret;
+
+       if (copy_to_user(iso7816_user, &port->iso7816, sizeof(port->iso7816)))
+               return -EFAULT;
+
+       return 0;
+}
+
 /*
  * Called via sys_ioctl.  We can use spin_lock_irq() here.
  */
@@ -1371,6 +1423,14 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
        case TIOCSRS485:
                ret = uart_set_rs485_config(uport, uarg);
                break;
+
+       case TIOCSISO7816:
+               ret = uart_set_iso7816_config(state->uart_port, uarg);
+               break;
+
+       case TIOCGISO7816:
+               ret = uart_get_iso7816_config(state->uart_port, uarg);
+               break;
        default:
                if (uport->ops->ioctl)
                        ret = uport->ops->ioctl(uport, cmd, arg);
index ab3f6e91853da3c269cdb6c22c82226195778ece..ff6ba6d86cd8bf9ba43349fde40ec2d576ffed05 100644 (file)
@@ -1516,7 +1516,7 @@ static struct dma_chan *sci_request_dma_chan(struct uart_port *port,
        chan = dma_request_slave_channel(port->dev,
                                         dir == DMA_MEM_TO_DEV ? "tx" : "rx");
        if (!chan) {
-               dev_warn(port->dev, "dma_request_slave_channel failed\n");
+               dev_dbg(port->dev, "dma_request_slave_channel failed\n");
                return NULL;
        }
 
@@ -3414,6 +3414,12 @@ static int __init scif_early_console_setup(struct earlycon_device *device,
 {
        return early_console_setup(device, PORT_SCIF);
 }
+static int __init rzscifa_early_console_setup(struct earlycon_device *device,
+                                         const char *opt)
+{
+       port_cfg.regtype = SCIx_RZ_SCIFA_REGTYPE;
+       return early_console_setup(device, PORT_SCIF);
+}
 static int __init scifa_early_console_setup(struct earlycon_device *device,
                                          const char *opt)
 {
@@ -3432,6 +3438,7 @@ static int __init hscif_early_console_setup(struct earlycon_device *device,
 
 OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup);
 OF_EARLYCON_DECLARE(scif, "renesas,scif", scif_early_console_setup);
+OF_EARLYCON_DECLARE(scif, "renesas,scif-r7s9210", rzscifa_early_console_setup);
 OF_EARLYCON_DECLARE(scifa, "renesas,scifa", scifa_early_console_setup);
 OF_EARLYCON_DECLARE(scifb, "renesas,scifb", scifb_early_console_setup);
 OF_EARLYCON_DECLARE(hscif, "renesas,hscif", hscif_early_console_setup);
index 42b9aded4eb1c6d47a9795d743a27af9627fa563..fe9170731c167a4f09ee0f60047de1ca46f05834 100644 (file)
@@ -888,7 +888,7 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count)
 
        /* somebody really wants this output, might be an
         * oops, kdb, panic, etc.  make sure they get it. */
-       if (spin_is_locked(&port->sc_port.lock)) {
+       if (!spin_trylock_irqsave(&port->sc_port.lock, flags)) {
                int lhead = port->sc_port.state->xmit.head;
                int ltail = port->sc_port.state->xmit.tail;
                int counter, got_lock = 0;
@@ -905,13 +905,11 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count)
                 */
 
                for (counter = 0; counter < 150; mdelay(125), counter++) {
-                       if (!spin_is_locked(&port->sc_port.lock)
-                           || stole_lock) {
-                               if (!stole_lock) {
-                                       spin_lock_irqsave(&port->sc_port.lock,
-                                                         flags);
-                                       got_lock = 1;
-                               }
+                       if (stole_lock)
+                               break;
+
+                       if (spin_trylock_irqsave(&port->sc_port.lock, flags)) {
+                               got_lock = 1;
                                break;
                        } else {
                                /* still locked */
@@ -938,7 +936,6 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count)
                puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
        } else {
                stole_lock = 0;
-               spin_lock_irqsave(&port->sc_port.lock, flags);
                sn_transmit_chars(port, 1);
                spin_unlock_irqrestore(&port->sc_port.lock, flags);
 
index 828f1143859c8010f9916fada4958e229ce4e555..4287ca305b6be269d246e82195453d3745d2e245 100644 (file)
@@ -45,6 +45,8 @@
 
 /* data number in TX and RX fifo */
 #define SPRD_STS1              0x000C
+#define SPRD_RX_FIFO_CNT_MASK  GENMASK(7, 0)
+#define SPRD_TX_FIFO_CNT_MASK  GENMASK(15, 8)
 
 /* interrupt enable register and its BITs */
 #define SPRD_IEN               0x0010
 #define SPRD_LCR_DATA_LEN6     0x4
 #define SPRD_LCR_DATA_LEN7     0x8
 #define SPRD_LCR_DATA_LEN8     0xc
-#define SPRD_LCR_PARITY        (BIT(0) | BIT(1))
+#define SPRD_LCR_PARITY                (BIT(0) | BIT(1))
 #define SPRD_LCR_PARITY_EN     0x2
 #define SPRD_LCR_EVEN_PAR      0x0
 #define SPRD_LCR_ODD_PAR       0x1
 
 /* control register 1 */
-#define SPRD_CTL1                      0x001C
+#define SPRD_CTL1              0x001C
 #define RX_HW_FLOW_CTL_THLD    BIT(6)
 #define RX_HW_FLOW_CTL_EN      BIT(7)
 #define TX_HW_FLOW_CTL_EN      BIT(8)
 #define RX_TOUT_THLD_DEF       0x3E00
-#define RX_HFC_THLD_DEF        0x40
+#define RX_HFC_THLD_DEF                0x40
 
 /* fifo threshold register */
 #define SPRD_CTL2              0x0020
-#define THLD_TX_EMPTY  0x40
-#define THLD_RX_FULL   0x40
+#define THLD_TX_EMPTY          0x40
+#define THLD_TX_EMPTY_SHIFT    8
+#define THLD_RX_FULL           0x40
 
 /* config baud rate register */
 #define SPRD_CLKD0             0x0024
+#define SPRD_CLKD0_MASK                GENMASK(15, 0)
 #define SPRD_CLKD1             0x0028
+#define SPRD_CLKD1_MASK                GENMASK(20, 16)
+#define SPRD_CLKD1_SHIFT       16
 
 /* interrupt mask status register */
-#define SPRD_IMSR                      0x002C
-#define SPRD_IMSR_RX_FIFO_FULL         BIT(0)
+#define SPRD_IMSR              0x002C
+#define SPRD_IMSR_RX_FIFO_FULL BIT(0)
 #define SPRD_IMSR_TX_FIFO_EMPTY        BIT(1)
-#define SPRD_IMSR_BREAK_DETECT         BIT(7)
-#define SPRD_IMSR_TIMEOUT              BIT(13)
-
-struct reg_backup {
-       u32 ien;
-       u32 ctrl0;
-       u32 ctrl1;
-       u32 ctrl2;
-       u32 clkd0;
-       u32 clkd1;
-       u32 dspwait;
-};
+#define SPRD_IMSR_BREAK_DETECT BIT(7)
+#define SPRD_IMSR_TIMEOUT      BIT(13)
 
 struct sprd_uart_port {
        struct uart_port port;
-       struct reg_backup reg_bak;
        char name[16];
 };
 
 static struct sprd_uart_port *sprd_port[UART_NR_MAX];
 static int sprd_ports_num;
 
-static inline unsigned int serial_in(struct uart_port *port, int offset)
+static inline unsigned int serial_in(struct uart_port *port,
+                                    unsigned int offset)
 {
        return readl_relaxed(port->membase + offset);
 }
 
-static inline void serial_out(struct uart_port *port, int offset, int value)
+static inline void serial_out(struct uart_port *port, unsigned int offset,
+                             int value)
 {
        writel_relaxed(value, port->membase + offset);
 }
 
 static unsigned int sprd_tx_empty(struct uart_port *port)
 {
-       if (serial_in(port, SPRD_STS1) & 0xff00)
+       if (serial_in(port, SPRD_STS1) & SPRD_TX_FIFO_CNT_MASK)
                return 0;
        else
                return TIOCSER_TEMT;
@@ -224,14 +221,15 @@ static inline void sprd_rx(struct uart_port *port)
        struct tty_port *tty = &port->state->port;
        unsigned int ch, flag, lsr, max_count = SPRD_TIMEOUT;
 
-       while ((serial_in(port, SPRD_STS1) & 0x00ff) && max_count--) {
+       while ((serial_in(port, SPRD_STS1) & SPRD_RX_FIFO_CNT_MASK) &&
+              max_count--) {
                lsr = serial_in(port, SPRD_LSR);
                ch = serial_in(port, SPRD_RXD);
                flag = TTY_NORMAL;
                port->icount.rx++;
 
                if (lsr & (SPRD_LSR_BI | SPRD_LSR_PE |
-                       SPRD_LSR_FE | SPRD_LSR_OE))
+                          SPRD_LSR_FE | SPRD_LSR_OE))
                        if (handle_lsr_errors(port, &lsr, &flag))
                                continue;
                if (uart_handle_sysrq_char(port, ch))
@@ -294,8 +292,8 @@ static irqreturn_t sprd_handle_irq(int irq, void *dev_id)
        if (ims & SPRD_IMSR_TIMEOUT)
                serial_out(port, SPRD_ICLR, SPRD_ICLR_TIMEOUT);
 
-       if (ims & (SPRD_IMSR_RX_FIFO_FULL |
-               SPRD_IMSR_BREAK_DETECT | SPRD_IMSR_TIMEOUT))
+       if (ims & (SPRD_IMSR_RX_FIFO_FULL | SPRD_IMSR_BREAK_DETECT |
+                  SPRD_IMSR_TIMEOUT))
                sprd_rx(port);
 
        if (ims & SPRD_IMSR_TX_FIFO_EMPTY)
@@ -314,16 +312,17 @@ static int sprd_startup(struct uart_port *port)
        struct sprd_uart_port *sp;
        unsigned long flags;
 
-       serial_out(port, SPRD_CTL2, ((THLD_TX_EMPTY << 8) | THLD_RX_FULL));
+       serial_out(port, SPRD_CTL2,
+                  THLD_TX_EMPTY << THLD_TX_EMPTY_SHIFT | THLD_RX_FULL);
 
        /* clear rx fifo */
        timeout = SPRD_TIMEOUT;
-       while (timeout-- && serial_in(port, SPRD_STS1) & 0x00ff)
+       while (timeout-- && serial_in(port, SPRD_STS1) & SPRD_RX_FIFO_CNT_MASK)
                serial_in(port, SPRD_RXD);
 
        /* clear tx fifo */
        timeout = SPRD_TIMEOUT;
-       while (timeout-- && serial_in(port, SPRD_STS1) & 0xff00)
+       while (timeout-- && serial_in(port, SPRD_STS1) & SPRD_TX_FIFO_CNT_MASK)
                cpu_relax();
 
        /* clear interrupt */
@@ -334,7 +333,7 @@ static int sprd_startup(struct uart_port *port)
        sp = container_of(port, struct sprd_uart_port, port);
        snprintf(sp->name, sizeof(sp->name), "sprd_serial%d", port->line);
        ret = devm_request_irq(port->dev, port->irq, sprd_handle_irq,
-                               IRQF_SHARED, sp->name, port);
+                              IRQF_SHARED, sp->name, port);
        if (ret) {
                dev_err(port->dev, "fail to request serial irq %d, ret=%d\n",
                        port->irq, ret);
@@ -362,8 +361,8 @@ static void sprd_shutdown(struct uart_port *port)
 }
 
 static void sprd_set_termios(struct uart_port *port,
-                                   struct ktermios *termios,
-                                   struct ktermios *old)
+                            struct ktermios *termios,
+                            struct ktermios *old)
 {
        unsigned int baud, quot;
        unsigned int lcr = 0, fc;
@@ -444,10 +443,11 @@ static void sprd_set_termios(struct uart_port *port,
        }
 
        /* clock divider bit0~bit15 */
-       serial_out(port, SPRD_CLKD0, quot & 0xffff);
+       serial_out(port, SPRD_CLKD0, quot & SPRD_CLKD0_MASK);
 
        /* clock divider bit16~bit20 */
-       serial_out(port, SPRD_CLKD1, (quot & 0x1f0000) >> 16);
+       serial_out(port, SPRD_CLKD1,
+                  (quot & SPRD_CLKD1_MASK) >> SPRD_CLKD1_SHIFT);
        serial_out(port, SPRD_LCR, lcr);
        fc |= RX_TOUT_THLD_DEF | RX_HFC_THLD_DEF;
        serial_out(port, SPRD_CTL1, fc);
@@ -480,8 +480,7 @@ static void sprd_config_port(struct uart_port *port, int flags)
                port->type = PORT_SPRD;
 }
 
-static int sprd_verify_port(struct uart_port *port,
-                                  struct serial_struct *ser)
+static int sprd_verify_port(struct uart_port *port, struct serial_struct *ser)
 {
        if (ser->type != PORT_SPRD)
                return -EINVAL;
@@ -521,7 +520,7 @@ static void wait_for_xmitr(struct uart_port *port)
                if (--tmout == 0)
                        break;
                udelay(1);
-       } while (status & 0xff00);
+       } while (status & SPRD_TX_FIFO_CNT_MASK);
 }
 
 static void sprd_console_putchar(struct uart_port *port, int ch)
@@ -531,7 +530,7 @@ static void sprd_console_putchar(struct uart_port *port, int ch)
 }
 
 static void sprd_console_write(struct console *co, const char *s,
-                                     unsigned int count)
+                              unsigned int count)
 {
        struct uart_port *port = &sprd_port[co->index]->port;
        int locked = 1;
@@ -594,23 +593,21 @@ static void sprd_putc(struct uart_port *port, int c)
        unsigned int timeout = SPRD_TIMEOUT;
 
        while (timeout-- &&
-                  !(readl(port->membase + SPRD_LSR) & SPRD_LSR_TX_OVER))
+              !(readl(port->membase + SPRD_LSR) & SPRD_LSR_TX_OVER))
                cpu_relax();
 
        writeb(c, port->membase + SPRD_TXD);
 }
 
-static void sprd_early_write(struct console *con, const char *s,
-                                   unsigned n)
+static void sprd_early_write(struct console *con, const char *s, unsigned int n)
 {
        struct earlycon_device *dev = con->data;
 
        uart_console_write(&dev->port, s, n, sprd_putc);
 }
 
-static int __init sprd_early_console_setup(
-                               struct earlycon_device *device,
-                               const char *opt)
+static int __init sprd_early_console_setup(struct earlycon_device *device,
+                                          const char *opt)
 {
        if (!device->port.membase)
                return -ENODEV;
@@ -692,8 +689,8 @@ static int sprd_probe(struct platform_device *pdev)
 
        index = sprd_probe_dt_alias(index, &pdev->dev);
 
-       sprd_port[index] = devm_kzalloc(&pdev->dev,
-               sizeof(*sprd_port[index]), GFP_KERNEL);
+       sprd_port[index] = devm_kzalloc(&pdev->dev, sizeof(*sprd_port[index]),
+                                       GFP_KERNEL);
        if (!sprd_port[index])
                return -ENOMEM;
 
@@ -712,15 +709,12 @@ static int sprd_probe(struct platform_device *pdev)
                up->uartclk = clk_get_rate(clk);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "not provide mem resource\n");
-               return -ENODEV;
-       }
-       up->mapbase = res->start;
        up->membase = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(up->membase))
                return PTR_ERR(up->membase);
 
+       up->mapbase = res->start;
+
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
                dev_err(&pdev->dev, "not provide irq resource: %d\n", irq);
index 98d3eadd2fd0380e467b90f3340020ca1f3ccdd6..f0344adc86db422a40940fd66426fb64596cb6f5 100644 (file)
 #define ULITE_CONTROL_RST_RX   0x02
 #define ULITE_CONTROL_IE       0x10
 
+/* Static pointer to console port */
+#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
+static struct uart_port *console_port;
+#endif
+
 struct uartlite_data {
        const struct uartlite_reg_ops *reg_ops;
        struct clk *clk;
@@ -472,7 +477,7 @@ static void ulite_console_putchar(struct uart_port *port, int ch)
 static void ulite_console_write(struct console *co, const char *s,
                                unsigned int count)
 {
-       struct uart_port *port = &ulite_ports[co->index];
+       struct uart_port *port = console_port;
        unsigned long flags;
        unsigned int ier;
        int locked = 1;
@@ -506,10 +511,8 @@ static int ulite_console_setup(struct console *co, char *options)
        int parity = 'n';
        int flow = 'n';
 
-       if (co->index < 0 || co->index >= ULITE_NR_UARTS)
-               return -EINVAL;
 
-       port = &ulite_ports[co->index];
+       port = console_port;
 
        /* Has the device been initialized yet? */
        if (!port->mapbase) {
@@ -541,14 +544,6 @@ static struct console ulite_console = {
        .data   = &ulite_uart_driver,
 };
 
-static int __init ulite_console_init(void)
-{
-       register_console(&ulite_console);
-       return 0;
-}
-
-console_initcall(ulite_console_init);
-
 static void early_uartlite_putc(struct uart_port *port, int c)
 {
        /*
@@ -660,6 +655,17 @@ static int ulite_assign(struct device *dev, int id, u32 base, int irq,
 
        dev_set_drvdata(dev, port);
 
+#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
+       /*
+        * If console hasn't been found yet try to assign this port
+        * because it is required to be assigned for console setup function.
+        * If register_console() don't assign value, then console_port pointer
+        * is cleanup.
+        */
+       if (ulite_uart_driver.cons->index == -1)
+               console_port = port;
+#endif
+
        /* Register the port */
        rc = uart_add_one_port(&ulite_uart_driver, port);
        if (rc) {
@@ -669,6 +675,12 @@ static int ulite_assign(struct device *dev, int id, u32 base, int irq,
                return rc;
        }
 
+#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
+       /* This is not port which is used for console that's why clean it up */
+       if (ulite_uart_driver.cons->index == -1)
+               console_port = NULL;
+#endif
+
        return 0;
 }
 
@@ -776,13 +788,26 @@ static int ulite_probe(struct platform_device *pdev)
                pdata->clk = NULL;
        }
 
-       ret = clk_prepare(pdata->clk);
+       ret = clk_prepare_enable(pdata->clk);
        if (ret) {
                dev_err(&pdev->dev, "Failed to prepare clock\n");
                return ret;
        }
 
-       return ulite_assign(&pdev->dev, id, res->start, irq, pdata);
+       if (!ulite_uart_driver.state) {
+               dev_dbg(&pdev->dev, "uartlite: calling uart_register_driver()\n");
+               ret = uart_register_driver(&ulite_uart_driver);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "Failed to register driver\n");
+                       return ret;
+               }
+       }
+
+       ret = ulite_assign(&pdev->dev, id, res->start, irq, pdata);
+
+       clk_disable(pdata->clk);
+
+       return ret;
 }
 
 static int ulite_remove(struct platform_device *pdev)
@@ -813,25 +838,9 @@ static struct platform_driver ulite_platform_driver = {
 
 static int __init ulite_init(void)
 {
-       int ret;
-
-       pr_debug("uartlite: calling uart_register_driver()\n");
-       ret = uart_register_driver(&ulite_uart_driver);
-       if (ret)
-               goto err_uart;
 
        pr_debug("uartlite: calling platform_driver_register()\n");
-       ret = platform_driver_register(&ulite_platform_driver);
-       if (ret)
-               goto err_plat;
-
-       return 0;
-
-err_plat:
-       uart_unregister_driver(&ulite_uart_driver);
-err_uart:
-       pr_err("registering uartlite driver failed: err=%i\n", ret);
-       return ret;
+       return platform_driver_register(&ulite_platform_driver);
 }
 
 static void __exit ulite_exit(void)
index a48f19b1b88f1d48c5c6ae43389eb1e0ef79b9b7..57c66d2c347141e596b2240f00049413d31e9754 100644 (file)
@@ -30,8 +30,6 @@
 #define CDNS_UART_TTY_NAME     "ttyPS"
 #define CDNS_UART_NAME         "xuartps"
 #define CDNS_UART_MAJOR                0       /* use dynamic node allocation */
-#define CDNS_UART_MINOR                0       /* works best with devtmpfs */
-#define CDNS_UART_NR_PORTS     2
 #define CDNS_UART_FIFO_SIZE    64      /* FIFO size */
 #define CDNS_UART_REGISTER_SPACE       0x1000
 
@@ -180,7 +178,9 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
  * @port:              Pointer to the UART port
  * @uartclk:           Reference clock
  * @pclk:              APB clock
+ * @cdns_uart_driver:  Pointer to UART driver
  * @baud:              Current baud rate
+ * @id:                        Port ID
  * @clk_rate_change_nb:        Notifier block for clock changes
  * @quirks:            Flags for RXBS support.
  */
@@ -188,7 +188,9 @@ struct cdns_uart {
        struct uart_port        *port;
        struct clk              *uartclk;
        struct clk              *pclk;
+       struct uart_driver      *cdns_uart_driver;
        unsigned int            baud;
+       int                     id;
        struct notifier_block   clk_rate_change_nb;
        u32                     quirks;
 };
@@ -1003,13 +1005,12 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
        val = readl(port->membase + CDNS_UART_MODEMCR);
        mode_reg = readl(port->membase + CDNS_UART_MR);
 
-       val &= ~(CDNS_UART_MODEMCR_RTS | CDNS_UART_MODEMCR_DTR);
+       val &= ~(CDNS_UART_MODEMCR_RTS | CDNS_UART_MODEMCR_DTR |
+                CDNS_UART_MODEMCR_FCM);
        mode_reg &= ~CDNS_UART_MR_CHMODE_MASK;
 
-       if (mctrl & TIOCM_RTS)
-               val |= CDNS_UART_MODEMCR_RTS;
-       if (mctrl & TIOCM_DTR)
-               val |= CDNS_UART_MODEMCR_DTR;
+       if (mctrl & TIOCM_RTS || mctrl & TIOCM_DTR)
+               val |= CDNS_UART_MODEMCR_FCM;
        if (mctrl & TIOCM_LOOP)
                mode_reg |= CDNS_UART_MR_CHMODE_L_LOOP;
        else
@@ -1217,7 +1218,7 @@ static void cdns_uart_console_write(struct console *co, const char *s,
  *
  * Return: 0 on success, negative errno otherwise.
  */
-static int __init cdns_uart_console_setup(struct console *co, char *options)
+static int cdns_uart_console_setup(struct console *co, char *options)
 {
        struct uart_port *port = console_port;
 
@@ -1237,32 +1238,8 @@ static int __init cdns_uart_console_setup(struct console *co, char *options)
 
        return uart_set_options(port, co, baud, parity, bits, flow);
 }
-
-static struct uart_driver cdns_uart_uart_driver;
-
-static struct console cdns_uart_console = {
-       .name   = CDNS_UART_TTY_NAME,
-       .write  = cdns_uart_console_write,
-       .device = uart_console_device,
-       .setup  = cdns_uart_console_setup,
-       .flags  = CON_PRINTBUFFER,
-       .index  = -1, /* Specified on the cmdline (e.g. console=ttyPS ) */
-       .data   = &cdns_uart_uart_driver,
-};
 #endif /* CONFIG_SERIAL_XILINX_PS_UART_CONSOLE */
 
-static struct uart_driver cdns_uart_uart_driver = {
-       .owner          = THIS_MODULE,
-       .driver_name    = CDNS_UART_NAME,
-       .dev_name       = CDNS_UART_TTY_NAME,
-       .major          = CDNS_UART_MAJOR,
-       .minor          = CDNS_UART_MINOR,
-       .nr             = CDNS_UART_NR_PORTS,
-#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
-       .cons           = &cdns_uart_console,
-#endif
-};
-
 #ifdef CONFIG_PM_SLEEP
 /**
  * cdns_uart_suspend - suspend event
@@ -1273,24 +1250,12 @@ static struct uart_driver cdns_uart_uart_driver = {
 static int cdns_uart_suspend(struct device *device)
 {
        struct uart_port *port = dev_get_drvdata(device);
-       struct tty_struct *tty;
-       struct device *tty_dev;
-       int may_wake = 0;
-
-       /* Get the tty which could be NULL so don't assume it's valid */
-       tty = tty_port_tty_get(&port->state->port);
-       if (tty) {
-               tty_dev = tty->dev;
-               may_wake = device_may_wakeup(tty_dev);
-               tty_kref_put(tty);
-       }
+       struct cdns_uart *cdns_uart = port->private_data;
+       int may_wake;
 
-       /*
-        * Call the API provided in serial_core.c file which handles
-        * the suspend.
-        */
-       uart_suspend_port(&cdns_uart_uart_driver, port);
-       if (!(console_suspend_enabled && !may_wake)) {
+       may_wake = device_may_wakeup(device);
+
+       if (console_suspend_enabled && may_wake) {
                unsigned long flags = 0;
 
                spin_lock_irqsave(&port->lock, flags);
@@ -1305,7 +1270,11 @@ static int cdns_uart_suspend(struct device *device)
                spin_unlock_irqrestore(&port->lock, flags);
        }
 
-       return 0;
+       /*
+        * Call the API provided in serial_core.c file which handles
+        * the suspend.
+        */
+       return uart_suspend_port(cdns_uart->cdns_uart_driver, port);
 }
 
 /**
@@ -1317,23 +1286,14 @@ static int cdns_uart_suspend(struct device *device)
 static int cdns_uart_resume(struct device *device)
 {
        struct uart_port *port = dev_get_drvdata(device);
+       struct cdns_uart *cdns_uart = port->private_data;
        unsigned long flags = 0;
        u32 ctrl_reg;
-       struct tty_struct *tty;
-       struct device *tty_dev;
-       int may_wake = 0;
-
-       /* Get the tty which could be NULL so don't assume it's valid */
-       tty = tty_port_tty_get(&port->state->port);
-       if (tty) {
-               tty_dev = tty->dev;
-               may_wake = device_may_wakeup(tty_dev);
-               tty_kref_put(tty);
-       }
+       int may_wake;
 
-       if (console_suspend_enabled && !may_wake) {
-               struct cdns_uart *cdns_uart = port->private_data;
+       may_wake = device_may_wakeup(device);
 
+       if (console_suspend_enabled && !may_wake) {
                clk_enable(cdns_uart->pclk);
                clk_enable(cdns_uart->uartclk);
 
@@ -1367,7 +1327,7 @@ static int cdns_uart_resume(struct device *device)
                spin_unlock_irqrestore(&port->lock, flags);
        }
 
-       return uart_resume_port(&cdns_uart_uart_driver, port);
+       return uart_resume_port(cdns_uart->cdns_uart_driver, port);
 }
 #endif /* ! CONFIG_PM_SLEEP */
 static int __maybe_unused cdns_runtime_suspend(struct device *dev)
@@ -1409,6 +1369,90 @@ static const struct of_device_id cdns_uart_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
 
+/*
+ * Maximum number of instances without alias IDs but if there is alias
+ * which target "< MAX_UART_INSTANCES" range this ID can't be used.
+ */
+#define MAX_UART_INSTANCES     32
+
+/* Stores static aliases list */
+static DECLARE_BITMAP(alias_bitmap, MAX_UART_INSTANCES);
+static int alias_bitmap_initialized;
+
+/* Stores actual bitmap of allocated IDs with alias IDs together */
+static DECLARE_BITMAP(bitmap, MAX_UART_INSTANCES);
+/* Protect bitmap operations to have unique IDs */
+static DEFINE_MUTEX(bitmap_lock);
+
+static int cdns_get_id(struct platform_device *pdev)
+{
+       int id, ret;
+
+       mutex_lock(&bitmap_lock);
+
+       /* Alias list is stable that's why get alias bitmap only once */
+       if (!alias_bitmap_initialized) {
+               ret = of_alias_get_alias_list(cdns_uart_of_match, "serial",
+                                             alias_bitmap, MAX_UART_INSTANCES);
+               if (ret && ret != -EOVERFLOW) {
+                       mutex_unlock(&bitmap_lock);
+                       return ret;
+               }
+
+               alias_bitmap_initialized++;
+       }
+
+       /* Make sure that alias ID is not taken by instance without alias */
+       bitmap_or(bitmap, bitmap, alias_bitmap, MAX_UART_INSTANCES);
+
+       dev_dbg(&pdev->dev, "Alias bitmap: %*pb\n",
+               MAX_UART_INSTANCES, bitmap);
+
+       /* Look for a serialN alias */
+       id = of_alias_get_id(pdev->dev.of_node, "serial");
+       if (id < 0) {
+               dev_warn(&pdev->dev,
+                        "No serial alias passed. Using the first free id\n");
+
+               /*
+                * Start with id 0 and check if there is no serial0 alias
+                * which points to device which is compatible with this driver.
+                * If alias exists then try next free position.
+                */
+               id = 0;
+
+               for (;;) {
+                       dev_info(&pdev->dev, "Checking id %d\n", id);
+                       id = find_next_zero_bit(bitmap, MAX_UART_INSTANCES, id);
+
+                       /* No free empty instance */
+                       if (id == MAX_UART_INSTANCES) {
+                               dev_err(&pdev->dev, "No free ID\n");
+                               mutex_unlock(&bitmap_lock);
+                               return -EINVAL;
+                       }
+
+                       dev_dbg(&pdev->dev, "The empty id is %d\n", id);
+                       /* Check if ID is empty */
+                       if (!test_and_set_bit(id, bitmap)) {
+                               /* Break the loop if bit is taken */
+                               dev_dbg(&pdev->dev,
+                                       "Selected ID %d allocation passed\n",
+                                       id);
+                               break;
+                       }
+                       dev_dbg(&pdev->dev,
+                               "Selected ID %d allocation failed\n", id);
+                       /* if taking bit fails then try next one */
+                       id++;
+               }
+       }
+
+       mutex_unlock(&bitmap_lock);
+
+       return id;
+}
+
 /**
  * cdns_uart_probe - Platform driver probe
  * @pdev: Pointer to the platform device structure
@@ -1417,11 +1461,16 @@ MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
  */
 static int cdns_uart_probe(struct platform_device *pdev)
 {
-       int rc, id, irq;
+       int rc, irq;
        struct uart_port *port;
        struct resource *res;
        struct cdns_uart *cdns_uart_data;
        const struct of_device_id *match;
+       struct uart_driver *cdns_uart_uart_driver;
+       char *driver_name;
+#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
+       struct console *cdns_uart_console;
+#endif
 
        cdns_uart_data = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_data),
                        GFP_KERNEL);
@@ -1431,6 +1480,63 @@ static int cdns_uart_probe(struct platform_device *pdev)
        if (!port)
                return -ENOMEM;
 
+       cdns_uart_uart_driver = devm_kzalloc(&pdev->dev,
+                                            sizeof(*cdns_uart_uart_driver),
+                                            GFP_KERNEL);
+       if (!cdns_uart_uart_driver)
+               return -ENOMEM;
+
+       cdns_uart_data->id = cdns_get_id(pdev);
+       if (cdns_uart_data->id < 0)
+               return cdns_uart_data->id;
+
+       /* There is a need to use unique driver name */
+       driver_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s%d",
+                                    CDNS_UART_NAME, cdns_uart_data->id);
+       if (!driver_name) {
+               rc = -ENOMEM;
+               goto err_out_id;
+       }
+
+       cdns_uart_uart_driver->owner = THIS_MODULE;
+       cdns_uart_uart_driver->driver_name = driver_name;
+       cdns_uart_uart_driver->dev_name = CDNS_UART_TTY_NAME;
+       cdns_uart_uart_driver->major = CDNS_UART_MAJOR;
+       cdns_uart_uart_driver->minor = cdns_uart_data->id;
+       cdns_uart_uart_driver->nr = 1;
+
+#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
+       cdns_uart_console = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_console),
+                                        GFP_KERNEL);
+       if (!cdns_uart_console)
+               return -ENOMEM;
+
+       strncpy(cdns_uart_console->name, CDNS_UART_TTY_NAME,
+               sizeof(cdns_uart_console->name));
+       cdns_uart_console->index = cdns_uart_data->id;
+       cdns_uart_console->write = cdns_uart_console_write;
+       cdns_uart_console->device = uart_console_device;
+       cdns_uart_console->setup = cdns_uart_console_setup;
+       cdns_uart_console->flags = CON_PRINTBUFFER;
+       cdns_uart_console->data = cdns_uart_uart_driver;
+       cdns_uart_uart_driver->cons = cdns_uart_console;
+#endif
+
+       rc = uart_register_driver(cdns_uart_uart_driver);
+       if (rc < 0) {
+               dev_err(&pdev->dev, "Failed to register driver\n");
+               goto err_out_id;
+       }
+
+       cdns_uart_data->cdns_uart_driver = cdns_uart_uart_driver;
+
+       /*
+        * Setting up proper name_base needs to be done after uart
+        * registration because tty_driver structure is not filled.
+        * name_base is 0 by default.
+        */
+       cdns_uart_uart_driver->tty_driver->name_base = cdns_uart_data->id;
+
        match = of_match_node(cdns_uart_of_match, pdev->dev.of_node);
        if (match && match->data) {
                const struct cdns_platform_data *data = match->data;
@@ -1446,7 +1552,8 @@ static int cdns_uart_probe(struct platform_device *pdev)
        }
        if (IS_ERR(cdns_uart_data->pclk)) {
                dev_err(&pdev->dev, "pclk clock not found.\n");
-               return PTR_ERR(cdns_uart_data->pclk);
+               rc = PTR_ERR(cdns_uart_data->pclk);
+               goto err_out_unregister_driver;
        }
 
        cdns_uart_data->uartclk = devm_clk_get(&pdev->dev, "uart_clk");
@@ -1457,13 +1564,14 @@ static int cdns_uart_probe(struct platform_device *pdev)
        }
        if (IS_ERR(cdns_uart_data->uartclk)) {
                dev_err(&pdev->dev, "uart_clk clock not found.\n");
-               return PTR_ERR(cdns_uart_data->uartclk);
+               rc = PTR_ERR(cdns_uart_data->uartclk);
+               goto err_out_unregister_driver;
        }
 
        rc = clk_prepare_enable(cdns_uart_data->pclk);
        if (rc) {
                dev_err(&pdev->dev, "Unable to enable pclk clock.\n");
-               return rc;
+               goto err_out_unregister_driver;
        }
        rc = clk_prepare_enable(cdns_uart_data->uartclk);
        if (rc) {
@@ -1490,28 +1598,14 @@ static int cdns_uart_probe(struct platform_device *pdev)
                                &cdns_uart_data->clk_rate_change_nb))
                dev_warn(&pdev->dev, "Unable to register clock notifier.\n");
 #endif
-       /* Look for a serialN alias */
-       id = of_alias_get_id(pdev->dev.of_node, "serial");
-       if (id < 0)
-               id = 0;
-
-       if (id >= CDNS_UART_NR_PORTS) {
-               dev_err(&pdev->dev, "Cannot get uart_port structure\n");
-               rc = -ENODEV;
-               goto err_out_notif_unreg;
-       }
 
        /* At this point, we've got an empty uart_port struct, initialize it */
        spin_lock_init(&port->lock);
-       port->membase   = NULL;
-       port->irq       = 0;
        port->type      = PORT_UNKNOWN;
        port->iotype    = UPIO_MEM32;
        port->flags     = UPF_BOOT_AUTOCONF;
        port->ops       = &cdns_uart_ops;
        port->fifosize  = CDNS_UART_FIFO_SIZE;
-       port->line      = id;
-       port->dev       = NULL;
 
        /*
         * Register the port.
@@ -1538,11 +1632,11 @@ static int cdns_uart_probe(struct platform_device *pdev)
         * If register_console() don't assign value, then console_port pointer
         * is cleanup.
         */
-       if (cdns_uart_uart_driver.cons->index == -1)
+       if (!console_port)
                console_port = port;
 #endif
 
-       rc = uart_add_one_port(&cdns_uart_uart_driver, port);
+       rc = uart_add_one_port(cdns_uart_uart_driver, port);
        if (rc) {
                dev_err(&pdev->dev,
                        "uart_add_one_port() failed; err=%i\n", rc);
@@ -1551,7 +1645,8 @@ static int cdns_uart_probe(struct platform_device *pdev)
 
 #ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
        /* This is not port which is used for console that's why clean it up */
-       if (cdns_uart_uart_driver.cons->index == -1)
+       if (console_port == port &&
+           !(cdns_uart_uart_driver->cons->flags & CON_ENABLED))
                console_port = NULL;
 #endif
 
@@ -1561,7 +1656,6 @@ err_out_pm_disable:
        pm_runtime_disable(&pdev->dev);
        pm_runtime_set_suspended(&pdev->dev);
        pm_runtime_dont_use_autosuspend(&pdev->dev);
-err_out_notif_unreg:
 #ifdef CONFIG_COMMON_CLK
        clk_notifier_unregister(cdns_uart_data->uartclk,
                        &cdns_uart_data->clk_rate_change_nb);
@@ -1570,7 +1664,13 @@ err_out_clk_disable:
        clk_disable_unprepare(cdns_uart_data->uartclk);
 err_out_clk_dis_pclk:
        clk_disable_unprepare(cdns_uart_data->pclk);
-
+err_out_unregister_driver:
+       uart_unregister_driver(cdns_uart_data->cdns_uart_driver);
+err_out_id:
+       mutex_lock(&bitmap_lock);
+       if (cdns_uart_data->id < MAX_UART_INSTANCES)
+               clear_bit(cdns_uart_data->id, bitmap);
+       mutex_unlock(&bitmap_lock);
        return rc;
 }
 
@@ -1591,13 +1691,24 @@ static int cdns_uart_remove(struct platform_device *pdev)
        clk_notifier_unregister(cdns_uart_data->uartclk,
                        &cdns_uart_data->clk_rate_change_nb);
 #endif
-       rc = uart_remove_one_port(&cdns_uart_uart_driver, port);
+       rc = uart_remove_one_port(cdns_uart_data->cdns_uart_driver, port);
        port->mapbase = 0;
+       mutex_lock(&bitmap_lock);
+       if (cdns_uart_data->id < MAX_UART_INSTANCES)
+               clear_bit(cdns_uart_data->id, bitmap);
+       mutex_unlock(&bitmap_lock);
        clk_disable_unprepare(cdns_uart_data->uartclk);
        clk_disable_unprepare(cdns_uart_data->pclk);
        pm_runtime_disable(&pdev->dev);
        pm_runtime_set_suspended(&pdev->dev);
        pm_runtime_dont_use_autosuspend(&pdev->dev);
+
+#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
+       if (console_port == port)
+               console_port = NULL;
+#endif
+
+       uart_unregister_driver(cdns_uart_data->cdns_uart_driver);
        return rc;
 }
 
@@ -1613,28 +1724,14 @@ static struct platform_driver cdns_uart_platform_driver = {
 
 static int __init cdns_uart_init(void)
 {
-       int retval = 0;
-
-       /* Register the cdns_uart driver with the serial core */
-       retval = uart_register_driver(&cdns_uart_uart_driver);
-       if (retval)
-               return retval;
-
        /* Register the platform driver */
-       retval = platform_driver_register(&cdns_uart_platform_driver);
-       if (retval)
-               uart_unregister_driver(&cdns_uart_uart_driver);
-
-       return retval;
+       return platform_driver_register(&cdns_uart_platform_driver);
 }
 
 static void __exit cdns_uart_exit(void)
 {
        /* Unregister the platform driver */
        platform_driver_unregister(&cdns_uart_platform_driver);
-
-       /* Unregister the cdns_uart driver */
-       uart_unregister_driver(&cdns_uart_uart_driver);
 }
 
 arch_initcall(cdns_uart_init);
index c996b6859c5e70c72827f28c33c46bd3d96a1cda..77070c2d1240421fa34f48db9a2ddb24a961f2f0 100644 (file)
@@ -118,9 +118,12 @@ void tty_buffer_free_all(struct tty_port *port)
        struct tty_bufhead *buf = &port->buf;
        struct tty_buffer *p, *next;
        struct llist_node *llist;
+       unsigned int freed = 0;
+       int still_used;
 
        while ((p = buf->head) != NULL) {
                buf->head = p->next;
+               freed += p->size;
                if (p->size > 0)
                        kfree(p);
        }
@@ -132,7 +135,9 @@ void tty_buffer_free_all(struct tty_port *port)
        buf->head = &buf->sentinel;
        buf->tail = &buf->sentinel;
 
-       atomic_set(&buf->mem_used, 0);
+       still_used = atomic_xchg(&buf->mem_used, 0);
+       WARN(still_used != freed, "we still have not freed %d bytes!",
+                       still_used - freed);
 }
 
 /**
@@ -468,11 +473,15 @@ receive_buf(struct tty_port *port, struct tty_buffer *head, int count)
 {
        unsigned char *p = char_buf_ptr(head, head->read);
        char          *f = NULL;
+       int n;
 
        if (~head->flags & TTYB_NORMAL)
                f = flag_buf_ptr(head, head->read);
 
-       return port->client_ops->receive_buf(port, p, f, count);
+       n = port->client_ops->receive_buf(port, p, f, count);
+       if (n > 0)
+               memset(p, 0, n);
+       return n;
 }
 
 /**
index da3c1c2f73c4dadc9e32d3ec8477296b29ba843f..ee80dfbd5442b034451e396cd66608e41e8e43bb 100644 (file)
@@ -409,7 +409,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
        mutex_lock(&tty_mutex);
        /* Search through the tty devices to look for a match */
        list_for_each_entry(p, &tty_drivers, tty_drivers) {
-               if (strncmp(name, p->name, len) != 0)
+               if (!len || strncmp(name, p->name, len) != 0)
                        continue;
                stp = str;
                if (*stp == ',')
index 25d736880013b256cf692a2f5d3e6f51c4af9ece..cb6075096a5b41b6fbf5e87b6b22239c8a5082e3 100644 (file)
@@ -279,7 +279,6 @@ EXPORT_SYMBOL(tty_port_put);
  *     Return a refcount protected tty instance or NULL if the port is not
  *     associated with a tty (eg due to close or hangup)
  */
-
 struct tty_struct *tty_port_tty_get(struct tty_port *port)
 {
        unsigned long flags;
@@ -300,7 +299,6 @@ EXPORT_SYMBOL(tty_port_tty_get);
  *     Associate the port and tty pair. Manages any internal refcounts.
  *     Pass NULL to deassociate a port
  */
-
 void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
 {
        unsigned long flags;
@@ -343,7 +341,6 @@ out:
  *
  *     Caller holds tty lock.
  */
-
 void tty_port_hangup(struct tty_port *port)
 {
        struct tty_struct *tty;
@@ -399,7 +396,6 @@ EXPORT_SYMBOL_GPL(tty_port_tty_wakeup);
  *     to hide some internal details. This will eventually become entirely
  *     internal to the tty port.
  */
-
 int tty_port_carrier_raised(struct tty_port *port)
 {
        if (port->ops->carrier_raised == NULL)
@@ -416,7 +412,6 @@ EXPORT_SYMBOL(tty_port_carrier_raised);
  *     to hide some internal details. This will eventually become entirely
  *     internal to the tty port.
  */
-
 void tty_port_raise_dtr_rts(struct tty_port *port)
 {
        if (port->ops->dtr_rts)
@@ -432,7 +427,6 @@ EXPORT_SYMBOL(tty_port_raise_dtr_rts);
  *     to hide some internal details. This will eventually become entirely
  *     internal to the tty port.
  */
-
 void tty_port_lower_dtr_rts(struct tty_port *port)
 {
        if (port->ops->dtr_rts)
@@ -464,7 +458,6 @@ EXPORT_SYMBOL(tty_port_lower_dtr_rts);
  *      NB: May drop and reacquire tty lock when blocking, so tty and tty_port
  *      may have changed state (eg., may have been hung up).
  */
-
 int tty_port_block_til_ready(struct tty_port *port,
                                struct tty_struct *tty, struct file *filp)
 {
index ab96025b238243ae3e8ebc4604749bceb744680b..a5aee3c438ade1e592411b875aa4bd0c064fdbc4 100644 (file)
@@ -388,6 +388,9 @@ extern int of_phandle_iterator_args(struct of_phandle_iterator *it,
 extern void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align));
 extern int of_alias_get_id(struct device_node *np, const char *stem);
 extern int of_alias_get_highest_id(const char *stem);
+extern int of_alias_get_alias_list(const struct of_device_id *matches,
+                                  const char *stem, unsigned long *bitmap,
+                                  unsigned int nbits);
 
 extern int of_machine_is_compatible(const char *compat);
 
@@ -898,6 +901,13 @@ static inline int of_alias_get_highest_id(const char *stem)
        return -ENOSYS;
 }
 
+static inline int of_alias_get_alias_list(const struct of_device_id *matches,
+                                         const char *stem, unsigned long *bitmap,
+                                         unsigned int nbits)
+{
+       return -ENOSYS;
+}
+
 static inline int of_machine_is_compatible(const char *compat)
 {
        return 0;
index 406edae44ca3070151c36ed04a72c7dda2e24305..047fa67d039bedfc505f1c4be4574beb2db58ca5 100644 (file)
@@ -144,6 +144,8 @@ struct uart_port {
        void                    (*handle_break)(struct uart_port *);
        int                     (*rs485_config)(struct uart_port *,
                                                struct serial_rs485 *rs485);
+       int                     (*iso7816_config)(struct uart_port *,
+                                                 struct serial_iso7816 *iso7816);
        unsigned int            irq;                    /* irq number */
        unsigned long           irqflags;               /* irq flags  */
        unsigned int            uartclk;                /* base uart clock */
@@ -260,6 +262,7 @@ struct uart_port {
        struct attribute_group  *attr_group;            /* port specific attributes */
        const struct attribute_group **tty_groups;      /* all attributes (serial core use only) */
        struct serial_rs485     rs485;
+       struct serial_iso7816   iso7816;
        void                    *private_data;          /* generic platform data pointer */
 };
 
index 040651735662983693d51f5645f311f128fe63f4..cdc9f4ca8c27504d7058903a2f8fc4de877a82bd 100644 (file)
@@ -79,6 +79,8 @@
 #define TIOCGPTLCK     _IOR('T', 0x39, int) /* Get Pty lock state */
 #define TIOCGEXCL      _IOR('T', 0x40, int) /* Get exclusive mode state */
 #define TIOCGPTPEER    _IO('T', 0x41) /* Safely open the slave */
+#define TIOCGISO7816   _IOR('T', 0x42, struct serial_iso7816)
+#define TIOCSISO7816   _IOWR('T', 0x43, struct serial_iso7816)
 
 #define FIONCLEX       0x5450
 #define FIOCLEX                0x5451
index 3fdd0dee8b41bb053c02b8b1ece649e386e7fb95..93eb3c496ff1e85a6af59c539596775c4c9bf35e 100644 (file)
@@ -132,4 +132,21 @@ struct serial_rs485 {
                                           are a royal PITA .. */
 };
 
+/*
+ * Serial interface for controlling ISO7816 settings on chips with suitable
+ * support. Set with TIOCSISO7816 and get with TIOCGISO7816 if supported by
+ * your platform.
+ */
+struct serial_iso7816 {
+       __u32   flags;                  /* ISO7816 feature flags */
+#define SER_ISO7816_ENABLED            (1 << 0)
+#define SER_ISO7816_T_PARAM            (0x0f << 4)
+#define SER_ISO7816_T(t)               (((t) & 0x0f) << 4)
+       __u32   tg;
+       __u32   sc_fi;
+       __u32   sc_di;
+       __u32   clk;
+       __u32   reserved[5];
+};
+
 #endif /* _UAPI_LINUX_SERIAL_H */