From: ppisa Date: Tue, 11 Nov 2008 12:06:22 +0000 (+0100) Subject: Merge branch 'master' into can-usb1 X-Git-Url: http://rtime.felk.cvut.cz/gitweb/lincan.git/commitdiff_plain/b8ebad64ba024cba4fa9984ade263dc50db97268?hp=fb1e8444b02cd7ae2536adc1bad79f5e01382767 Merge branch 'master' into can-usb1 --- diff --git a/lincan/include/ts7kv.h b/lincan/include/ts7kv.h new file mode 100644 index 0000000..343d0e9 --- /dev/null +++ b/lincan/include/ts7kv.h @@ -0,0 +1,60 @@ +/* ts7kv.h + * Header file for the Linux CAN-bus driver. + * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz + * This software is released under the GPL-License. + * Version lincan-0.3 17 Jun 2004 + */ + +//Ids SECTION +#define TS7KV_ID0 0x41 +#define TS7KV_ID1 0x20 + +//MEMORY SECTION +#if defined(CONFIG_TS7800_PLATFORM) +#define TSXXX_BASE_IO 0xee000000 +#elif defined(CONFIG_MACH_TS72XX) +#define TSXXX_BASE_IO 0x01E00000 +#elif defined(CONFIG_X86) +#define TSXXX_BASE_IO 0x0 +#endif + +//IRQs +#if defined(CONFIG_TS7800_PLATFORM) +#define TSXXX_IRQ5 64+5 +#define TSXXX_IRQ6 64+6 +#define TSXXX_IRQ7 64+7 +#elif defined(CONFIG_MACH_TS72XX) +#define TSXXX_IRQ5 22 +#define TSXXX_IRQ6 33 +#define TSXXX_IRQ7 40 +#elif defined(CONFIG_X86) +#define TSXXX_IRQ5 5 +#define TSXXX_IRQ6 6 +#define TSXXX_IRQ7 7 +#endif + +#define TS7KV_BASE_IO 0xE0 +#define TS7KV_IO_RANGE 0x8 +#define TS7KV_CAN_RANGE 0x20 + +#define TS7KV_ID0_REG 0x0 +#define TS7KV_ID1_REG 0x1 +#define TS7KV_PLD_REG 0x2 + +#define TS7KV_CTR1_REG 0x4 +#define TS7KV_CTR2_REG 0x5 +#define TS7KV_FPGA_REG 0x6 +#define TS7KV_JMP_REG 0x7 +#define TS7KV_WIN_REG 0x1E + +int ts7kv_request_io(struct candevice_t *candev); +int ts7kv_release_io(struct candevice_t *candev); +int ts7kv_reset(struct candevice_t *candev); +int ts7kv_init_hw_data(struct candevice_t *candev); +int ts7kv_init_chip_data(struct candevice_t *candev, int chipnr); +int ts7kv_init_obj_data(struct canchip_t *chip, int objnr); +void ts7kv_write_register(unsigned data, can_ioptr_t address); +unsigned ts7kv_read_register(can_ioptr_t address); +int ts7kv_program_irq(struct candevice_t *candev); diff --git a/lincan/include/tscan1.h b/lincan/include/tscan1.h index 427b387..4d3aee7 100644 --- a/lincan/include/tscan1.h +++ b/lincan/include/tscan1.h @@ -1,4 +1,4 @@ -/* template.h +/* tscan1.h * Header file for the Linux CAN-bus driver. * Written by Arnaud Westenberg email:arnaud@wanadoo.nl * Rewritten for new CAN queues by Pavel Pisa - OCERA team member @@ -10,48 +10,42 @@ //Ids SECTION #define TSCAN1_ID0 0xF6 #define TSCAN1_ID1 0xB9 -#define TS7KV_ID0 0x41 -#define TS7KV_ID1 0x20 //MEMORY SECTION -#ifdef CONFIG_ARM -#include -#define TSXXX_BASE_IO 0x01E00000 +#if defined(CONFIG_TS7800_PLATFORM) +#define TSXXX_BASE_IO 0xee000000 +#elif defined(CONFIG_MACH_TS72XX) +#define TSXXX_BASE_IO 0x01E00000 +#elif defined(CONFIG_X86) +#define TSXXX_BASE_IO 0x0 #endif -#define TSCAN1_BASE_IO 0x150 -#define TS7KV_BASE_IO 0xE0 -#define TSXXX_IO_RANGE 0x8 -#define TSXXX_CAN_RANGE 0x20 +//IRQs +#if defined(CONFIG_TS7800_PLATFORM) +#define TSXXX_IRQ5 64+5 +#define TSXXX_IRQ6 64+6 +#define TSXXX_IRQ7 64+7 +#elif defined(CONFIG_MACH_TS72XX) +#define TSXXX_IRQ5 22 +#define TSXXX_IRQ6 33 +#define TSXXX_IRQ7 40 +#elif defined(CONFIG_X86) +#define TSXXX_IRQ5 5 +#define TSXXX_IRQ6 6 +#define TSXXX_IRQ7 7 +#endif -#define TSXXX_ID0_REG 0x0 -#define TSXXX_ID1_REG 0x1 -#define TSXXX_PLD_REG 0x2 +#define TSCAN1_BASE_IO 0x150 +#define TSCAN1_IO_RANGE 0x8 +#define TSCAN1_CAN_RANGE 0x20 +#define TSCAN1_ID0_REG 0x0 +#define TSCAN1_ID1_REG 0x1 +#define TSCAN1_PLD_REG 0x2 #define TSCAN1_WIN_REG 0x4 #define TSCAN1_MOD_REG 0x5 #define TSCAN1_JMP_REG 0x6 -#define TS7KV_CTR1_REG 0x4 -#define TS7KV_CTR2_REG 0x5 -#define TS7KV_FPGA_REG 0x6 -#define TS7KV_JMP_REG 0x7 -#define TS7KV_WIN_REG 0x1E - -//IRQs -#ifdef CONFIG_ARM -#define TSXXX_IRQ5 5 -#define TSXXX_IRQ6 33 -#define TSXXX_IRQ7 40 -#endif - -#ifdef CONFIG_X86 -#define TSXXX_IRQ5 5 -#define TSXXX_IRQ6 6 -#define TSXXX_IRQ7 7 -#endif - - int tscan1_request_io(struct candevice_t *candev); int tscan1_release_io(struct candevice_t *candev); int tscan1_reset(struct candevice_t *candev); @@ -61,7 +55,3 @@ int tscan1_init_obj_data(struct canchip_t *chip, int objnr); void tscan1_write_register(unsigned data, can_ioptr_t address); unsigned tscan1_read_register(can_ioptr_t address); int tscan1_program_irq(struct candevice_t *candev); - -unsigned long tscan1_getmappedaddr(unsigned long address); -unsigned short tscan1_getcandevidx(unsigned long address); -unsigned long tscan1_setpage_getaddr(unsigned long address, signed short *nwinbak, unsigned long *winaddr); diff --git a/lincan/src/Makefile.omk b/lincan/src/Makefile.omk index 72d2811..29e0ba4 100644 --- a/lincan/src/Makefile.omk +++ b/lincan/src/Makefile.omk @@ -2,7 +2,7 @@ lincan_cards_NAMES = pip pccan smartcan nsi cc_can104 ems_cpcpci \ pc_i03 pcm3680 aim104 m437 pcccan ssv bfadcan gensja1000io pikronisa eb8245 \ kv_pcican msmcan oscar adlink7841 pcan_pci esdpci200 unican usbcan virtual template -lincan_morecards_NAMES = hms30c7202_can ns_dev_can ipci165 pimx1 tscan1 nsi_canpci sh7760 +lincan_morecards_NAMES = hms30c7202_can ns_dev_can ipci165 pimx1 tscan1 ts7kv nsi_canpci sh7760 default_CONFIG = CONFIG_OC_LINCAN=y CONFIG_OC_LINCANRTL=n CONFIG_OC_LINCANVME=n default_CONFIG += CONFIG_OC_LINCAN_PORTIO_ONLY=n CONFIG_OC_LINCAN_MEMIO_ONLY=n diff --git a/lincan/src/boardlist.c b/lincan/src/boardlist.c index 0c2696a..d7cf342 100644 --- a/lincan/src/boardlist.c +++ b/lincan/src/boardlist.c @@ -41,6 +41,7 @@ extern int pcan_dongle_register(struct hwspecops_t *hwspecops); extern int eb8245_register(struct hwspecops_t *hwspecops); extern int adlink7841_register(struct hwspecops_t *hwspecops); extern int tscan1_register(struct hwspecops_t *hwspecops); +extern int tscan1mmio_register(struct hwspecops_t *hwspecops); extern int ts7kv_register(struct hwspecops_t *hwspecops); extern int ns_dev_register(struct hwspecops_t *hwspecops); extern int hms30c7202_register(struct hwspecops_t *hwspecops); @@ -148,6 +149,9 @@ const struct boardtype_t can_boardtypes[]={ #endif #if defined(CONFIG_OC_LINCAN_CARD_tscan1) {"tscan1", tscan1_register, 1}, + {"tscan1mmio", tscan1mmio_register, 1}, + #endif + #if defined(CONFIG_OC_LINCAN_CARD_ts7kv) {"ts7kv", ts7kv_register, 1}, #endif #if defined(CONFIG_OC_LINCAN_CARD_ns_dev_can) diff --git a/lincan/src/ts7kv.c b/lincan/src/ts7kv.c new file mode 100644 index 0000000..c5f20e4 --- /dev/null +++ b/lincan/src/ts7kv.c @@ -0,0 +1,434 @@ +/* ts7kv.c + * Linux CAN-bus device driver. + * Written by Arnaud Westenberg email:arnaud@wanadoo.nl + * Rewritten for new CAN queues by Pavel Pisa - OCERA team member + * email:pisa@cmp.felk.cvut.cz + * This software is released under the GPL-License. + * Version lincan-0.3 17 Jun 2004 + * + * The support for TS-CAN1 and TS-7KV provided by Ronald Gomes + * from Technologic Systems + */ + +#include "../include/can.h" +#include "../include/can_sysdep.h" +#include "../include/main.h" +#include "../include/sja1000p.h" + +#include +#include "../include/modparms.h" +#include "../include/devcommon.h" + +#include "../include/ts7kv.h" + +static CAN_DEFINE_SPINLOCK(ts7kv_win_lock); + +#ifdef CONFIG_OC_LINCAN_CARD_tscan1 + +extern unsigned long tsxxx_base; + +#else /*CONFIG_OC_LINCAN_CARD_tscan1*/ + +#if defined(TSXXX_BASE_IO) +unsigned long tsxxx_base=TSXXX_BASE_IO; +#else +unsigned long tsxxx_base=0; +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)) +MODULE_PARM(tsxxx_base, "1i"); +#else /* LINUX_VERSION_CODE >= 2,6,12 */ +module_param(tsxxx_base, ulong, 0); +#endif /* LINUX_VERSION_CODE >= 2,6,12 */ + +MODULE_PARM_DESC(tscanio,"TSCAN CAN controller IO address for each board"); +MODULE_PARM_DESC(tsxxx_base,"The base of the ISA/8-bit IO space for TSxxx CAN peripherals in the system"); + +#endif /*CONFIG_OC_LINCAN_CARD_tscan1*/ + +/** + * ts7kv_request_io: - reserve io or memory range for can board + * @candev: pointer to candevice/board which asks for io. Field @io_addr + * of @candev is used in most cases to define start of the range + * + * The function ts7kv_request_io() is used to reserve the io-memory. If your + * hardware uses a dedicated memory range as hardware control registers you + * will have to add the code to reserve this memory as well. + * %IO_RANGE is the io-memory range that gets reserved, please adjust according + * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or + * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode. + * Return Value: The function returns zero on success or %-ENODEV on failure + * File: src/ts7kv.c + */ +int ts7kv_request_io(struct candevice_t *candev) +{ + if (!can_request_io_region(candev->io_addr, TS7KV_CAN_RANGE, "ts7kv-can")) { + CANMSG("Unable to request CAN IO port: 0x%lx\n", candev->io_addr); + return -ENODEV; + } else { + DEBUGMSG("Registered CAN IO port: 0x%lx - 0x%lx\n", + candev->io_addr, candev->io_addr+TS7KV_CAN_RANGE-1); + } + + return 0; +} + +/** + * ts7kv_release_io - free reserved io memory range + * @candev: pointer to candevice/board which releases io + * + * The function ts7kv_release_io() is used to free reserved io-memory. + * In case you have reserved more io memory, don't forget to free it here. + * IO_RANGE is the io-memory range that gets released, please adjust according + * your hardware. Example: #define IO_RANGE 0x100 for i82527 chips or + * #define IO_RANGE 0x20 for sja1000 chips in basic CAN mode. + * Return Value: The function always returns zero + * File: src/ts7kv.c + */ +int ts7kv_release_io(struct candevice_t *candev) +{ + can_release_io_region(candev->io_addr, TS7KV_CAN_RANGE); + return 0; +} + +/** + * ts7kv_reset - hardware reset routine + * @candev: Pointer to candevice/board structure + * + * The function ts7kv_reset() is used to give a hardware reset. This is + * rather hardware specific so I haven't included example code. Don't forget to + * check the reset status of the chip before returning. + * Return Value: The function returns zero on success or %-ENODEV on failure + * File: src/ts7kv.c + */ +int ts7kv_reset(struct candevice_t *candev) +{ + unsigned short i=0, chipnr; + struct canchip_t *chip; + + DEBUGMSG("Resetting %s hardware ...\n", candev->hwname); + + for(chipnr=0;chipnrnr_sja1000_chips;chipnr++) { + chip=candev->chip[chipnr]; + can_write_reg(chip, sjaMOD_RM, SJAMOD); + udelay(1000); + can_write_reg(chip, 0x00, SJAIER); + udelay(1000); + i=20; + while (can_read_reg(chip, SJAMOD)&sjaMOD_RM){ + if(!i--) return -ENODEV; + udelay(1000); + can_write_reg(chip, 0, SJAMOD); + } + udelay(1000); + can_write_reg(chip, sjaCDR_PELICAN, SJACDR); + can_write_reg(chip, 0x00, SJAIER); + } + + return 0; +} + +int ts7kv_check_presence(unsigned long remap_io_addr, int *pjmp) +{ + int result = -ENODEV; + + if (!can_request_io_region(remap_io_addr, TS7KV_IO_RANGE, "ts7kv-probe")) + return -ENODEV; + + do { + if (can_inb(remap_io_addr+TS7KV_ID0_REG)!=TS7KV_ID0 || + can_inb(remap_io_addr+TS7KV_ID1_REG)!=TS7KV_ID1) + break; + + if(pjmp) + *pjmp = can_inb(remap_io_addr+TS7KV_JMP_REG); + + result = 0; + } while (0); + + can_release_io_region(remap_io_addr, TS7KV_IO_RANGE); + + return result; +} + +#define RESET_ADDR 0x100 +#define NR_82527 0 +#define NR_SJA1000 1 + +/** + * ts7kv_init_hw_data - Initialize hardware cards + * @candev: Pointer to candevice/board structure + * + * The function ts7kv_init_hw_data() is used to initialize the hardware + * structure containing information about the installed CAN-board. + * %RESET_ADDR represents the io-address of the hardware reset register. + * %NR_82527 represents the number of intel 82527 chips on the board. + * %NR_SJA1000 represents the number of philips sja1000 chips on the board. + * The flags entry can currently only be %CANDEV_PROGRAMMABLE_IRQ to indicate that + * the hardware uses programmable interrupts. + * Return Value: The function always returns zero + * File: src/ts7kv.c + */ +int ts7kv_init_hw_data(struct candevice_t *candev) +{ + int i, j, jmp; + unsigned long io_addr; + unsigned long remap_io_addr; + unsigned long can_io_addr; + + io_addr = candev->io_addr; + + if(io_addr && (io_addr != (unsigned long)-1)) { + remap_io_addr = io_addr + tsxxx_base; + + if(ts7kv_check_presence(remap_io_addr, &jmp)){ + CANMSG("No TS7KV card found at address 0x%lx\n", + remap_io_addr); + return -ENODEV; + } + } else { + DEBUGMSG("Scanning bus for TS7KV boards...\n"); + + for (i=0; 1;i++) + { + if(i >= 4) { + CANMSG("No TS7KV boards found for slot %d\n", candev->candev_idx); + return -ENODEV; + } + + io_addr = TS7KV_BASE_IO + i*TS7KV_IO_RANGE; + remap_io_addr = io_addr + tsxxx_base; + + for (j = 0; j < MAX_HW_CARDS; j++) { + if(io[j] == io_addr){ + j = -1; + break; + } + } + if(j<0) + continue; + + if(!ts7kv_check_presence(remap_io_addr, &jmp)) + break; + + } + DEBUGMSG("TS7KV board was found at 0x%lx for driver slot %d\n", + io_addr, candev->candev_idx); + + io[candev->candev_idx] = io_addr; + } + + can_io_addr = ((io_addr>>3)&0x03)*0x20; + + /* dev_base_addr address is used to store remapped PLD base address */ + candev->dev_base_addr = remap_io_addr; + + /* dev_base_addr address is used to store remapped slave window address */ + candev->io_addr = can_io_addr+tsxxx_base; + + /* unused reset address is used to store jumper setting */ + candev->res_addr = jmp; + + candev->nr_82527_chips=NR_82527; + candev->nr_sja1000_chips=NR_SJA1000; + candev->nr_all_chips=NR_82527+NR_SJA1000; + candev->flags &= ~CANDEV_PROGRAMMABLE_IRQ; + + DEBUGMSG("Memory region at 0x%lx assigned to sja1000 of driver %d/%s\n", + candev->io_addr, candev->candev_idx, candev->hwname); + + return 0; +} + +/** + * ts7kv_init_chip_data - Initialize chips + * @candev: Pointer to candevice/board structure + * @chipnr: Number of the CAN chip on the hardware card + * + * The function ts7kv_init_chip_data() is used to initialize the hardware + * structure containing information about the CAN chips. + * %CHIP_TYPE represents the type of CAN chip. %CHIP_TYPE can be "i82527" or + * "sja1000". + * The @chip_base_addr entry represents the start of the 'official' memory map + * of the installed chip. It's likely that this is the same as the @io_addr + * argument supplied at module loading time. + * The @clock entry holds the chip clock value in Hz. + * The entry @sja_cdr_reg holds hardware specific options for the Clock Divider + * register. Options defined in the %sja1000.h file: + * %sjaCDR_CLKOUT_MASK, %sjaCDR_CLK_OFF, %sjaCDR_RXINPEN, %sjaCDR_CBP, %sjaCDR_PELICAN + * The entry @sja_ocr_reg holds hardware specific options for the Output Control + * register. Options defined in the %sja1000.h file: + * %sjaOCR_MODE_BIPHASE, %sjaOCR_MODE_TEST, %sjaOCR_MODE_NORMAL, %sjaOCR_MODE_CLOCK, + * %sjaOCR_TX0_LH, %sjaOCR_TX1_ZZ. + * The entry @int_clk_reg holds hardware specific options for the Clock Out + * register. Options defined in the %i82527.h file: + * %iCLK_CD0, %iCLK_CD1, %iCLK_CD2, %iCLK_CD3, %iCLK_SL0, %iCLK_SL1. + * The entry @int_bus_reg holds hardware specific options for the Bus + * Configuration register. Options defined in the %i82527.h file: + * %iBUS_DR0, %iBUS_DR1, %iBUS_DT1, %iBUS_POL, %iBUS_CBY. + * Return Value: The function always returns zero + * File: src/ts7kv.c + */ +int ts7kv_init_chip_data(struct candevice_t *candev, int chipnr) +{ + unsigned long default_clk = 16000 * 1000; + int jmp; + int irq = -1; + + /* unused reset address is used to store jumper setting */ + jmp = candev->res_addr; + + if (jmp&0x10 && jmp&0x20) irq=TSXXX_IRQ5; + else if (jmp&0x10) irq=TSXXX_IRQ6; + else if (jmp&0x20) irq=TSXXX_IRQ7; + + if(irq<0) { + CANMSG("Jumpers select no IRQ for TS7KV CAN at 0x%lx of driver %d/%s\n", + candev->io_addr, candev->candev_idx, candev->hwname); + return -ENODEV; + } + + candev->chip[chipnr]->chip_irq = irq; + + sja1000p_fill_chipspecops(candev->chip[chipnr]); + + if(candev->chip[chipnr]->clock <= 0) + candev->chip[chipnr]->clock = default_clk; + candev->chip[chipnr]->int_clk_reg = 0x0; + candev->chip[chipnr]->int_bus_reg = 0x0; + candev->chip[chipnr]->sja_cdr_reg = sjaCDR_CBP | sjaCDR_CLK_OFF; + candev->chip[chipnr]->sja_ocr_reg = sjaOCR_MODE_NORMAL | sjaOCR_TX0_LH; + candev->chip[chipnr]->chip_base_addr = candev->io_addr; + + return 0; +} + +/** + * ts7kv_init_obj_data - Initialize message buffers + * @chip: Pointer to chip specific structure + * @objnr: Number of the message buffer + * + * The function ts7kv_init_obj_data() is used to initialize the hardware + * structure containing information about the different message objects on the + * CAN chip. In case of the sja1000 there's only one message object but on the + * i82527 chip there are 15. + * The code below is for a i82527 chip and initializes the object base addresses + * The entry @obj_base_addr represents the first memory address of the message + * object. In case of the sja1000 @obj_base_addr is taken the same as the chips + * base address. + * Unless the hardware uses a segmented memory map, flags can be set zero. + * Return Value: The function always returns zero + * File: src/ts7kv.c + */ +int ts7kv_init_obj_data(struct canchip_t *chip, int objnr) +{ + chip->msgobj[objnr]->obj_base_addr = chip->chip_base_addr; + return 0; +} + +/** + * ts7kv_program_irq - program interrupts + * @candev: Pointer to candevice/board structure + * + * The function ts7kv_program_irq() is used for hardware that uses + * programmable interrupts. If your hardware doesn't use programmable interrupts + * you should not set the @candevices_t->flags entry to %CANDEV_PROGRAMMABLE_IRQ and + * leave this function unedited. Again this function is hardware specific so + * there's no example code. + * Return value: The function returns zero on success or %-ENODEV on failure + * File: src/ts7kv.c + */ +int ts7kv_program_irq(struct candevice_t *candev) +{ + return 0; +} + +/** + * ts7kv_write_register - Low level write register routine + * @data: data to be written + * @address: memory address to write to + * + * The function ts7kv_write_register() is used to write to hardware registers + * on the CAN chip. You should only have to edit this function if your hardware + * uses some specific write process. + * Return Value: The function does not return a value + * File: src/ts7kv.c + */ +void ts7kv_write_register(unsigned data, can_ioptr_t address) +{ + unsigned long addr=can_ioptr2ulong(address); + can_ioptr_t base = can_ulong2ioptr(addr & ~0x1f); + unsigned char nwin = 0x10; + unsigned char savewin; + + can_spin_irqflags_t flags; + + if((addr&0x1f) > 0x1d) { + nwin++; + address -= 0x10; + } + + can_spin_lock_irqsave(&ts7kv_win_lock,flags); + savewin = can_inb(base+TS7KV_WIN_REG); + if(nwin == savewin) { + can_outb(data, address); + }else{ + can_outb(nwin, base+TS7KV_WIN_REG); + can_outb(data, address); + can_outb(savewin, base+TS7KV_WIN_REG); + } + can_spin_unlock_irqrestore(&ts7kv_win_lock,flags); +} + +/** + * ts7kv_read_register - Low level read register routine + * @address: memory address to read from + * + * The function ts7kv_read_register() is used to read from hardware registers + * on the CAN chip. You should only have to edit this function if your hardware + * uses some specific read process. + * Return Value: The function returns the value stored in @address + * File: src/ts7kv.c + */ +unsigned ts7kv_read_register(can_ioptr_t address) +{ + unsigned long addr=can_ioptr2ulong(address); + can_ioptr_t base = can_ulong2ioptr(addr & ~0x1f); + unsigned char nwin = 0x10; + unsigned char savewin; + unsigned val; + + can_spin_irqflags_t flags; + + if((addr&0x1f) > 0x1d) { + nwin++; + address -= 0x10; + } + + can_spin_lock_irqsave(&ts7kv_win_lock,flags); + savewin = can_inb(base+TS7KV_WIN_REG); + if(nwin == savewin) { + val = can_inb(address); + }else{ + can_outb(nwin, base+TS7KV_WIN_REG); + val = can_inb(address); + can_outb(savewin, base+TS7KV_WIN_REG); + } + can_spin_unlock_irqrestore(&ts7kv_win_lock,flags); + + return val; +} + +extern int ts7kv_register(struct hwspecops_t *hwspecops) +{ + hwspecops->request_io = ts7kv_request_io; + hwspecops->release_io = ts7kv_release_io; + hwspecops->reset = ts7kv_reset; + hwspecops->init_hw_data = ts7kv_init_hw_data; + hwspecops->init_chip_data = ts7kv_init_chip_data; + hwspecops->init_obj_data = ts7kv_init_obj_data; + hwspecops->write_register = ts7kv_write_register; + hwspecops->read_register = ts7kv_read_register; + hwspecops->program_irq = ts7kv_program_irq; + return 0; +} diff --git a/lincan/src/tscan1.c b/lincan/src/tscan1.c index dab8584..c3ff8d1 100644 --- a/lincan/src/tscan1.c +++ b/lincan/src/tscan1.c @@ -13,7 +13,6 @@ #include "../include/can.h" #include "../include/can_sysdep.h" #include "../include/main.h" -#include "../include/pcm3680.h" #include "../include/sja1000p.h" #include @@ -22,30 +21,38 @@ #include "../include/tscan1.h" -static CAN_DEFINE_SPINLOCK(ts7kv_win_lock); - unsigned long tscanio[MAX_HW_CARDS]={-1,-1,-1,-1,-1,-1,-1,-1}; unsigned int tscanio_specified; -#if defined(TS7XXX_IO8_BASE)&&defined(TSXXX_BASE_IO) -int tsxxx_base=TS7XXX_IO8_BASE+TSXXX_BASE_IO; -#elif defined(TS7XXX_IO8_BASE) -int tsxxx_base=TS7XXX_IO8_BASE; -#else /*TS7XXX_IO8_BASE*/ +#if defined(TSXXX_BASE_IO) +unsigned long tsxxx_base=TSXXX_BASE_IO; +#else unsigned long tsxxx_base=0; -#endif /*TS7XXX_IO8_BASE*/ +#endif #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)) MODULE_PARM(tscanio, "1-" __MODULE_STRING(MAX_HW_CARDS)"i"); MODULE_PARM(tsxxx_base, "1i"); #else /* LINUX_VERSION_CODE >= 2,6,12 */ -module_param_array(tscanio, int, &tscanio_specified, 0); +module_param_array(tscanio, ulong, &tscanio_specified, 0); module_param(tsxxx_base, ulong, 0); #endif /* LINUX_VERSION_CODE >= 2,6,12 */ MODULE_PARM_DESC(tscanio,"TSCAN CAN controller IO address for each board"); MODULE_PARM_DESC(tsxxx_base,"The base of the ISA/8-bit IO space for TSxxx CAN peripherals in the system"); +static unsigned long tscan1_tscanio_ranges[] = + { 0x100, 0x120, 0x180, 0x1A0, 0x200, 0x240, 0x280, 0x320}; + +static inline unsigned tscan1_read_pld_register(struct candevice_t *candev, can_ioptr_t address) +{ + return candev->hwspecops->read_register(address); +} + +static inline void tscan1_write_pld_register(struct candevice_t *candev, unsigned data, can_ioptr_t address) +{ + candev->hwspecops->write_register(data, address); +} /** * tscan1_request_io: - reserve io or memory range for can board @@ -64,42 +71,44 @@ MODULE_PARM_DESC(tsxxx_base,"The base of the ISA/8-bit IO space for TSxxx CAN pe int tscan1_request_io(struct candevice_t *candev) { unsigned long can_io_addr; - unsigned long remap_can_io_addr = 0; + unsigned long rebased_can_io_addr; + can_ioptr_t remap_can_io_addr; + can_ioptr_t remap_pld_io_addr; unsigned char mode; int i, j; - if (!can_request_io_region(candev->io_addr, TSXXX_IO_RANGE, "tscan1-base")) { + if (!can_request_io_region(candev->io_addr, TSCAN1_IO_RANGE, "tscan1-base")) { CANMSG("Unable to request base IO port: 0x%lx\n", candev->io_addr); return -ENODEV; } else { DEBUGMSG("Registered base IO port: 0x%lx - 0x%lx\n", - candev->io_addr, candev->io_addr+TSXXX_IO_RANGE-1); + candev->io_addr, candev->io_addr+TSCAN1_IO_RANGE-1); } can_io_addr = tscanio[candev->candev_idx]; if(can_io_addr && (can_io_addr != (unsigned long)-1)) { - remap_can_io_addr = tsxxx_base + can_io_addr; + rebased_can_io_addr = tsxxx_base + can_io_addr; - if (!can_request_io_region(remap_can_io_addr, TSXXX_CAN_RANGE, "tscan1-can")) { - CANMSG("Unable to request CAN IO port: 0x%lx\n", remap_can_io_addr); - can_release_io_region(candev->io_addr, TSXXX_IO_RANGE); + if (!can_request_io_region(rebased_can_io_addr, TSCAN1_CAN_RANGE, "tscan1-can")) { + CANMSG("Unable to request CAN IO port: 0x%lx\n", rebased_can_io_addr); + can_release_io_region(candev->io_addr, TSCAN1_IO_RANGE); return -ENODEV; } else { DEBUGMSG("Registered CAN IO port: 0x%lx - 0x%lx\n", - remap_can_io_addr, remap_can_io_addr+TSXXX_CAN_RANGE-1); + rebased_can_io_addr, rebased_can_io_addr+TSCAN1_CAN_RANGE-1); } } else { for(i = 0; 1; i++) { if(i>=8) { CANMSG("Unable find range for CAN IO port\n"); - can_release_io_region(candev->io_addr, TSXXX_IO_RANGE); + can_release_io_region(candev->io_addr, TSCAN1_IO_RANGE); return -ENODEV; } - can_io_addr = 0x100 + i * TSXXX_CAN_RANGE; + can_io_addr = tscan1_tscanio_ranges[i]; for (j = 0; j < MAX_HW_CARDS; j++) { if(tscanio[j] == can_io_addr) { j = -1; @@ -109,48 +118,35 @@ int tscan1_request_io(struct candevice_t *candev) if(j<0) continue; - remap_can_io_addr = tsxxx_base + can_io_addr; + rebased_can_io_addr = tsxxx_base + can_io_addr; - if (can_request_io_region(remap_can_io_addr, TSXXX_CAN_RANGE, "tscan1-can")) + if (can_request_io_region(rebased_can_io_addr, TSCAN1_CAN_RANGE, "tscan1-can")) break; } tscanio[candev->candev_idx] = can_io_addr; DEBUGMSG("Found free range and registered CAN IO port: 0x%lx - 0x%lx\n", - remap_can_io_addr, remap_can_io_addr+TSXXX_CAN_RANGE-1); + rebased_can_io_addr, rebased_can_io_addr+TSCAN1_CAN_RANGE-1); } + remap_can_io_addr = can_ulong2ioptr(rebased_can_io_addr); + candev->chip[0]->chip_base_addr = remap_can_io_addr; candev->chip[0]->msgobj[0]->obj_base_addr = remap_can_io_addr; - switch(can_io_addr) { - case 0x100: mode=0x60; break; - case 0x120: mode=0x61; break; - case 0x180: mode=0x62; break; - case 0x1A0: mode=0x63; break; - case 0x200: mode=0x64; break; - case 0x240: mode=0x65; break; - case 0x280: mode=0x66; break; - case 0x320: mode=0x67; break; - default: mode=0x60; break; + mode = 0x60; + for(i = 0; i < 8; i++) { + if (can_io_addr == tscan1_tscanio_ranges[i]) { + mode |= i; + break; + } } - can_outb(0x00, candev->io_addr+TSCAN1_WIN_REG); - can_outb(mode, candev->io_addr+TSCAN1_MOD_REG); - - return 0; -} + remap_pld_io_addr = can_ulong2ioptr(candev->io_addr); -int ts7kv_request_io(struct candevice_t *candev) -{ - if (!can_request_io_region(candev->io_addr, TSXXX_CAN_RANGE, "ts7kv-can")) { - CANMSG("Unable to request CAN IO port: 0x%lx\n", candev->io_addr); - return -ENODEV; - } else { - DEBUGMSG("Registered CAN IO port: 0x%lx - 0x%lx\n", - candev->io_addr, candev->io_addr+TSXXX_CAN_RANGE-1); - } + tscan1_write_pld_register(candev, 0x00, remap_pld_io_addr+TSCAN1_WIN_REG); + tscan1_write_pld_register(candev, mode, remap_pld_io_addr+TSCAN1_MOD_REG); return 0; } @@ -169,23 +165,18 @@ int ts7kv_request_io(struct candevice_t *candev) */ int tscan1_release_io(struct candevice_t *candev) { - unsigned long remap_can_io_addr; + unsigned long rebased_can_io_addr; + can_ioptr_t remap_pld_io_addr = can_ulong2ioptr(candev->io_addr); if(candev->chip[0]){ - remap_can_io_addr = candev->chip[0]->chip_base_addr; - if(remap_can_io_addr != (unsigned long)-1) - can_release_io_region(remap_can_io_addr, TSXXX_CAN_RANGE); + rebased_can_io_addr = candev->chip[0]->chip_base_addr; + if(rebased_can_io_addr != (unsigned long)-1) + can_release_io_region(rebased_can_io_addr, TSCAN1_CAN_RANGE); } - can_outb(0x20, candev->io_addr+TSCAN1_MOD_REG); + tscan1_write_pld_register(candev, 0x20, remap_pld_io_addr+TSCAN1_MOD_REG); - can_release_io_region(candev->io_addr, TSXXX_IO_RANGE); - return 0; -} - -int ts7kv_release_io(struct candevice_t *candev) -{ - can_release_io_region(candev->io_addr, TSXXX_CAN_RANGE); + can_release_io_region(candev->io_addr, TSCAN1_IO_RANGE); return 0; } @@ -230,28 +221,31 @@ int tscan1_reset(struct candevice_t *candev) #define NR_82527 0 #define NR_SJA1000 1 -int tscan1_check_presence(unsigned long remap_io_addr, int *pjmp) +int tscan1_check_presence(struct candevice_t *candev, unsigned long rebased_pld_io_addr, int *pjmp) { + can_ioptr_t remap_pld_io_addr; int result = -ENODEV; - if (!can_request_io_region(remap_io_addr, TSXXX_IO_RANGE, "tscan1-probe")) + if (!can_request_io_region(rebased_pld_io_addr, TSCAN1_IO_RANGE, "tscan1-probe")) return -ENODEV; do { - if (can_inb(remap_io_addr+TSXXX_ID0_REG)!=TSCAN1_ID0 || - can_inb(remap_io_addr+TSXXX_ID1_REG)!=TSCAN1_ID1) + remap_pld_io_addr = can_ulong2ioptr(rebased_pld_io_addr); + + if (tscan1_read_pld_register(candev, remap_pld_io_addr+TSCAN1_ID0_REG)!=TSCAN1_ID0 || + tscan1_read_pld_register(candev, remap_pld_io_addr+TSCAN1_ID1_REG)!=TSCAN1_ID1) break; - can_outb(0x00, remap_io_addr+TSCAN1_WIN_REG); - can_outb(0x20, remap_io_addr+TSCAN1_MOD_REG); + tscan1_write_pld_register(candev, 0x00, remap_pld_io_addr+TSCAN1_WIN_REG); + tscan1_write_pld_register(candev, 0x20, remap_pld_io_addr+TSCAN1_MOD_REG); if(pjmp) - *pjmp = can_inb(remap_io_addr+TSCAN1_JMP_REG); + *pjmp = tscan1_read_pld_register(candev, remap_pld_io_addr+TSCAN1_JMP_REG); result = 0; } while (0); - can_release_io_region(remap_io_addr, TSXXX_IO_RANGE); + can_release_io_region(rebased_pld_io_addr, TSCAN1_IO_RANGE); return result; } @@ -276,15 +270,16 @@ int tscan1_init_hw_data(struct candevice_t *candev) { int i, j, jmp; unsigned long io_addr; - unsigned long remap_io_addr; + unsigned long rebased_pld_io_addr; io_addr = candev->io_addr; if(io_addr && (io_addr != (unsigned long)-1)) { - remap_io_addr = io_addr + tsxxx_base; + rebased_pld_io_addr = io_addr + tsxxx_base; - if(tscan1_check_presence(remap_io_addr, &jmp)){ - CANMSG("No TSCAN1 card found at address 0xlx\n"); + if(tscan1_check_presence(candev, rebased_pld_io_addr, &jmp)){ + CANMSG("No TSCAN1 card found at address 0x%lx\n", + rebased_pld_io_addr); return -ENODEV; } } else { @@ -297,8 +292,8 @@ int tscan1_init_hw_data(struct candevice_t *candev) return -ENODEV; } - io_addr = TSCAN1_BASE_IO + i*TSXXX_IO_RANGE; - remap_io_addr = io_addr + tsxxx_base; + io_addr = TSCAN1_BASE_IO + i*TSCAN1_IO_RANGE; + rebased_pld_io_addr = io_addr + tsxxx_base; for (j = 0; j < MAX_HW_CARDS; j++) { if(io[j] == io_addr){ @@ -309,7 +304,7 @@ int tscan1_init_hw_data(struct candevice_t *candev) if(j<0) continue; - if(!tscan1_check_presence(remap_io_addr, &jmp)) + if(!tscan1_check_presence(candev, rebased_pld_io_addr, &jmp)) break; } @@ -319,7 +314,7 @@ int tscan1_init_hw_data(struct candevice_t *candev) io[candev->candev_idx] = io_addr; } - candev->io_addr = remap_io_addr; + candev->io_addr = rebased_pld_io_addr; /* unused reset address is used to store jumper setting */ candev->res_addr = jmp; @@ -335,100 +330,6 @@ int tscan1_init_hw_data(struct candevice_t *candev) } -int ts7kv_check_presence(unsigned long remap_io_addr, int *pjmp) -{ - int result = -ENODEV; - - if (!can_request_io_region(remap_io_addr, TSXXX_IO_RANGE, "ts7kv-probe")) - return -ENODEV; - - do { - if (can_inb(remap_io_addr+TSXXX_ID0_REG)!=TS7KV_ID0 || - can_inb(remap_io_addr+TSXXX_ID1_REG)!=TS7KV_ID1) - break; - - if(pjmp) - *pjmp = can_inb(remap_io_addr+TS7KV_JMP_REG); - - result = 0; - } while (0); - - can_release_io_region(remap_io_addr, TSXXX_IO_RANGE); - - return result; -} - -int ts7kv_init_hw_data(struct candevice_t *candev) -{ - int i, j, jmp; - unsigned long io_addr; - unsigned long remap_io_addr; - unsigned long can_io_addr; - - io_addr = candev->io_addr; - - if(io_addr && (io_addr != (unsigned long)-1)) { - remap_io_addr = io_addr + tsxxx_base; - - if(ts7kv_check_presence(remap_io_addr, &jmp)){ - CANMSG("No TS7KV card found at address 0xlx\n"); - return -ENODEV; - } - } else { - DEBUGMSG("Scanning bus for TS7KV boards...\n"); - - for (i=0; 1;i++) - { - if(i >= 4) { - CANMSG("No TS7KV boards found for slot %d\n", candev->candev_idx); - return -ENODEV; - } - - io_addr = TS7KV_BASE_IO + i*TSXXX_IO_RANGE; - remap_io_addr = io_addr + tsxxx_base; - - for (j = 0; j < MAX_HW_CARDS; j++) { - if(io[j] == io_addr){ - j = -1; - break; - } - } - if(j<0) - continue; - - if(!ts7kv_check_presence(remap_io_addr, &jmp)) - break; - - } - DEBUGMSG("TS7KV board was found at 0x%lx for driver slot %d\n", - io_addr, candev->candev_idx); - - io[candev->candev_idx] = io_addr; - } - - can_io_addr = ((io_addr>>3)&0x03)*0x20; - tscanio[candev->candev_idx] = can_io_addr; - - /* dev_base_addr address is used to store remapped PLD base address */ - candev->dev_base_addr = remap_io_addr; - - /* dev_base_addr address is used to store remapped slave window address */ - candev->io_addr = can_io_addr+tsxxx_base; - - /* unused reset address is used to store jumper setting */ - candev->res_addr = jmp; - - candev->nr_82527_chips=NR_82527; - candev->nr_sja1000_chips=NR_SJA1000; - candev->nr_all_chips=NR_82527+NR_SJA1000; - candev->flags &= ~CANDEV_PROGRAMMABLE_IRQ; - - DEBUGMSG("Memory region at 0x%lx assigned to sja1000 of driver %d/%s\n", - candev->io_addr, candev->candev_idx, candev->hwname); - - return 0; -} - /** * tscan1_init_chip_data - Initialize chips * @candev: Pointer to candevice/board structure @@ -495,40 +396,6 @@ int tscan1_init_chip_data(struct candevice_t *candev, int chipnr) return 0; } -int ts7kv_init_chip_data(struct candevice_t *candev, int chipnr) -{ - unsigned long default_clk = 16000 * 1000; - int jmp; - int irq = -1; - - /* unused reset address is used to store jumper setting */ - jmp = candev->res_addr; - - if (jmp&0x10 && jmp&0x20) irq=TSXXX_IRQ5; - else if (jmp&0x10) irq=TSXXX_IRQ6; - else if (jmp&0x20) irq=TSXXX_IRQ7; - - if(irq<0) { - CANMSG("Jumpers select no IRQ for TS7KV CAN at 0x%lx of driver %d/%s\n", - candev->io_addr, candev->candev_idx, candev->hwname); - return -ENODEV; - } - - candev->chip[chipnr]->chip_irq = irq; - - sja1000p_fill_chipspecops(candev->chip[chipnr]); - - if(candev->chip[chipnr]->clock <= 0) - candev->chip[chipnr]->clock = default_clk; - candev->chip[chipnr]->int_clk_reg = 0x0; - candev->chip[chipnr]->int_bus_reg = 0x0; - candev->chip[chipnr]->sja_cdr_reg = sjaCDR_CBP | sjaCDR_CLK_OFF; - candev->chip[chipnr]->sja_ocr_reg = sjaOCR_MODE_NORMAL | sjaOCR_TX0_LH; - candev->chip[chipnr]->chip_base_addr = candev->io_addr; - - return 0; -} - /** * tscan1_init_obj_data - Initialize message buffers * @chip: Pointer to chip specific structure @@ -585,32 +452,12 @@ void tscan1_write_register(unsigned data, can_ioptr_t address) can_outb(data, address); } -void ts7kv_write_register(unsigned data, can_ioptr_t address) +void tscan1mmio_write_register(unsigned data, can_ioptr_t address) { - unsigned long addr=can_ioptr2ulong(address); - can_ioptr_t base = can_ulong2ioptr(addr & ~0x1f); - unsigned char nwin = 0x10; - unsigned char savewin; - - can_spin_irqflags_t flags; - - if((addr&0x1f) > 0x1d) { - nwin++; - address -= 0x10; - } - - can_spin_lock_irqsave(&ts7kv_win_lock,flags); - savewin = can_inb(base+TS7KV_WIN_REG); - if(nwin == savewin) { - can_outb(data, address); - }else{ - can_outb(nwin, base+TS7KV_WIN_REG); - can_outb(data, address); - can_outb(savewin, base+TS7KV_WIN_REG); - } - can_spin_unlock_irqrestore(&ts7kv_win_lock,flags); + can_writeb(data, address); } + /** * tscan1_read_register - Low level read register routine * @address: memory address to read from @@ -626,33 +473,9 @@ unsigned tscan1_read_register(can_ioptr_t address) return can_inb(address); } -unsigned ts7kv_read_register(can_ioptr_t address) +unsigned tscan1mmio_read_register(can_ioptr_t address) { - unsigned long addr=can_ioptr2ulong(address); - can_ioptr_t base = can_ulong2ioptr(addr & ~0x1f); - unsigned char nwin = 0x10; - unsigned char savewin; - unsigned val; - - can_spin_irqflags_t flags; - - if((addr&0x1f) > 0x1d) { - nwin++; - address -= 0x10; - } - - can_spin_lock_irqsave(&ts7kv_win_lock,flags); - savewin = can_inb(base+TS7KV_WIN_REG); - if(nwin == savewin) { - val = can_inb(address); - }else{ - can_outb(nwin, base+TS7KV_WIN_REG); - val = can_inb(address); - can_outb(savewin, base+TS7KV_WIN_REG); - } - can_spin_unlock_irqrestore(&ts7kv_win_lock,flags); - - return val; + return can_readb(address); } int tscan1_register(struct hwspecops_t *hwspecops) @@ -669,16 +492,16 @@ int tscan1_register(struct hwspecops_t *hwspecops) return 0; } -extern int ts7kv_register(struct hwspecops_t *hwspecops) +int tscan1mmio_register(struct hwspecops_t *hwspecops) { - hwspecops->request_io = ts7kv_request_io; - hwspecops->release_io = ts7kv_release_io; + hwspecops->request_io = tscan1_request_io; + hwspecops->release_io = tscan1_release_io; hwspecops->reset = tscan1_reset; - hwspecops->init_hw_data = ts7kv_init_hw_data; - hwspecops->init_chip_data = ts7kv_init_chip_data; + hwspecops->init_hw_data = tscan1_init_hw_data; + hwspecops->init_chip_data = tscan1_init_chip_data; hwspecops->init_obj_data = tscan1_init_obj_data; - hwspecops->write_register = ts7kv_write_register; - hwspecops->read_register = ts7kv_read_register; + hwspecops->write_register = tscan1mmio_write_register; + hwspecops->read_register = tscan1mmio_read_register; hwspecops->program_irq = tscan1_program_irq; return 0; }