Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * uio_aec.c -- simple driver for Adrienne Electronics Corp time code PCI device
0004  *
0005  * Copyright (C) 2008 Brandon Philips <brandon@ifup.org>
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/pci.h>
0011 #include <linux/init.h>
0012 #include <linux/interrupt.h>
0013 #include <linux/cdev.h>
0014 #include <linux/fs.h>
0015 #include <linux/io.h>
0016 #include <linux/uaccess.h>
0017 #include <linux/uio_driver.h>
0018 #include <linux/slab.h>
0019 
0020 #define PCI_VENDOR_ID_AEC 0xaecb
0021 #define PCI_DEVICE_ID_AEC_VITCLTC 0x6250
0022 
0023 #define INT_ENABLE_ADDR     0xFC
0024 #define INT_ENABLE      0x10
0025 #define INT_DISABLE     0x0
0026 
0027 #define INT_MASK_ADDR       0x2E
0028 #define INT_MASK_ALL        0x3F
0029 
0030 #define INTA_DRVR_ADDR      0xFE
0031 #define INTA_ENABLED_FLAG   0x08
0032 #define INTA_FLAG       0x01
0033 
0034 #define MAILBOX         0x0F
0035 
0036 static struct pci_device_id ids[] = {
0037     { PCI_DEVICE(PCI_VENDOR_ID_AEC, PCI_DEVICE_ID_AEC_VITCLTC), },
0038     { 0, }
0039 };
0040 MODULE_DEVICE_TABLE(pci, ids);
0041 
0042 static irqreturn_t aectc_irq(int irq, struct uio_info *dev_info)
0043 {
0044     void __iomem *int_flag = dev_info->priv + INTA_DRVR_ADDR;
0045     unsigned char status = ioread8(int_flag);
0046 
0047 
0048     if ((status & INTA_ENABLED_FLAG) && (status & INTA_FLAG)) {
0049         /* application writes 0x00 to 0x2F to get next interrupt */
0050         status = ioread8(dev_info->priv + MAILBOX);
0051         return IRQ_HANDLED;
0052     }
0053 
0054     return IRQ_NONE;
0055 }
0056 
0057 static void print_board_data(struct pci_dev *pdev, struct uio_info *i)
0058 {
0059     dev_info(&pdev->dev, "PCI-TC board vendor: %x%x number: %x%x"
0060         " revision: %c%c\n",
0061         ioread8(i->priv + 0x01),
0062         ioread8(i->priv + 0x00),
0063         ioread8(i->priv + 0x03),
0064         ioread8(i->priv + 0x02),
0065         ioread8(i->priv + 0x06),
0066         ioread8(i->priv + 0x07));
0067 }
0068 
0069 static int probe(struct pci_dev *pdev, const struct pci_device_id *id)
0070 {
0071     struct uio_info *info;
0072     int ret;
0073 
0074     info = devm_kzalloc(&pdev->dev, sizeof(struct uio_info), GFP_KERNEL);
0075     if (!info)
0076         return -ENOMEM;
0077 
0078     if (pci_enable_device(pdev))
0079         return -ENODEV;
0080 
0081     if (pci_request_regions(pdev, "aectc"))
0082         goto out_disable;
0083 
0084     info->name = "aectc";
0085     info->port[0].start = pci_resource_start(pdev, 0);
0086     if (!info->port[0].start)
0087         goto out_release;
0088     info->priv = pci_iomap(pdev, 0, 0);
0089     if (!info->priv)
0090         goto out_release;
0091     info->port[0].size = pci_resource_len(pdev, 0);
0092     info->port[0].porttype = UIO_PORT_GPIO;
0093 
0094     info->version = "0.0.1";
0095     info->irq = pdev->irq;
0096     info->irq_flags = IRQF_SHARED;
0097     info->handler = aectc_irq;
0098 
0099     print_board_data(pdev, info);
0100     ret = uio_register_device(&pdev->dev, info);
0101     if (ret)
0102         goto out_unmap;
0103 
0104     iowrite32(INT_ENABLE, info->priv + INT_ENABLE_ADDR);
0105     iowrite8(INT_MASK_ALL, info->priv + INT_MASK_ADDR);
0106     if (!(ioread8(info->priv + INTA_DRVR_ADDR)
0107             & INTA_ENABLED_FLAG))
0108         dev_err(&pdev->dev, "aectc: interrupts not enabled\n");
0109 
0110     pci_set_drvdata(pdev, info);
0111 
0112     return 0;
0113 
0114 out_unmap:
0115     pci_iounmap(pdev, info->priv);
0116 out_release:
0117     pci_release_regions(pdev);
0118 out_disable:
0119     pci_disable_device(pdev);
0120     return -ENODEV;
0121 }
0122 
0123 static void remove(struct pci_dev *pdev)
0124 {
0125     struct uio_info *info = pci_get_drvdata(pdev);
0126 
0127     /* disable interrupts */
0128     iowrite8(INT_DISABLE, info->priv + INT_MASK_ADDR);
0129     iowrite32(INT_DISABLE, info->priv + INT_ENABLE_ADDR);
0130     /* read mailbox to ensure board drops irq */
0131     ioread8(info->priv + MAILBOX);
0132 
0133     uio_unregister_device(info);
0134     pci_release_regions(pdev);
0135     pci_disable_device(pdev);
0136     pci_iounmap(pdev, info->priv);
0137 }
0138 
0139 static struct pci_driver pci_driver = {
0140     .name = "aectc",
0141     .id_table = ids,
0142     .probe = probe,
0143     .remove = remove,
0144 };
0145 
0146 module_pci_driver(pci_driver);
0147 MODULE_LICENSE("GPL");