1*bce5c2eaSStephen Hemminger // SPDX-License-Identifier: GPL-2.0 28f314cfcSHans J. Koch /* 38f314cfcSHans J. Koch * UIO driver for Hilscher NetX based fieldbus cards (cifX, comX). 48f314cfcSHans J. Koch * See http://www.hilscher.com for details. 58f314cfcSHans J. Koch * 6318af55dSHans J. Koch * (C) 2007 Hans J. Koch <hjk@hansjkoch.de> 78f314cfcSHans J. Koch * (C) 2008 Manuel Traut <manut@linutronix.de> 88f314cfcSHans J. Koch * 98f314cfcSHans J. Koch */ 108f314cfcSHans J. Koch 118f314cfcSHans J. Koch #include <linux/device.h> 128f314cfcSHans J. Koch #include <linux/io.h> 138f314cfcSHans J. Koch #include <linux/module.h> 148f314cfcSHans J. Koch #include <linux/pci.h> 155a0e3ad6STejun Heo #include <linux/slab.h> 168f314cfcSHans J. Koch #include <linux/uio_driver.h> 178f314cfcSHans J. Koch 188f314cfcSHans J. Koch #define PCI_VENDOR_ID_HILSCHER 0x15CF 198f314cfcSHans J. Koch #define PCI_DEVICE_ID_HILSCHER_NETX 0x0000 20d8408aefSDaniel Trautmann #define PCI_DEVICE_ID_HILSCHER_NETPLC 0x0010 21d8408aefSDaniel Trautmann #define PCI_SUBDEVICE_ID_NETPLC_RAM 0x0000 22d8408aefSDaniel Trautmann #define PCI_SUBDEVICE_ID_NETPLC_FLASH 0x0001 238f314cfcSHans J. Koch #define PCI_SUBDEVICE_ID_NXSB_PCA 0x3235 248f314cfcSHans J. Koch #define PCI_SUBDEVICE_ID_NXPCA 0x3335 258f314cfcSHans J. Koch 268f314cfcSHans J. Koch #define DPM_HOST_INT_EN0 0xfff0 278f314cfcSHans J. Koch #define DPM_HOST_INT_STAT0 0xffe0 288f314cfcSHans J. Koch 298f314cfcSHans J. Koch #define DPM_HOST_INT_MASK 0xe600ffff 308f314cfcSHans J. Koch #define DPM_HOST_INT_GLOBAL_EN 0x80000000 318f314cfcSHans J. Koch 328f314cfcSHans J. Koch static irqreturn_t netx_handler(int irq, struct uio_info *dev_info) 338f314cfcSHans J. Koch { 348f314cfcSHans J. Koch void __iomem *int_enable_reg = dev_info->mem[0].internal_addr 358f314cfcSHans J. Koch + DPM_HOST_INT_EN0; 368f314cfcSHans J. Koch void __iomem *int_status_reg = dev_info->mem[0].internal_addr 378f314cfcSHans J. Koch + DPM_HOST_INT_STAT0; 388f314cfcSHans J. Koch 398f314cfcSHans J. Koch /* Is one of our interrupts enabled and active ? */ 408f314cfcSHans J. Koch if (!(ioread32(int_enable_reg) & ioread32(int_status_reg) 418f314cfcSHans J. Koch & DPM_HOST_INT_MASK)) 428f314cfcSHans J. Koch return IRQ_NONE; 438f314cfcSHans J. Koch 448f314cfcSHans J. Koch /* Disable interrupt */ 458f314cfcSHans J. Koch iowrite32(ioread32(int_enable_reg) & ~DPM_HOST_INT_GLOBAL_EN, 468f314cfcSHans J. Koch int_enable_reg); 478f314cfcSHans J. Koch return IRQ_HANDLED; 488f314cfcSHans J. Koch } 498f314cfcSHans J. Koch 50b17b75bbSBill Pemberton static int netx_pci_probe(struct pci_dev *dev, 518f314cfcSHans J. Koch const struct pci_device_id *id) 528f314cfcSHans J. Koch { 538f314cfcSHans J. Koch struct uio_info *info; 548f314cfcSHans J. Koch int bar; 558f314cfcSHans J. Koch 568f314cfcSHans J. Koch info = kzalloc(sizeof(struct uio_info), GFP_KERNEL); 578f314cfcSHans J. Koch if (!info) 588f314cfcSHans J. Koch return -ENOMEM; 598f314cfcSHans J. Koch 608f314cfcSHans J. Koch if (pci_enable_device(dev)) 618f314cfcSHans J. Koch goto out_free; 628f314cfcSHans J. Koch 638f314cfcSHans J. Koch if (pci_request_regions(dev, "netx")) 648f314cfcSHans J. Koch goto out_disable; 658f314cfcSHans J. Koch 668f314cfcSHans J. Koch switch (id->device) { 678f314cfcSHans J. Koch case PCI_DEVICE_ID_HILSCHER_NETX: 688f314cfcSHans J. Koch bar = 0; 698f314cfcSHans J. Koch info->name = "netx"; 708f314cfcSHans J. Koch break; 71d8408aefSDaniel Trautmann case PCI_DEVICE_ID_HILSCHER_NETPLC: 72d8408aefSDaniel Trautmann bar = 0; 73d8408aefSDaniel Trautmann info->name = "netplc"; 74d8408aefSDaniel Trautmann break; 758f314cfcSHans J. Koch default: 768f314cfcSHans J. Koch bar = 2; 778f314cfcSHans J. Koch info->name = "netx_plx"; 788f314cfcSHans J. Koch } 798f314cfcSHans J. Koch 808f314cfcSHans J. Koch /* BAR0 or 2 points to the card's dual port memory */ 818f314cfcSHans J. Koch info->mem[0].addr = pci_resource_start(dev, bar); 828f314cfcSHans J. Koch if (!info->mem[0].addr) 838f314cfcSHans J. Koch goto out_release; 848f314cfcSHans J. Koch info->mem[0].internal_addr = ioremap(pci_resource_start(dev, bar), 858f314cfcSHans J. Koch pci_resource_len(dev, bar)); 868f314cfcSHans J. Koch 878f314cfcSHans J. Koch if (!info->mem[0].internal_addr) 888f314cfcSHans J. Koch goto out_release; 898f314cfcSHans J. Koch 908f314cfcSHans J. Koch info->mem[0].size = pci_resource_len(dev, bar); 918f314cfcSHans J. Koch info->mem[0].memtype = UIO_MEM_PHYS; 928f314cfcSHans J. Koch info->irq = dev->irq; 938f314cfcSHans J. Koch info->irq_flags = IRQF_SHARED; 948f314cfcSHans J. Koch info->handler = netx_handler; 958f314cfcSHans J. Koch info->version = "0.0.1"; 968f314cfcSHans J. Koch 978f314cfcSHans J. Koch /* Make sure all interrupts are disabled */ 988f314cfcSHans J. Koch iowrite32(0, info->mem[0].internal_addr + DPM_HOST_INT_EN0); 998f314cfcSHans J. Koch 1008f314cfcSHans J. Koch if (uio_register_device(&dev->dev, info)) 1018f314cfcSHans J. Koch goto out_unmap; 1028f314cfcSHans J. Koch 1038f314cfcSHans J. Koch pci_set_drvdata(dev, info); 1048f314cfcSHans J. Koch dev_info(&dev->dev, "Found %s card, registered UIO device.\n", 1058f314cfcSHans J. Koch info->name); 1068f314cfcSHans J. Koch 1078f314cfcSHans J. Koch return 0; 1088f314cfcSHans J. Koch 1098f314cfcSHans J. Koch out_unmap: 1108f314cfcSHans J. Koch iounmap(info->mem[0].internal_addr); 1118f314cfcSHans J. Koch out_release: 1128f314cfcSHans J. Koch pci_release_regions(dev); 1138f314cfcSHans J. Koch out_disable: 1148f314cfcSHans J. Koch pci_disable_device(dev); 1158f314cfcSHans J. Koch out_free: 1168f314cfcSHans J. Koch kfree(info); 1178f314cfcSHans J. Koch return -ENODEV; 1188f314cfcSHans J. Koch } 1198f314cfcSHans J. Koch 1208f314cfcSHans J. Koch static void netx_pci_remove(struct pci_dev *dev) 1218f314cfcSHans J. Koch { 1228f314cfcSHans J. Koch struct uio_info *info = pci_get_drvdata(dev); 1238f314cfcSHans J. Koch 1248f314cfcSHans J. Koch /* Disable all interrupts */ 1258f314cfcSHans J. Koch iowrite32(0, info->mem[0].internal_addr + DPM_HOST_INT_EN0); 1268f314cfcSHans J. Koch uio_unregister_device(info); 1278f314cfcSHans J. Koch pci_release_regions(dev); 1288f314cfcSHans J. Koch pci_disable_device(dev); 1298f314cfcSHans J. Koch iounmap(info->mem[0].internal_addr); 1308f314cfcSHans J. Koch 1318f314cfcSHans J. Koch kfree(info); 1328f314cfcSHans J. Koch } 1338f314cfcSHans J. Koch 1348f314cfcSHans J. Koch static struct pci_device_id netx_pci_ids[] = { 1358f314cfcSHans J. Koch { 1368f314cfcSHans J. Koch .vendor = PCI_VENDOR_ID_HILSCHER, 1378f314cfcSHans J. Koch .device = PCI_DEVICE_ID_HILSCHER_NETX, 1388f314cfcSHans J. Koch .subvendor = 0, 1398f314cfcSHans J. Koch .subdevice = 0, 1408f314cfcSHans J. Koch }, 1418f314cfcSHans J. Koch { 142d8408aefSDaniel Trautmann .vendor = PCI_VENDOR_ID_HILSCHER, 143d8408aefSDaniel Trautmann .device = PCI_DEVICE_ID_HILSCHER_NETPLC, 144d8408aefSDaniel Trautmann .subvendor = PCI_VENDOR_ID_HILSCHER, 145d8408aefSDaniel Trautmann .subdevice = PCI_SUBDEVICE_ID_NETPLC_RAM, 146d8408aefSDaniel Trautmann }, 147d8408aefSDaniel Trautmann { 148d8408aefSDaniel Trautmann .vendor = PCI_VENDOR_ID_HILSCHER, 149d8408aefSDaniel Trautmann .device = PCI_DEVICE_ID_HILSCHER_NETPLC, 150d8408aefSDaniel Trautmann .subvendor = PCI_VENDOR_ID_HILSCHER, 151d8408aefSDaniel Trautmann .subdevice = PCI_SUBDEVICE_ID_NETPLC_FLASH, 152d8408aefSDaniel Trautmann }, 153d8408aefSDaniel Trautmann { 1548f314cfcSHans J. Koch .vendor = PCI_VENDOR_ID_PLX, 1558f314cfcSHans J. Koch .device = PCI_DEVICE_ID_PLX_9030, 1568f314cfcSHans J. Koch .subvendor = PCI_VENDOR_ID_PLX, 1578f314cfcSHans J. Koch .subdevice = PCI_SUBDEVICE_ID_NXSB_PCA, 1588f314cfcSHans J. Koch }, 1598f314cfcSHans J. Koch { 1608f314cfcSHans J. Koch .vendor = PCI_VENDOR_ID_PLX, 1618f314cfcSHans J. Koch .device = PCI_DEVICE_ID_PLX_9030, 1628f314cfcSHans J. Koch .subvendor = PCI_VENDOR_ID_PLX, 1638f314cfcSHans J. Koch .subdevice = PCI_SUBDEVICE_ID_NXPCA, 1648f314cfcSHans J. Koch }, 1658f314cfcSHans J. Koch { 0, } 1668f314cfcSHans J. Koch }; 1678f314cfcSHans J. Koch 1688f314cfcSHans J. Koch static struct pci_driver netx_pci_driver = { 1698f314cfcSHans J. Koch .name = "netx", 1708f314cfcSHans J. Koch .id_table = netx_pci_ids, 1718f314cfcSHans J. Koch .probe = netx_pci_probe, 1728f314cfcSHans J. Koch .remove = netx_pci_remove, 1738f314cfcSHans J. Koch }; 1748f314cfcSHans J. Koch 175b59f9a05SPeter Huewe module_pci_driver(netx_pci_driver); 1768f314cfcSHans J. Koch MODULE_DEVICE_TABLE(pci, netx_pci_ids); 1778f314cfcSHans J. Koch MODULE_LICENSE("GPL v2"); 1788f314cfcSHans J. Koch MODULE_AUTHOR("Hans J. Koch, Manuel Traut"); 179