From 6d1158545bf86bf3478a1e247d6c3d80b8e4ed13 Mon Sep 17 00:00:00 2001 From: ppisa Date: Wed, 16 Jul 2008 23:43:36 +0000 Subject: [PATCH 1/1] Fixes and updates for SECO M437 provided by Philippe Corbes The SECO M437 has not been used from pre LinCAn driver days so there has been accumulated more bugs in its support. Thanks to Philippe Corbes, email:philippe.corbes _AT_ logibag.com for providing fixes and testing. --- lincan/src/m437.c | 110 +++++++++++++++++++++++++++++++++++----------- lincan/src/main.c | 2 + lincan/src/open.c | 2 +- 3 files changed, 88 insertions(+), 26 deletions(-) diff --git a/lincan/src/m437.c b/lincan/src/m437.c index d90db12..00ac7c3 100644 --- a/lincan/src/m437.c +++ b/lincan/src/m437.c @@ -5,13 +5,19 @@ * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. * Version lincan-0.3 17 Jun 2004 - */ + * + * 15 July 2008 updated by Philippe Corbes, email:philippe.corbes@logibag.com + * This driver has been designed to support "Memory (MEM)" mode. + * For example: Memory, MEM:0xD0000 => io=0xD0000. + * Configure the card with m437set.com provided by seco before loading driver. + * This software is released under the GPL-License. + */ -/* - * Support for the SECO M437 - * +/* + * Support for the SECO M437 + * * SECO M437 is a pc104 format, i82527 controller based card - * produced by SECO http://www.seco.it + * produced by SECO http://www.seco.it * This driver uses the Memory Mapped I/O mode, and should be * working with all cards supporting this mode. * @@ -43,7 +49,7 @@ * * The function m437_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. + * 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. @@ -52,19 +58,34 @@ */ int m437_request_io(struct candevice_t *candev) { + can_ioptr_t remap_addr; if (!can_request_mem_region(candev->io_addr,IO_RANGE,DEVICE_NAME)) { - CANMSG("Unable to request IO-memory: 0x%lx\n",candev->io_addr); + CANMSG("M437 Unable to request IO-memory: 0x%lx\n",candev->io_addr); return -ENODEV; } - if ( !( candev->dev_base_addr = ioremap( candev->io_addr, IO_RANGE ) ) ) { - CANMSG("Unable to access I/O memory at: 0x%lx\n", candev->io_addr); + if ( !( remap_addr = ioremap( candev->io_addr, IO_RANGE ) ) ) { + CANMSG("M437 Unable to access I/O memory at: 0x%lx\n", candev->io_addr); can_release_mem_region(candev->io_addr,IO_RANGE); return -ENODEV; - + } - DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", candev->io_addr, candev->io_addr + IO_RANGE - 1); + CANMSG("M437 Registered IO-memory: 0x%lx - 0x%lx\n", candev->io_addr, candev->io_addr + IO_RANGE - 1); + CANMSG("M437 IO-memory: 0x%lx Remapped to: 0x%lx\n", candev->io_addr, remap_addr); + + /* remap the chip and pointers on objects */ + can_base_addr_fixup(candev, remap_addr); + +#ifdef CAN_DEBUG + { + int objnr; + for (objnr=0; objnr<15 ; objnr++) { + DEBUGMSG("M437 Message%d remapped to: 0x%lx\n", objnr+1, candev->chip[0]->msgobj[objnr]->obj_base_addr); + } + } +#endif /*CAN_DEBUG*/ + return 0; } @@ -82,6 +103,12 @@ int m437_request_io(struct candevice_t *candev) */ int m437_release_io(struct candevice_t *candev) { + /* + * The full board reset is more robust solution + * than reset of communication objects + * Philippe Corbes, 06 jun 2008 + */ +#if 0 /* Object reset method */ unsigned i; /* disable IRQ generation */ @@ -103,15 +130,21 @@ int m437_release_io(struct candevice_t *candev) RMPD_RES, candev->dev_base_addr+i*0x10+iMSGCTL1); } - + /* power down i82527 */ m437_write_register(iCPU_PWD, candev->dev_base_addr+iCPU); - + +#else /* Full board reset */ + m437_reset(candev); +#endif /* Full board reset */ + /* release I/O memory mapping */ iounmap(candev->dev_base_addr); can_release_mem_region(candev->io_addr,IO_RANGE); + CANMSG("M437 release - OK\n"); + return 0; } @@ -119,14 +152,36 @@ int m437_release_io(struct candevice_t *candev) * m437_reset - hardware reset routine * @candev: Pointer to candevice/board structure * - * The function m437_reset() is used to give a hardware reset. This is - * rather hardware specific so I haven't included example code. Don't forget to + * The function m437_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/m437.c + * from Philippe Corbes, 08 July 2008 */ int m437_reset(struct candevice_t *candev) { + int i=0; + + DEBUGMSG("Resetting %s hardware ...\n", candev->hwname); + for (i = 0 ; i < 10 ; i++) { + m437_write_register(0x01,candev->dev_base_addr+candev->res_addr); + } + m437_write_register(0x0,candev->dev_base_addr+candev->res_addr); + + /* Check hardware reset status */ + i=0; + while ( (m437_read_register(candev->dev_base_addr+iCPU) & iCPU_RST) && (i<=15)) { + udelay(20000); + i++; + } + if (i>=15) { + CANMSG("M437 Reset status timeout! Please check your hardware.\n"); + return -ENODEV; + } + else + DEBUGMSG("Chip0 reset status ok.\n"); + return 0; } @@ -148,13 +203,13 @@ int m437_reset(struct candevice_t *candev) * Return Value: The function always returns zero * File: src/m437.c */ -int m437_init_hw_data(struct candevice_t *candev) +int m437_init_hw_data(struct candevice_t *candev) { DEBUGMSG("m437_init_hw_data()\n"); candev->res_addr=RESET_ADDR; candev->nr_82527_chips=1; candev->nr_sja1000_chips=0; - candev->nr_all_chips=1; + candev->nr_all_chips=1; candev->flags &= ~CANDEV_PROGRAMMABLE_IRQ; /* The M437 has no programmable IRQ */ @@ -184,7 +239,7 @@ int m437_init_hw_data(struct candevice_t *candev) * 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 + * 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. * The entry @int_cpu_reg holds hardware specific options for the cpu interface @@ -199,7 +254,7 @@ int m437_init_chip_data(struct candevice_t *candev, int chipnr) candev->chip[chipnr]->chip_base_addr=candev->dev_base_addr; candev->chip[chipnr]->clock = 16000000; candev->chip[chipnr]->int_cpu_reg = iCPU_DSC | iCPU_CEN; - candev->chip[chipnr]->int_clk_reg = + candev->chip[chipnr]->int_clk_reg = iCLK_CD0 | iCLK_CD1 | iCLK_CD2 | iCLK_SL0 | iCLK_SL1; candev->chip[chipnr]->int_bus_reg = iBUS_CBY; @@ -216,7 +271,7 @@ int m437_init_chip_data(struct candevice_t *candev, int chipnr) * 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 + * 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. @@ -226,7 +281,7 @@ int m437_init_chip_data(struct candevice_t *candev, int chipnr) int m437_init_obj_data(struct canchip_t *chip, int objnr) { chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr+(objnr+1)*0x10; - + return 0; } @@ -234,16 +289,17 @@ int m437_init_obj_data(struct canchip_t *chip, int objnr) * m437_program_irq - program interrupts * @candev: Pointer to candevice/board structure * - * The function m437_program_irq() is used for hardware that uses + * The function m437_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 + * 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/m437.c */ int m437_program_irq(struct candevice_t *candev) { + DEBUGMSG("M437 Programmable interrupt is not supported by the hardware!\n"); return 0; } @@ -260,6 +316,7 @@ int m437_program_irq(struct candevice_t *candev) */ void m437_write_register(unsigned data, can_ioptr_t address) { + DEBUGMSG("m437_write_register(@0x%lx=0x%x)\n", address, data); can_writeb(data,address); } @@ -275,7 +332,10 @@ void m437_write_register(unsigned data, can_ioptr_t address) */ unsigned m437_read_register(can_ioptr_t address) { - return can_readb(address); + unsigned data; + data = can_readb(address); + DEBUGMSG("m437_read_register(@0x%lx=0x%x)\n", address, data); + return data; } /* !!! Don't change this function !!! */ diff --git a/lincan/src/main.c b/lincan/src/main.c index e114082..e021761 100644 --- a/lincan/src/main.c +++ b/lincan/src/main.c @@ -396,7 +396,9 @@ int init_module(void) void cleanup_module(void) { +#if defined(CONFIG_DEVFS_FS) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) int i=0; +#endif #ifdef CONFIG_PROC_FS if (can_delete_procdir()) diff --git a/lincan/src/open.c b/lincan/src/open.c index 76fb9ee..e471470 100644 --- a/lincan/src/open.c +++ b/lincan/src/open.c @@ -90,7 +90,7 @@ int can_open(struct inode *inode, struct file *file) #endif return 0; - + no_rx_qedge: canque_notify_bothends(edge, CANQUEUE_NOTIFY_DEAD_WANTED); canque_edge_decref(edge); -- 2.39.2