]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Serial: Add support for new devices: Exar's XR17V35x family of multi-port PCIe UARTs
authorMatt Schulte <matts@commtech-fastcom.com>
Mon, 19 Nov 2012 15:12:04 +0000 (09:12 -0600)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 21 Nov 2012 23:37:46 +0000 (15:37 -0800)
Add support for new devices: Exar's XR17V35x family of multi-port PCIe UARTs.

Signed-off-by: Matt Schulte <matts@commtech-fastcom.com>
Acked-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/8250/8250.c
drivers/tty/serial/8250/8250_pci.c
include/linux/pci_ids.h
include/uapi/linux/serial_core.h
include/uapi/linux/serial_reg.h

index 2af83a246499c61c3ec323d40253b76fa04b4e7a..3624df674a31125381079f132e23e6bebda72a35 100644 (file)
@@ -282,6 +282,15 @@ static const struct serial8250_config uart_config[] = {
                .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
                .flags          = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR,
        },
+       [PORT_XR17V35X] = {
+               .name           = "XR17V35X",
+               .fifo_size      = 256,
+               .tx_loadsz      = 256,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11 |
+                                 UART_FCR_T_TRIG_11,
+               .flags          = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR |
+                                 UART_CAP_SLEEP,
+       },
        [PORT_LPC3220] = {
                .name           = "LPC3220",
                .fifo_size      = 64,
@@ -455,6 +464,7 @@ static void io_serial_out(struct uart_port *p, int offset, int value)
 }
 
 static int serial8250_default_handle_irq(struct uart_port *port);
+static int exar_handle_irq(struct uart_port *port);
 
 static void set_io_from_upio(struct uart_port *p)
 {
@@ -574,6 +584,18 @@ EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos);
  */
 static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
 {
+       /*
+        * Exar UARTs have a SLEEP register that enables or disables
+        * each UART to enter sleep mode separately.  On the XR17V35x the
+        * register is accessible to each UART at the UART_EXAR_SLEEP
+        * offset but the UART channel may only write to the corresponding
+        * bit.
+        */
+       if (p->port.type == PORT_XR17V35X) {
+               serial_out(p, UART_EXAR_SLEEP, 0xff);
+               return;
+       }
+
        if (p->capabilities & UART_CAP_SLEEP) {
                if (p->capabilities & UART_CAP_EFR) {
                        serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B);
@@ -881,6 +903,27 @@ static void autoconfig_16550a(struct uart_8250_port *up)
        up->port.type = PORT_16550A;
        up->capabilities |= UART_CAP_FIFO;
 
+       /*
+        * XR17V35x UARTs have an extra divisor register, DLD
+        * that gets enabled with when DLAB is set which will
+        * cause the device to incorrectly match and assign
+        * port type to PORT_16650.  The EFR for this UART is
+        * found at offset 0x09. Instead check the Deice ID (DVID)
+        * register for a 2, 4 or 8 port UART.
+        */
+       status1 = serial_in(up, UART_EXAR_DVID);
+       if (status1 == 0x82 || status1 == 0x84 || status1 == 0x88) {
+               if (up->port.flags & UPF_EXAR_EFR) {
+                       DEBUG_AUTOCONF("Exar XR17V35x ");
+                       up->port.type = PORT_XR17V35X;
+                       up->capabilities |= UART_CAP_AFE | UART_CAP_EFR |
+                                               UART_CAP_SLEEP;
+
+                       return;
+               }
+
+       }
+
        /*
         * Check for presence of the EFR when DLAB is set.
         * Only ST16C650V1 UARTs pass this test.
@@ -1515,6 +1558,30 @@ static int serial8250_default_handle_irq(struct uart_port *port)
        return serial8250_handle_irq(port, iir);
 }
 
+/*
+ * These Exar UARTs have an extra interrupt indicator that could
+ * fire for a few unimplemented interrupts.  One of which is a
+ * wakeup event when coming out of sleep.  Put this here just
+ * to be on the safe side that these interrupts don't go unhandled.
+ */
+static int exar_handle_irq(struct uart_port *port)
+{
+       unsigned char int0, int1, int2, int3;
+       unsigned int iir = serial_port_in(port, UART_IIR);
+       int ret;
+
+       ret = serial8250_handle_irq(port, iir);
+
+       if (port->type == PORT_XR17V35X) {
+               int0 = serial_port_in(port, 0x80);
+               int1 = serial_port_in(port, 0x81);
+               int2 = serial_port_in(port, 0x82);
+               int3 = serial_port_in(port, 0x83);
+       }
+
+       return ret;
+}
+
 /*
  * This is the serial driver's interrupt routine.
  *
@@ -2614,6 +2681,10 @@ static void serial8250_config_port(struct uart_port *port, int flags)
                serial8250_release_rsa_resource(up);
        if (port->type == PORT_UNKNOWN)
                serial8250_release_std_resource(up);
+
+       /* Fixme: probably not the best place for this */
+       if (port->type == PORT_XR17V35X)
+               port->handle_irq = exar_handle_irq;
 }
 
 static int
index 97058c1d7d45c6f48add1c5ac30de3f87bf4f506..2285d3283b3be61a35cf5d88c147b90446216c3e 100644 (file)
@@ -1164,6 +1164,39 @@ pci_xr17c154_setup(struct serial_private *priv,
        return pci_default_setup(priv, board, port, idx);
 }
 
+static int
+pci_xr17v35x_setup(struct serial_private *priv,
+                 const struct pciserial_board *board,
+                 struct uart_8250_port *port, int idx)
+{
+       u8 __iomem *p;
+
+       p = pci_ioremap_bar(priv->dev, 0);
+
+       port->port.flags |= UPF_EXAR_EFR;
+
+       /*
+        * Setup Multipurpose Input/Output pins.
+        */
+       if (idx == 0) {
+               writeb(0x00, p + 0x8f); /*MPIOINT[7:0]*/
+               writeb(0x00, p + 0x90); /*MPIOLVL[7:0]*/
+               writeb(0x00, p + 0x91); /*MPIO3T[7:0]*/
+               writeb(0x00, p + 0x92); /*MPIOINV[7:0]*/
+               writeb(0x00, p + 0x93); /*MPIOSEL[7:0]*/
+               writeb(0x00, p + 0x94); /*MPIOOD[7:0]*/
+               writeb(0x00, p + 0x95); /*MPIOINT[15:8]*/
+               writeb(0x00, p + 0x96); /*MPIOLVL[15:8]*/
+               writeb(0x00, p + 0x97); /*MPIO3T[15:8]*/
+               writeb(0x00, p + 0x98); /*MPIOINV[15:8]*/
+               writeb(0x00, p + 0x99); /*MPIOSEL[15:8]*/
+               writeb(0x00, p + 0x9a); /*MPIOOD[15:8]*/
+       }
+       iounmap(p);
+
+       return pci_default_setup(priv, board, port, idx);
+}
+
 static int
 pci_wch_ch353_setup(struct serial_private *priv,
                     const struct pciserial_board *board,
@@ -1622,6 +1655,27 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
                .subdevice      = PCI_ANY_ID,
                .setup          = pci_xr17c154_setup,
        },
+       {
+               .vendor = PCI_VENDOR_ID_EXAR,
+               .device = PCI_DEVICE_ID_EXAR_XR17V352,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = pci_xr17v35x_setup,
+       },
+       {
+               .vendor = PCI_VENDOR_ID_EXAR,
+               .device = PCI_DEVICE_ID_EXAR_XR17V354,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = pci_xr17v35x_setup,
+       },
+       {
+               .vendor = PCI_VENDOR_ID_EXAR,
+               .device = PCI_DEVICE_ID_EXAR_XR17V358,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = pci_xr17v35x_setup,
+       },
        /*
         * Xircom cards
         */
@@ -1962,6 +2016,9 @@ enum pci_board_num_t {
        pbn_exar_XR17C152,
        pbn_exar_XR17C154,
        pbn_exar_XR17C158,
+       pbn_exar_XR17V352,
+       pbn_exar_XR17V354,
+       pbn_exar_XR17V358,
        pbn_exar_ibm_saturn,
        pbn_pasemi_1682M,
        pbn_ni8430_2,
@@ -2580,6 +2637,30 @@ static struct pciserial_board pci_boards[] = {
                .base_baud      = 921600,
                .uart_offset    = 0x200,
        },
+       [pbn_exar_XR17V352] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 2,
+               .base_baud      = 7812500,
+               .uart_offset    = 0x400,
+               .reg_shift      = 0,
+               .first_offset   = 0,
+       },
+       [pbn_exar_XR17V354] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 4,
+               .base_baud      = 7812500,
+               .uart_offset    = 0x400,
+               .reg_shift      = 0,
+               .first_offset   = 0,
+       },
+       [pbn_exar_XR17V358] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 8,
+               .base_baud      = 7812500,
+               .uart_offset    = 0x400,
+               .reg_shift      = 0,
+               .first_offset   = 0,
+       },
        [pbn_exar_ibm_saturn] = {
                .flags          = FL_BASE0,
                .num_ports      = 1,
@@ -3826,6 +3907,21 @@ static struct pci_device_id serial_pci_tbl[] = {
                PCI_ANY_ID, PCI_ANY_ID,
                0,
                0, pbn_exar_XR17C158 },
+       /*
+        * Exar Corp. XR17V35[248] Dual/Quad/Octal PCIe UARTs
+        */
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V352,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0,
+               0, pbn_exar_XR17V352 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V354,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0,
+               0, pbn_exar_XR17V354 },
+       {       PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V358,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0,
+               0, pbn_exar_XR17V358 },
 
        /*
         * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke)
index 9d36b829533a91f3a26e2bab08e7e0214f6b0e3c..0199a7a76fcb5cf5115e5969cc9acc56e8c0bb83 100644 (file)
 #define PCI_DEVICE_ID_EXAR_XR17C152    0x0152
 #define PCI_DEVICE_ID_EXAR_XR17C154    0x0154
 #define PCI_DEVICE_ID_EXAR_XR17C158    0x0158
+#define PCI_DEVICE_ID_EXAR_XR17V352    0x0352
+#define PCI_DEVICE_ID_EXAR_XR17V354    0x0354
+#define PCI_DEVICE_ID_EXAR_XR17V358    0x0358
 
 #define PCI_VENDOR_ID_MICROGATE                0x13c0
 #define PCI_DEVICE_ID_MICROGATE_USC    0x0010
index ebcc73f0418a35ad17b72b4c2b00fe707b6cc4ca..78f99d97475b50c8427607d9bd23a3457a27319a 100644 (file)
@@ -49,7 +49,8 @@
 #define PORT_XR17D15X  21      /* Exar XR17D15x UART */
 #define PORT_LPC3220   22      /* NXP LPC32xx SoC "Standard" UART */
 #define PORT_8250_CIR  23      /* CIR infrared port, has its own driver */
-#define PORT_MAX_8250  23      /* max port ID */
+#define PORT_XR17V35X  24      /* Exar XR17V35x UARTs */
+#define PORT_MAX_8250  24      /* max port ID */
 
 /*
  * ARM specific type numbers.  These are not currently guaranteed
index 5ed325e88a81feb7961cd84e0c82ca982df4520d..d0b47607b90bfdc72fbc5d5dcb932052b8b8e6fd 100644 (file)
 #define UART_OMAP_MDR1_CIR_MODE                0x06    /* CIR mode */
 #define UART_OMAP_MDR1_DISABLE         0x07    /* Disable (default state) */
 
+/*
+ * These are definitions for the XR17V35X and XR17D15X
+ */
+#define UART_EXAR_SLEEP                0x8b    /* Sleep mode */
+#define UART_EXAR_DVID         0x8d    /* Device identification */
+
 #endif /* _LINUX_SERIAL_REG_H */