Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * tscan1.c: driver for Technologic Systems TS-CAN1 PC104 boards
0004  *
0005  * Copyright 2010 Andre B. Oliveira
0006  */
0007 
0008 /* References:
0009  * - Getting started with TS-CAN1, Technologic Systems, Feb 2022
0010  *  https://docs.embeddedts.com/TS-CAN1
0011  */
0012 
0013 #include <linux/init.h>
0014 #include <linux/io.h>
0015 #include <linux/ioport.h>
0016 #include <linux/isa.h>
0017 #include <linux/module.h>
0018 #include <linux/netdevice.h>
0019 #include "sja1000.h"
0020 
0021 MODULE_DESCRIPTION("Driver for Technologic Systems TS-CAN1 PC104 boards");
0022 MODULE_AUTHOR("Andre B. Oliveira <anbadeol@gmail.com>");
0023 MODULE_LICENSE("GPL");
0024 
0025 /* Maximum number of boards (one in each JP1:JP2 setting of IO address) */
0026 #define TSCAN1_MAXDEV 4
0027 
0028 /* PLD registers address offsets */
0029 #define TSCAN1_ID1  0
0030 #define TSCAN1_ID2  1
0031 #define TSCAN1_VERSION  2
0032 #define TSCAN1_LED  3
0033 #define TSCAN1_PAGE 4
0034 #define TSCAN1_MODE 5
0035 #define TSCAN1_JUMPERS  6
0036 
0037 /* PLD board identifier registers magic values */
0038 #define TSCAN1_ID1_VALUE 0xf6
0039 #define TSCAN1_ID2_VALUE 0xb9
0040 
0041 /* PLD mode register SJA1000 IO enable bit */
0042 #define TSCAN1_MODE_ENABLE 0x40
0043 
0044 /* PLD jumpers register bits */
0045 #define TSCAN1_JP4 0x10
0046 #define TSCAN1_JP5 0x20
0047 
0048 /* PLD IO base addresses start */
0049 #define TSCAN1_PLD_ADDRESS 0x150
0050 
0051 /* PLD register space size */
0052 #define TSCAN1_PLD_SIZE 8
0053 
0054 /* SJA1000 register space size */
0055 #define TSCAN1_SJA1000_SIZE 32
0056 
0057 /* SJA1000 crystal frequency (16MHz) */
0058 #define TSCAN1_SJA1000_XTAL 16000000
0059 
0060 /* SJA1000 IO base addresses */
0061 static const unsigned short tscan1_sja1000_addresses[] = {
0062     0x100, 0x120, 0x180, 0x1a0, 0x200, 0x240, 0x280, 0x320
0063 };
0064 
0065 /* Read SJA1000 register */
0066 static u8 tscan1_read(const struct sja1000_priv *priv, int reg)
0067 {
0068     return inb((unsigned long)priv->reg_base + reg);
0069 }
0070 
0071 /* Write SJA1000 register */
0072 static void tscan1_write(const struct sja1000_priv *priv, int reg, u8 val)
0073 {
0074     outb(val, (unsigned long)priv->reg_base + reg);
0075 }
0076 
0077 /* Probe for a TS-CAN1 board with JP2:JP1 jumper setting ID */
0078 static int tscan1_probe(struct device *dev, unsigned id)
0079 {
0080     struct net_device *netdev;
0081     struct sja1000_priv *priv;
0082     unsigned long pld_base, sja1000_base;
0083     int irq, i;
0084 
0085     pld_base = TSCAN1_PLD_ADDRESS + id * TSCAN1_PLD_SIZE;
0086     if (!request_region(pld_base, TSCAN1_PLD_SIZE, dev_name(dev)))
0087         return -EBUSY;
0088 
0089     if (inb(pld_base + TSCAN1_ID1) != TSCAN1_ID1_VALUE ||
0090         inb(pld_base + TSCAN1_ID2) != TSCAN1_ID2_VALUE) {
0091         release_region(pld_base, TSCAN1_PLD_SIZE);
0092         return -ENODEV;
0093     }
0094 
0095     switch (inb(pld_base + TSCAN1_JUMPERS) & (TSCAN1_JP4 | TSCAN1_JP5)) {
0096     case TSCAN1_JP4:
0097         irq = 6;
0098         break;
0099     case TSCAN1_JP5:
0100         irq = 7;
0101         break;
0102     case TSCAN1_JP4 | TSCAN1_JP5:
0103         irq = 5;
0104         break;
0105     default:
0106         dev_err(dev, "invalid JP4:JP5 setting (no IRQ)\n");
0107         release_region(pld_base, TSCAN1_PLD_SIZE);
0108         return -EINVAL;
0109     }
0110 
0111     netdev = alloc_sja1000dev(0);
0112     if (!netdev) {
0113         release_region(pld_base, TSCAN1_PLD_SIZE);
0114         return -ENOMEM;
0115     }
0116 
0117     dev_set_drvdata(dev, netdev);
0118     SET_NETDEV_DEV(netdev, dev);
0119 
0120     netdev->base_addr = pld_base;
0121     netdev->irq = irq;
0122 
0123     priv = netdev_priv(netdev);
0124     priv->read_reg = tscan1_read;
0125     priv->write_reg = tscan1_write;
0126     priv->can.clock.freq = TSCAN1_SJA1000_XTAL / 2;
0127     priv->cdr = CDR_CBP | CDR_CLK_OFF;
0128     priv->ocr = OCR_TX0_PUSHPULL;
0129 
0130     /* Select the first SJA1000 IO address that is free and that works */
0131     for (i = 0; i < ARRAY_SIZE(tscan1_sja1000_addresses); i++) {
0132         sja1000_base = tscan1_sja1000_addresses[i];
0133         if (!request_region(sja1000_base, TSCAN1_SJA1000_SIZE,
0134                                 dev_name(dev)))
0135             continue;
0136 
0137         /* Set SJA1000 IO base address and enable it */
0138         outb(TSCAN1_MODE_ENABLE | i, pld_base + TSCAN1_MODE);
0139 
0140         priv->reg_base = (void __iomem *)sja1000_base;
0141         if (!register_sja1000dev(netdev)) {
0142             /* SJA1000 probe succeeded; turn LED off and return */
0143             outb(0, pld_base + TSCAN1_LED);
0144             netdev_info(netdev, "TS-CAN1 at 0x%lx 0x%lx irq %d\n",
0145                         pld_base, sja1000_base, irq);
0146             return 0;
0147         }
0148 
0149         /* SJA1000 probe failed; release and try next address */
0150         outb(0, pld_base + TSCAN1_MODE);
0151         release_region(sja1000_base, TSCAN1_SJA1000_SIZE);
0152     }
0153 
0154     dev_err(dev, "failed to assign SJA1000 IO address\n");
0155     dev_set_drvdata(dev, NULL);
0156     free_sja1000dev(netdev);
0157     release_region(pld_base, TSCAN1_PLD_SIZE);
0158     return -ENXIO;
0159 }
0160 
0161 static void tscan1_remove(struct device *dev, unsigned id /*unused*/)
0162 {
0163     struct net_device *netdev;
0164     struct sja1000_priv *priv;
0165     unsigned long pld_base, sja1000_base;
0166 
0167     netdev = dev_get_drvdata(dev);
0168     unregister_sja1000dev(netdev);
0169     dev_set_drvdata(dev, NULL);
0170 
0171     priv = netdev_priv(netdev);
0172     pld_base = netdev->base_addr;
0173     sja1000_base = (unsigned long)priv->reg_base;
0174 
0175     outb(0, pld_base + TSCAN1_MODE);    /* disable SJA1000 IO space */
0176 
0177     release_region(sja1000_base, TSCAN1_SJA1000_SIZE);
0178     release_region(pld_base, TSCAN1_PLD_SIZE);
0179 
0180     free_sja1000dev(netdev);
0181 }
0182 
0183 static struct isa_driver tscan1_isa_driver = {
0184     .probe = tscan1_probe,
0185     .remove = tscan1_remove,
0186     .driver = {
0187         .name = "tscan1",
0188     },
0189 };
0190 
0191 module_isa_driver(tscan1_isa_driver, TSCAN1_MAXDEV);