LCOV - code coverage report
Current view: top level - tty/serial/8250 - 8250_pericom.c (source / functions) Coverage Total Hit
Test: TTY Combined Coverage Lines: 0.0 % 70 0
Test Date: 2025-08-26 15:45:50 Functions: 0.0 % 5 0

            Line data    Source code
       1              : // SPDX-License-Identifier: GPL-2.0
       2              : /* Driver for Pericom UART */
       3              : 
       4              : #include <linux/bits.h>
       5              : #include <linux/module.h>
       6              : #include <linux/overflow.h>
       7              : #include <linux/pci.h>
       8              : 
       9              : #include "8250.h"
      10              : 
      11              : #define PCI_DEVICE_ID_ACCESSIO_PCIE_COM_2SDB    0x1051
      12              : #define PCI_DEVICE_ID_ACCESSIO_MPCIE_COM_2S     0x1053
      13              : #define PCI_DEVICE_ID_ACCESSIO_PCIE_COM422_4    0x105a
      14              : #define PCI_DEVICE_ID_ACCESSIO_PCIE_COM485_4    0x105b
      15              : #define PCI_DEVICE_ID_ACCESSIO_PCIE_COM_4SDB    0x105c
      16              : #define PCI_DEVICE_ID_ACCESSIO_MPCIE_COM_4S     0x105e
      17              : #define PCI_DEVICE_ID_ACCESSIO_PCIE_COM422_8    0x106a
      18              : #define PCI_DEVICE_ID_ACCESSIO_PCIE_COM485_8    0x106b
      19              : #define PCI_DEVICE_ID_ACCESSIO_PCIE_COM232_2DB  0x1091
      20              : #define PCI_DEVICE_ID_ACCESSIO_MPCIE_COM232_2   0x1093
      21              : #define PCI_DEVICE_ID_ACCESSIO_PCIE_COM232_4    0x1098
      22              : #define PCI_DEVICE_ID_ACCESSIO_PCIE_COM232_4DB  0x1099
      23              : #define PCI_DEVICE_ID_ACCESSIO_MPCIE_COM232_4   0x109b
      24              : #define PCI_DEVICE_ID_ACCESSIO_PCIE_COM232_8    0x10a9
      25              : #define PCI_DEVICE_ID_ACCESSIO_PCIE_COM_2SMDB   0x10d1
      26              : #define PCI_DEVICE_ID_ACCESSIO_MPCIE_COM_2SM    0x10d3
      27              : #define PCI_DEVICE_ID_ACCESSIO_PCIE_COM_4SM     0x10d9
      28              : #define PCI_DEVICE_ID_ACCESSIO_PCIE_COM_4SMDB   0x10da
      29              : #define PCI_DEVICE_ID_ACCESSIO_MPCIE_COM_4SM    0x10dc
      30              : #define PCI_DEVICE_ID_ACCESSIO_PCIE_COM_8SM     0x10e9
      31              : #define PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM485_1   0x1108
      32              : #define PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM422_2   0x1110
      33              : #define PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM485_2   0x1111
      34              : #define PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM422_4   0x1118
      35              : #define PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM485_4   0x1119
      36              : #define PCI_DEVICE_ID_ACCESSIO_PCIE_ICM_2S      0x1152
      37              : #define PCI_DEVICE_ID_ACCESSIO_PCIE_ICM_4S      0x115a
      38              : #define PCI_DEVICE_ID_ACCESSIO_PCIE_ICM232_2    0x1190
      39              : #define PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM232_2   0x1191
      40              : #define PCI_DEVICE_ID_ACCESSIO_PCIE_ICM232_4    0x1198
      41              : #define PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM232_4   0x1199
      42              : #define PCI_DEVICE_ID_ACCESSIO_PCIE_ICM_2SM     0x11d0
      43              : #define PCI_DEVICE_ID_ACCESSIO_PCIE_ICM_4SM     0x11d8
      44              : 
      45              : struct pericom8250 {
      46              :         void __iomem *virt;
      47              :         unsigned int nr;
      48              :         int line[];
      49              : };
      50              : 
      51            0 : static void pericom_do_set_divisor(struct uart_port *port, unsigned int baud,
      52              :                                    unsigned int quot, unsigned int quot_frac)
      53              : {
      54            0 :         int scr;
      55              : 
      56            0 :         for (scr = 16; scr > 4; scr--) {
      57            0 :                 unsigned int maxrate = port->uartclk / scr;
      58            0 :                 unsigned int divisor = max(maxrate / baud, 1U);
      59            0 :                 int delta = maxrate / divisor - baud;
      60              : 
      61            0 :                 if (baud > maxrate + baud / 50)
      62            0 :                         continue;
      63              : 
      64            0 :                 if (delta > baud / 50)
      65            0 :                         divisor++;
      66              : 
      67            0 :                 if (divisor > 0xffff)
      68            0 :                         continue;
      69              : 
      70              :                 /* Update delta due to possible divisor change */
      71            0 :                 delta = maxrate / divisor - baud;
      72            0 :                 if (abs(delta) < baud / 50) {
      73            0 :                         struct uart_8250_port *up = up_to_u8250p(port);
      74            0 :                         int lcr = serial_port_in(port, UART_LCR);
      75              : 
      76            0 :                         serial_port_out(port, UART_LCR, lcr | UART_LCR_DLAB);
      77            0 :                         serial_dl_write(up, divisor);
      78            0 :                         serial_port_out(port, 2, 16 - scr);
      79            0 :                         serial_port_out(port, UART_LCR, lcr);
      80              :                         return;
      81            0 :                 }
      82            0 :         }
      83            0 : }
      84              : 
      85            0 : static int pericom8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
      86              : {
      87            0 :         unsigned int nr, i, bar = 0, maxnr;
      88            0 :         struct pericom8250 *pericom;
      89            0 :         struct uart_8250_port uart;
      90            0 :         int ret;
      91              : 
      92            0 :         ret = pcim_enable_device(pdev);
      93            0 :         if (ret)
      94            0 :                 return ret;
      95              : 
      96            0 :         maxnr = pci_resource_len(pdev, bar) >> 3;
      97              : 
      98            0 :         if (pdev->vendor == PCI_VENDOR_ID_PERICOM)
      99            0 :                 nr = pdev->device & 0x0f;
     100            0 :         else if (pdev->vendor == PCI_VENDOR_ID_ACCESSIO)
     101            0 :                 nr = BIT(((pdev->device & 0x38) >> 3) - 1);
     102              :         else
     103            0 :                 nr = 1;
     104              : 
     105            0 :         pericom = devm_kzalloc(&pdev->dev, struct_size(pericom, line, nr), GFP_KERNEL);
     106            0 :         if (!pericom)
     107            0 :                 return -ENOMEM;
     108              : 
     109            0 :         pericom->virt = pcim_iomap(pdev, bar, 0);
     110            0 :         if (!pericom->virt)
     111            0 :                 return -ENOMEM;
     112              : 
     113            0 :         memset(&uart, 0, sizeof(uart));
     114              : 
     115            0 :         uart.port.dev = &pdev->dev;
     116            0 :         uart.port.irq = pdev->irq;
     117            0 :         uart.port.private_data = pericom;
     118            0 :         uart.port.iotype = UPIO_PORT;
     119            0 :         uart.port.uartclk = 921600 * 16;
     120            0 :         uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
     121            0 :         uart.port.set_divisor = pericom_do_set_divisor;
     122            0 :         for (i = 0; i < nr && i < maxnr; i++) {
     123            0 :                 unsigned int offset = (i == 3 && nr == 4) ? 0x38 : i * 0x8;
     124              : 
     125            0 :                 uart.port.iobase = pci_resource_start(pdev, bar) + offset;
     126              : 
     127              :                 dev_dbg(&pdev->dev, "Setup PCI port: port %lx, irq %d, type %d\n",
     128              :                         uart.port.iobase, uart.port.irq, uart.port.iotype);
     129              : 
     130            0 :                 pericom->line[i] = serial8250_register_8250_port(&uart);
     131            0 :                 if (pericom->line[i] < 0) {
     132            0 :                         dev_err(&pdev->dev,
     133              :                                 "Couldn't register serial port %lx, irq %d, type %d, error %d\n",
     134              :                                 uart.port.iobase, uart.port.irq,
     135              :                                 uart.port.iotype, pericom->line[i]);
     136            0 :                         break;
     137              :                 }
     138            0 :         }
     139            0 :         pericom->nr = i;
     140              : 
     141            0 :         pci_set_drvdata(pdev, pericom);
     142            0 :         return 0;
     143            0 : }
     144              : 
     145            0 : static void pericom8250_remove(struct pci_dev *pdev)
     146              : {
     147            0 :         struct pericom8250 *pericom = pci_get_drvdata(pdev);
     148            0 :         unsigned int i;
     149              : 
     150            0 :         for (i = 0; i < pericom->nr; i++)
     151            0 :                 serial8250_unregister_port(pericom->line[i]);
     152            0 : }
     153              : 
     154              : static const struct pci_device_id pericom8250_pci_ids[] = {
     155              :         /*
     156              :          * Pericom PI7C9X795[1248] Uno/Dual/Quad/Octal UART
     157              :          * (Only 7954 has an offset jump for port 4)
     158              :          */
     159              :         { PCI_VDEVICE(PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7951) },
     160              :         { PCI_VDEVICE(PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7952) },
     161              :         { PCI_VDEVICE(PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7954) },
     162              :         { PCI_VDEVICE(PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7958) },
     163              : 
     164              :         /*
     165              :          * ACCES I/O Products quad
     166              :          * (Only 7954 has an offset jump for port 4)
     167              :          */
     168              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM_2SDB) },
     169              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_COM_2S) },
     170              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM422_4) },
     171              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM485_4) },
     172              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM_4SDB) },
     173              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_COM_4S) },
     174              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM422_8) },
     175              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM485_8) },
     176              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM232_2DB) },
     177              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_COM232_2) },
     178              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM232_4) },
     179              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM232_4DB) },
     180              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_COM232_4) },
     181              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM232_8) },
     182              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM_2SMDB) },
     183              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_COM_2SM) },
     184              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM_4SM) },
     185              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM_4SMDB) },
     186              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_COM_4SM) },
     187              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM_8SM) },
     188              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM485_1) },
     189              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM422_2) },
     190              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM485_2) },
     191              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM422_4) },
     192              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM485_4) },
     193              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_ICM_2S) },
     194              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_ICM_4S) },
     195              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_ICM232_2) },
     196              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM232_2) },
     197              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_ICM232_4) },
     198              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM232_4) },
     199              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_ICM_2SM) },
     200              :         { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_ICM_4SM) },
     201              :         { }
     202              : };
     203              : MODULE_DEVICE_TABLE(pci, pericom8250_pci_ids);
     204              : 
     205              : static struct pci_driver pericom8250_pci_driver = {
     206              :         .name           = "8250_pericom",
     207              :         .id_table       = pericom8250_pci_ids,
     208              :         .probe          = pericom8250_probe,
     209              :         .remove         = pericom8250_remove,
     210              : };
     211            0 : module_pci_driver(pericom8250_pci_driver);
     212              : 
     213              : MODULE_LICENSE("GPL v2");
     214              : MODULE_DESCRIPTION("Pericom UART driver");
        

Generated by: LCOV version 2.0-1