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