]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
serial: 8250_pci: add support for Fintek 4, 8, and 12 port cards
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 17 Oct 2013 17:44:26 +0000 (10:44 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 17 Oct 2013 20:21:59 +0000 (13:21 -0700)
This adds support for Fintek's 4, 8, and 12 port PCIE serial cards.

Thanks to Fintek for the sample devices, and the spec needed in order to
implement this.

Cc: Amanda Ying <amanda_ying@fintek.com.tw>
Cc: Felix Shih <felix_shih@fintek.com.tw>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/8250/8250_pci.c

index 0774c02d6c49c63e0dce358f440e8bbda19aaacf..4ea45c15388cc8148cf9e5b5773f909962b28e4c 100644 (file)
@@ -1457,6 +1457,71 @@ pci_brcm_trumanage_setup(struct serial_private *priv,
        return ret;
 }
 
+static int pci_fintek_setup(struct serial_private *priv,
+                           const struct pciserial_board *board,
+                           struct uart_8250_port *port, int idx)
+{
+       struct pci_dev *pdev = priv->dev;
+       unsigned long base;
+       unsigned long iobase;
+       unsigned long ciobase = 0;
+       u8 config_base;
+
+       /*
+        * We are supposed to be able to read these from the PCI config space,
+        * but the values there don't seem to match what we need to use, so
+        * just use these hard-coded values for now, as they are correct.
+        */
+       switch (idx) {
+       case 0: iobase = 0xe000; config_base = 0x40; break;
+       case 1: iobase = 0xe008; config_base = 0x48; break;
+       case 2: iobase = 0xe010; config_base = 0x50; break;
+       case 3: iobase = 0xe018; config_base = 0x58; break;
+       case 4: iobase = 0xe020; config_base = 0x60; break;
+       case 5: iobase = 0xe028; config_base = 0x68; break;
+       case 6: iobase = 0xe030; config_base = 0x70; break;
+       case 7: iobase = 0xe038; config_base = 0x78; break;
+       case 8: iobase = 0xe040; config_base = 0x80; break;
+       case 9: iobase = 0xe048; config_base = 0x88; break;
+       case 10: iobase = 0xe050; config_base = 0x90; break;
+       case 11: iobase = 0xe058; config_base = 0x98; break;
+       default:
+               /* Unknown number of ports, get out of here */
+               return -EINVAL;
+       }
+
+       if (idx < 4) {
+               base = pci_resource_start(priv->dev, 3);
+               ciobase = (int)(base + (0x8 * idx));
+       }
+
+       dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%lx ciobase=0x%lx config_base=0x%2x\n",
+               __func__, idx, iobase, ciobase, config_base);
+
+       /* Enable UART I/O port */
+       pci_write_config_byte(pdev, config_base + 0x00, 0x01);
+
+       /* Select 128-byte FIFO and 8x FIFO threshold */
+       pci_write_config_byte(pdev, config_base + 0x01, 0x33);
+
+       /* LSB UART */
+       pci_write_config_byte(pdev, config_base + 0x04, (u8)(iobase & 0xff));
+
+       /* MSB UART */
+       pci_write_config_byte(pdev, config_base + 0x05, (u8)((iobase & 0xff00) >> 8));
+
+       /* irq number, this usually fails, but the spec says to do it anyway. */
+       pci_write_config_byte(pdev, config_base + 0x06, pdev->irq);
+
+       port->port.iotype = UPIO_PORT;
+       port->port.iobase = iobase;
+       port->port.mapbase = 0;
+       port->port.membase = NULL;
+       port->port.regshift = 0;
+
+       return 0;
+}
+
 static int skip_tx_en_setup(struct serial_private *priv,
                        const struct pciserial_board *board,
                        struct uart_8250_port *port, int idx)
@@ -2380,6 +2445,27 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
                .subdevice      = PCI_ANY_ID,
                .setup          = pci_brcm_trumanage_setup,
        },
+       {
+               .vendor         = 0x1c29,
+               .device         = 0x1104,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = pci_fintek_setup,
+       },
+       {
+               .vendor         = 0x1c29,
+               .device         = 0x1108,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = pci_fintek_setup,
+       },
+       {
+               .vendor         = 0x1c29,
+               .device         = 0x1112,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = pci_fintek_setup,
+       },
 
        /*
         * Default "match everything" terminator entry
@@ -2578,6 +2664,9 @@ enum pci_board_num_t {
        pbn_omegapci,
        pbn_NETMOS9900_2s_115200,
        pbn_brcm_trumanage,
+       pbn_fintek_4,
+       pbn_fintek_8,
+       pbn_fintek_12,
 };
 
 /*
@@ -3335,6 +3424,24 @@ static struct pciserial_board pci_boards[] = {
                .reg_shift      = 2,
                .base_baud      = 115200,
        },
+       [pbn_fintek_4] = {
+               .num_ports      = 4,
+               .uart_offset    = 8,
+               .base_baud      = 115200,
+               .first_offset   = 0x40,
+       },
+       [pbn_fintek_8] = {
+               .num_ports      = 8,
+               .uart_offset    = 8,
+               .base_baud      = 115200,
+               .first_offset   = 0x40,
+       },
+       [pbn_fintek_12] = {
+               .num_ports      = 12,
+               .uart_offset    = 8,
+               .base_baud      = 115200,
+               .first_offset   = 0x40,
+       },
 };
 
 static const struct pci_device_id blacklist[] = {
@@ -5059,6 +5166,11 @@ static struct pci_device_id serial_pci_tbl[] = {
                0,
                0, pbn_exar_XR17V358 },
 
+       /* Fintek PCI serial cards */
+       { PCI_DEVICE(0x1c29, 0x1104), .driver_data = pbn_fintek_4 },
+       { PCI_DEVICE(0x1c29, 0x1108), .driver_data = pbn_fintek_8 },
+       { PCI_DEVICE(0x1c29, 0x1112), .driver_data = pbn_fintek_12 },
+
        /*
         * These entries match devices with class COMMUNICATION_SERIAL,
         * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL