diff options
author | Matt Schulte <matts@commtech-fastcom.com> | 2012-11-19 10:12:04 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-11-21 18:37:46 -0500 |
commit | dc96efb72054985c0912f831da009a2da4e9f6dd (patch) | |
tree | 15a27b27040eb43fa2ff161d536a593623211e97 | |
parent | ae8d8a146725a966bd7c59c94f4d0016dcf7a04f (diff) |
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.
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>
-rw-r--r-- | drivers/tty/serial/8250/8250.c | 71 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_pci.c | 96 | ||||
-rw-r--r-- | include/linux/pci_ids.h | 3 | ||||
-rw-r--r-- | include/uapi/linux/serial_core.h | 3 | ||||
-rw-r--r-- | include/uapi/linux/serial_reg.h | 6 |
5 files changed, 178 insertions, 1 deletions
diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c index 2af83a246499..3624df674a31 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250.c | |||
@@ -282,6 +282,15 @@ static const struct serial8250_config uart_config[] = { | |||
282 | .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, | 282 | .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, |
283 | .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR, | 283 | .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR, |
284 | }, | 284 | }, |
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 | }, | ||
285 | [PORT_LPC3220] = { | 294 | [PORT_LPC3220] = { |
286 | .name = "LPC3220", | 295 | .name = "LPC3220", |
287 | .fifo_size = 64, | 296 | .fifo_size = 64, |
@@ -455,6 +464,7 @@ static void io_serial_out(struct uart_port *p, int offset, int value) | |||
455 | } | 464 | } |
456 | 465 | ||
457 | static int serial8250_default_handle_irq(struct uart_port *port); | 466 | static int serial8250_default_handle_irq(struct uart_port *port); |
467 | static int exar_handle_irq(struct uart_port *port); | ||
458 | 468 | ||
459 | static void set_io_from_upio(struct uart_port *p) | 469 | static void set_io_from_upio(struct uart_port *p) |
460 | { | 470 | { |
@@ -574,6 +584,18 @@ EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos); | |||
574 | */ | 584 | */ |
575 | static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) | 585 | static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) |
576 | { | 586 | { |
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 | |||
577 | if (p->capabilities & UART_CAP_SLEEP) { | 599 | if (p->capabilities & UART_CAP_SLEEP) { |
578 | if (p->capabilities & UART_CAP_EFR) { | 600 | if (p->capabilities & UART_CAP_EFR) { |
579 | serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); | 601 | serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); |
@@ -882,6 +904,27 @@ static void autoconfig_16550a(struct uart_8250_port *up) | |||
882 | up->capabilities |= UART_CAP_FIFO; | 904 | up->capabilities |= UART_CAP_FIFO; |
883 | 905 | ||
884 | /* | 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 | |||
927 | /* | ||
885 | * Check for presence of the EFR when DLAB is set. | 928 | * Check for presence of the EFR when DLAB is set. |
886 | * Only ST16C650V1 UARTs pass this test. | 929 | * Only ST16C650V1 UARTs pass this test. |
887 | */ | 930 | */ |
@@ -1516,6 +1559,30 @@ static int serial8250_default_handle_irq(struct uart_port *port) | |||
1516 | } | 1559 | } |
1517 | 1560 | ||
1518 | /* | 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 | |||
1585 | /* | ||
1519 | * This is the serial driver's interrupt routine. | 1586 | * This is the serial driver's interrupt routine. |
1520 | * | 1587 | * |
1521 | * Arjan thinks the old way was overly complex, so it got simplified. | 1588 | * Arjan thinks the old way was overly complex, so it got simplified. |
@@ -2614,6 +2681,10 @@ static void serial8250_config_port(struct uart_port *port, int flags) | |||
2614 | serial8250_release_rsa_resource(up); | 2681 | serial8250_release_rsa_resource(up); |
2615 | if (port->type == PORT_UNKNOWN) | 2682 | if (port->type == PORT_UNKNOWN) |
2616 | serial8250_release_std_resource(up); | 2683 | 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; | ||
2617 | } | 2688 | } |
2618 | 2689 | ||
2619 | static int | 2690 | static int |
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 97058c1d7d45..2285d3283b3b 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c | |||
@@ -1165,6 +1165,39 @@ pci_xr17c154_setup(struct serial_private *priv, | |||
1165 | } | 1165 | } |
1166 | 1166 | ||
1167 | static int | 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 | |||
1200 | static int | ||
1168 | pci_wch_ch353_setup(struct serial_private *priv, | 1201 | pci_wch_ch353_setup(struct serial_private *priv, |
1169 | const struct pciserial_board *board, | 1202 | const struct pciserial_board *board, |
1170 | struct uart_8250_port *port, int idx) | 1203 | struct uart_8250_port *port, int idx) |
@@ -1622,6 +1655,27 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { | |||
1622 | .subdevice = PCI_ANY_ID, | 1655 | .subdevice = PCI_ANY_ID, |
1623 | .setup = pci_xr17c154_setup, | 1656 | .setup = pci_xr17c154_setup, |
1624 | }, | 1657 | }, |
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 | }, | ||
1625 | /* | 1679 | /* |
1626 | * Xircom cards | 1680 | * Xircom cards |
1627 | */ | 1681 | */ |
@@ -1962,6 +2016,9 @@ enum pci_board_num_t { | |||
1962 | pbn_exar_XR17C152, | 2016 | pbn_exar_XR17C152, |
1963 | pbn_exar_XR17C154, | 2017 | pbn_exar_XR17C154, |
1964 | pbn_exar_XR17C158, | 2018 | pbn_exar_XR17C158, |
2019 | pbn_exar_XR17V352, | ||
2020 | pbn_exar_XR17V354, | ||
2021 | pbn_exar_XR17V358, | ||
1965 | pbn_exar_ibm_saturn, | 2022 | pbn_exar_ibm_saturn, |
1966 | pbn_pasemi_1682M, | 2023 | pbn_pasemi_1682M, |
1967 | pbn_ni8430_2, | 2024 | pbn_ni8430_2, |
@@ -2580,6 +2637,30 @@ static struct pciserial_board pci_boards[] = { | |||
2580 | .base_baud = 921600, | 2637 | .base_baud = 921600, |
2581 | .uart_offset = 0x200, | 2638 | .uart_offset = 0x200, |
2582 | }, | 2639 | }, |
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 | }, | ||
2583 | [pbn_exar_ibm_saturn] = { | 2664 | [pbn_exar_ibm_saturn] = { |
2584 | .flags = FL_BASE0, | 2665 | .flags = FL_BASE0, |
2585 | .num_ports = 1, | 2666 | .num_ports = 1, |
@@ -3826,6 +3907,21 @@ static struct pci_device_id serial_pci_tbl[] = { | |||
3826 | PCI_ANY_ID, PCI_ANY_ID, | 3907 | PCI_ANY_ID, PCI_ANY_ID, |
3827 | 0, | 3908 | 0, |
3828 | 0, pbn_exar_XR17C158 }, | 3909 | 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 }, | ||
3829 | 3925 | ||
3830 | /* | 3926 | /* |
3831 | * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke) | 3927 | * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke) |
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 9d36b829533a..0199a7a76fcb 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h | |||
@@ -1985,6 +1985,9 @@ | |||
1985 | #define PCI_DEVICE_ID_EXAR_XR17C152 0x0152 | 1985 | #define PCI_DEVICE_ID_EXAR_XR17C152 0x0152 |
1986 | #define PCI_DEVICE_ID_EXAR_XR17C154 0x0154 | 1986 | #define PCI_DEVICE_ID_EXAR_XR17C154 0x0154 |
1987 | #define PCI_DEVICE_ID_EXAR_XR17C158 0x0158 | 1987 | #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 | ||
1988 | 1991 | ||
1989 | #define PCI_VENDOR_ID_MICROGATE 0x13c0 | 1992 | #define PCI_VENDOR_ID_MICROGATE 0x13c0 |
1990 | #define PCI_DEVICE_ID_MICROGATE_USC 0x0010 | 1993 | #define PCI_DEVICE_ID_MICROGATE_USC 0x0010 |
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h index ebcc73f0418a..78f99d97475b 100644 --- a/include/uapi/linux/serial_core.h +++ b/include/uapi/linux/serial_core.h | |||
@@ -49,7 +49,8 @@ | |||
49 | #define PORT_XR17D15X 21 /* Exar XR17D15x UART */ | 49 | #define PORT_XR17D15X 21 /* Exar XR17D15x UART */ |
50 | #define PORT_LPC3220 22 /* NXP LPC32xx SoC "Standard" UART */ | 50 | #define PORT_LPC3220 22 /* NXP LPC32xx SoC "Standard" UART */ |
51 | #define PORT_8250_CIR 23 /* CIR infrared port, has its own driver */ | 51 | #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 */ | ||
53 | 54 | ||
54 | /* | 55 | /* |
55 | * ARM specific type numbers. These are not currently guaranteed | 56 | * ARM specific type numbers. These are not currently guaranteed |
diff --git a/include/uapi/linux/serial_reg.h b/include/uapi/linux/serial_reg.h index 5ed325e88a81..d0b47607b90b 100644 --- a/include/uapi/linux/serial_reg.h +++ b/include/uapi/linux/serial_reg.h | |||
@@ -367,5 +367,11 @@ | |||
367 | #define UART_OMAP_MDR1_CIR_MODE 0x06 /* CIR mode */ | 367 | #define UART_OMAP_MDR1_CIR_MODE 0x06 /* CIR mode */ |
368 | #define UART_OMAP_MDR1_DISABLE 0x07 /* Disable (default state) */ | 368 | #define UART_OMAP_MDR1_DISABLE 0x07 /* Disable (default state) */ |
369 | 369 | ||
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 | |||
370 | #endif /* _LINUX_SERIAL_REG_H */ | 376 | #endif /* _LINUX_SERIAL_REG_H */ |
371 | 377 | ||