2 * Linux CAN-bus device driver.
3 * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
4 * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
5 * email:pisa@cmp.felk.cvut.cz
6 * This software is released under the GPL-License.
7 * Version lincan-0.3 17 Jun 2004
9 * The support for TS-CAN1 and TS-7KV provided by Ronald Gomes
10 * from Technologic Systems <http://www.embeddedarm.com/>
13 #include "../include/can.h"
14 #include "../include/can_sysdep.h"
15 #include "../include/main.h"
16 #include "../include/sja1000p.h"
18 #include <linux/module.h>
19 #include "../include/modparms.h"
20 #include "../include/devcommon.h"
22 #include "../include/ts7kv.h"
24 static CAN_DEFINE_SPINLOCK(ts7kv_win_lock);
26 #ifdef CONFIG_OC_LINCAN_CARD_tscan1
28 extern unsigned long tsxxx_base;
30 #else /*CONFIG_OC_LINCAN_CARD_tscan1*/
32 #if defined(TSXXX_BASE_IO)
33 unsigned long tsxxx_base=TSXXX_BASE_IO;
35 unsigned long tsxxx_base=0;
38 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12))
39 MODULE_PARM(tsxxx_base, "1i");
40 #else /* LINUX_VERSION_CODE >= 2,6,12 */
41 module_param(tsxxx_base, ulong, 0);
42 #endif /* LINUX_VERSION_CODE >= 2,6,12 */
44 MODULE_PARM_DESC(tscanio,"TSCAN CAN controller IO address for each board");
45 MODULE_PARM_DESC(tsxxx_base,"The base of the ISA/8-bit IO space for TSxxx CAN peripherals in the system");
47 #endif /*CONFIG_OC_LINCAN_CARD_tscan1*/
50 * ts7kv_request_io: - reserve io or memory range for can board
51 * @candev: pointer to candevice/board which asks for io. Field @io_addr
52 * of @candev is used in most cases to define start of the range
54 * The function ts7kv_request_io() is used to reserve the io-memory. If your
55 * hardware uses a dedicated memory range as hardware control registers you
56 * will have to add the code to reserve this memory as well.
57 * %IO_RANGE is the io-memory range that gets reserved, please adjust according
58 * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
59 * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
60 * Return Value: The function returns zero on success or %-ENODEV on failure
63 int ts7kv_request_io(struct candevice_t *candev)
65 if (!can_request_io_region(candev->io_addr, TS7KV_CAN_RANGE, "ts7kv-can")) {
66 CANMSG("Unable to request CAN IO port: 0x%lx\n", candev->io_addr);
69 DEBUGMSG("Registered CAN IO port: 0x%lx - 0x%lx\n",
70 candev->io_addr, candev->io_addr+TS7KV_CAN_RANGE-1);
77 * ts7kv_release_io - free reserved io memory range
78 * @candev: pointer to candevice/board which releases io
80 * The function ts7kv_release_io() is used to free reserved io-memory.
81 * In case you have reserved more io memory, don't forget to free it here.
82 * IO_RANGE is the io-memory range that gets released, please adjust according
83 * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or
84 * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode.
85 * Return Value: The function always returns zero
88 int ts7kv_release_io(struct candevice_t *candev)
90 can_release_io_region(candev->io_addr, TS7KV_CAN_RANGE);
95 * ts7kv_reset - hardware reset routine
96 * @candev: Pointer to candevice/board structure
98 * The function ts7kv_reset() is used to give a hardware reset. This is
99 * rather hardware specific so I haven't included example code. Don't forget to
100 * check the reset status of the chip before returning.
101 * Return Value: The function returns zero on success or %-ENODEV on failure
104 int ts7kv_reset(struct candevice_t *candev)
106 unsigned short i=0, chipnr;
107 struct canchip_t *chip;
109 DEBUGMSG("Resetting %s hardware ...\n", candev->hwname);
111 for(chipnr=0;chipnr<candev->nr_sja1000_chips;chipnr++) {
112 chip=candev->chip[chipnr];
113 can_write_reg(chip, sjaMOD_RM, SJAMOD);
115 can_write_reg(chip, 0x00, SJAIER);
118 while (can_read_reg(chip, SJAMOD)&sjaMOD_RM){
119 if(!i--) return -ENODEV;
121 can_write_reg(chip, 0, SJAMOD);
124 can_write_reg(chip, sjaCDR_PELICAN, SJACDR);
125 can_write_reg(chip, 0x00, SJAIER);
131 int ts7kv_check_presence(unsigned long remap_io_addr, int *pjmp)
133 int result = -ENODEV;
135 if (!can_request_io_region(remap_io_addr, TS7KV_IO_RANGE, "ts7kv-probe"))
139 if (can_inb(remap_io_addr+TS7KV_ID0_REG)!=TS7KV_ID0 ||
140 can_inb(remap_io_addr+TS7KV_ID1_REG)!=TS7KV_ID1)
144 *pjmp = can_inb(remap_io_addr+TS7KV_JMP_REG);
149 can_release_io_region(remap_io_addr, TS7KV_IO_RANGE);
154 #define RESET_ADDR 0x100
159 * ts7kv_init_hw_data - Initialize hardware cards
160 * @candev: Pointer to candevice/board structure
162 * The function ts7kv_init_hw_data() is used to initialize the hardware
163 * structure containing information about the installed CAN-board.
164 * %RESET_ADDR represents the io-address of the hardware reset register.
165 * %NR_82527 represents the number of intel 82527 chips on the board.
166 * %NR_SJA1000 represents the number of philips sja1000 chips on the board.
167 * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that
168 * the hardware uses programmable interrupts.
169 * Return Value: The function always returns zero
172 int ts7kv_init_hw_data(struct candevice_t *candev)
175 unsigned long io_addr;
176 unsigned long remap_io_addr;
177 unsigned long can_io_addr;
179 io_addr = candev->io_addr;
181 if(io_addr && (io_addr != (unsigned long)-1)) {
182 remap_io_addr = io_addr + tsxxx_base;
184 if(ts7kv_check_presence(remap_io_addr, &jmp)){
185 CANMSG("No TS7KV card found at address 0x%lx\n",
190 DEBUGMSG("Scanning bus for TS7KV boards...\n");
195 CANMSG("No TS7KV boards found for slot %d\n", candev->candev_idx);
199 io_addr = TS7KV_BASE_IO + i*TS7KV_IO_RANGE;
200 remap_io_addr = io_addr + tsxxx_base;
202 for (j = 0; j < MAX_HW_CARDS; j++) {
203 if(io[j] == io_addr){
211 if(!ts7kv_check_presence(remap_io_addr, &jmp))
215 DEBUGMSG("TS7KV board was found at 0x%lx for driver slot %d\n",
216 io_addr, candev->candev_idx);
218 io[candev->candev_idx] = io_addr;
221 can_io_addr = ((io_addr>>3)&0x03)*0x20;
223 /* dev_base_addr address is used to store remapped PLD base address */
224 candev->dev_base_addr = remap_io_addr;
226 /* dev_base_addr address is used to store remapped slave window address */
227 candev->io_addr = can_io_addr+tsxxx_base;
229 /* unused reset address is used to store jumper setting */
230 candev->res_addr = jmp;
232 candev->nr_82527_chips=NR_82527;
233 candev->nr_sja1000_chips=NR_SJA1000;
234 candev->nr_all_chips=NR_82527+NR_SJA1000;
235 candev->flags &= ~CANDEV_PROGRAMMABLE_IRQ;
237 DEBUGMSG("Memory region at 0x%lx assigned to sja1000 of driver %d/%s\n",
238 candev->io_addr, candev->candev_idx, candev->hwname);
244 * ts7kv_init_chip_data - Initialize chips
245 * @candev: Pointer to candevice/board structure
246 * @chipnr: Number of the CAN chip on the hardware card
248 * The function ts7kv_init_chip_data() is used to initialize the hardware
249 * structure containing information about the CAN chips.
250 * %CHIP_TYPE represents the type of CAN chip. %CHIP_TYPE can be "i82527" or
252 * The @chip_base_addr entry represents the start of the 'official' memory map
253 * of the installed chip. It's likely that this is the same as the @io_addr
254 * argument supplied at module loading time.
255 * The @clock entry holds the chip clock value in Hz.
256 * The entry @sja_cdr_reg holds hardware specific options for the Clock Divider
257 * register. Options defined in the %sja1000.h file:
258 * %sjaCDR_CLKOUT_MASK, %sjaCDR_CLK_OFF, %sjaCDR_RXINPEN, %sjaCDR_CBP, %sjaCDR_PELICAN
259 * The entry @sja_ocr_reg holds hardware specific options for the Output Control
260 * register. Options defined in the %sja1000.h file:
261 * %sjaOCR_MODE_BIPHASE, %sjaOCR_MODE_TEST, %sjaOCR_MODE_NORMAL, %sjaOCR_MODE_CLOCK,
262 * %sjaOCR_TX0_LH, %sjaOCR_TX1_ZZ.
263 * The entry @int_clk_reg holds hardware specific options for the Clock Out
264 * register. Options defined in the %i82527.h file:
265 * %iCLK_CD0, %iCLK_CD1, %iCLK_CD2, %iCLK_CD3, %iCLK_SL0, %iCLK_SL1.
266 * The entry @int_bus_reg holds hardware specific options for the Bus
267 * Configuration register. Options defined in the %i82527.h file:
268 * %iBUS_DR0, %iBUS_DR1, %iBUS_DT1, %iBUS_POL, %iBUS_CBY.
269 * Return Value: The function always returns zero
272 int ts7kv_init_chip_data(struct candevice_t *candev, int chipnr)
274 unsigned long default_clk = 16000 * 1000;
278 /* unused reset address is used to store jumper setting */
279 jmp = candev->res_addr;
281 if (jmp&0x10 && jmp&0x20) irq=TSXXX_IRQ5;
282 else if (jmp&0x10) irq=TSXXX_IRQ6;
283 else if (jmp&0x20) irq=TSXXX_IRQ7;
286 CANMSG("Jumpers select no IRQ for TS7KV CAN at 0x%lx of driver %d/%s\n",
287 candev->io_addr, candev->candev_idx, candev->hwname);
291 candev->chip[chipnr]->chip_irq = irq;
293 sja1000p_fill_chipspecops(candev->chip[chipnr]);
295 if(candev->chip[chipnr]->clock <= 0)
296 candev->chip[chipnr]->clock = default_clk;
297 candev->chip[chipnr]->int_clk_reg = 0x0;
298 candev->chip[chipnr]->int_bus_reg = 0x0;
299 candev->chip[chipnr]->sja_cdr_reg = sjaCDR_CBP | sjaCDR_CLK_OFF;
300 candev->chip[chipnr]->sja_ocr_reg = sjaOCR_MODE_NORMAL | sjaOCR_TX0_LH;
301 candev->chip[chipnr]->chip_base_addr = candev->io_addr;
307 * ts7kv_init_obj_data - Initialize message buffers
308 * @chip: Pointer to chip specific structure
309 * @objnr: Number of the message buffer
311 * The function ts7kv_init_obj_data() is used to initialize the hardware
312 * structure containing information about the different message objects on the
313 * CAN chip. In case of the sja1000 there's only one message object but on the
314 * i82527 chip there are 15.
315 * The code below is for a i82527 chip and initializes the object base addresses
316 * The entry @obj_base_addr represents the first memory address of the message
317 * object. In case of the sja1000 @obj_base_addr is taken the same as the chips
319 * Unless the hardware uses a segmented memory map, flags can be set zero.
320 * Return Value: The function always returns zero
323 int ts7kv_init_obj_data(struct canchip_t *chip, int objnr)
325 chip->msgobj[objnr]->obj_base_addr = chip->chip_base_addr;
330 * ts7kv_program_irq - program interrupts
331 * @candev: Pointer to candevice/board structure
333 * The function ts7kv_program_irq() is used for hardware that uses
334 * programmable interrupts. If your hardware doesn't use programmable interrupts
335 * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and
336 * leave this function unedited. Again this function is hardware specific so
337 * there's no example code.
338 * Return value: The function returns zero on success or %-ENODEV on failure
341 int ts7kv_program_irq(struct candevice_t *candev)
347 * ts7kv_write_register - Low level write register routine
348 * @data: data to be written
349 * @address: memory address to write to
351 * The function ts7kv_write_register() is used to write to hardware registers
352 * on the CAN chip. You should only have to edit this function if your hardware
353 * uses some specific write process.
354 * Return Value: The function does not return a value
357 void ts7kv_write_register(unsigned data, can_ioptr_t address)
359 unsigned long addr=can_ioptr2ulong(address);
360 can_ioptr_t base = can_ulong2ioptr(addr & ~0x1f);
361 unsigned char nwin = 0x10;
362 unsigned char savewin;
364 can_spin_irqflags_t flags;
366 if((addr&0x1f) > 0x1d) {
371 can_spin_lock_irqsave(&ts7kv_win_lock,flags);
372 savewin = can_inb(base+TS7KV_WIN_REG);
373 if(nwin == savewin) {
374 can_outb(data, address);
376 can_outb(nwin, base+TS7KV_WIN_REG);
377 can_outb(data, address);
378 can_outb(savewin, base+TS7KV_WIN_REG);
380 can_spin_unlock_irqrestore(&ts7kv_win_lock,flags);
384 * ts7kv_read_register - Low level read register routine
385 * @address: memory address to read from
387 * The function ts7kv_read_register() is used to read from hardware registers
388 * on the CAN chip. You should only have to edit this function if your hardware
389 * uses some specific read process.
390 * Return Value: The function returns the value stored in @address
393 unsigned ts7kv_read_register(can_ioptr_t address)
395 unsigned long addr=can_ioptr2ulong(address);
396 can_ioptr_t base = can_ulong2ioptr(addr & ~0x1f);
397 unsigned char nwin = 0x10;
398 unsigned char savewin;
401 can_spin_irqflags_t flags;
403 if((addr&0x1f) > 0x1d) {
408 can_spin_lock_irqsave(&ts7kv_win_lock,flags);
409 savewin = can_inb(base+TS7KV_WIN_REG);
410 if(nwin == savewin) {
411 val = can_inb(address);
413 can_outb(nwin, base+TS7KV_WIN_REG);
414 val = can_inb(address);
415 can_outb(savewin, base+TS7KV_WIN_REG);
417 can_spin_unlock_irqrestore(&ts7kv_win_lock,flags);
422 extern int ts7kv_register(struct hwspecops_t *hwspecops)
424 hwspecops->request_io = ts7kv_request_io;
425 hwspecops->release_io = ts7kv_release_io;
426 hwspecops->reset = ts7kv_reset;
427 hwspecops->init_hw_data = ts7kv_init_hw_data;
428 hwspecops->init_chip_data = ts7kv_init_chip_data;
429 hwspecops->init_obj_data = ts7kv_init_obj_data;
430 hwspecops->write_register = ts7kv_write_register;
431 hwspecops->read_register = ts7kv_read_register;
432 hwspecops->program_irq = ts7kv_program_irq;