Commit | Line | Data |
---|---|---|
3878fb6f WG |
1 | /* |
2 | * Copyright (C) 2008 Per Dalen <per.dalen@cnw.se> | |
3 | * | |
4 | * Parts of this software are based on (derived) the following: | |
5 | * | |
6 | * - Kvaser linux driver, version 4.72 BETA | |
7 | * Copyright (C) 2002-2007 KVASER AB | |
8 | * | |
9 | * - Lincan driver, version 0.3.3, OCERA project | |
10 | * Copyright (C) 2004 Pavel Pisa | |
11 | * Copyright (C) 2001 Arnaud Westenberg | |
12 | * | |
13 | * - Socketcan SJA1000 drivers | |
14 | * Copyright (C) 2007 Wolfgang Grandegger <wg@grandegger.com> | |
15 | * Copyright (c) 2002-2007 Volkswagen Group Electronic Research | |
16 | * Copyright (c) 2003 Matthias Brukner, Trajet Gmbh, Rebenring 33, | |
17 | * 38106 Braunschweig, GERMANY | |
18 | * | |
19 | * This program is free software; you can redistribute it and/or modify | |
20 | * it under the terms of the version 2 of the GNU General Public License | |
21 | * as published by the Free Software Foundation | |
22 | * | |
23 | * This program is distributed in the hope that it will be useful, but | |
24 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
26 | * General Public License for more details. | |
27 | * | |
28 | * You should have received a copy of the GNU General Public License | |
05780d98 | 29 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
3878fb6f WG |
30 | */ |
31 | ||
32 | #include <linux/kernel.h> | |
33 | #include <linux/module.h> | |
34 | #include <linux/interrupt.h> | |
35 | #include <linux/netdevice.h> | |
36 | #include <linux/delay.h> | |
37 | #include <linux/pci.h> | |
3878fb6f WG |
38 | #include <linux/can/dev.h> |
39 | #include <linux/io.h> | |
40 | ||
41 | #include "sja1000.h" | |
42 | ||
43 | #define DRV_NAME "kvaser_pci" | |
44 | ||
45 | MODULE_AUTHOR("Per Dalen <per.dalen@cnw.se>"); | |
46 | MODULE_DESCRIPTION("Socket-CAN driver for KVASER PCAN PCI cards"); | |
47 | MODULE_SUPPORTED_DEVICE("KVASER PCAN PCI CAN card"); | |
48 | MODULE_LICENSE("GPL v2"); | |
49 | ||
50 | #define MAX_NO_OF_CHANNELS 4 /* max no of channels on a single card */ | |
51 | ||
52 | struct kvaser_pci { | |
53 | int channel; | |
54 | struct pci_dev *pci_dev; | |
55 | struct net_device *slave_dev[MAX_NO_OF_CHANNELS-1]; | |
56 | void __iomem *conf_addr; | |
57 | void __iomem *res_addr; | |
58 | int no_channels; | |
59 | u8 xilinx_ver; | |
60 | }; | |
61 | ||
62 | #define KVASER_PCI_CAN_CLOCK (16000000 / 2) | |
63 | ||
64 | /* | |
65 | * The board configuration is probably following: | |
66 | * RX1 is connected to ground. | |
67 | * TX1 is not connected. | |
68 | * CLKO is not connected. | |
69 | * Setting the OCR register to 0xDA is a good idea. | |
70 | * This means normal output mode , push-pull and the correct polarity. | |
71 | */ | |
72 | #define KVASER_PCI_OCR (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL) | |
73 | ||
74 | /* | |
75 | * In the CDR register, you should set CBP to 1. | |
76 | * You will probably also want to set the clock divider value to 0 | |
77 | * (meaning divide-by-2), the Pelican bit, and the clock-off bit | |
78 | * (you will have no need for CLKOUT anyway). | |
79 | */ | |
80 | #define KVASER_PCI_CDR (CDR_CBP | CDR_CLKOUT_MASK) | |
81 | ||
82 | /* | |
83 | * These register values are valid for revision 14 of the Xilinx logic. | |
84 | */ | |
85 | #define XILINX_VERINT 7 /* Lower nibble simulate interrupts, | |
86 | high nibble version number. */ | |
87 | ||
88 | #define XILINX_PRESUMED_VERSION 14 | |
89 | ||
90 | /* | |
91 | * Important S5920 registers | |
92 | */ | |
93 | #define S5920_INTCSR 0x38 | |
94 | #define S5920_PTCR 0x60 | |
95 | #define INTCSR_ADDON_INTENABLE_M 0x2000 | |
96 | ||
97 | ||
98 | #define KVASER_PCI_PORT_BYTES 0x20 | |
99 | ||
100 | #define PCI_CONFIG_PORT_SIZE 0x80 /* size of the config io-memory */ | |
101 | #define PCI_PORT_SIZE 0x80 /* size of a channel io-memory */ | |
102 | #define PCI_PORT_XILINX_SIZE 0x08 /* size of a xilinx io-memory */ | |
103 | ||
104 | #define KVASER_PCI_VENDOR_ID1 0x10e8 /* the PCI device and vendor IDs */ | |
105 | #define KVASER_PCI_DEVICE_ID1 0x8406 | |
106 | ||
107 | #define KVASER_PCI_VENDOR_ID2 0x1a07 /* the PCI device and vendor IDs */ | |
108 | #define KVASER_PCI_DEVICE_ID2 0x0008 | |
109 | ||
9baa3c34 | 110 | static const struct pci_device_id kvaser_pci_tbl[] = { |
3878fb6f WG |
111 | {KVASER_PCI_VENDOR_ID1, KVASER_PCI_DEVICE_ID1, PCI_ANY_ID, PCI_ANY_ID,}, |
112 | {KVASER_PCI_VENDOR_ID2, KVASER_PCI_DEVICE_ID2, PCI_ANY_ID, PCI_ANY_ID,}, | |
113 | { 0,} | |
114 | }; | |
115 | ||
116 | MODULE_DEVICE_TABLE(pci, kvaser_pci_tbl); | |
117 | ||
255a9154 | 118 | static u8 kvaser_pci_read_reg(const struct sja1000_priv *priv, int port) |
3878fb6f | 119 | { |
255a9154 | 120 | return ioread8(priv->reg_base + port); |
3878fb6f WG |
121 | } |
122 | ||
255a9154 WG |
123 | static void kvaser_pci_write_reg(const struct sja1000_priv *priv, |
124 | int port, u8 val) | |
3878fb6f | 125 | { |
255a9154 | 126 | iowrite8(val, priv->reg_base + port); |
3878fb6f WG |
127 | } |
128 | ||
129 | static void kvaser_pci_disable_irq(struct net_device *dev) | |
130 | { | |
131 | struct sja1000_priv *priv = netdev_priv(dev); | |
132 | struct kvaser_pci *board = priv->priv; | |
133 | u32 intcsr; | |
134 | ||
135 | /* Disable interrupts from card */ | |
136 | intcsr = ioread32(board->conf_addr + S5920_INTCSR); | |
137 | intcsr &= ~INTCSR_ADDON_INTENABLE_M; | |
138 | iowrite32(intcsr, board->conf_addr + S5920_INTCSR); | |
139 | } | |
140 | ||
141 | static void kvaser_pci_enable_irq(struct net_device *dev) | |
142 | { | |
143 | struct sja1000_priv *priv = netdev_priv(dev); | |
144 | struct kvaser_pci *board = priv->priv; | |
145 | u32 tmp_en_io; | |
146 | ||
147 | /* Enable interrupts from card */ | |
148 | tmp_en_io = ioread32(board->conf_addr + S5920_INTCSR); | |
149 | tmp_en_io |= INTCSR_ADDON_INTENABLE_M; | |
150 | iowrite32(tmp_en_io, board->conf_addr + S5920_INTCSR); | |
151 | } | |
152 | ||
153 | static int number_of_sja1000_chip(void __iomem *base_addr) | |
154 | { | |
155 | u8 status; | |
156 | int i; | |
157 | ||
158 | for (i = 0; i < MAX_NO_OF_CHANNELS; i++) { | |
159 | /* reset chip */ | |
160 | iowrite8(MOD_RM, base_addr + | |
06e1d1d7 | 161 | (i * KVASER_PCI_PORT_BYTES) + SJA1000_MOD); |
3878fb6f | 162 | status = ioread8(base_addr + |
06e1d1d7 | 163 | (i * KVASER_PCI_PORT_BYTES) + SJA1000_MOD); |
3878fb6f WG |
164 | /* check reset bit */ |
165 | if (!(status & MOD_RM)) | |
166 | break; | |
167 | } | |
168 | ||
169 | return i; | |
170 | } | |
171 | ||
172 | static void kvaser_pci_del_chan(struct net_device *dev) | |
173 | { | |
174 | struct sja1000_priv *priv; | |
175 | struct kvaser_pci *board; | |
176 | int i; | |
177 | ||
178 | if (!dev) | |
179 | return; | |
180 | priv = netdev_priv(dev); | |
181 | board = priv->priv; | |
182 | if (!board) | |
183 | return; | |
184 | ||
185 | dev_info(&board->pci_dev->dev, "Removing device %s\n", | |
186 | dev->name); | |
187 | ||
188 | /* Disable PCI interrupts */ | |
189 | kvaser_pci_disable_irq(dev); | |
190 | ||
191 | for (i = 0; i < board->no_channels - 1; i++) { | |
192 | if (board->slave_dev[i]) { | |
193 | dev_info(&board->pci_dev->dev, "Removing device %s\n", | |
194 | board->slave_dev[i]->name); | |
195 | unregister_sja1000dev(board->slave_dev[i]); | |
196 | free_sja1000dev(board->slave_dev[i]); | |
197 | } | |
198 | } | |
199 | unregister_sja1000dev(dev); | |
200 | ||
255a9154 | 201 | pci_iounmap(board->pci_dev, priv->reg_base); |
3878fb6f WG |
202 | pci_iounmap(board->pci_dev, board->conf_addr); |
203 | pci_iounmap(board->pci_dev, board->res_addr); | |
204 | ||
205 | free_sja1000dev(dev); | |
206 | } | |
207 | ||
208 | static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel, | |
209 | struct net_device **master_dev, | |
210 | void __iomem *conf_addr, | |
211 | void __iomem *res_addr, | |
255a9154 | 212 | void __iomem *base_addr) |
3878fb6f WG |
213 | { |
214 | struct net_device *dev; | |
215 | struct sja1000_priv *priv; | |
216 | struct kvaser_pci *board; | |
4e2061b1 | 217 | int err; |
3878fb6f WG |
218 | |
219 | dev = alloc_sja1000dev(sizeof(struct kvaser_pci)); | |
220 | if (dev == NULL) | |
221 | return -ENOMEM; | |
222 | ||
223 | priv = netdev_priv(dev); | |
224 | board = priv->priv; | |
225 | ||
226 | board->pci_dev = pdev; | |
227 | board->channel = channel; | |
228 | ||
229 | /* S5920 */ | |
230 | board->conf_addr = conf_addr; | |
231 | ||
232 | /* XILINX board wide address */ | |
233 | board->res_addr = res_addr; | |
234 | ||
235 | if (channel == 0) { | |
236 | board->xilinx_ver = | |
237 | ioread8(board->res_addr + XILINX_VERINT) >> 4; | |
3878fb6f WG |
238 | |
239 | /* Assert PTADR# - we're in passive mode so the other bits are | |
240 | not important */ | |
241 | iowrite32(0x80808080UL, board->conf_addr + S5920_PTCR); | |
242 | ||
243 | /* Enable interrupts from card */ | |
244 | kvaser_pci_enable_irq(dev); | |
245 | } else { | |
246 | struct sja1000_priv *master_priv = netdev_priv(*master_dev); | |
247 | struct kvaser_pci *master_board = master_priv->priv; | |
248 | master_board->slave_dev[channel - 1] = dev; | |
249 | master_board->no_channels = channel + 1; | |
250 | board->xilinx_ver = master_board->xilinx_ver; | |
251 | } | |
252 | ||
255a9154 | 253 | priv->reg_base = base_addr + channel * KVASER_PCI_PORT_BYTES; |
3878fb6f WG |
254 | |
255 | priv->read_reg = kvaser_pci_read_reg; | |
256 | priv->write_reg = kvaser_pci_write_reg; | |
257 | ||
258 | priv->can.clock.freq = KVASER_PCI_CAN_CLOCK; | |
259 | ||
260 | priv->ocr = KVASER_PCI_OCR; | |
261 | priv->cdr = KVASER_PCI_CDR; | |
262 | ||
263 | priv->irq_flags = IRQF_SHARED; | |
264 | dev->irq = pdev->irq; | |
265 | ||
255a9154 WG |
266 | dev_info(&pdev->dev, "reg_base=%p conf_addr=%p irq=%d\n", |
267 | priv->reg_base, board->conf_addr, dev->irq); | |
3878fb6f WG |
268 | |
269 | SET_NETDEV_DEV(dev, &pdev->dev); | |
3e66d013 | 270 | dev->dev_id = channel; |
3878fb6f WG |
271 | |
272 | /* Register SJA1000 device */ | |
273 | err = register_sja1000dev(dev); | |
274 | if (err) { | |
275 | dev_err(&pdev->dev, "Registering device failed (err=%d)\n", | |
276 | err); | |
277 | goto failure; | |
278 | } | |
279 | ||
280 | if (channel == 0) | |
281 | *master_dev = dev; | |
282 | ||
283 | return 0; | |
284 | ||
285 | failure: | |
286 | kvaser_pci_del_chan(dev); | |
287 | return err; | |
288 | } | |
289 | ||
3c8ac0f2 | 290 | static int kvaser_pci_init_one(struct pci_dev *pdev, |
1dd06ae8 | 291 | const struct pci_device_id *ent) |
3878fb6f WG |
292 | { |
293 | int err; | |
294 | struct net_device *master_dev = NULL; | |
295 | struct sja1000_priv *priv; | |
296 | struct kvaser_pci *board; | |
297 | int no_channels; | |
298 | void __iomem *base_addr = NULL; | |
299 | void __iomem *conf_addr = NULL; | |
300 | void __iomem *res_addr = NULL; | |
301 | int i; | |
302 | ||
303 | dev_info(&pdev->dev, "initializing device %04x:%04x\n", | |
304 | pdev->vendor, pdev->device); | |
305 | ||
306 | err = pci_enable_device(pdev); | |
307 | if (err) | |
308 | goto failure; | |
309 | ||
310 | err = pci_request_regions(pdev, DRV_NAME); | |
311 | if (err) | |
312 | goto failure_release_pci; | |
313 | ||
314 | /* S5920 */ | |
315 | conf_addr = pci_iomap(pdev, 0, PCI_CONFIG_PORT_SIZE); | |
316 | if (conf_addr == NULL) { | |
317 | err = -ENODEV; | |
318 | goto failure_release_regions; | |
319 | } | |
320 | ||
321 | /* XILINX board wide address */ | |
322 | res_addr = pci_iomap(pdev, 2, PCI_PORT_XILINX_SIZE); | |
323 | if (res_addr == NULL) { | |
324 | err = -ENOMEM; | |
325 | goto failure_iounmap; | |
326 | } | |
327 | ||
328 | base_addr = pci_iomap(pdev, 1, PCI_PORT_SIZE); | |
329 | if (base_addr == NULL) { | |
330 | err = -ENOMEM; | |
331 | goto failure_iounmap; | |
332 | } | |
333 | ||
334 | no_channels = number_of_sja1000_chip(base_addr); | |
335 | if (no_channels == 0) { | |
336 | err = -ENOMEM; | |
337 | goto failure_iounmap; | |
338 | } | |
339 | ||
340 | for (i = 0; i < no_channels; i++) { | |
341 | err = kvaser_pci_add_chan(pdev, i, &master_dev, | |
342 | conf_addr, res_addr, | |
255a9154 | 343 | base_addr); |
3878fb6f WG |
344 | if (err) |
345 | goto failure_cleanup; | |
346 | } | |
347 | ||
348 | priv = netdev_priv(master_dev); | |
349 | board = priv->priv; | |
350 | ||
351 | dev_info(&pdev->dev, "xilinx version=%d number of channels=%d\n", | |
352 | board->xilinx_ver, board->no_channels); | |
353 | ||
354 | pci_set_drvdata(pdev, master_dev); | |
355 | return 0; | |
356 | ||
357 | failure_cleanup: | |
358 | kvaser_pci_del_chan(master_dev); | |
359 | ||
360 | failure_iounmap: | |
361 | if (conf_addr != NULL) | |
362 | pci_iounmap(pdev, conf_addr); | |
363 | if (res_addr != NULL) | |
364 | pci_iounmap(pdev, res_addr); | |
365 | if (base_addr != NULL) | |
366 | pci_iounmap(pdev, base_addr); | |
367 | ||
368 | failure_release_regions: | |
369 | pci_release_regions(pdev); | |
370 | ||
371 | failure_release_pci: | |
372 | pci_disable_device(pdev); | |
373 | ||
374 | failure: | |
375 | return err; | |
376 | ||
377 | } | |
378 | ||
3c8ac0f2 | 379 | static void kvaser_pci_remove_one(struct pci_dev *pdev) |
3878fb6f WG |
380 | { |
381 | struct net_device *dev = pci_get_drvdata(pdev); | |
382 | ||
383 | kvaser_pci_del_chan(dev); | |
384 | ||
385 | pci_release_regions(pdev); | |
386 | pci_disable_device(pdev); | |
3878fb6f WG |
387 | } |
388 | ||
389 | static struct pci_driver kvaser_pci_driver = { | |
390 | .name = DRV_NAME, | |
391 | .id_table = kvaser_pci_tbl, | |
392 | .probe = kvaser_pci_init_one, | |
3c8ac0f2 | 393 | .remove = kvaser_pci_remove_one, |
3878fb6f WG |
394 | }; |
395 | ||
fb7944b3 | 396 | module_pci_driver(kvaser_pci_driver); |