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