linux/drivers/net/can/sja1000/tscan1.c
<<
>>
Prefs
   1/*
   2 * tscan1.c: driver for Technologic Systems TS-CAN1 PC104 boards
   3 *
   4 * Copyright 2010 Andre B. Oliveira
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License
   8 * as published by the Free Software Foundation; either version 2
   9 * of the License, or (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18 */
  19
  20/*
  21 * References:
  22 * - Getting started with TS-CAN1, Technologic Systems, Jun 2009
  23 *      http://www.embeddedarm.com/documentation/ts-can1-manual.pdf
  24 */
  25
  26#include <linux/init.h>
  27#include <linux/io.h>
  28#include <linux/ioport.h>
  29#include <linux/isa.h>
  30#include <linux/module.h>
  31#include <linux/netdevice.h>
  32#include "sja1000.h"
  33
  34MODULE_DESCRIPTION("Driver for Technologic Systems TS-CAN1 PC104 boards");
  35MODULE_AUTHOR("Andre B. Oliveira <anbadeol@gmail.com>");
  36MODULE_LICENSE("GPL");
  37
  38/* Maximum number of boards (one in each JP1:JP2 setting of IO address) */
  39#define TSCAN1_MAXDEV 4
  40
  41/* PLD registers address offsets */
  42#define TSCAN1_ID1      0
  43#define TSCAN1_ID2      1
  44#define TSCAN1_VERSION  2
  45#define TSCAN1_LED      3
  46#define TSCAN1_PAGE     4
  47#define TSCAN1_MODE     5
  48#define TSCAN1_JUMPERS  6
  49
  50/* PLD board identifier registers magic values */
  51#define TSCAN1_ID1_VALUE 0xf6
  52#define TSCAN1_ID2_VALUE 0xb9
  53
  54/* PLD mode register SJA1000 IO enable bit */
  55#define TSCAN1_MODE_ENABLE 0x40
  56
  57/* PLD jumpers register bits */
  58#define TSCAN1_JP4 0x10
  59#define TSCAN1_JP5 0x20
  60
  61/* PLD IO base addresses start */
  62#define TSCAN1_PLD_ADDRESS 0x150
  63
  64/* PLD register space size */
  65#define TSCAN1_PLD_SIZE 8
  66
  67/* SJA1000 register space size */
  68#define TSCAN1_SJA1000_SIZE 32
  69
  70/* SJA1000 crystal frequency (16MHz) */
  71#define TSCAN1_SJA1000_XTAL 16000000
  72
  73/* SJA1000 IO base addresses */
  74static const unsigned short tscan1_sja1000_addresses[] = {
  75        0x100, 0x120, 0x180, 0x1a0, 0x200, 0x240, 0x280, 0x320
  76};
  77
  78/* Read SJA1000 register */
  79static u8 tscan1_read(const struct sja1000_priv *priv, int reg)
  80{
  81        return inb((unsigned long)priv->reg_base + reg);
  82}
  83
  84/* Write SJA1000 register */
  85static void tscan1_write(const struct sja1000_priv *priv, int reg, u8 val)
  86{
  87        outb(val, (unsigned long)priv->reg_base + reg);
  88}
  89
  90/* Probe for a TS-CAN1 board with JP2:JP1 jumper setting ID */
  91static int tscan1_probe(struct device *dev, unsigned id)
  92{
  93        struct net_device *netdev;
  94        struct sja1000_priv *priv;
  95        unsigned long pld_base, sja1000_base;
  96        int irq, i;
  97
  98        pld_base = TSCAN1_PLD_ADDRESS + id * TSCAN1_PLD_SIZE;
  99        if (!request_region(pld_base, TSCAN1_PLD_SIZE, dev_name(dev)))
 100                return -EBUSY;
 101
 102        if (inb(pld_base + TSCAN1_ID1) != TSCAN1_ID1_VALUE ||
 103            inb(pld_base + TSCAN1_ID2) != TSCAN1_ID2_VALUE) {
 104                release_region(pld_base, TSCAN1_PLD_SIZE);
 105                return -ENODEV;
 106        }
 107
 108        switch (inb(pld_base + TSCAN1_JUMPERS) & (TSCAN1_JP4 | TSCAN1_JP5)) {
 109        case TSCAN1_JP4:
 110                irq = 6;
 111                break;
 112        case TSCAN1_JP5:
 113                irq = 7;
 114                break;
 115        case TSCAN1_JP4 | TSCAN1_JP5:
 116                irq = 5;
 117                break;
 118        default:
 119                dev_err(dev, "invalid JP4:JP5 setting (no IRQ)\n");
 120                release_region(pld_base, TSCAN1_PLD_SIZE);
 121                return -EINVAL;
 122        }
 123
 124        netdev = alloc_sja1000dev(0);
 125        if (!netdev) {
 126                release_region(pld_base, TSCAN1_PLD_SIZE);
 127                return -ENOMEM;
 128        }
 129
 130        dev_set_drvdata(dev, netdev);
 131        SET_NETDEV_DEV(netdev, dev);
 132
 133        netdev->base_addr = pld_base;
 134        netdev->irq = irq;
 135
 136        priv = netdev_priv(netdev);
 137        priv->read_reg = tscan1_read;
 138        priv->write_reg = tscan1_write;
 139        priv->can.clock.freq = TSCAN1_SJA1000_XTAL / 2;
 140        priv->cdr = CDR_CBP | CDR_CLK_OFF;
 141        priv->ocr = OCR_TX0_PUSHPULL;
 142
 143        /* Select the first SJA1000 IO address that is free and that works */
 144        for (i = 0; i < ARRAY_SIZE(tscan1_sja1000_addresses); i++) {
 145                sja1000_base = tscan1_sja1000_addresses[i];
 146                if (!request_region(sja1000_base, TSCAN1_SJA1000_SIZE,
 147                                                                dev_name(dev)))
 148                        continue;
 149
 150                /* Set SJA1000 IO base address and enable it */
 151                outb(TSCAN1_MODE_ENABLE | i, pld_base + TSCAN1_MODE);
 152
 153                priv->reg_base = (void __iomem *)sja1000_base;
 154                if (!register_sja1000dev(netdev)) {
 155                        /* SJA1000 probe succeeded; turn LED off and return */
 156                        outb(0, pld_base + TSCAN1_LED);
 157                        netdev_info(netdev, "TS-CAN1 at 0x%lx 0x%lx irq %d\n",
 158                                                pld_base, sja1000_base, irq);
 159                        return 0;
 160                }
 161
 162                /* SJA1000 probe failed; release and try next address */
 163                outb(0, pld_base + TSCAN1_MODE);
 164                release_region(sja1000_base, TSCAN1_SJA1000_SIZE);
 165        }
 166
 167        dev_err(dev, "failed to assign SJA1000 IO address\n");
 168        dev_set_drvdata(dev, NULL);
 169        free_sja1000dev(netdev);
 170        release_region(pld_base, TSCAN1_PLD_SIZE);
 171        return -ENXIO;
 172}
 173
 174static int tscan1_remove(struct device *dev, unsigned id /*unused*/)
 175{
 176        struct net_device *netdev;
 177        struct sja1000_priv *priv;
 178        unsigned long pld_base, sja1000_base;
 179
 180        netdev = dev_get_drvdata(dev);
 181        unregister_sja1000dev(netdev);
 182        dev_set_drvdata(dev, NULL);
 183
 184        priv = netdev_priv(netdev);
 185        pld_base = netdev->base_addr;
 186        sja1000_base = (unsigned long)priv->reg_base;
 187
 188        outb(0, pld_base + TSCAN1_MODE);        /* disable SJA1000 IO space */
 189
 190        release_region(sja1000_base, TSCAN1_SJA1000_SIZE);
 191        release_region(pld_base, TSCAN1_PLD_SIZE);
 192
 193        free_sja1000dev(netdev);
 194
 195        return 0;
 196}
 197
 198static struct isa_driver tscan1_isa_driver = {
 199        .probe = tscan1_probe,
 200        .remove = tscan1_remove,
 201        .driver = {
 202                .name = "tscan1",
 203        },
 204};
 205
 206static int __init tscan1_init(void)
 207{
 208        return isa_register_driver(&tscan1_isa_driver, TSCAN1_MAXDEV);
 209}
 210module_init(tscan1_init);
 211
 212static void __exit tscan1_exit(void)
 213{
 214        isa_unregister_driver(&tscan1_isa_driver);
 215}
 216module_exit(tscan1_exit);
 217