1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * UIO driver for Hilscher NetX based fieldbus cards (cifX, comX). 4 * See http://www.hilscher.com for details. 5 * 6 * (C) 2007 Hans J. Koch <hjk@hansjkoch.de> 7 * (C) 2008 Manuel Traut <manut@linutronix.de> 8 * 9 */ 10 11 #include <linux/device.h> 12 #include <linux/io.h> 13 #include <linux/module.h> 14 #include <linux/pci.h> 15 #include <linux/slab.h> 16 #include <linux/uio_driver.h> 17 18 #define PCI_VENDOR_ID_HILSCHER 0x15CF 19 #define PCI_DEVICE_ID_HILSCHER_NETX 0x0000 20 #define PCI_DEVICE_ID_HILSCHER_NETPLC 0x0010 21 #define PCI_SUBDEVICE_ID_NETPLC_RAM 0x0000 22 #define PCI_SUBDEVICE_ID_NETPLC_FLASH 0x0001 23 #define PCI_SUBDEVICE_ID_NXSB_PCA 0x3235 24 #define PCI_SUBDEVICE_ID_NXPCA 0x3335 25 26 #define DPM_HOST_INT_EN0 0xfff0 27 #define DPM_HOST_INT_STAT0 0xffe0 28 29 #define DPM_HOST_INT_MASK 0xe600ffff 30 #define DPM_HOST_INT_GLOBAL_EN 0x80000000 31 32 static irqreturn_t netx_handler(int irq, struct uio_info *dev_info) 33 { 34 void __iomem *int_enable_reg = dev_info->mem[0].internal_addr 35 + DPM_HOST_INT_EN0; 36 void __iomem *int_status_reg = dev_info->mem[0].internal_addr 37 + DPM_HOST_INT_STAT0; 38 39 /* Is one of our interrupts enabled and active ? */ 40 if (!(ioread32(int_enable_reg) & ioread32(int_status_reg) 41 & DPM_HOST_INT_MASK)) 42 return IRQ_NONE; 43 44 /* Disable interrupt */ 45 iowrite32(ioread32(int_enable_reg) & ~DPM_HOST_INT_GLOBAL_EN, 46 int_enable_reg); 47 return IRQ_HANDLED; 48 } 49 50 static int netx_pci_probe(struct pci_dev *dev, 51 const struct pci_device_id *id) 52 { 53 struct uio_info *info; 54 int bar; 55 56 info = devm_kzalloc(&dev->dev, sizeof(struct uio_info), GFP_KERNEL); 57 if (!info) 58 return -ENOMEM; 59 60 if (pci_enable_device(dev)) 61 return -ENODEV; 62 63 if (pci_request_regions(dev, "netx")) 64 goto out_disable; 65 66 switch (id->device) { 67 case PCI_DEVICE_ID_HILSCHER_NETX: 68 bar = 0; 69 info->name = "netx"; 70 break; 71 case PCI_DEVICE_ID_HILSCHER_NETPLC: 72 bar = 0; 73 info->name = "netplc"; 74 break; 75 default: 76 bar = 2; 77 info->name = "netx_plx"; 78 } 79 80 /* BAR0 or 2 points to the card's dual port memory */ 81 info->mem[0].addr = pci_resource_start(dev, bar); 82 if (!info->mem[0].addr) 83 goto out_release; 84 info->mem[0].internal_addr = ioremap(pci_resource_start(dev, bar), 85 pci_resource_len(dev, bar)); 86 87 if (!info->mem[0].internal_addr) 88 goto out_release; 89 90 info->mem[0].size = pci_resource_len(dev, bar); 91 info->mem[0].memtype = UIO_MEM_PHYS; 92 info->irq = dev->irq; 93 info->irq_flags = IRQF_SHARED; 94 info->handler = netx_handler; 95 info->version = "0.0.1"; 96 97 /* Make sure all interrupts are disabled */ 98 iowrite32(0, info->mem[0].internal_addr + DPM_HOST_INT_EN0); 99 100 if (uio_register_device(&dev->dev, info)) 101 goto out_unmap; 102 103 pci_set_drvdata(dev, info); 104 dev_info(&dev->dev, "Found %s card, registered UIO device.\n", 105 info->name); 106 107 return 0; 108 109 out_unmap: 110 iounmap(info->mem[0].internal_addr); 111 out_release: 112 pci_release_regions(dev); 113 out_disable: 114 pci_disable_device(dev); 115 return -ENODEV; 116 } 117 118 static void netx_pci_remove(struct pci_dev *dev) 119 { 120 struct uio_info *info = pci_get_drvdata(dev); 121 122 /* Disable all interrupts */ 123 iowrite32(0, info->mem[0].internal_addr + DPM_HOST_INT_EN0); 124 uio_unregister_device(info); 125 pci_release_regions(dev); 126 pci_disable_device(dev); 127 iounmap(info->mem[0].internal_addr); 128 } 129 130 static struct pci_device_id netx_pci_ids[] = { 131 { 132 .vendor = PCI_VENDOR_ID_HILSCHER, 133 .device = PCI_DEVICE_ID_HILSCHER_NETX, 134 .subvendor = 0, 135 .subdevice = 0, 136 }, 137 { 138 .vendor = PCI_VENDOR_ID_HILSCHER, 139 .device = PCI_DEVICE_ID_HILSCHER_NETPLC, 140 .subvendor = PCI_VENDOR_ID_HILSCHER, 141 .subdevice = PCI_SUBDEVICE_ID_NETPLC_RAM, 142 }, 143 { 144 .vendor = PCI_VENDOR_ID_HILSCHER, 145 .device = PCI_DEVICE_ID_HILSCHER_NETPLC, 146 .subvendor = PCI_VENDOR_ID_HILSCHER, 147 .subdevice = PCI_SUBDEVICE_ID_NETPLC_FLASH, 148 }, 149 { 150 .vendor = PCI_VENDOR_ID_PLX, 151 .device = PCI_DEVICE_ID_PLX_9030, 152 .subvendor = PCI_VENDOR_ID_PLX, 153 .subdevice = PCI_SUBDEVICE_ID_NXSB_PCA, 154 }, 155 { 156 .vendor = PCI_VENDOR_ID_PLX, 157 .device = PCI_DEVICE_ID_PLX_9030, 158 .subvendor = PCI_VENDOR_ID_PLX, 159 .subdevice = PCI_SUBDEVICE_ID_NXPCA, 160 }, 161 { 0, } 162 }; 163 164 static struct pci_driver netx_pci_driver = { 165 .name = "netx", 166 .id_table = netx_pci_ids, 167 .probe = netx_pci_probe, 168 .remove = netx_pci_remove, 169 }; 170 171 module_pci_driver(netx_pci_driver); 172 MODULE_DEVICE_TABLE(pci, netx_pci_ids); 173 MODULE_LICENSE("GPL v2"); 174 MODULE_AUTHOR("Hans J. Koch, Manuel Traut"); 175