xref: /OK3568_Linux_fs/kernel/drivers/net/can/sja1000/tscan1.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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