xref: /linux/drivers/net/arcnet/com20020-pci.c (revision b8d312aa075f33282565467662c4628dae0a2aff)
1 /*
2  * Linux ARCnet driver - COM20020 PCI support
3  * Contemporary Controls PCI20 and SOHARD SH-ARC PCI
4  *
5  * 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 
30 #define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
31 
32 #include <linux/module.h>
33 #include <linux/moduleparam.h>
34 #include <linux/kernel.h>
35 #include <linux/types.h>
36 #include <linux/ioport.h>
37 #include <linux/errno.h>
38 #include <linux/netdevice.h>
39 #include <linux/init.h>
40 #include <linux/interrupt.h>
41 #include <linux/pci.h>
42 #include <linux/list.h>
43 #include <linux/io.h>
44 #include <linux/leds.h>
45 
46 #include "arcdevice.h"
47 #include "com20020.h"
48 
49 /* Module parameters */
50 
51 static int node;
52 static char device[9];		/* use eg. device="arc1" to change name */
53 static int timeout = 3;
54 static int backplane;
55 static int clockp;
56 static int clockm;
57 
58 module_param(node, int, 0);
59 module_param_string(device, device, sizeof(device), 0);
60 module_param(timeout, int, 0);
61 module_param(backplane, int, 0);
62 module_param(clockp, int, 0);
63 module_param(clockm, int, 0);
64 MODULE_LICENSE("GPL");
65 
66 static void led_tx_set(struct led_classdev *led_cdev,
67 			     enum led_brightness value)
68 {
69 	struct com20020_dev *card;
70 	struct com20020_priv *priv;
71 	struct com20020_pci_card_info *ci;
72 
73 	card = container_of(led_cdev, struct com20020_dev, tx_led);
74 
75 	priv = card->pci_priv;
76 	ci = priv->ci;
77 
78 	outb(!!value, priv->misc + ci->leds[card->index].green);
79 }
80 
81 static void led_recon_set(struct led_classdev *led_cdev,
82 			     enum led_brightness value)
83 {
84 	struct com20020_dev *card;
85 	struct com20020_priv *priv;
86 	struct com20020_pci_card_info *ci;
87 
88 	card = container_of(led_cdev, struct com20020_dev, recon_led);
89 
90 	priv = card->pci_priv;
91 	ci = priv->ci;
92 
93 	outb(!!value, priv->misc + ci->leds[card->index].red);
94 }
95 
96 static ssize_t backplane_mode_show(struct device *dev,
97 				   struct device_attribute *attr,
98 				   char *buf)
99 {
100 	struct net_device *net_dev = to_net_dev(dev);
101 	struct arcnet_local *lp = netdev_priv(net_dev);
102 
103 	return sprintf(buf, "%s\n", lp->backplane ? "true" : "false");
104 }
105 static DEVICE_ATTR_RO(backplane_mode);
106 
107 static struct attribute *com20020_state_attrs[] = {
108 	&dev_attr_backplane_mode.attr,
109 	NULL,
110 };
111 
112 static const struct attribute_group com20020_state_group = {
113 	.name = NULL,
114 	.attrs = com20020_state_attrs,
115 };
116 
117 static void com20020pci_remove(struct pci_dev *pdev);
118 
119 static int com20020pci_probe(struct pci_dev *pdev,
120 			     const struct pci_device_id *id)
121 {
122 	struct com20020_pci_card_info *ci;
123 	struct com20020_pci_channel_map *mm;
124 	struct net_device *dev;
125 	struct arcnet_local *lp;
126 	struct com20020_priv *priv;
127 	int i, ioaddr, ret;
128 	struct resource *r;
129 
130 	if (pci_enable_device(pdev))
131 		return -EIO;
132 
133 	priv = devm_kzalloc(&pdev->dev, sizeof(struct com20020_priv),
134 			    GFP_KERNEL);
135 	if (!priv)
136 		return -ENOMEM;
137 
138 	ci = (struct com20020_pci_card_info *)id->driver_data;
139 	priv->ci = ci;
140 	mm = &ci->misc_map;
141 
142 	INIT_LIST_HEAD(&priv->list_dev);
143 
144 	if (mm->size) {
145 		ioaddr = pci_resource_start(pdev, mm->bar) + mm->offset;
146 		r = devm_request_region(&pdev->dev, ioaddr, mm->size,
147 					"com20020-pci");
148 		if (!r) {
149 			pr_err("IO region %xh-%xh already allocated.\n",
150 			       ioaddr, ioaddr + mm->size - 1);
151 			return -EBUSY;
152 		}
153 		priv->misc = ioaddr;
154 	}
155 
156 	for (i = 0; i < ci->devcount; i++) {
157 		struct com20020_pci_channel_map *cm = &ci->chan_map_tbl[i];
158 		struct com20020_dev *card;
159 		int dev_id_mask = 0xf;
160 
161 		dev = alloc_arcdev(device);
162 		if (!dev) {
163 			ret = -ENOMEM;
164 			goto out_port;
165 		}
166 		dev->dev_port = i;
167 
168 		dev->netdev_ops = &com20020_netdev_ops;
169 
170 		lp = netdev_priv(dev);
171 
172 		arc_printk(D_NORMAL, dev, "%s Controls\n", ci->name);
173 		ioaddr = pci_resource_start(pdev, cm->bar) + cm->offset;
174 
175 		r = devm_request_region(&pdev->dev, ioaddr, cm->size,
176 					"com20020-pci");
177 		if (!r) {
178 			pr_err("IO region %xh-%xh already allocated\n",
179 			       ioaddr, ioaddr + cm->size - 1);
180 			ret = -EBUSY;
181 			goto out_port;
182 		}
183 
184 		/* Dummy access after Reset
185 		 * ARCNET controller needs
186 		 * this access to detect bustype
187 		 */
188 		arcnet_outb(0x00, ioaddr, COM20020_REG_W_COMMAND);
189 		arcnet_inb(ioaddr, COM20020_REG_R_DIAGSTAT);
190 
191 		SET_NETDEV_DEV(dev, &pdev->dev);
192 		dev->base_addr = ioaddr;
193 		dev->dev_addr[0] = node;
194 		dev->sysfs_groups[0] = &com20020_state_group;
195 		dev->irq = pdev->irq;
196 		lp->card_name = "PCI COM20020";
197 		lp->card_flags = ci->flags;
198 		lp->backplane = backplane;
199 		lp->clockp = clockp & 7;
200 		lp->clockm = clockm & 3;
201 		lp->timeout = timeout;
202 		lp->hw.owner = THIS_MODULE;
203 
204 		lp->backplane = (inb(priv->misc) >> (2 + i)) & 0x1;
205 
206 		if (!strncmp(ci->name, "EAE PLX-PCI FB2", 15))
207 			lp->backplane = 1;
208 
209 		/* Get the dev_id from the PLX rotary coder */
210 		if (!strncmp(ci->name, "EAE PLX-PCI MA1", 15))
211 			dev_id_mask = 0x3;
212 		dev->dev_id = (inb(priv->misc + ci->rotary) >> 4) & dev_id_mask;
213 
214 		snprintf(dev->name, sizeof(dev->name), "arc%d-%d", dev->dev_id, i);
215 
216 		if (arcnet_inb(ioaddr, COM20020_REG_R_STATUS) == 0xFF) {
217 			pr_err("IO address %Xh is empty!\n", ioaddr);
218 			ret = -EIO;
219 			goto out_port;
220 		}
221 		if (com20020_check(dev)) {
222 			ret = -EIO;
223 			goto out_port;
224 		}
225 
226 		card = devm_kzalloc(&pdev->dev, sizeof(struct com20020_dev),
227 				    GFP_KERNEL);
228 		if (!card) {
229 			ret = -ENOMEM;
230 			goto out_port;
231 		}
232 
233 		card->index = i;
234 		card->pci_priv = priv;
235 		card->tx_led.brightness_set = led_tx_set;
236 		card->tx_led.default_trigger = devm_kasprintf(&pdev->dev,
237 						GFP_KERNEL, "arc%d-%d-tx",
238 						dev->dev_id, i);
239 		card->tx_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
240 						"pci:green:tx:%d-%d",
241 						dev->dev_id, i);
242 
243 		card->tx_led.dev = &dev->dev;
244 		card->recon_led.brightness_set = led_recon_set;
245 		card->recon_led.default_trigger = devm_kasprintf(&pdev->dev,
246 						GFP_KERNEL, "arc%d-%d-recon",
247 						dev->dev_id, i);
248 		card->recon_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
249 						"pci:red:recon:%d-%d",
250 						dev->dev_id, i);
251 		card->recon_led.dev = &dev->dev;
252 		card->dev = dev;
253 
254 		ret = devm_led_classdev_register(&pdev->dev, &card->tx_led);
255 		if (ret)
256 			goto out_port;
257 
258 		ret = devm_led_classdev_register(&pdev->dev, &card->recon_led);
259 		if (ret)
260 			goto out_port;
261 
262 		dev_set_drvdata(&dev->dev, card);
263 
264 		ret = com20020_found(dev, IRQF_SHARED);
265 		if (ret)
266 			goto out_port;
267 
268 		devm_arcnet_led_init(dev, dev->dev_id, i);
269 
270 		list_add(&card->list, &priv->list_dev);
271 	}
272 
273 	pci_set_drvdata(pdev, priv);
274 
275 	return 0;
276 
277 out_port:
278 	com20020pci_remove(pdev);
279 	return ret;
280 }
281 
282 static void com20020pci_remove(struct pci_dev *pdev)
283 {
284 	struct com20020_dev *card, *tmpcard;
285 	struct com20020_priv *priv;
286 
287 	priv = pci_get_drvdata(pdev);
288 
289 	list_for_each_entry_safe(card, tmpcard, &priv->list_dev, list) {
290 		struct net_device *dev = card->dev;
291 
292 		unregister_netdev(dev);
293 		free_irq(dev->irq, dev);
294 		free_netdev(dev);
295 	}
296 }
297 
298 static struct com20020_pci_card_info card_info_10mbit = {
299 	.name = "ARC-PCI",
300 	.devcount = 1,
301 	.chan_map_tbl = {
302 		{
303 			.bar = 2,
304 			.offset = 0x00,
305 			.size = 0x08,
306 		},
307 	},
308 	.flags = ARC_CAN_10MBIT,
309 };
310 
311 static struct com20020_pci_card_info card_info_5mbit = {
312 	.name = "ARC-PCI",
313 	.devcount = 1,
314 	.chan_map_tbl = {
315 		{
316 			.bar = 2,
317 			.offset = 0x00,
318 			.size = 0x08,
319 		},
320 	},
321 	.flags = ARC_IS_5MBIT,
322 };
323 
324 static struct com20020_pci_card_info card_info_sohard = {
325 	.name = "PLX-PCI",
326 	.devcount = 1,
327 	/* SOHARD needs PCI base addr 4 */
328 	.chan_map_tbl = {
329 		{
330 			.bar = 4,
331 			.offset = 0x00,
332 			.size = 0x08
333 		},
334 	},
335 	.flags = ARC_CAN_10MBIT,
336 };
337 
338 static struct com20020_pci_card_info card_info_eae_arc1 = {
339 	.name = "EAE PLX-PCI ARC1",
340 	.devcount = 1,
341 	.chan_map_tbl = {
342 		{
343 			.bar = 2,
344 			.offset = 0x00,
345 			.size = 0x08,
346 		},
347 	},
348 	.misc_map = {
349 		.bar = 2,
350 		.offset = 0x10,
351 		.size = 0x04,
352 	},
353 	.leds = {
354 		{
355 			.green = 0x0,
356 			.red = 0x1,
357 		},
358 	},
359 	.rotary = 0x0,
360 	.flags = ARC_CAN_10MBIT,
361 };
362 
363 static struct com20020_pci_card_info card_info_eae_ma1 = {
364 	.name = "EAE PLX-PCI MA1",
365 	.devcount = 2,
366 	.chan_map_tbl = {
367 		{
368 			.bar = 2,
369 			.offset = 0x00,
370 			.size = 0x08,
371 		}, {
372 			.bar = 2,
373 			.offset = 0x08,
374 			.size = 0x08,
375 		}
376 	},
377 	.misc_map = {
378 		.bar = 2,
379 		.offset = 0x10,
380 		.size = 0x04,
381 	},
382 	.leds = {
383 		{
384 			.green = 0x0,
385 			.red = 0x1,
386 		}, {
387 			.green = 0x2,
388 			.red = 0x3,
389 		},
390 	},
391 	.rotary = 0x0,
392 	.flags = ARC_CAN_10MBIT,
393 };
394 
395 static struct com20020_pci_card_info card_info_eae_fb2 = {
396 	.name = "EAE PLX-PCI FB2",
397 	.devcount = 1,
398 	.chan_map_tbl = {
399 		{
400 			.bar = 2,
401 			.offset = 0x00,
402 			.size = 0x08,
403 		},
404 	},
405 	.misc_map = {
406 		.bar = 2,
407 		.offset = 0x10,
408 		.size = 0x04,
409 	},
410 	.leds = {
411 		{
412 			.green = 0x0,
413 			.red = 0x1,
414 		},
415 	},
416 	.rotary = 0x0,
417 	.flags = ARC_CAN_10MBIT,
418 };
419 
420 static const struct pci_device_id com20020pci_id_table[] = {
421 	{
422 		0x1571, 0xa001,
423 		PCI_ANY_ID, PCI_ANY_ID,
424 		0, 0,
425 		0,
426 	},
427 	{
428 		0x1571, 0xa002,
429 		PCI_ANY_ID, PCI_ANY_ID,
430 		0, 0,
431 		0,
432 	},
433 	{
434 		0x1571, 0xa003,
435 		PCI_ANY_ID, PCI_ANY_ID,
436 		0, 0,
437 		0
438 	},
439 	{
440 		0x1571, 0xa004,
441 		PCI_ANY_ID, PCI_ANY_ID,
442 		0, 0,
443 		0,
444 	},
445 	{
446 		0x1571, 0xa005,
447 		PCI_ANY_ID, PCI_ANY_ID,
448 		0, 0,
449 		0
450 	},
451 	{
452 		0x1571, 0xa006,
453 		PCI_ANY_ID, PCI_ANY_ID,
454 		0, 0,
455 		0
456 	},
457 	{
458 		0x1571, 0xa007,
459 		PCI_ANY_ID, PCI_ANY_ID,
460 		0, 0,
461 		0
462 	},
463 	{
464 		0x1571, 0xa008,
465 		PCI_ANY_ID, PCI_ANY_ID,
466 		0, 0,
467 		0
468 	},
469 	{
470 		0x1571, 0xa009,
471 		PCI_ANY_ID, PCI_ANY_ID,
472 		0, 0,
473 		(kernel_ulong_t)&card_info_5mbit
474 	},
475 	{
476 		0x1571, 0xa00a,
477 		PCI_ANY_ID, PCI_ANY_ID,
478 		0, 0,
479 		(kernel_ulong_t)&card_info_5mbit
480 	},
481 	{
482 		0x1571, 0xa00b,
483 		PCI_ANY_ID, PCI_ANY_ID,
484 		0, 0,
485 		(kernel_ulong_t)&card_info_5mbit
486 	},
487 	{
488 		0x1571, 0xa00c,
489 		PCI_ANY_ID, PCI_ANY_ID,
490 		0, 0,
491 		(kernel_ulong_t)&card_info_5mbit
492 	},
493 	{
494 		0x1571, 0xa00d,
495 		PCI_ANY_ID, PCI_ANY_ID,
496 		0, 0,
497 		(kernel_ulong_t)&card_info_5mbit
498 	},
499 	{
500 		0x1571, 0xa00e,
501 		PCI_ANY_ID, PCI_ANY_ID,
502 		0, 0,
503 		(kernel_ulong_t)&card_info_5mbit
504 	},
505 	{
506 		0x1571, 0xa201,
507 		PCI_ANY_ID, PCI_ANY_ID,
508 		0, 0,
509 		(kernel_ulong_t)&card_info_10mbit
510 	},
511 	{
512 		0x1571, 0xa202,
513 		PCI_ANY_ID, PCI_ANY_ID,
514 		0, 0,
515 		(kernel_ulong_t)&card_info_10mbit
516 	},
517 	{
518 		0x1571, 0xa203,
519 		PCI_ANY_ID, PCI_ANY_ID,
520 		0, 0,
521 		(kernel_ulong_t)&card_info_10mbit
522 	},
523 	{
524 		0x1571, 0xa204,
525 		PCI_ANY_ID, PCI_ANY_ID,
526 		0, 0,
527 		(kernel_ulong_t)&card_info_10mbit
528 	},
529 	{
530 		0x1571, 0xa205,
531 		PCI_ANY_ID, PCI_ANY_ID,
532 		0, 0,
533 		(kernel_ulong_t)&card_info_10mbit
534 	},
535 	{
536 		0x1571, 0xa206,
537 		PCI_ANY_ID, PCI_ANY_ID,
538 		0, 0,
539 		(kernel_ulong_t)&card_info_10mbit
540 	},
541 	{
542 		0x10B5, 0x9030,
543 		0x10B5, 0x2978,
544 		0, 0,
545 		(kernel_ulong_t)&card_info_sohard
546 	},
547 	{
548 		0x10B5, 0x9050,
549 		0x10B5, 0x2273,
550 		0, 0,
551 		(kernel_ulong_t)&card_info_sohard
552 	},
553 	{
554 		0x10B5, 0x9050,
555 		0x10B5, 0x3263,
556 		0, 0,
557 		(kernel_ulong_t)&card_info_eae_arc1
558 	},
559 	{
560 		0x10B5, 0x9050,
561 		0x10B5, 0x3292,
562 		0, 0,
563 		(kernel_ulong_t)&card_info_eae_ma1
564 	},
565 	{
566 		0x10B5, 0x9050,
567 		0x10B5, 0x3294,
568 		0, 0,
569 		(kernel_ulong_t)&card_info_eae_fb2
570 	},
571 	{
572 		0x14BA, 0x6000,
573 		PCI_ANY_ID, PCI_ANY_ID,
574 		0, 0,
575 		(kernel_ulong_t)&card_info_10mbit
576 	},
577 	{
578 		0x10B5, 0x2200,
579 		PCI_ANY_ID, PCI_ANY_ID,
580 		0, 0,
581 		(kernel_ulong_t)&card_info_10mbit
582 	},
583 	{ 0, }
584 };
585 
586 MODULE_DEVICE_TABLE(pci, com20020pci_id_table);
587 
588 static struct pci_driver com20020pci_driver = {
589 	.name		= "com20020",
590 	.id_table	= com20020pci_id_table,
591 	.probe		= com20020pci_probe,
592 	.remove		= com20020pci_remove,
593 };
594 
595 static int __init com20020pci_init(void)
596 {
597 	if (BUGLVL(D_NORMAL))
598 		pr_info("%s\n", "COM20020 PCI support");
599 	return pci_register_driver(&com20020pci_driver);
600 }
601 
602 static void __exit com20020pci_cleanup(void)
603 {
604 	pci_unregister_driver(&com20020pci_driver);
605 }
606 
607 module_init(com20020pci_init)
608 module_exit(com20020pci_cleanup)
609