0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0043
0044 #include <linux/kernel.h>
0045 #include <linux/module.h>
0046 #include <linux/platform_device.h>
0047 #include <linux/interrupt.h>
0048 #include <linux/netdevice.h>
0049 #include <linux/delay.h>
0050 #include <linux/irq.h>
0051 #include <linux/io.h>
0052 #include <linux/can.h>
0053 #include <linux/can/dev.h>
0054 #include <linux/can/platform/cc770.h>
0055
0056 #include "cc770.h"
0057
0058 #define MAXDEV 8
0059
0060 MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
0061 MODULE_DESCRIPTION("Socket-CAN driver for CC770 on the ISA bus");
0062 MODULE_LICENSE("GPL v2");
0063
0064 #define CLK_DEFAULT 16000000
0065 #define COR_DEFAULT 0x00
0066 #define BCR_DEFAULT BUSCFG_CBY
0067
0068 static unsigned long port[MAXDEV];
0069 static unsigned long mem[MAXDEV];
0070 static int irq[MAXDEV];
0071 static int clk[MAXDEV];
0072 static u8 cir[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
0073 static u8 cor[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
0074 static u8 bcr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
0075 static int indirect[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1};
0076
0077 module_param_hw_array(port, ulong, ioport, NULL, 0444);
0078 MODULE_PARM_DESC(port, "I/O port number");
0079
0080 module_param_hw_array(mem, ulong, iomem, NULL, 0444);
0081 MODULE_PARM_DESC(mem, "I/O memory address");
0082
0083 module_param_hw_array(indirect, int, ioport, NULL, 0444);
0084 MODULE_PARM_DESC(indirect, "Indirect access via address and data port");
0085
0086 module_param_hw_array(irq, int, irq, NULL, 0444);
0087 MODULE_PARM_DESC(irq, "IRQ number");
0088
0089 module_param_array(clk, int, NULL, 0444);
0090 MODULE_PARM_DESC(clk, "External oscillator clock frequency "
0091 "(default=16000000 [16 MHz])");
0092
0093 module_param_array(cir, byte, NULL, 0444);
0094 MODULE_PARM_DESC(cir, "CPU interface register (default=0x40 [DSC])");
0095
0096 module_param_array(cor, byte, NULL, 0444);
0097 MODULE_PARM_DESC(cor, "Clockout register (default=0x00)");
0098
0099 module_param_array(bcr, byte, NULL, 0444);
0100 MODULE_PARM_DESC(bcr, "Bus configuration register (default=0x40 [CBY])");
0101
0102 #define CC770_IOSIZE 0x20
0103 #define CC770_IOSIZE_INDIRECT 0x02
0104
0105
0106
0107
0108 static DEFINE_SPINLOCK(cc770_isa_port_lock);
0109
0110 static struct platform_device *cc770_isa_devs[MAXDEV];
0111
0112 static u8 cc770_isa_mem_read_reg(const struct cc770_priv *priv, int reg)
0113 {
0114 return readb(priv->reg_base + reg);
0115 }
0116
0117 static void cc770_isa_mem_write_reg(const struct cc770_priv *priv,
0118 int reg, u8 val)
0119 {
0120 writeb(val, priv->reg_base + reg);
0121 }
0122
0123 static u8 cc770_isa_port_read_reg(const struct cc770_priv *priv, int reg)
0124 {
0125 return inb((unsigned long)priv->reg_base + reg);
0126 }
0127
0128 static void cc770_isa_port_write_reg(const struct cc770_priv *priv,
0129 int reg, u8 val)
0130 {
0131 outb(val, (unsigned long)priv->reg_base + reg);
0132 }
0133
0134 static u8 cc770_isa_port_read_reg_indirect(const struct cc770_priv *priv,
0135 int reg)
0136 {
0137 unsigned long base = (unsigned long)priv->reg_base;
0138 unsigned long flags;
0139 u8 val;
0140
0141 spin_lock_irqsave(&cc770_isa_port_lock, flags);
0142 outb(reg, base);
0143 val = inb(base + 1);
0144 spin_unlock_irqrestore(&cc770_isa_port_lock, flags);
0145
0146 return val;
0147 }
0148
0149 static void cc770_isa_port_write_reg_indirect(const struct cc770_priv *priv,
0150 int reg, u8 val)
0151 {
0152 unsigned long base = (unsigned long)priv->reg_base;
0153 unsigned long flags;
0154
0155 spin_lock_irqsave(&cc770_isa_port_lock, flags);
0156 outb(reg, base);
0157 outb(val, base + 1);
0158 spin_unlock_irqrestore(&cc770_isa_port_lock, flags);
0159 }
0160
0161 static int cc770_isa_probe(struct platform_device *pdev)
0162 {
0163 struct net_device *dev;
0164 struct cc770_priv *priv;
0165 void __iomem *base = NULL;
0166 int iosize = CC770_IOSIZE;
0167 int idx = pdev->id;
0168 int err;
0169 u32 clktmp;
0170
0171 dev_dbg(&pdev->dev, "probing idx=%d: port=%#lx, mem=%#lx, irq=%d\n",
0172 idx, port[idx], mem[idx], irq[idx]);
0173 if (mem[idx]) {
0174 if (!request_mem_region(mem[idx], iosize, KBUILD_MODNAME)) {
0175 err = -EBUSY;
0176 goto exit;
0177 }
0178 base = ioremap(mem[idx], iosize);
0179 if (!base) {
0180 err = -ENOMEM;
0181 goto exit_release;
0182 }
0183 } else {
0184 if (indirect[idx] > 0 ||
0185 (indirect[idx] == -1 && indirect[0] > 0))
0186 iosize = CC770_IOSIZE_INDIRECT;
0187 if (!request_region(port[idx], iosize, KBUILD_MODNAME)) {
0188 err = -EBUSY;
0189 goto exit;
0190 }
0191 }
0192
0193 dev = alloc_cc770dev(0);
0194 if (!dev) {
0195 err = -ENOMEM;
0196 goto exit_unmap;
0197 }
0198 priv = netdev_priv(dev);
0199
0200 dev->irq = irq[idx];
0201 priv->irq_flags = IRQF_SHARED;
0202 if (mem[idx]) {
0203 priv->reg_base = base;
0204 dev->base_addr = mem[idx];
0205 priv->read_reg = cc770_isa_mem_read_reg;
0206 priv->write_reg = cc770_isa_mem_write_reg;
0207 } else {
0208 priv->reg_base = (void __iomem *)port[idx];
0209 dev->base_addr = port[idx];
0210
0211 if (iosize == CC770_IOSIZE_INDIRECT) {
0212 priv->read_reg = cc770_isa_port_read_reg_indirect;
0213 priv->write_reg = cc770_isa_port_write_reg_indirect;
0214 } else {
0215 priv->read_reg = cc770_isa_port_read_reg;
0216 priv->write_reg = cc770_isa_port_write_reg;
0217 }
0218 }
0219
0220 if (clk[idx])
0221 clktmp = clk[idx];
0222 else if (clk[0])
0223 clktmp = clk[0];
0224 else
0225 clktmp = CLK_DEFAULT;
0226 priv->can.clock.freq = clktmp;
0227
0228 if (cir[idx] != 0xff) {
0229 priv->cpu_interface = cir[idx];
0230 } else if (cir[0] != 0xff) {
0231 priv->cpu_interface = cir[0];
0232 } else {
0233
0234 if (clktmp > 10000000) {
0235 priv->cpu_interface |= CPUIF_DSC;
0236 clktmp /= 2;
0237 }
0238
0239 if (clktmp > 8000000)
0240 priv->cpu_interface |= CPUIF_DMC;
0241 }
0242
0243 if (priv->cpu_interface & CPUIF_DSC)
0244 priv->can.clock.freq /= 2;
0245
0246 if (bcr[idx] != 0xff)
0247 priv->bus_config = bcr[idx];
0248 else if (bcr[0] != 0xff)
0249 priv->bus_config = bcr[0];
0250 else
0251 priv->bus_config = BCR_DEFAULT;
0252
0253 if (cor[idx] != 0xff)
0254 priv->clkout = cor[idx];
0255 else if (cor[0] != 0xff)
0256 priv->clkout = cor[0];
0257 else
0258 priv->clkout = COR_DEFAULT;
0259
0260 platform_set_drvdata(pdev, dev);
0261 SET_NETDEV_DEV(dev, &pdev->dev);
0262
0263 err = register_cc770dev(dev);
0264 if (err) {
0265 dev_err(&pdev->dev,
0266 "couldn't register device (err=%d)\n", err);
0267 goto exit_unmap;
0268 }
0269
0270 dev_info(&pdev->dev, "device registered (reg_base=0x%p, irq=%d)\n",
0271 priv->reg_base, dev->irq);
0272 return 0;
0273
0274 exit_unmap:
0275 if (mem[idx])
0276 iounmap(base);
0277 exit_release:
0278 if (mem[idx])
0279 release_mem_region(mem[idx], iosize);
0280 else
0281 release_region(port[idx], iosize);
0282 exit:
0283 return err;
0284 }
0285
0286 static int cc770_isa_remove(struct platform_device *pdev)
0287 {
0288 struct net_device *dev = platform_get_drvdata(pdev);
0289 struct cc770_priv *priv = netdev_priv(dev);
0290 int idx = pdev->id;
0291
0292 unregister_cc770dev(dev);
0293
0294 if (mem[idx]) {
0295 iounmap(priv->reg_base);
0296 release_mem_region(mem[idx], CC770_IOSIZE);
0297 } else {
0298 if (priv->read_reg == cc770_isa_port_read_reg_indirect)
0299 release_region(port[idx], CC770_IOSIZE_INDIRECT);
0300 else
0301 release_region(port[idx], CC770_IOSIZE);
0302 }
0303 free_cc770dev(dev);
0304
0305 return 0;
0306 }
0307
0308 static struct platform_driver cc770_isa_driver = {
0309 .probe = cc770_isa_probe,
0310 .remove = cc770_isa_remove,
0311 .driver = {
0312 .name = KBUILD_MODNAME,
0313 },
0314 };
0315
0316 static int __init cc770_isa_init(void)
0317 {
0318 int idx, err;
0319
0320 for (idx = 0; idx < ARRAY_SIZE(cc770_isa_devs); idx++) {
0321 if ((port[idx] || mem[idx]) && irq[idx]) {
0322 cc770_isa_devs[idx] =
0323 platform_device_alloc(KBUILD_MODNAME, idx);
0324 if (!cc770_isa_devs[idx]) {
0325 err = -ENOMEM;
0326 goto exit_free_devices;
0327 }
0328 err = platform_device_add(cc770_isa_devs[idx]);
0329 if (err) {
0330 platform_device_put(cc770_isa_devs[idx]);
0331 goto exit_free_devices;
0332 }
0333 pr_debug("platform device %d: port=%#lx, mem=%#lx, "
0334 "irq=%d\n",
0335 idx, port[idx], mem[idx], irq[idx]);
0336 } else if (idx == 0 || port[idx] || mem[idx]) {
0337 pr_err("insufficient parameters supplied\n");
0338 err = -EINVAL;
0339 goto exit_free_devices;
0340 }
0341 }
0342
0343 err = platform_driver_register(&cc770_isa_driver);
0344 if (err)
0345 goto exit_free_devices;
0346
0347 pr_info("driver for max. %d devices registered\n", MAXDEV);
0348
0349 return 0;
0350
0351 exit_free_devices:
0352 while (--idx >= 0) {
0353 if (cc770_isa_devs[idx])
0354 platform_device_unregister(cc770_isa_devs[idx]);
0355 }
0356
0357 return err;
0358 }
0359 module_init(cc770_isa_init);
0360
0361 static void __exit cc770_isa_exit(void)
0362 {
0363 int idx;
0364
0365 platform_driver_unregister(&cc770_isa_driver);
0366 for (idx = 0; idx < ARRAY_SIZE(cc770_isa_devs); idx++) {
0367 if (cc770_isa_devs[idx])
0368 platform_device_unregister(cc770_isa_devs[idx]);
0369 }
0370 }
0371 module_exit(cc770_isa_exit);