GNU Linux-libre 6.7.9-gnu
[releases.git] / drivers / net / arcnet / com20020-pci.c
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         ret = 0;
131
132         if (pci_enable_device(pdev))
133                 return -EIO;
134
135         priv = devm_kzalloc(&pdev->dev, sizeof(struct com20020_priv),
136                             GFP_KERNEL);
137         if (!priv)
138                 return -ENOMEM;
139
140         ci = (struct com20020_pci_card_info *)id->driver_data;
141         if (!ci)
142                 return -EINVAL;
143
144         priv->ci = ci;
145         mm = &ci->misc_map;
146
147         pci_set_drvdata(pdev, priv);
148
149         INIT_LIST_HEAD(&priv->list_dev);
150
151         if (mm->size) {
152                 ioaddr = pci_resource_start(pdev, mm->bar) + mm->offset;
153                 r = devm_request_region(&pdev->dev, ioaddr, mm->size,
154                                         "com20020-pci");
155                 if (!r) {
156                         pr_err("IO region %xh-%xh already allocated.\n",
157                                ioaddr, ioaddr + mm->size - 1);
158                         return -EBUSY;
159                 }
160                 priv->misc = ioaddr;
161         }
162
163         for (i = 0; i < ci->devcount; i++) {
164                 struct com20020_pci_channel_map *cm = &ci->chan_map_tbl[i];
165                 struct com20020_dev *card;
166                 int dev_id_mask = 0xf;
167
168                 dev = alloc_arcdev(device);
169                 if (!dev) {
170                         ret = -ENOMEM;
171                         break;
172                 }
173                 dev->dev_port = i;
174
175                 dev->netdev_ops = &com20020_netdev_ops;
176
177                 lp = netdev_priv(dev);
178
179                 arc_printk(D_NORMAL, dev, "%s Controls\n", ci->name);
180                 ioaddr = pci_resource_start(pdev, cm->bar) + cm->offset;
181
182                 r = devm_request_region(&pdev->dev, ioaddr, cm->size,
183                                         "com20020-pci");
184                 if (!r) {
185                         pr_err("IO region %xh-%xh already allocated\n",
186                                ioaddr, ioaddr + cm->size - 1);
187                         ret = -EBUSY;
188                         goto err_free_arcdev;
189                 }
190
191                 /* Dummy access after Reset
192                  * ARCNET controller needs
193                  * this access to detect bustype
194                  */
195                 arcnet_outb(0x00, ioaddr, COM20020_REG_W_COMMAND);
196                 arcnet_inb(ioaddr, COM20020_REG_R_DIAGSTAT);
197
198                 SET_NETDEV_DEV(dev, &pdev->dev);
199                 dev->base_addr = ioaddr;
200                 arcnet_set_addr(dev, node);
201                 dev->sysfs_groups[0] = &com20020_state_group;
202                 dev->irq = pdev->irq;
203                 lp->card_name = "PCI COM20020";
204                 lp->card_flags = ci->flags;
205                 lp->backplane = backplane;
206                 lp->clockp = clockp & 7;
207                 lp->clockm = clockm & 3;
208                 lp->timeout = timeout;
209                 lp->hw.owner = THIS_MODULE;
210
211                 lp->backplane = (inb(priv->misc) >> (2 + i)) & 0x1;
212
213                 if (!strncmp(ci->name, "EAE PLX-PCI FB2", 15))
214                         lp->backplane = 1;
215
216                 if (ci->flags & ARC_HAS_ROTARY) {
217                         /* Get the dev_id from the PLX rotary coder */
218                         if (!strncmp(ci->name, "EAE PLX-PCI MA1", 15))
219                                 dev_id_mask = 0x3;
220                         dev->dev_id = (inb(priv->misc + ci->rotary) >> 4) & dev_id_mask;
221                         snprintf(dev->name, sizeof(dev->name), "arc%d-%d", dev->dev_id, i);
222                 }
223
224                 if (arcnet_inb(ioaddr, COM20020_REG_R_STATUS) == 0xFF) {
225                         pr_err("IO address %Xh is empty!\n", ioaddr);
226                         ret = -EIO;
227                         goto err_free_arcdev;
228                 }
229                 if (com20020_check(dev)) {
230                         ret = -EIO;
231                         goto err_free_arcdev;
232                 }
233
234                 ret = com20020_found(dev, IRQF_SHARED);
235                 if (ret)
236                         goto err_free_arcdev;
237
238                 card = devm_kzalloc(&pdev->dev, sizeof(struct com20020_dev),
239                                     GFP_KERNEL);
240                 if (!card) {
241                         ret = -ENOMEM;
242                         goto err_free_arcdev;
243                 }
244
245                 card->index = i;
246                 card->pci_priv = priv;
247
248                 if (ci->flags & ARC_HAS_LED) {
249                         card->tx_led.brightness_set = led_tx_set;
250                         card->tx_led.default_trigger = devm_kasprintf(&pdev->dev,
251                                                         GFP_KERNEL, "arc%d-%d-tx",
252                                                         dev->dev_id, i);
253                         card->tx_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
254                                                         "pci:green:tx:%d-%d",
255                                                         dev->dev_id, i);
256
257                         card->tx_led.dev = &dev->dev;
258                         card->recon_led.brightness_set = led_recon_set;
259                         card->recon_led.default_trigger = devm_kasprintf(&pdev->dev,
260                                                         GFP_KERNEL, "arc%d-%d-recon",
261                                                         dev->dev_id, i);
262                         card->recon_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
263                                                         "pci:red:recon:%d-%d",
264                                                         dev->dev_id, i);
265                         card->recon_led.dev = &dev->dev;
266
267                         ret = devm_led_classdev_register(&pdev->dev, &card->tx_led);
268                         if (ret)
269                                 goto err_free_arcdev;
270
271                         ret = devm_led_classdev_register(&pdev->dev, &card->recon_led);
272                         if (ret)
273                                 goto err_free_arcdev;
274
275                         dev_set_drvdata(&dev->dev, card);
276                         devm_arcnet_led_init(dev, dev->dev_id, i);
277                 }
278
279                 card->dev = dev;
280                 list_add(&card->list, &priv->list_dev);
281                 continue;
282
283 err_free_arcdev:
284                 free_arcdev(dev);
285                 break;
286         }
287         if (ret)
288                 com20020pci_remove(pdev);
289         return ret;
290 }
291
292 static void com20020pci_remove(struct pci_dev *pdev)
293 {
294         struct com20020_dev *card, *tmpcard;
295         struct com20020_priv *priv;
296
297         priv = pci_get_drvdata(pdev);
298
299         list_for_each_entry_safe(card, tmpcard, &priv->list_dev, list) {
300                 struct net_device *dev = card->dev;
301
302                 unregister_netdev(dev);
303                 free_irq(dev->irq, dev);
304                 free_arcdev(dev);
305         }
306 }
307
308 static struct com20020_pci_card_info card_info_10mbit = {
309         .name = "ARC-PCI",
310         .devcount = 1,
311         .chan_map_tbl = {
312                 {
313                         .bar = 2,
314                         .offset = 0x00,
315                         .size = 0x08,
316                 },
317         },
318         .flags = ARC_CAN_10MBIT,
319 };
320
321 static struct com20020_pci_card_info card_info_5mbit = {
322         .name = "ARC-PCI",
323         .devcount = 1,
324         .chan_map_tbl = {
325                 {
326                         .bar = 2,
327                         .offset = 0x00,
328                         .size = 0x08,
329                 },
330         },
331         .flags = ARC_IS_5MBIT,
332 };
333
334 static struct com20020_pci_card_info card_info_sohard = {
335         .name = "SOHARD SH ARC-PCI",
336         .devcount = 1,
337         /* SOHARD needs PCI base addr 4 */
338         .chan_map_tbl = {
339                 {
340                         .bar = 4,
341                         .offset = 0x00,
342                         .size = 0x08
343                 },
344         },
345         .flags = ARC_CAN_10MBIT,
346 };
347
348 static struct com20020_pci_card_info card_info_eae_arc1 = {
349         .name = "EAE PLX-PCI ARC1",
350         .devcount = 1,
351         .chan_map_tbl = {
352                 {
353                         .bar = 2,
354                         .offset = 0x00,
355                         .size = 0x08,
356                 },
357         },
358         .misc_map = {
359                 .bar = 2,
360                 .offset = 0x10,
361                 .size = 0x04,
362         },
363         .leds = {
364                 {
365                         .green = 0x0,
366                         .red = 0x1,
367                 },
368         },
369         .rotary = 0x0,
370         .flags = ARC_HAS_ROTARY | ARC_HAS_LED | ARC_CAN_10MBIT,
371 };
372
373 static struct com20020_pci_card_info card_info_eae_ma1 = {
374         .name = "EAE PLX-PCI MA1",
375         .devcount = 2,
376         .chan_map_tbl = {
377                 {
378                         .bar = 2,
379                         .offset = 0x00,
380                         .size = 0x08,
381                 }, {
382                         .bar = 2,
383                         .offset = 0x08,
384                         .size = 0x08,
385                 }
386         },
387         .misc_map = {
388                 .bar = 2,
389                 .offset = 0x10,
390                 .size = 0x04,
391         },
392         .leds = {
393                 {
394                         .green = 0x0,
395                         .red = 0x1,
396                 }, {
397                         .green = 0x2,
398                         .red = 0x3,
399                 },
400         },
401         .rotary = 0x0,
402         .flags = ARC_HAS_ROTARY | ARC_HAS_LED | ARC_CAN_10MBIT,
403 };
404
405 static struct com20020_pci_card_info card_info_eae_fb2 = {
406         .name = "EAE PLX-PCI FB2",
407         .devcount = 1,
408         .chan_map_tbl = {
409                 {
410                         .bar = 2,
411                         .offset = 0x00,
412                         .size = 0x08,
413                 },
414         },
415         .misc_map = {
416                 .bar = 2,
417                 .offset = 0x10,
418                 .size = 0x04,
419         },
420         .leds = {
421                 {
422                         .green = 0x0,
423                         .red = 0x1,
424                 },
425         },
426         .rotary = 0x0,
427         .flags = ARC_HAS_ROTARY | ARC_HAS_LED | ARC_CAN_10MBIT,
428 };
429
430 static const struct pci_device_id com20020pci_id_table[] = {
431         {
432                 0x1571, 0xa001,
433                 PCI_ANY_ID, PCI_ANY_ID,
434                 0, 0,
435                 0,
436         },
437         {
438                 0x1571, 0xa002,
439                 PCI_ANY_ID, PCI_ANY_ID,
440                 0, 0,
441                 0,
442         },
443         {
444                 0x1571, 0xa003,
445                 PCI_ANY_ID, PCI_ANY_ID,
446                 0, 0,
447                 0
448         },
449         {
450                 0x1571, 0xa004,
451                 PCI_ANY_ID, PCI_ANY_ID,
452                 0, 0,
453                 0,
454         },
455         {
456                 0x1571, 0xa005,
457                 PCI_ANY_ID, PCI_ANY_ID,
458                 0, 0,
459                 0
460         },
461         {
462                 0x1571, 0xa006,
463                 PCI_ANY_ID, PCI_ANY_ID,
464                 0, 0,
465                 0
466         },
467         {
468                 0x1571, 0xa007,
469                 PCI_ANY_ID, PCI_ANY_ID,
470                 0, 0,
471                 0
472         },
473         {
474                 0x1571, 0xa008,
475                 PCI_ANY_ID, PCI_ANY_ID,
476                 0, 0,
477                 0
478         },
479         {
480                 0x1571, 0xa009,
481                 PCI_ANY_ID, PCI_ANY_ID,
482                 0, 0,
483                 (kernel_ulong_t)&card_info_5mbit
484         },
485         {
486                 0x1571, 0xa00a,
487                 PCI_ANY_ID, PCI_ANY_ID,
488                 0, 0,
489                 (kernel_ulong_t)&card_info_5mbit
490         },
491         {
492                 0x1571, 0xa00b,
493                 PCI_ANY_ID, PCI_ANY_ID,
494                 0, 0,
495                 (kernel_ulong_t)&card_info_5mbit
496         },
497         {
498                 0x1571, 0xa00c,
499                 PCI_ANY_ID, PCI_ANY_ID,
500                 0, 0,
501                 (kernel_ulong_t)&card_info_5mbit
502         },
503         {
504                 0x1571, 0xa00d,
505                 PCI_ANY_ID, PCI_ANY_ID,
506                 0, 0,
507                 (kernel_ulong_t)&card_info_5mbit
508         },
509         {
510                 0x1571, 0xa00e,
511                 PCI_ANY_ID, PCI_ANY_ID,
512                 0, 0,
513                 (kernel_ulong_t)&card_info_5mbit
514         },
515         {
516                 0x1571, 0xa201,
517                 PCI_ANY_ID, PCI_ANY_ID,
518                 0, 0,
519                 (kernel_ulong_t)&card_info_10mbit
520         },
521         {
522                 0x1571, 0xa202,
523                 PCI_ANY_ID, PCI_ANY_ID,
524                 0, 0,
525                 (kernel_ulong_t)&card_info_10mbit
526         },
527         {
528                 0x1571, 0xa203,
529                 PCI_ANY_ID, PCI_ANY_ID,
530                 0, 0,
531                 (kernel_ulong_t)&card_info_10mbit
532         },
533         {
534                 0x1571, 0xa204,
535                 PCI_ANY_ID, PCI_ANY_ID,
536                 0, 0,
537                 (kernel_ulong_t)&card_info_10mbit
538         },
539         {
540                 0x1571, 0xa205,
541                 PCI_ANY_ID, PCI_ANY_ID,
542                 0, 0,
543                 (kernel_ulong_t)&card_info_10mbit
544         },
545         {
546                 0x1571, 0xa206,
547                 PCI_ANY_ID, PCI_ANY_ID,
548                 0, 0,
549                 (kernel_ulong_t)&card_info_10mbit
550         },
551         {
552                 0x10B5, 0x9030,
553                 0x10B5, 0x2978,
554                 0, 0,
555                 (kernel_ulong_t)&card_info_sohard
556         },
557         {
558                 0x10B5, 0x9050,
559                 0x10B5, 0x2273,
560                 0, 0,
561                 (kernel_ulong_t)&card_info_sohard
562         },
563         {
564                 0x10B5, 0x9050,
565                 0x10B5, 0x3263,
566                 0, 0,
567                 (kernel_ulong_t)&card_info_eae_arc1
568         },
569         {
570                 0x10B5, 0x9050,
571                 0x10B5, 0x3292,
572                 0, 0,
573                 (kernel_ulong_t)&card_info_eae_ma1
574         },
575         {
576                 0x10B5, 0x9050,
577                 0x10B5, 0x3294,
578                 0, 0,
579                 (kernel_ulong_t)&card_info_eae_fb2
580         },
581         {
582                 0x14BA, 0x6000,
583                 PCI_ANY_ID, PCI_ANY_ID,
584                 0, 0,
585                 (kernel_ulong_t)&card_info_10mbit
586         },
587         {
588                 0x10B5, 0x2200,
589                 PCI_ANY_ID, PCI_ANY_ID,
590                 0, 0,
591                 (kernel_ulong_t)&card_info_10mbit
592         },
593         { 0, }
594 };
595
596 MODULE_DEVICE_TABLE(pci, com20020pci_id_table);
597
598 static struct pci_driver com20020pci_driver = {
599         .name           = "com20020",
600         .id_table       = com20020pci_id_table,
601         .probe          = com20020pci_probe,
602         .remove         = com20020pci_remove,
603 };
604
605 static int __init com20020pci_init(void)
606 {
607         if (BUGLVL(D_NORMAL))
608                 pr_info("%s\n", "COM20020 PCI support");
609         return pci_register_driver(&com20020pci_driver);
610 }
611
612 static void __exit com20020pci_cleanup(void)
613 {
614         pci_unregister_driver(&com20020pci_driver);
615 }
616
617 module_init(com20020pci_init)
618 module_exit(com20020pci_cleanup)