History

Serial: Add support for new devices: Exar's XR17V35x family of multi-port PCIe UARTs

Add support for new devices: Exar's XR17V35x family of multi-port PCIe UARTs.

Matt Schulte committed 13 years ago

Commit dc96efb1 parent ae8d8a15 files · +178 −1Browse files

Unified · Split

5 files
  1. drivers/tty/serial/8250/8250.c +71 −0
  2. drivers/tty/serial/8250/8250_pci.c +96 −0
  3. include/linux/pci_ids.h +3 −0
  4. include/uapi/linux/serial_core.h +2 −1
  5. include/uapi/linux/serial_reg.h +6 −0
drivers/tty/serial/8250/8250.c+71−0
@@ -282,6 +282,15 @@ static const struct serial8250_config uart_config[] = { · 281 unmodified lines
282282 .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
283283 .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR,
284284 },
285+ [PORT_XR17V35X] = {
286+ .name = "XR17V35X",
287+ .fifo_size = 256,
288+ .tx_loadsz = 256,
289+ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11 |
290+ UART_FCR_T_TRIG_11,
291+ .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR |
292+ UART_CAP_SLEEP,
293+ },
285294 [PORT_LPC3220] = {
286295 .name = "LPC3220",
287296 .fifo_size = 64,
@@ -455,6 +464,7 @@ static void io_serial_out(struct uart_port *p, int offset, int value) · 167 unmodified lines
455464 }
456465
457466 static int serial8250_default_handle_irq(struct uart_port *port);
467+static int exar_handle_irq(struct uart_port *port);
458468
459469 static void set_io_from_upio(struct uart_port *p)
460470 {
@@ -574,6 +584,18 @@ EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos); · 113 unmodified lines
574584 */
575585 static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
576586 {
587+ /*
588+ * Exar UARTs have a SLEEP register that enables or disables
589+ * each UART to enter sleep mode separately. On the XR17V35x the
590+ * register is accessible to each UART at the UART_EXAR_SLEEP
591+ * offset but the UART channel may only write to the corresponding
592+ * bit.
593+ */
594+ if (p->port.type == PORT_XR17V35X) {
595+ serial_out(p, UART_EXAR_SLEEP, 0xff);
596+ return;
597+ }
598+
577599 if (p->capabilities & UART_CAP_SLEEP) {
578600 if (p->capabilities & UART_CAP_EFR) {
579601 serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B);
@@ -881,6 +903,27 @@ static void autoconfig_16550a(struct uart_8250_port *up) · 301 unmodified lines
881903 up->port.type = PORT_16550A;
882904 up->capabilities |= UART_CAP_FIFO;
883905
906+ /*
907+ * XR17V35x UARTs have an extra divisor register, DLD
908+ * that gets enabled with when DLAB is set which will
909+ * cause the device to incorrectly match and assign
910+ * port type to PORT_16650. The EFR for this UART is
911+ * found at offset 0x09. Instead check the Deice ID (DVID)
912+ * register for a 2, 4 or 8 port UART.
913+ */
914+ status1 = serial_in(up, UART_EXAR_DVID);
915+ if (status1 == 0x82 || status1 == 0x84 || status1 == 0x88) {
916+ if (up->port.flags & UPF_EXAR_EFR) {
917+ DEBUG_AUTOCONF("Exar XR17V35x ");
918+ up->port.type = PORT_XR17V35X;
919+ up->capabilities |= UART_CAP_AFE | UART_CAP_EFR |
920+ UART_CAP_SLEEP;
921+
922+ return;
923+ }
924+
925+ }
926+
884927 /*
885928 * Check for presence of the EFR when DLAB is set.
886929 * Only ST16C650V1 UARTs pass this test.
@@ -1515,6 +1558,30 @@ static int serial8250_default_handle_irq(struct uart_port *port) · 628 unmodified lines
15151558 return serial8250_handle_irq(port, iir);
15161559 }
15171560
1561+/*
1562+ * These Exar UARTs have an extra interrupt indicator that could
1563+ * fire for a few unimplemented interrupts. One of which is a
1564+ * wakeup event when coming out of sleep. Put this here just
1565+ * to be on the safe side that these interrupts don't go unhandled.
1566+ */
1567+static int exar_handle_irq(struct uart_port *port)
1568+{
1569+ unsigned char int0, int1, int2, int3;
1570+ unsigned int iir = serial_port_in(port, UART_IIR);
1571+ int ret;
1572+
1573+ ret = serial8250_handle_irq(port, iir);
1574+
1575+ if (port->type == PORT_XR17V35X) {
1576+ int0 = serial_port_in(port, 0x80);
1577+ int1 = serial_port_in(port, 0x81);
1578+ int2 = serial_port_in(port, 0x82);
1579+ int3 = serial_port_in(port, 0x83);
1580+ }
1581+
1582+ return ret;
1583+}
1584+
15181585 /*
15191586 * This is the serial driver's interrupt routine.
15201587 *
@@ -2614,6 +2681,10 @@ static void serial8250_config_port(struct uart_port *port, int flags) · 1093 unmodified lines
26142681 serial8250_release_rsa_resource(up);
26152682 if (port->type == PORT_UNKNOWN)
26162683 serial8250_release_std_resource(up);
2684+
2685+ /* Fixme: probably not the best place for this */
2686+ if (port->type == PORT_XR17V35X)
2687+ port->handle_irq = exar_handle_irq;
26172688 }
26182689
26192690 static int
drivers/tty/serial/8250/8250_pci.c+96−0
@@ -1164,6 +1164,39 @@ pci_xr17c154_setup(struct serial_private *priv, · 1163 unmodified lines
11641164 return pci_default_setup(priv, board, port, idx);
11651165 }
11661166
1167+static int
1168+pci_xr17v35x_setup(struct serial_private *priv,
1169+ const struct pciserial_board *board,
1170+ struct uart_8250_port *port, int idx)
1171+{
1172+ u8 __iomem *p;
1173+
1174+ p = pci_ioremap_bar(priv->dev, 0);
1175+
1176+ port->port.flags |= UPF_EXAR_EFR;
1177+
1178+ /*
1179+ * Setup Multipurpose Input/Output pins.
1180+ */
1181+ if (idx == 0) {
1182+ writeb(0x00, p + 0x8f); /*MPIOINT[7:0]*/
1183+ writeb(0x00, p + 0x90); /*MPIOLVL[7:0]*/
1184+ writeb(0x00, p + 0x91); /*MPIO3T[7:0]*/
1185+ writeb(0x00, p + 0x92); /*MPIOINV[7:0]*/
1186+ writeb(0x00, p + 0x93); /*MPIOSEL[7:0]*/
1187+ writeb(0x00, p + 0x94); /*MPIOOD[7:0]*/
1188+ writeb(0x00, p + 0x95); /*MPIOINT[15:8]*/
1189+ writeb(0x00, p + 0x96); /*MPIOLVL[15:8]*/
1190+ writeb(0x00, p + 0x97); /*MPIO3T[15:8]*/
1191+ writeb(0x00, p + 0x98); /*MPIOINV[15:8]*/
1192+ writeb(0x00, p + 0x99); /*MPIOSEL[15:8]*/
1193+ writeb(0x00, p + 0x9a); /*MPIOOD[15:8]*/
1194+ }
1195+ iounmap(p);
1196+
1197+ return pci_default_setup(priv, board, port, idx);
1198+}
1199+
11671200 static int
11681201 pci_wch_ch353_setup(struct serial_private *priv,
11691202 const struct pciserial_board *board,
@@ -1622,6 +1655,27 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { · 452 unmodified lines
16221655 .subdevice = PCI_ANY_ID,
16231656 .setup = pci_xr17c154_setup,
16241657 },
1658+ {
1659+ .vendor = PCI_VENDOR_ID_EXAR,
1660+ .device = PCI_DEVICE_ID_EXAR_XR17V352,
1661+ .subvendor = PCI_ANY_ID,
1662+ .subdevice = PCI_ANY_ID,
1663+ .setup = pci_xr17v35x_setup,
1664+ },
1665+ {
1666+ .vendor = PCI_VENDOR_ID_EXAR,
1667+ .device = PCI_DEVICE_ID_EXAR_XR17V354,
1668+ .subvendor = PCI_ANY_ID,
1669+ .subdevice = PCI_ANY_ID,
1670+ .setup = pci_xr17v35x_setup,
1671+ },
1672+ {
1673+ .vendor = PCI_VENDOR_ID_EXAR,
1674+ .device = PCI_DEVICE_ID_EXAR_XR17V358,
1675+ .subvendor = PCI_ANY_ID,
1676+ .subdevice = PCI_ANY_ID,
1677+ .setup = pci_xr17v35x_setup,
1678+ },
16251679 /*
16261680 * Xircom cards
16271681 */
@@ -1962,6 +2016,9 @@ enum pci_board_num_t { · 334 unmodified lines
19622016 pbn_exar_XR17C152,
19632017 pbn_exar_XR17C154,
19642018 pbn_exar_XR17C158,
2019+ pbn_exar_XR17V352,
2020+ pbn_exar_XR17V354,
2021+ pbn_exar_XR17V358,
19652022 pbn_exar_ibm_saturn,
19662023 pbn_pasemi_1682M,
19672024 pbn_ni8430_2,
@@ -2580,6 +2637,30 @@ static struct pciserial_board pci_boards[] = { · 612 unmodified lines
25802637 .base_baud = 921600,
25812638 .uart_offset = 0x200,
25822639 },
2640+ [pbn_exar_XR17V352] = {
2641+ .flags = FL_BASE0,
2642+ .num_ports = 2,
2643+ .base_baud = 7812500,
2644+ .uart_offset = 0x400,
2645+ .reg_shift = 0,
2646+ .first_offset = 0,
2647+ },
2648+ [pbn_exar_XR17V354] = {
2649+ .flags = FL_BASE0,
2650+ .num_ports = 4,
2651+ .base_baud = 7812500,
2652+ .uart_offset = 0x400,
2653+ .reg_shift = 0,
2654+ .first_offset = 0,
2655+ },
2656+ [pbn_exar_XR17V358] = {
2657+ .flags = FL_BASE0,
2658+ .num_ports = 8,
2659+ .base_baud = 7812500,
2660+ .uart_offset = 0x400,
2661+ .reg_shift = 0,
2662+ .first_offset = 0,
2663+ },
25832664 [pbn_exar_ibm_saturn] = {
25842665 .flags = FL_BASE0,
25852666 .num_ports = 1,
@@ -3826,6 +3907,21 @@ static struct pci_device_id serial_pci_tbl[] = { · 1240 unmodified lines
38263907 PCI_ANY_ID, PCI_ANY_ID,
38273908 0,
38283909 0, pbn_exar_XR17C158 },
3910+ /*
3911+ * Exar Corp. XR17V35[248] Dual/Quad/Octal PCIe UARTs
3912+ */
3913+ { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V352,
3914+ PCI_ANY_ID, PCI_ANY_ID,
3915+ 0,
3916+ 0, pbn_exar_XR17V352 },
3917+ { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V354,
3918+ PCI_ANY_ID, PCI_ANY_ID,
3919+ 0,
3920+ 0, pbn_exar_XR17V354 },
3921+ { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V358,
3922+ PCI_ANY_ID, PCI_ANY_ID,
3923+ 0,
3924+ 0, pbn_exar_XR17V358 },
38293925
38303926 /*
38313927 * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke)
include/linux/pci_ids.h+3−0
@@ -1985,6 +1985,9 @@ · 1984 unmodified lines
19851985 #define PCI_DEVICE_ID_EXAR_XR17C152 0x0152
19861986 #define PCI_DEVICE_ID_EXAR_XR17C154 0x0154
19871987 #define PCI_DEVICE_ID_EXAR_XR17C158 0x0158
1988+#define PCI_DEVICE_ID_EXAR_XR17V352 0x0352
1989+#define PCI_DEVICE_ID_EXAR_XR17V354 0x0354
1990+#define PCI_DEVICE_ID_EXAR_XR17V358 0x0358
19881991
19891992 #define PCI_VENDOR_ID_MICROGATE 0x13c0
19901993 #define PCI_DEVICE_ID_MICROGATE_USC 0x0010
include/uapi/linux/serial_core.h+2−1
@@ -49,7 +49,8 @@ · 48 unmodified lines
4949 #define PORT_XR17D15X 21 /* Exar XR17D15x UART */
5050 #define PORT_LPC3220 22 /* NXP LPC32xx SoC "Standard" UART */
5151 #define PORT_8250_CIR 23 /* CIR infrared port, has its own driver */
52−#define PORT_MAX_8250 23 /* max port ID */
52+#define PORT_XR17V35X 24 /* Exar XR17V35x UARTs */
53+#define PORT_MAX_8250 24 /* max port ID */
5354
5455 /*
5556 * ARM specific type numbers. These are not currently guaranteed
include/uapi/linux/serial_reg.h+6−0
@@ -367,5 +367,11 @@ · 366 unmodified lines
367367 #define UART_OMAP_MDR1_CIR_MODE 0x06 /* CIR mode */
368368 #define UART_OMAP_MDR1_DISABLE 0x07 /* Disable (default state) */
369369
370+/*
371+ * These are definitions for the XR17V35X and XR17D15X
372+ */
373+#define UART_EXAR_SLEEP 0x8b /* Sleep mode */
374+#define UART_EXAR_DVID 0x8d /* Device identification */
375+
370376 #endif /* _LINUX_SERIAL_REG_H */
371377