diff options
Diffstat (limited to 'drivers/tty/serial/8250/8250_pci.c')
-rw-r--r-- | drivers/tty/serial/8250/8250_pci.c | 97 |
1 files changed, 79 insertions, 18 deletions
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index df41397de478..7ba1c3b2381d 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1326,7 +1326,36 @@ static int pci_default_setup(struct serial_private *priv, return setup_port(priv, port, bar, offset, board->reg_shift); } - +void +pericom_do_set_divisor(struct uart_port *port, unsigned int baud, + unsigned int quot, unsigned int quot_frac) +{ + int scr; + int lcr; + int actual_baud; + int tolerance; + + for (scr = 5 ; scr <= 15 ; scr++) { + actual_baud = 921600 * 16 / scr; + tolerance = actual_baud / 50; + + if ((baud < actual_baud + tolerance) && + (baud > actual_baud - tolerance)) { + + lcr = serial_port_in(port, UART_LCR); + serial_port_out(port, UART_LCR, lcr | 0x80); + + serial_port_out(port, UART_DLL, 1); + serial_port_out(port, UART_DLM, 0); + serial_port_out(port, 2, 16 - scr); + serial_port_out(port, UART_LCR, lcr); + return; + } else if (baud > actual_baud) { + break; + } + } + serial8250_do_set_divisor(port, baud, quot, quot_frac); +} static int pci_pericom_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) @@ -1339,6 +1368,30 @@ static int pci_pericom_setup(struct serial_private *priv, else offset += idx * board->uart_offset; + + maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >> + (board->reg_shift + 3); + + if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr) + return 1; + + port->port.set_divisor = pericom_do_set_divisor; + + return setup_port(priv, port, bar, offset, board->reg_shift); +} + +static int pci_pericom_setup_four_at_eight(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) +{ + unsigned int bar, offset = board->first_offset, maxnr; + + bar = FL_GET_BASE(board->flags); + if (board->flags & FL_BASE_BARS) + bar += idx; + else + offset += idx * board->uart_offset; + if (idx==3) offset = 0x38; @@ -1348,6 +1401,8 @@ static int pci_pericom_setup(struct serial_private *priv, if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr) return 1; + port->port.set_divisor = pericom_do_set_divisor; + return setup_port(priv, port, bar, offset, board->reg_shift); } @@ -1995,7 +2050,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .device = PCI_DEVICE_ID_PERICOM_PI7C9X7954, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup, + .setup = pci_pericom_setup_four_at_eight, }, /* * PLX @@ -2032,107 +2087,113 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup, + .setup = pci_pericom_setup_four_at_eight, }, { .vendor = PCI_VENDOR_ID_ACCESIO, .device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4S, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup, + .setup = pci_pericom_setup_four_at_eight, }, { .vendor = PCI_VENDOR_ID_ACCESIO, .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup, + .setup = pci_pericom_setup_four_at_eight, }, { .vendor = PCI_VENDOR_ID_ACCESIO, .device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_4, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup, + .setup = pci_pericom_setup_four_at_eight, }, { .vendor = PCI_VENDOR_ID_ACCESIO, .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup, + .setup = pci_pericom_setup_four_at_eight, }, { .vendor = PCI_VENDOR_ID_ACCESIO, .device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4SM, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup, + .setup = pci_pericom_setup_four_at_eight, }, { .vendor = PCI_VENDOR_ID_ACCESIO, .device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup, + .setup = pci_pericom_setup_four_at_eight, }, { .vendor = PCI_VENDOR_ID_ACCESIO, .device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_4, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup, + .setup = pci_pericom_setup_four_at_eight, }, { .vendor = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S, .device = PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup, + .setup = pci_pericom_setup_four_at_eight, }, { .vendor = PCI_VENDOR_ID_ACCESIO, .device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup, + .setup = pci_pericom_setup_four_at_eight, }, { .vendor = PCI_VENDOR_ID_ACCESIO, .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup, + .setup = pci_pericom_setup_four_at_eight, }, { .vendor = PCI_VENDOR_ID_ACCESIO, .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup, + .setup = pci_pericom_setup_four_at_eight, }, { .vendor = PCI_VENDOR_ID_ACCESIO, .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup, + .setup = pci_pericom_setup_four_at_eight, }, { .vendor = PCI_VENDOR_ID_ACCESIO, .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup, + .setup = pci_pericom_setup_four_at_eight, }, { .vendor = PCI_VENDOR_ID_ACCESIO, .device = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup, + .setup = pci_pericom_setup_four_at_eight, }, - /* + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, /* * SBS Technologies, Inc., PMC-OCTALPRO 232 */ { |