Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cc770_isa.c
Go to the documentation of this file.
1 /*
2  * Driver for CC770 and AN82527 CAN controllers on the legacy ISA bus
3  *
4  * Copyright (C) 2009, 2011 Wolfgang Grandegger <[email protected]>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the version 2 of the GNU General Public License
8  * as published by the Free Software Foundation
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  */
15 
16 /*
17  * Bosch CC770 and Intel AN82527 CAN controllers on the ISA or PC-104 bus.
18  * The I/O port or memory address and the IRQ number must be specified via
19  * module parameters:
20  *
21  * insmod cc770_isa.ko port=0x310,0x380 irq=7,11
22  *
23  * for ISA devices using I/O ports or:
24  *
25  * insmod cc770_isa.ko mem=0xd1000,0xd1000 irq=7,11
26  *
27  * for memory mapped ISA devices.
28  *
29  * Indirect access via address and data port is supported as well:
30  *
31  * insmod cc770_isa.ko port=0x310,0x380 indirect=1 irq=7,11
32  *
33  * Furthermore, the following mode parameter can be defined:
34  *
35  * clk: External oscillator clock frequency (default=16000000 [16 MHz])
36  * cir: CPU interface register (default=0x40 [DSC])
37  * bcr: Bus configuration register (default=0x40 [CBY])
38  * cor: Clockout register (default=0x00)
39  *
40  * Note: for clk, cir, bcr and cor, the first argument re-defines the
41  * default for all other devices, e.g.:
42  *
43  * insmod cc770_isa.ko mem=0xd1000,0xd1000 irq=7,11 clk=24000000
44  *
45  * is equivalent to
46  *
47  * insmod cc770_isa.ko mem=0xd1000,0xd1000 irq=7,11 clk=24000000,24000000
48  */
49 
50 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
51 
52 #include <linux/kernel.h>
53 #include <linux/module.h>
54 #include <linux/platform_device.h>
55 #include <linux/interrupt.h>
56 #include <linux/netdevice.h>
57 #include <linux/delay.h>
58 #include <linux/irq.h>
59 #include <linux/io.h>
60 #include <linux/can.h>
61 #include <linux/can/dev.h>
63 
64 #include "cc770.h"
65 
66 #define MAXDEV 8
67 
68 MODULE_AUTHOR("Wolfgang Grandegger <[email protected]>");
69 MODULE_DESCRIPTION("Socket-CAN driver for CC770 on the ISA bus");
70 MODULE_LICENSE("GPL v2");
71 
72 #define CLK_DEFAULT 16000000 /* 16 MHz */
73 #define COR_DEFAULT 0x00
74 #define BCR_DEFAULT BUSCFG_CBY
75 
76 static unsigned long port[MAXDEV];
77 static unsigned long mem[MAXDEV];
78 static int __devinitdata irq[MAXDEV];
79 static int __devinitdata clk[MAXDEV];
80 static u8 __devinitdata cir[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
81 static u8 __devinitdata cor[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
82 static u8 __devinitdata bcr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
83 static int __devinitdata indirect[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1};
84 
86 MODULE_PARM_DESC(port, "I/O port number");
87 
89 MODULE_PARM_DESC(mem, "I/O memory address");
90 
91 module_param_array(indirect, int, NULL, S_IRUGO);
92 MODULE_PARM_DESC(indirect, "Indirect access via address and data port");
93 
94 module_param_array(irq, int, NULL, S_IRUGO);
95 MODULE_PARM_DESC(irq, "IRQ number");
96 
98 MODULE_PARM_DESC(clk, "External oscillator clock frequency "
99  "(default=16000000 [16 MHz])");
100 
102 MODULE_PARM_DESC(cir, "CPU interface register (default=0x40 [DSC])");
103 
105 MODULE_PARM_DESC(cor, "Clockout register (default=0x00)");
106 
108 MODULE_PARM_DESC(bcr, "Bus configuration register (default=0x40 [CBY])");
109 
110 #define CC770_IOSIZE 0x20
111 #define CC770_IOSIZE_INDIRECT 0x02
112 
113 /* Spinlock for cc770_isa_port_write_reg_indirect
114  * and cc770_isa_port_read_reg_indirect
115  */
116 static DEFINE_SPINLOCK(cc770_isa_port_lock);
117 
118 static struct platform_device *cc770_isa_devs[MAXDEV];
119 
120 static u8 cc770_isa_mem_read_reg(const struct cc770_priv *priv, int reg)
121 {
122  return readb(priv->reg_base + reg);
123 }
124 
125 static void cc770_isa_mem_write_reg(const struct cc770_priv *priv,
126  int reg, u8 val)
127 {
128  writeb(val, priv->reg_base + reg);
129 }
130 
131 static u8 cc770_isa_port_read_reg(const struct cc770_priv *priv, int reg)
132 {
133  return inb((unsigned long)priv->reg_base + reg);
134 }
135 
136 static void cc770_isa_port_write_reg(const struct cc770_priv *priv,
137  int reg, u8 val)
138 {
139  outb(val, (unsigned long)priv->reg_base + reg);
140 }
141 
142 static u8 cc770_isa_port_read_reg_indirect(const struct cc770_priv *priv,
143  int reg)
144 {
145  unsigned long base = (unsigned long)priv->reg_base;
146  unsigned long flags;
147  u8 val;
148 
149  spin_lock_irqsave(&cc770_isa_port_lock, flags);
150  outb(reg, base);
151  val = inb(base + 1);
152  spin_unlock_irqrestore(&cc770_isa_port_lock, flags);
153 
154  return val;
155 }
156 
157 static void cc770_isa_port_write_reg_indirect(const struct cc770_priv *priv,
158  int reg, u8 val)
159 {
160  unsigned long base = (unsigned long)priv->reg_base;
161  unsigned long flags;
162 
163  spin_lock_irqsave(&cc770_isa_port_lock, flags);
164  outb(reg, base);
165  outb(val, base + 1);
166  spin_unlock_irqrestore(&cc770_isa_port_lock, flags);
167 }
168 
169 static int __devinit cc770_isa_probe(struct platform_device *pdev)
170 {
171  struct net_device *dev;
172  struct cc770_priv *priv;
173  void __iomem *base = NULL;
174  int iosize = CC770_IOSIZE;
175  int idx = pdev->id;
176  int err;
177  u32 clktmp;
178 
179  dev_dbg(&pdev->dev, "probing idx=%d: port=%#lx, mem=%#lx, irq=%d\n",
180  idx, port[idx], mem[idx], irq[idx]);
181  if (mem[idx]) {
182  if (!request_mem_region(mem[idx], iosize, KBUILD_MODNAME)) {
183  err = -EBUSY;
184  goto exit;
185  }
186  base = ioremap_nocache(mem[idx], iosize);
187  if (!base) {
188  err = -ENOMEM;
189  goto exit_release;
190  }
191  } else {
192  if (indirect[idx] > 0 ||
193  (indirect[idx] == -1 && indirect[0] > 0))
194  iosize = CC770_IOSIZE_INDIRECT;
195  if (!request_region(port[idx], iosize, KBUILD_MODNAME)) {
196  err = -EBUSY;
197  goto exit;
198  }
199  }
200 
201  dev = alloc_cc770dev(0);
202  if (!dev) {
203  err = -ENOMEM;
204  goto exit_unmap;
205  }
206  priv = netdev_priv(dev);
207 
208  dev->irq = irq[idx];
209  priv->irq_flags = IRQF_SHARED;
210  if (mem[idx]) {
211  priv->reg_base = base;
212  dev->base_addr = mem[idx];
213  priv->read_reg = cc770_isa_mem_read_reg;
214  priv->write_reg = cc770_isa_mem_write_reg;
215  } else {
216  priv->reg_base = (void __iomem *)port[idx];
217  dev->base_addr = port[idx];
218 
219  if (iosize == CC770_IOSIZE_INDIRECT) {
220  priv->read_reg = cc770_isa_port_read_reg_indirect;
221  priv->write_reg = cc770_isa_port_write_reg_indirect;
222  } else {
223  priv->read_reg = cc770_isa_port_read_reg;
224  priv->write_reg = cc770_isa_port_write_reg;
225  }
226  }
227 
228  if (clk[idx])
229  clktmp = clk[idx];
230  else if (clk[0])
231  clktmp = clk[0];
232  else
233  clktmp = CLK_DEFAULT;
234  priv->can.clock.freq = clktmp;
235 
236  if (cir[idx] != 0xff) {
237  priv->cpu_interface = cir[idx];
238  } else if (cir[0] != 0xff) {
239  priv->cpu_interface = cir[0];
240  } else {
241  /* The system clock may not exceed 10 MHz */
242  if (clktmp > 10000000) {
243  priv->cpu_interface |= CPUIF_DSC;
244  clktmp /= 2;
245  }
246  /* The memory clock may not exceed 8 MHz */
247  if (clktmp > 8000000)
248  priv->cpu_interface |= CPUIF_DMC;
249  }
250 
251  if (priv->cpu_interface & CPUIF_DSC)
252  priv->can.clock.freq /= 2;
253 
254  if (bcr[idx] != 0xff)
255  priv->bus_config = bcr[idx];
256  else if (bcr[0] != 0xff)
257  priv->bus_config = bcr[0];
258  else
259  priv->bus_config = BCR_DEFAULT;
260 
261  if (cor[idx] != 0xff)
262  priv->clkout = cor[idx];
263  else if (cor[0] != 0xff)
264  priv->clkout = cor[0];
265  else
266  priv->clkout = COR_DEFAULT;
267 
268  dev_set_drvdata(&pdev->dev, dev);
269  SET_NETDEV_DEV(dev, &pdev->dev);
270 
271  err = register_cc770dev(dev);
272  if (err) {
273  dev_err(&pdev->dev,
274  "couldn't register device (err=%d)\n", err);
275  goto exit_unmap;
276  }
277 
278  dev_info(&pdev->dev, "device registered (reg_base=0x%p, irq=%d)\n",
279  priv->reg_base, dev->irq);
280  return 0;
281 
282  exit_unmap:
283  if (mem[idx])
284  iounmap(base);
285  exit_release:
286  if (mem[idx])
287  release_mem_region(mem[idx], iosize);
288  else
289  release_region(port[idx], iosize);
290  exit:
291  return err;
292 }
293 
294 static int __devexit cc770_isa_remove(struct platform_device *pdev)
295 {
296  struct net_device *dev = dev_get_drvdata(&pdev->dev);
297  struct cc770_priv *priv = netdev_priv(dev);
298  int idx = pdev->id;
299 
300  unregister_cc770dev(dev);
301  dev_set_drvdata(&pdev->dev, NULL);
302 
303  if (mem[idx]) {
304  iounmap(priv->reg_base);
306  } else {
307  if (priv->read_reg == cc770_isa_port_read_reg_indirect)
309  else
311  }
312  free_cc770dev(dev);
313 
314  return 0;
315 }
316 
317 static struct platform_driver cc770_isa_driver = {
318  .probe = cc770_isa_probe,
319  .remove = __devexit_p(cc770_isa_remove),
320  .driver = {
321  .name = KBUILD_MODNAME,
322  .owner = THIS_MODULE,
323  },
324 };
325 
326 static int __init cc770_isa_init(void)
327 {
328  int idx, err;
329 
330  for (idx = 0; idx < ARRAY_SIZE(cc770_isa_devs); idx++) {
331  if ((port[idx] || mem[idx]) && irq[idx]) {
332  cc770_isa_devs[idx] =
333  platform_device_alloc(KBUILD_MODNAME, idx);
334  if (!cc770_isa_devs[idx]) {
335  err = -ENOMEM;
336  goto exit_free_devices;
337  }
338  err = platform_device_add(cc770_isa_devs[idx]);
339  if (err) {
340  platform_device_put(cc770_isa_devs[idx]);
341  goto exit_free_devices;
342  }
343  pr_debug("platform device %d: port=%#lx, mem=%#lx, "
344  "irq=%d\n",
345  idx, port[idx], mem[idx], irq[idx]);
346  } else if (idx == 0 || port[idx] || mem[idx]) {
347  pr_err("insufficient parameters supplied\n");
348  err = -EINVAL;
349  goto exit_free_devices;
350  }
351  }
352 
353  err = platform_driver_register(&cc770_isa_driver);
354  if (err)
355  goto exit_free_devices;
356 
357  pr_info("driver for max. %d devices registered\n", MAXDEV);
358 
359  return 0;
360 
361 exit_free_devices:
362  while (--idx >= 0) {
363  if (cc770_isa_devs[idx])
364  platform_device_unregister(cc770_isa_devs[idx]);
365  }
366 
367  return err;
368 }
369 module_init(cc770_isa_init);
370 
371 static void __exit cc770_isa_exit(void)
372 {
373  int idx;
374 
375  platform_driver_unregister(&cc770_isa_driver);
376  for (idx = 0; idx < ARRAY_SIZE(cc770_isa_devs); idx++) {
377  if (cc770_isa_devs[idx])
378  platform_device_unregister(cc770_isa_devs[idx]);
379  }
380 }
381 module_exit(cc770_isa_exit);