0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027 #include <linux/device.h>
0028 #include <linux/module.h>
0029 #include <linux/pci.h>
0030 #include <linux/uio_driver.h>
0031 #include <linux/io.h>
0032 #include <linux/slab.h>
0033
0034
0035 #define SERCOS_SUB_VENDOR_ID 0x1971
0036 #define SERCOS_SUB_SYSID_3530 0x3530
0037 #define SERCOS_SUB_SYSID_3535 0x3535
0038 #define SERCOS_SUB_SYSID_3780 0x3780
0039
0040
0041 #define IER0_OFFSET 0x08
0042
0043
0044 #define ISR0_OFFSET 0x18
0045
0046 struct sercos3_priv {
0047 u32 ier0_cache;
0048 spinlock_t ier0_cache_lock;
0049 };
0050
0051
0052 static void sercos3_disable_interrupts(struct uio_info *info,
0053 struct sercos3_priv *priv)
0054 {
0055 void __iomem *ier0 = info->mem[3].internal_addr + IER0_OFFSET;
0056
0057
0058 priv->ier0_cache |= ioread32(ier0);
0059
0060
0061 iowrite32(0, ier0);
0062 }
0063
0064
0065 static void sercos3_enable_interrupts(struct uio_info *info,
0066 struct sercos3_priv *priv)
0067 {
0068 void __iomem *ier0 = info->mem[3].internal_addr + IER0_OFFSET;
0069
0070
0071 iowrite32(ioread32(ier0) | priv->ier0_cache, ier0);
0072 priv->ier0_cache = 0;
0073 }
0074
0075 static irqreturn_t sercos3_handler(int irq, struct uio_info *info)
0076 {
0077 struct sercos3_priv *priv = info->priv;
0078 void __iomem *isr0 = info->mem[3].internal_addr + ISR0_OFFSET;
0079 void __iomem *ier0 = info->mem[3].internal_addr + IER0_OFFSET;
0080
0081 if (!(ioread32(isr0) & ioread32(ier0)))
0082 return IRQ_NONE;
0083
0084 spin_lock(&priv->ier0_cache_lock);
0085 sercos3_disable_interrupts(info, priv);
0086 spin_unlock(&priv->ier0_cache_lock);
0087
0088 return IRQ_HANDLED;
0089 }
0090
0091 static int sercos3_irqcontrol(struct uio_info *info, s32 irq_on)
0092 {
0093 struct sercos3_priv *priv = info->priv;
0094
0095 spin_lock_irq(&priv->ier0_cache_lock);
0096 if (irq_on)
0097 sercos3_enable_interrupts(info, priv);
0098 else
0099 sercos3_disable_interrupts(info, priv);
0100 spin_unlock_irq(&priv->ier0_cache_lock);
0101
0102 return 0;
0103 }
0104
0105 static int sercos3_setup_iomem(struct pci_dev *dev, struct uio_info *info,
0106 int n, int pci_bar)
0107 {
0108 info->mem[n].addr = pci_resource_start(dev, pci_bar);
0109 if (!info->mem[n].addr)
0110 return -1;
0111 info->mem[n].internal_addr = ioremap(pci_resource_start(dev, pci_bar),
0112 pci_resource_len(dev, pci_bar));
0113 if (!info->mem[n].internal_addr)
0114 return -1;
0115 info->mem[n].size = pci_resource_len(dev, pci_bar);
0116 info->mem[n].memtype = UIO_MEM_PHYS;
0117 return 0;
0118 }
0119
0120 static int sercos3_pci_probe(struct pci_dev *dev,
0121 const struct pci_device_id *id)
0122 {
0123 struct uio_info *info;
0124 struct sercos3_priv *priv;
0125 int i;
0126
0127 info = devm_kzalloc(&dev->dev, sizeof(struct uio_info), GFP_KERNEL);
0128 if (!info)
0129 return -ENOMEM;
0130
0131 priv = devm_kzalloc(&dev->dev, sizeof(struct sercos3_priv), GFP_KERNEL);
0132 if (!priv)
0133 return -ENOMEM;
0134
0135 if (pci_enable_device(dev))
0136 return -ENODEV;
0137
0138 if (pci_request_regions(dev, "sercos3"))
0139 goto out_disable;
0140
0141
0142 if (sercos3_setup_iomem(dev, info, 0, 0))
0143 goto out_unmap;
0144 if (sercos3_setup_iomem(dev, info, 1, 2))
0145 goto out_unmap;
0146 if (sercos3_setup_iomem(dev, info, 2, 3))
0147 goto out_unmap;
0148 if (sercos3_setup_iomem(dev, info, 3, 4))
0149 goto out_unmap;
0150 if (sercos3_setup_iomem(dev, info, 4, 5))
0151 goto out_unmap;
0152
0153 spin_lock_init(&priv->ier0_cache_lock);
0154 info->priv = priv;
0155 info->name = "Sercos_III_PCI";
0156 info->version = "0.0.1";
0157 info->irq = dev->irq;
0158 info->irq_flags = IRQF_SHARED;
0159 info->handler = sercos3_handler;
0160 info->irqcontrol = sercos3_irqcontrol;
0161
0162 pci_set_drvdata(dev, info);
0163
0164 if (uio_register_device(&dev->dev, info))
0165 goto out_unmap;
0166
0167 return 0;
0168
0169 out_unmap:
0170 for (i = 0; i < 5; i++) {
0171 if (info->mem[i].internal_addr)
0172 iounmap(info->mem[i].internal_addr);
0173 }
0174 pci_release_regions(dev);
0175 out_disable:
0176 pci_disable_device(dev);
0177 return -ENODEV;
0178 }
0179
0180 static void sercos3_pci_remove(struct pci_dev *dev)
0181 {
0182 struct uio_info *info = pci_get_drvdata(dev);
0183 int i;
0184
0185 uio_unregister_device(info);
0186 pci_release_regions(dev);
0187 pci_disable_device(dev);
0188 for (i = 0; i < 5; i++) {
0189 if (info->mem[i].internal_addr)
0190 iounmap(info->mem[i].internal_addr);
0191 }
0192 }
0193
0194 static struct pci_device_id sercos3_pci_ids[] = {
0195 {
0196 .vendor = PCI_VENDOR_ID_PLX,
0197 .device = PCI_DEVICE_ID_PLX_9030,
0198 .subvendor = SERCOS_SUB_VENDOR_ID,
0199 .subdevice = SERCOS_SUB_SYSID_3530,
0200 },
0201 {
0202 .vendor = PCI_VENDOR_ID_PLX,
0203 .device = PCI_DEVICE_ID_PLX_9030,
0204 .subvendor = SERCOS_SUB_VENDOR_ID,
0205 .subdevice = SERCOS_SUB_SYSID_3535,
0206 },
0207 {
0208 .vendor = PCI_VENDOR_ID_PLX,
0209 .device = PCI_DEVICE_ID_PLX_9030,
0210 .subvendor = SERCOS_SUB_VENDOR_ID,
0211 .subdevice = SERCOS_SUB_SYSID_3780,
0212 },
0213 { 0, }
0214 };
0215
0216 static struct pci_driver sercos3_pci_driver = {
0217 .name = "sercos3",
0218 .id_table = sercos3_pci_ids,
0219 .probe = sercos3_pci_probe,
0220 .remove = sercos3_pci_remove,
0221 };
0222
0223 module_pci_driver(sercos3_pci_driver);
0224 MODULE_DESCRIPTION("UIO driver for the Automata Sercos III PCI card");
0225 MODULE_AUTHOR("John Ogness <john.ogness@linutronix.de>");
0226 MODULE_LICENSE("GPL v2");