blob: 72334b59aa260f308fbadffd699024fc428dee32 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Linux ARCnet driver - COM20020 PCI support
3 * Contemporary Controls PCI20 and SOHARD SH-ARC PCI
Joe Perchescb334642015-05-05 10:05:47 -07004 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Written 1994-1999 by Avery Pennarun,
6 * based on an ISA version by David Woodhouse.
7 * Written 1999-2000 by Martin Mares <mj@ucw.cz>.
8 * Derived from skeleton.c by Donald Becker.
9 *
10 * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
11 * for sponsoring the further development of this driver.
12 *
13 * **********************
14 *
15 * The original copyright of skeleton.c was as follows:
16 *
17 * skeleton.c Written 1993 by Donald Becker.
18 * Copyright 1993 United States Government as represented by the
19 * Director, National Security Agency. This software may only be used
20 * and distributed according to the terms of the GNU General Public License as
21 * modified by SRC, incorporated herein by reference.
22 *
23 * **********************
24 *
25 * For more details, see drivers/net/arcnet.c
26 *
27 * **********************
28 */
29#include <linux/module.h>
30#include <linux/moduleparam.h>
31#include <linux/kernel.h>
32#include <linux/types.h>
33#include <linux/ioport.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/errno.h>
35#include <linux/netdevice.h>
36#include <linux/init.h>
Alexey Dobriyana6b7a402011-06-06 10:43:46 +000037#include <linux/interrupt.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <linux/pci.h>
39#include <linux/arcdevice.h>
40#include <linux/com20020.h>
Michael Grzeschikc51da422014-09-29 11:55:37 +020041#include <linux/list.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
Joe Perches5e7ef912015-05-05 10:05:51 -070043#include <linux/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#define VERSION "arcnet: COM20020 PCI support\n"
46
47/* Module parameters */
48
49static int node;
50static char device[9]; /* use eg. device="arc1" to change name */
51static int timeout = 3;
52static int backplane;
53static int clockp;
54static int clockm;
55
56module_param(node, int, 0);
57module_param_string(device, device, sizeof(device), 0);
58module_param(timeout, int, 0);
59module_param(backplane, int, 0);
60module_param(clockp, int, 0);
61module_param(clockm, int, 0);
62MODULE_LICENSE("GPL");
63
Michael Grzeschikc51da422014-09-29 11:55:37 +020064static void com20020pci_remove(struct pci_dev *pdev);
65
Bill Pemberton7c47bab2012-12-03 09:22:43 -050066static int com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -070067{
Michael Grzeschik8c14f9c2014-09-29 11:55:36 +020068 struct com20020_pci_card_info *ci;
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 struct net_device *dev;
70 struct arcnet_local *lp;
Michael Grzeschikc51da422014-09-29 11:55:37 +020071 struct com20020_priv *priv;
72 int i, ioaddr, ret;
73 struct resource *r;
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
75 if (pci_enable_device(pdev))
76 return -EIO;
Stephen Hemmingera1799af2009-01-09 13:01:10 +000077
Michael Grzeschikc51da422014-09-29 11:55:37 +020078 priv = devm_kzalloc(&pdev->dev, sizeof(struct com20020_priv),
79 GFP_KERNEL);
Kiran Padwale8a308a2015-02-05 17:01:37 +053080 if (!priv)
81 return -ENOMEM;
82
Michael Grzeschik8c14f9c2014-09-29 11:55:36 +020083 ci = (struct com20020_pci_card_info *)id->driver_data;
Michael Grzeschikc51da422014-09-29 11:55:37 +020084 priv->ci = ci;
Michael Grzeschik8c14f9c2014-09-29 11:55:36 +020085
Michael Grzeschikc51da422014-09-29 11:55:37 +020086 INIT_LIST_HEAD(&priv->list_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087
Michael Grzeschikc51da422014-09-29 11:55:37 +020088 for (i = 0; i < ci->devcount; i++) {
89 struct com20020_pci_channel_map *cm = &ci->chan_map_tbl[i];
90 struct com20020_dev *card;
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
Michael Grzeschikc51da422014-09-29 11:55:37 +020092 dev = alloc_arcdev(device);
93 if (!dev) {
94 ret = -ENOMEM;
95 goto out_port;
96 }
97
98 dev->netdev_ops = &com20020_netdev_ops;
99
100 lp = netdev_priv(dev);
101
102 BUGMSG(D_NORMAL, "%s Controls\n", ci->name);
103 ioaddr = pci_resource_start(pdev, cm->bar) + cm->offset;
104
105 r = devm_request_region(&pdev->dev, ioaddr, cm->size,
106 "com20020-pci");
107 if (!r) {
108 pr_err("IO region %xh-%xh already allocated.\n",
109 ioaddr, ioaddr + cm->size - 1);
110 ret = -EBUSY;
111 goto out_port;
112 }
113
114 /* Dummy access after Reset
115 * ARCNET controller needs
116 * this access to detect bustype
117 */
118 outb(0x00, ioaddr + 1);
119 inb(ioaddr + 1);
120
121 dev->base_addr = ioaddr;
122 dev->dev_addr[0] = node;
123 dev->irq = pdev->irq;
124 lp->card_name = "PCI COM20020";
125 lp->card_flags = ci->flags;
126 lp->backplane = backplane;
127 lp->clockp = clockp & 7;
128 lp->clockm = clockm & 3;
129 lp->timeout = timeout;
130 lp->hw.owner = THIS_MODULE;
131
132 if (ASTATUS() == 0xFF) {
133 pr_err("IO address %Xh is empty!\n", ioaddr);
134 ret = -EIO;
135 goto out_port;
136 }
137 if (com20020_check(dev)) {
138 ret = -EIO;
139 goto out_port;
140 }
141
142 card = devm_kzalloc(&pdev->dev, sizeof(struct com20020_dev),
143 GFP_KERNEL);
144 if (!card) {
145 pr_err("%s out of memory!\n", __func__);
146 return -ENOMEM;
147 }
148
149 card->index = i;
150 card->pci_priv = priv;
151 card->dev = dev;
152
153 dev_set_drvdata(&dev->dev, card);
154
155 ret = com20020_found(dev, IRQF_SHARED);
156 if (ret)
157 goto out_port;
158
159 list_add(&card->list, &priv->list_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 }
161
Michael Grzeschikc51da422014-09-29 11:55:37 +0200162 pci_set_drvdata(pdev, priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
164 return 0;
165
166out_port:
Michael Grzeschikc51da422014-09-29 11:55:37 +0200167 com20020pci_remove(pdev);
168 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169}
170
Bill Pemberton7c47bab2012-12-03 09:22:43 -0500171static void com20020pci_remove(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172{
Michael Grzeschikc51da422014-09-29 11:55:37 +0200173 struct com20020_dev *card, *tmpcard;
174 struct com20020_priv *priv;
175
176 priv = pci_get_drvdata(pdev);
177
178 list_for_each_entry_safe(card, tmpcard, &priv->list_dev, list) {
179 struct net_device *dev = card->dev;
180
181 unregister_netdev(dev);
182 free_irq(dev->irq, dev);
183 free_netdev(dev);
184 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185}
186
Michael Grzeschik8c14f9c2014-09-29 11:55:36 +0200187static struct com20020_pci_card_info card_info_10mbit = {
188 .name = "ARC-PCI",
189 .devcount = 1,
190 .chan_map_tbl = {
191 { 2, 0x00, 0x08 },
192 },
193 .flags = ARC_CAN_10MBIT,
194};
195
196static struct com20020_pci_card_info card_info_5mbit = {
197 .name = "ARC-PCI",
198 .devcount = 1,
199 .chan_map_tbl = {
200 { 2, 0x00, 0x08 },
201 },
202 .flags = ARC_IS_5MBIT,
203};
204
205static struct com20020_pci_card_info card_info_sohard = {
206 .name = "PLX-PCI",
207 .devcount = 1,
208 /* SOHARD needs PCI base addr 4 */
209 .chan_map_tbl = {
210 {4, 0x00, 0x08},
211 },
212 .flags = ARC_CAN_10MBIT,
213};
214
Michael Grzeschikd95e2fe2015-02-13 13:03:50 +0100215static struct com20020_pci_card_info card_info_eae_arc1 = {
216 .name = "EAE PLX-PCI ARC1",
217 .devcount = 1,
218 .chan_map_tbl = {
219 { 2, 0x00, 0x08 },
220 },
221 .flags = ARC_CAN_10MBIT,
222};
223
224static struct com20020_pci_card_info card_info_eae_ma1 = {
225 .name = "EAE PLX-PCI MA1",
Michael Grzeschik5b85bad2014-09-29 11:55:38 +0200226 .devcount = 2,
227 .chan_map_tbl = {
228 { 2, 0x00, 0x08 },
229 { 2, 0x08, 0x08 }
230 },
231 .flags = ARC_CAN_10MBIT,
232};
233
Benoit Taine9baa3c32014-08-08 15:56:03 +0200234static const struct pci_device_id com20020pci_id_table[] = {
Michael Grzeschik8c14f9c2014-09-29 11:55:36 +0200235 {
236 0x1571, 0xa001,
237 PCI_ANY_ID, PCI_ANY_ID,
238 0, 0,
239 0,
240 },
241 {
242 0x1571, 0xa002,
243 PCI_ANY_ID, PCI_ANY_ID,
244 0, 0,
245 0,
246 },
247 {
248 0x1571, 0xa003,
249 PCI_ANY_ID, PCI_ANY_ID,
250 0, 0,
251 0
252 },
253 {
254 0x1571, 0xa004,
255 PCI_ANY_ID, PCI_ANY_ID,
256 0, 0,
257 0,
258 },
259 {
260 0x1571, 0xa005,
261 PCI_ANY_ID, PCI_ANY_ID,
262 0, 0,
263 0
264 },
265 {
266 0x1571, 0xa006,
267 PCI_ANY_ID, PCI_ANY_ID,
268 0, 0,
269 0
270 },
271 {
272 0x1571, 0xa007,
273 PCI_ANY_ID, PCI_ANY_ID,
274 0, 0,
275 0
276 },
277 {
278 0x1571, 0xa008,
279 PCI_ANY_ID, PCI_ANY_ID,
280 0, 0,
281 0
282 },
283 {
284 0x1571, 0xa009,
285 PCI_ANY_ID, PCI_ANY_ID,
286 0, 0,
287 (kernel_ulong_t)&card_info_5mbit
288 },
289 {
290 0x1571, 0xa00a,
291 PCI_ANY_ID, PCI_ANY_ID,
292 0, 0,
293 (kernel_ulong_t)&card_info_5mbit
294 },
295 {
296 0x1571, 0xa00b,
297 PCI_ANY_ID, PCI_ANY_ID,
298 0, 0,
299 (kernel_ulong_t)&card_info_5mbit
300 },
301 {
302 0x1571, 0xa00c,
303 PCI_ANY_ID, PCI_ANY_ID,
304 0, 0,
305 (kernel_ulong_t)&card_info_5mbit
306 },
307 {
308 0x1571, 0xa00d,
309 PCI_ANY_ID, PCI_ANY_ID,
310 0, 0,
311 (kernel_ulong_t)&card_info_5mbit
312 },
313 {
314 0x1571, 0xa00e,
315 PCI_ANY_ID, PCI_ANY_ID,
316 0, 0,
317 (kernel_ulong_t)&card_info_5mbit
318 },
319 {
320 0x1571, 0xa201,
321 PCI_ANY_ID, PCI_ANY_ID,
322 0, 0,
323 (kernel_ulong_t)&card_info_10mbit
324 },
325 {
326 0x1571, 0xa202,
327 PCI_ANY_ID, PCI_ANY_ID,
328 0, 0,
329 (kernel_ulong_t)&card_info_10mbit
330 },
331 {
332 0x1571, 0xa203,
333 PCI_ANY_ID, PCI_ANY_ID,
334 0, 0,
335 (kernel_ulong_t)&card_info_10mbit
336 },
337 {
338 0x1571, 0xa204,
339 PCI_ANY_ID, PCI_ANY_ID,
340 0, 0,
341 (kernel_ulong_t)&card_info_10mbit
342 },
343 {
344 0x1571, 0xa205,
345 PCI_ANY_ID, PCI_ANY_ID,
346 0, 0,
347 (kernel_ulong_t)&card_info_10mbit
348 },
349 {
350 0x1571, 0xa206,
351 PCI_ANY_ID, PCI_ANY_ID,
352 0, 0,
353 (kernel_ulong_t)&card_info_10mbit
354 },
355 {
356 0x10B5, 0x9030,
357 0x10B5, 0x2978,
358 0, 0,
359 (kernel_ulong_t)&card_info_sohard
360 },
361 {
362 0x10B5, 0x9050,
363 0x10B5, 0x2273,
364 0, 0,
365 (kernel_ulong_t)&card_info_sohard
366 },
367 {
Michael Grzeschik5b85bad2014-09-29 11:55:38 +0200368 0x10B5, 0x9050,
Michael Grzeschikd95e2fe2015-02-13 13:03:50 +0100369 0x10B5, 0x3263,
370 0, 0,
371 (kernel_ulong_t)&card_info_eae_arc1
372 },
373 {
374 0x10B5, 0x9050,
Michael Grzeschik5b85bad2014-09-29 11:55:38 +0200375 0x10B5, 0x3292,
376 0, 0,
Michael Grzeschikd95e2fe2015-02-13 13:03:50 +0100377 (kernel_ulong_t)&card_info_eae_ma1
Michael Grzeschik5b85bad2014-09-29 11:55:38 +0200378 },
379 {
Michael Grzeschik8c14f9c2014-09-29 11:55:36 +0200380 0x14BA, 0x6000,
381 PCI_ANY_ID, PCI_ANY_ID,
382 0, 0,
383 (kernel_ulong_t)&card_info_10mbit
384 },
385 {
386 0x10B5, 0x2200,
387 PCI_ANY_ID, PCI_ANY_ID,
388 0, 0,
389 (kernel_ulong_t)&card_info_10mbit
390 },
391 { 0, }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392};
393
394MODULE_DEVICE_TABLE(pci, com20020pci_id_table);
395
396static struct pci_driver com20020pci_driver = {
397 .name = "com20020",
398 .id_table = com20020pci_id_table,
399 .probe = com20020pci_probe,
Bill Pemberton7c47bab2012-12-03 09:22:43 -0500400 .remove = com20020pci_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401};
402
403static int __init com20020pci_init(void)
404{
405 BUGLVL(D_NORMAL) printk(VERSION);
Jeff Garzik29917622006-08-19 17:48:59 -0400406 return pci_register_driver(&com20020pci_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407}
408
409static void __exit com20020pci_cleanup(void)
410{
411 pci_unregister_driver(&com20020pci_driver);
412}
413
414module_init(com20020pci_init)
415module_exit(com20020pci_cleanup)