linux/drivers/net/can/sja1000/sja1000_isa.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2009 Wolfgang Grandegger <wg@grandegger.com>
   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, see <http://www.gnu.org/licenses/>.
  15 */
  16
  17#include <linux/kernel.h>
  18#include <linux/module.h>
  19#include <linux/platform_device.h>
  20#include <linux/interrupt.h>
  21#include <linux/netdevice.h>
  22#include <linux/delay.h>
  23#include <linux/irq.h>
  24#include <linux/io.h>
  25#include <linux/can/dev.h>
  26#include <linux/can/platform/sja1000.h>
  27
  28#include "sja1000.h"
  29
  30#define DRV_NAME "sja1000_isa"
  31
  32#define MAXDEV 8
  33
  34MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
  35MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the ISA bus");
  36MODULE_LICENSE("GPL v2");
  37
  38#define CLK_DEFAULT     16000000        /* 16 MHz */
  39#define CDR_DEFAULT     (CDR_CBP | CDR_CLK_OFF)
  40#define OCR_DEFAULT     OCR_TX0_PUSHPULL
  41
  42static unsigned long port[MAXDEV];
  43static unsigned long mem[MAXDEV];
  44static int irq[MAXDEV];
  45static int clk[MAXDEV];
  46static unsigned char cdr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
  47static unsigned char ocr[MAXDEV] = {[0 ... (MAXDEV - 1)] = 0xff};
  48static int indirect[MAXDEV] = {[0 ... (MAXDEV - 1)] = -1};
  49static spinlock_t indirect_lock[MAXDEV];  /* lock for indirect access mode */
  50
  51module_param_array(port, ulong, NULL, S_IRUGO);
  52MODULE_PARM_DESC(port, "I/O port number");
  53
  54module_param_array(mem, ulong, NULL, S_IRUGO);
  55MODULE_PARM_DESC(mem, "I/O memory address");
  56
  57module_param_array(indirect, int, NULL, S_IRUGO);
  58MODULE_PARM_DESC(indirect, "Indirect access via address and data port");
  59
  60module_param_array(irq, int, NULL, S_IRUGO);
  61MODULE_PARM_DESC(irq, "IRQ number");
  62
  63module_param_array(clk, int, NULL, S_IRUGO);
  64MODULE_PARM_DESC(clk, "External oscillator clock frequency "
  65                 "(default=16000000 [16 MHz])");
  66
  67module_param_array(cdr, byte, NULL, S_IRUGO);
  68MODULE_PARM_DESC(cdr, "Clock divider register "
  69                 "(default=0x48 [CDR_CBP | CDR_CLK_OFF])");
  70
  71module_param_array(ocr, byte, NULL, S_IRUGO);
  72MODULE_PARM_DESC(ocr, "Output control register "
  73                 "(default=0x18 [OCR_TX0_PUSHPULL])");
  74
  75#define SJA1000_IOSIZE          0x20
  76#define SJA1000_IOSIZE_INDIRECT 0x02
  77
  78static struct platform_device *sja1000_isa_devs[MAXDEV];
  79
  80static u8 sja1000_isa_mem_read_reg(const struct sja1000_priv *priv, int reg)
  81{
  82        return readb(priv->reg_base + reg);
  83}
  84
  85static void sja1000_isa_mem_write_reg(const struct sja1000_priv *priv,
  86                                      int reg, u8 val)
  87{
  88        writeb(val, priv->reg_base + reg);
  89}
  90
  91static u8 sja1000_isa_port_read_reg(const struct sja1000_priv *priv, int reg)
  92{
  93        return inb((unsigned long)priv->reg_base + reg);
  94}
  95
  96static void sja1000_isa_port_write_reg(const struct sja1000_priv *priv,
  97                                       int reg, u8 val)
  98{
  99        outb(val, (unsigned long)priv->reg_base + reg);
 100}
 101
 102static u8 sja1000_isa_port_read_reg_indirect(const struct sja1000_priv *priv,
 103                                             int reg)
 104{
 105        unsigned long flags, base = (unsigned long)priv->reg_base;
 106        u8 readval;
 107
 108        spin_lock_irqsave(&indirect_lock[priv->dev->dev_id], flags);
 109        outb(reg, base);
 110        readval = inb(base + 1);
 111        spin_unlock_irqrestore(&indirect_lock[priv->dev->dev_id], flags);
 112
 113        return readval;
 114}
 115
 116static void sja1000_isa_port_write_reg_indirect(const struct sja1000_priv *priv,
 117                                                int reg, u8 val)
 118{
 119        unsigned long flags, base = (unsigned long)priv->reg_base;
 120
 121        spin_lock_irqsave(&indirect_lock[priv->dev->dev_id], flags);
 122        outb(reg, base);
 123        outb(val, base + 1);
 124        spin_unlock_irqrestore(&indirect_lock[priv->dev->dev_id], flags);
 125}
 126
 127static int sja1000_isa_probe(struct platform_device *pdev)
 128{
 129        struct net_device *dev;
 130        struct sja1000_priv *priv;
 131        void __iomem *base = NULL;
 132        int iosize = SJA1000_IOSIZE;
 133        int idx = pdev->id;
 134        int err;
 135
 136        dev_dbg(&pdev->dev, "probing idx=%d: port=%#lx, mem=%#lx, irq=%d\n",
 137                idx, port[idx], mem[idx], irq[idx]);
 138
 139        if (mem[idx]) {
 140                if (!request_mem_region(mem[idx], iosize, DRV_NAME)) {
 141                        err = -EBUSY;
 142                        goto exit;
 143                }
 144                base = ioremap_nocache(mem[idx], iosize);
 145                if (!base) {
 146                        err = -ENOMEM;
 147                        goto exit_release;
 148                }
 149        } else {
 150                if (indirect[idx] > 0 ||
 151                    (indirect[idx] == -1 && indirect[0] > 0))
 152                        iosize = SJA1000_IOSIZE_INDIRECT;
 153                if (!request_region(port[idx], iosize, DRV_NAME)) {
 154                        err = -EBUSY;
 155                        goto exit;
 156                }
 157        }
 158
 159        dev = alloc_sja1000dev(0);
 160        if (!dev) {
 161                err = -ENOMEM;
 162                goto exit_unmap;
 163        }
 164        priv = netdev_priv(dev);
 165
 166        dev->irq = irq[idx];
 167        priv->irq_flags = IRQF_SHARED;
 168        if (mem[idx]) {
 169                priv->reg_base = base;
 170                dev->base_addr = mem[idx];
 171                priv->read_reg = sja1000_isa_mem_read_reg;
 172                priv->write_reg = sja1000_isa_mem_write_reg;
 173        } else {
 174                priv->reg_base = (void __iomem *)port[idx];
 175                dev->base_addr = port[idx];
 176
 177                if (iosize == SJA1000_IOSIZE_INDIRECT) {
 178                        priv->read_reg = sja1000_isa_port_read_reg_indirect;
 179                        priv->write_reg = sja1000_isa_port_write_reg_indirect;
 180                        spin_lock_init(&indirect_lock[idx]);
 181                } else {
 182                        priv->read_reg = sja1000_isa_port_read_reg;
 183                        priv->write_reg = sja1000_isa_port_write_reg;
 184                }
 185        }
 186
 187        if (clk[idx])
 188                priv->can.clock.freq = clk[idx] / 2;
 189        else if (clk[0])
 190                priv->can.clock.freq = clk[0] / 2;
 191        else
 192                priv->can.clock.freq = CLK_DEFAULT / 2;
 193
 194        if (ocr[idx] != 0xff)
 195                priv->ocr = ocr[idx];
 196        else if (ocr[0] != 0xff)
 197                priv->ocr = ocr[0];
 198        else
 199                priv->ocr = OCR_DEFAULT;
 200
 201        if (cdr[idx] != 0xff)
 202                priv->cdr = cdr[idx];
 203        else if (cdr[0] != 0xff)
 204                priv->cdr = cdr[0];
 205        else
 206                priv->cdr = CDR_DEFAULT;
 207
 208        platform_set_drvdata(pdev, dev);
 209        SET_NETDEV_DEV(dev, &pdev->dev);
 210        dev->dev_id = idx;
 211
 212        err = register_sja1000dev(dev);
 213        if (err) {
 214                dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
 215                        DRV_NAME, err);
 216                goto exit_unmap;
 217        }
 218
 219        dev_info(&pdev->dev, "%s device registered (reg_base=0x%p, irq=%d)\n",
 220                 DRV_NAME, priv->reg_base, dev->irq);
 221        return 0;
 222
 223 exit_unmap:
 224        if (mem[idx])
 225                iounmap(base);
 226 exit_release:
 227        if (mem[idx])
 228                release_mem_region(mem[idx], iosize);
 229        else
 230                release_region(port[idx], iosize);
 231 exit:
 232        return err;
 233}
 234
 235static int sja1000_isa_remove(struct platform_device *pdev)
 236{
 237        struct net_device *dev = platform_get_drvdata(pdev);
 238        struct sja1000_priv *priv = netdev_priv(dev);
 239        int idx = pdev->id;
 240
 241        unregister_sja1000dev(dev);
 242
 243        if (mem[idx]) {
 244                iounmap(priv->reg_base);
 245                release_mem_region(mem[idx], SJA1000_IOSIZE);
 246        } else {
 247                if (priv->read_reg == sja1000_isa_port_read_reg_indirect)
 248                        release_region(port[idx], SJA1000_IOSIZE_INDIRECT);
 249                else
 250                        release_region(port[idx], SJA1000_IOSIZE);
 251        }
 252        free_sja1000dev(dev);
 253
 254        return 0;
 255}
 256
 257static struct platform_driver sja1000_isa_driver = {
 258        .probe = sja1000_isa_probe,
 259        .remove = sja1000_isa_remove,
 260        .driver = {
 261                .name = DRV_NAME,
 262                .owner = THIS_MODULE,
 263        },
 264};
 265
 266static int __init sja1000_isa_init(void)
 267{
 268        int idx, err;
 269
 270        for (idx = 0; idx < MAXDEV; idx++) {
 271                if ((port[idx] || mem[idx]) && irq[idx]) {
 272                        sja1000_isa_devs[idx] =
 273                                platform_device_alloc(DRV_NAME, idx);
 274                        if (!sja1000_isa_devs[idx]) {
 275                                err = -ENOMEM;
 276                                goto exit_free_devices;
 277                        }
 278                        err = platform_device_add(sja1000_isa_devs[idx]);
 279                        if (err) {
 280                                platform_device_put(sja1000_isa_devs[idx]);
 281                                goto exit_free_devices;
 282                        }
 283                        pr_debug("%s: platform device %d: port=%#lx, mem=%#lx, "
 284                                 "irq=%d\n",
 285                                 DRV_NAME, idx, port[idx], mem[idx], irq[idx]);
 286                } else if (idx == 0 || port[idx] || mem[idx]) {
 287                                pr_err("%s: insufficient parameters supplied\n",
 288                                       DRV_NAME);
 289                                err = -EINVAL;
 290                                goto exit_free_devices;
 291                }
 292        }
 293
 294        err = platform_driver_register(&sja1000_isa_driver);
 295        if (err)
 296                goto exit_free_devices;
 297
 298        pr_info("Legacy %s driver for max. %d devices registered\n",
 299                DRV_NAME, MAXDEV);
 300
 301        return 0;
 302
 303exit_free_devices:
 304        while (--idx >= 0) {
 305                if (sja1000_isa_devs[idx])
 306                        platform_device_unregister(sja1000_isa_devs[idx]);
 307        }
 308
 309        return err;
 310}
 311
 312static void __exit sja1000_isa_exit(void)
 313{
 314        int idx;
 315
 316        platform_driver_unregister(&sja1000_isa_driver);
 317        for (idx = 0; idx < MAXDEV; idx++) {
 318                if (sja1000_isa_devs[idx])
 319                        platform_device_unregister(sja1000_isa_devs[idx]);
 320        }
 321}
 322
 323module_init(sja1000_isa_init);
 324module_exit(sja1000_isa_exit);
 325
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.