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