This source file includes following definitions.
- sercos3_disable_interrupts
- sercos3_enable_interrupts
- sercos3_handler
- sercos3_irqcontrol
- sercos3_setup_iomem
- sercos3_pci_probe
- sercos3_pci_remove
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 #include <linux/device.h>
28 #include <linux/module.h>
29 #include <linux/pci.h>
30 #include <linux/uio_driver.h>
31 #include <linux/io.h>
32 #include <linux/slab.h>
33
34
35 #define SERCOS_SUB_VENDOR_ID 0x1971
36 #define SERCOS_SUB_SYSID_3530 0x3530
37 #define SERCOS_SUB_SYSID_3535 0x3535
38 #define SERCOS_SUB_SYSID_3780 0x3780
39
40
41 #define IER0_OFFSET 0x08
42
43
44 #define ISR0_OFFSET 0x18
45
46 struct sercos3_priv {
47 u32 ier0_cache;
48 spinlock_t ier0_cache_lock;
49 };
50
51
52 static void sercos3_disable_interrupts(struct uio_info *info,
53 struct sercos3_priv *priv)
54 {
55 void __iomem *ier0 = info->mem[3].internal_addr + IER0_OFFSET;
56
57
58 priv->ier0_cache |= ioread32(ier0);
59
60
61 iowrite32(0, ier0);
62 }
63
64
65 static void sercos3_enable_interrupts(struct uio_info *info,
66 struct sercos3_priv *priv)
67 {
68 void __iomem *ier0 = info->mem[3].internal_addr + IER0_OFFSET;
69
70
71 iowrite32(ioread32(ier0) | priv->ier0_cache, ier0);
72 priv->ier0_cache = 0;
73 }
74
75 static irqreturn_t sercos3_handler(int irq, struct uio_info *info)
76 {
77 struct sercos3_priv *priv = info->priv;
78 void __iomem *isr0 = info->mem[3].internal_addr + ISR0_OFFSET;
79 void __iomem *ier0 = info->mem[3].internal_addr + IER0_OFFSET;
80
81 if (!(ioread32(isr0) & ioread32(ier0)))
82 return IRQ_NONE;
83
84 spin_lock(&priv->ier0_cache_lock);
85 sercos3_disable_interrupts(info, priv);
86 spin_unlock(&priv->ier0_cache_lock);
87
88 return IRQ_HANDLED;
89 }
90
91 static int sercos3_irqcontrol(struct uio_info *info, s32 irq_on)
92 {
93 struct sercos3_priv *priv = info->priv;
94
95 spin_lock_irq(&priv->ier0_cache_lock);
96 if (irq_on)
97 sercos3_enable_interrupts(info, priv);
98 else
99 sercos3_disable_interrupts(info, priv);
100 spin_unlock_irq(&priv->ier0_cache_lock);
101
102 return 0;
103 }
104
105 static int sercos3_setup_iomem(struct pci_dev *dev, struct uio_info *info,
106 int n, int pci_bar)
107 {
108 info->mem[n].addr = pci_resource_start(dev, pci_bar);
109 if (!info->mem[n].addr)
110 return -1;
111 info->mem[n].internal_addr = ioremap(pci_resource_start(dev, pci_bar),
112 pci_resource_len(dev, pci_bar));
113 if (!info->mem[n].internal_addr)
114 return -1;
115 info->mem[n].size = pci_resource_len(dev, pci_bar);
116 info->mem[n].memtype = UIO_MEM_PHYS;
117 return 0;
118 }
119
120 static int sercos3_pci_probe(struct pci_dev *dev,
121 const struct pci_device_id *id)
122 {
123 struct uio_info *info;
124 struct sercos3_priv *priv;
125 int i;
126
127 info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
128 if (!info)
129 return -ENOMEM;
130
131 priv = kzalloc(sizeof(struct sercos3_priv), GFP_KERNEL);
132 if (!priv)
133 goto out_free;
134
135 if (pci_enable_device(dev))
136 goto out_free_priv;
137
138 if (pci_request_regions(dev, "sercos3"))
139 goto out_disable;
140
141
142 if (sercos3_setup_iomem(dev, info, 0, 0))
143 goto out_unmap;
144 if (sercos3_setup_iomem(dev, info, 1, 2))
145 goto out_unmap;
146 if (sercos3_setup_iomem(dev, info, 2, 3))
147 goto out_unmap;
148 if (sercos3_setup_iomem(dev, info, 3, 4))
149 goto out_unmap;
150 if (sercos3_setup_iomem(dev, info, 4, 5))
151 goto out_unmap;
152
153 spin_lock_init(&priv->ier0_cache_lock);
154 info->priv = priv;
155 info->name = "Sercos_III_PCI";
156 info->version = "0.0.1";
157 info->irq = dev->irq;
158 info->irq_flags = IRQF_SHARED;
159 info->handler = sercos3_handler;
160 info->irqcontrol = sercos3_irqcontrol;
161
162 pci_set_drvdata(dev, info);
163
164 if (uio_register_device(&dev->dev, info))
165 goto out_unmap;
166
167 return 0;
168
169 out_unmap:
170 for (i = 0; i < 5; i++) {
171 if (info->mem[i].internal_addr)
172 iounmap(info->mem[i].internal_addr);
173 }
174 pci_release_regions(dev);
175 out_disable:
176 pci_disable_device(dev);
177 out_free_priv:
178 kfree(priv);
179 out_free:
180 kfree(info);
181 return -ENODEV;
182 }
183
184 static void sercos3_pci_remove(struct pci_dev *dev)
185 {
186 struct uio_info *info = pci_get_drvdata(dev);
187 int i;
188
189 uio_unregister_device(info);
190 pci_release_regions(dev);
191 pci_disable_device(dev);
192 for (i = 0; i < 5; i++) {
193 if (info->mem[i].internal_addr)
194 iounmap(info->mem[i].internal_addr);
195 }
196 kfree(info->priv);
197 kfree(info);
198 }
199
200 static struct pci_device_id sercos3_pci_ids[] = {
201 {
202 .vendor = PCI_VENDOR_ID_PLX,
203 .device = PCI_DEVICE_ID_PLX_9030,
204 .subvendor = SERCOS_SUB_VENDOR_ID,
205 .subdevice = SERCOS_SUB_SYSID_3530,
206 },
207 {
208 .vendor = PCI_VENDOR_ID_PLX,
209 .device = PCI_DEVICE_ID_PLX_9030,
210 .subvendor = SERCOS_SUB_VENDOR_ID,
211 .subdevice = SERCOS_SUB_SYSID_3535,
212 },
213 {
214 .vendor = PCI_VENDOR_ID_PLX,
215 .device = PCI_DEVICE_ID_PLX_9030,
216 .subvendor = SERCOS_SUB_VENDOR_ID,
217 .subdevice = SERCOS_SUB_SYSID_3780,
218 },
219 { 0, }
220 };
221
222 static struct pci_driver sercos3_pci_driver = {
223 .name = "sercos3",
224 .id_table = sercos3_pci_ids,
225 .probe = sercos3_pci_probe,
226 .remove = sercos3_pci_remove,
227 };
228
229 module_pci_driver(sercos3_pci_driver);
230 MODULE_DESCRIPTION("UIO driver for the Automata Sercos III PCI card");
231 MODULE_AUTHOR("John Ogness <john.ogness@linutronix.de>");
232 MODULE_LICENSE("GPL v2");