]> rtime.felk.cvut.cz Git - lisovros/linux_canprio.git/blob - drivers/net/can/sja1000/pipcan.c
Added socketcan from SVN r903
[lisovros/linux_canprio.git] / drivers / net / can / sja1000 / pipcan.c
1 /*
2  * Copyright (C) 2008 David Müller, <d.mueller@elsoft.ch>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the version 2 of the GNU General Public License
6  * as published by the Free Software Foundation
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  */
17
18 #include <linux/kernel.h>
19 #include <linux/module.h>
20 #include <linux/interrupt.h>
21 #include <linux/netdevice.h>
22 #include <linux/delay.h>
23 #include <linux/platform_device.h>
24 #include <linux/can.h>
25 #include <linux/can/dev.h>
26 #include <linux/io.h>
27
28 #include "sja1000.h"
29
30 #define DRV_NAME "pipcan"
31
32 MODULE_AUTHOR("David Müller <d.mueller@elsoft.ch>");
33 MODULE_DESCRIPTION("Socket-CAN driver for MPL PIPCAN module");
34 MODULE_SUPPORTED_DEVICE("MPL PIPCAN module");
35 MODULE_LICENSE("GPL v2");
36
37 #define PIPCAN_CAN_CLOCK  (16000000 / 2)
38
39 #define PIPCAN_OCR        (OCR_TX1_PUSHPULL)
40 #define PIPCAN_CDR        (CDR_CBP | CDR_CLK_OFF)
41
42 #define PIPCAN_IOSIZE     (0x100)
43
44 #define PIPCAN_RES        (0x804)
45 #define PIPCAN_RST        (0x805)
46
47 static u8 pc_read_reg(struct net_device *dev, int reg)
48 {
49         return inb(dev->base_addr + reg);
50 }
51
52 static void pc_write_reg(struct net_device *dev, int reg, u8 val)
53 {
54         outb(val, dev->base_addr + reg);
55 }
56
57 static int __init pc_probe(struct platform_device *pdev)
58 {
59         struct net_device *dev;
60         struct sja1000_priv *priv;
61         struct resource *res;
62         int rc, irq;
63
64         rc = -ENODEV;
65         res = platform_get_resource(pdev, IORESOURCE_IO, 0);
66         irq = platform_get_irq(pdev, 0);
67         if (!res || !irq)
68                 goto exit;
69
70         rc = -EBUSY;
71         if (!request_region(res->start, res->end - res->start + 1, DRV_NAME))
72                 goto exit;
73
74         rc = -ENOMEM;
75         dev = alloc_sja1000dev(0);
76         if (!dev)
77                 goto exit_release;
78
79         priv = netdev_priv(dev);
80
81         priv->read_reg = pc_read_reg;
82         priv->write_reg = pc_write_reg;
83         priv->can.bittiming.clock = PIPCAN_CAN_CLOCK;
84         priv->ocr = PIPCAN_OCR;
85         priv->cdr = PIPCAN_CDR;
86
87         dev->irq = irq;
88         dev->base_addr = res->start;
89
90         dev_set_drvdata(&pdev->dev, dev);
91         SET_NETDEV_DEV(dev, &pdev->dev);
92
93         /* deactivate RST */
94         outb(inb(PIPCAN_RST) & ~0x01, PIPCAN_RST);
95
96         rc = register_sja1000dev(dev);
97         if (rc) {
98                 dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
99                         DRV_NAME, rc);
100                 goto exit_free;
101         }
102
103         dev_info(&pdev->dev, "device registered (base_addr=%#lx, irq=%d)\n",
104                  dev->base_addr, dev->irq);
105         return 0;
106
107 exit_free:
108         free_sja1000dev(dev);
109
110 exit_release:
111         release_region(res->start, res->end - res->start + 1);
112
113 exit:
114         return rc;
115 }
116
117 static int __exit pc_remove(struct platform_device *pdev)
118 {
119         struct net_device *dev = dev_get_drvdata(&pdev->dev);
120         struct resource *res;
121
122         dev_set_drvdata(&pdev->dev, NULL);
123         unregister_sja1000dev(dev);
124         res = platform_get_resource(pdev, IORESOURCE_IO, 0);
125
126         free_sja1000dev(dev);
127
128         release_region(res->start, res->end - res->start + 1);
129
130         /* activate RST */
131         outb(inb(PIPCAN_RST) | 0x01, PIPCAN_RST);
132
133         return 0;
134 }
135
136 static struct platform_driver pc_driver = {
137         .remove = __exit_p(pc_remove),
138         .driver = {
139                    .name = DRV_NAME,
140                    .owner = THIS_MODULE,
141                    },
142 };
143
144 static struct platform_device *pc_pdev;
145 static const u16 pipcan_ioport[] = {0x1000, 0x8000, 0xE000};
146
147 static int __init pc_init(void)
148 {
149         struct resource r[2];
150         int rc, addr, irq, idx;
151         u8 pc_res;
152
153         /* get PIPCAN resources from EPLD */
154         pc_res = inb(PIPCAN_RES);
155
156         idx = (pc_res & 0x0F);
157         if ((idx <= 0) || (idx > ARRAY_SIZE(pipcan_ioport))) {
158                 printk(KERN_ERR DRV_NAME " invalid base address\n");
159                 return -EINVAL;
160         }
161         addr = pipcan_ioport[idx-1];
162
163         irq = (pc_res >> 4) & 0x0F;
164         if ((irq < 3) || (irq == 8) || (irq == 13)) {
165                 printk(KERN_ERR DRV_NAME " invalid IRQ\n");
166                 return -EINVAL;
167         }
168
169         /* fill in resources */
170         memset(&r, 0, sizeof(r));
171         r[0].start = addr;
172         r[0].end = addr + PIPCAN_IOSIZE - 1;
173         r[0].name = DRV_NAME;
174         r[0].flags = IORESOURCE_IO;
175         r[1].start = r[1].end = irq;
176         r[1].name = DRV_NAME;
177         r[1].flags = IORESOURCE_IRQ;
178
179         pc_pdev = platform_device_register_simple(DRV_NAME, 0, r,
180                                                   ARRAY_SIZE(r));
181         if (IS_ERR(pc_pdev))
182                 return PTR_ERR(pc_pdev);
183
184         rc = platform_driver_probe(&pc_driver, pc_probe);
185         if (rc) {
186                 platform_device_unregister(pc_pdev);
187                 printk(KERN_ERR DRV_NAME
188                        " platform_driver_probe() failed (%d)\n", rc);
189         }
190
191         return rc;
192 }
193
194 static void __exit pc_exit(void)
195 {
196         platform_driver_unregister(&pc_driver);
197         platform_device_unregister(pc_pdev);
198 }
199
200 module_init(pc_init);
201 module_exit(pc_exit);