From cb551cc1582f3b51cf17e80730bee3c2f0701c3f Mon Sep 17 00:00:00 2001 From: ppisa Date: Sun, 6 Jun 2004 03:23:21 +0000 Subject: [PATCH] The first phase of integration of Hynix HMS30c7202 C_CAN support --- lincan/include/c_can.h | 247 +++++++++ lincan/include/constants.h | 4 + lincan/include/hms30c7202_can.h | 28 + lincan/include/main.h | 4 + lincan/src/c_can.c | 944 ++++++++++++++++++++++++++++++++ lincan/src/c_can_irq.c | 510 +++++++++++++++++ lincan/src/hms30c7202_can.c | 436 +++++++++++++++ lincan/src/i82527.c | 47 +- lincan/src/pcm3680.c | 2 +- lincan/src/unican.c | 2 +- 10 files changed, 2198 insertions(+), 26 deletions(-) create mode 100644 lincan/include/c_can.h create mode 100644 lincan/include/hms30c7202_can.h create mode 100644 lincan/src/c_can.c create mode 100644 lincan/src/c_can_irq.c create mode 100644 lincan/src/hms30c7202_can.c diff --git a/lincan/include/c_can.h b/lincan/include/c_can.h new file mode 100644 index 0000000..4955d86 --- /dev/null +++ b/lincan/include/c_can.h @@ -0,0 +1,247 @@ +/* c_can.h - Hynix HMS30c7202 ARM generic C_CAN module handling + * Linux CAN-bus device driver. + * Written by Sebastian Stolzenberg email:stolzi@sebastian-stolzenberg.de + * Based on code from Arnaud Westenberg email:arnaud@wanadoo.nl + * and Ake Hedman, eurosource, akhe@eurosource.se + * 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.2 9 Jul 2003 + */ + +void hms30c7202_write_reg_w(const struct chip_t *pchip, u16 data, unsigned reg); + +u16 hms30c7202_read_reg_w(const struct chip_t *pchip, unsigned reg); + +#ifndef CONFIG_OC_LINCAN_DYNAMICIO +/* + * optimized inline version, may it be, that it can be too fast for the chip + */ +extern inline void c_can_write_reg_w(const struct chip_t *pchip, u16 data, unsigned reg) +{ + u32 address = pchip->chip_base_addr + reg; + writew(data,address); +} + +extern inline u16 c_can_read_reg_w(const struct chip_t *pchip, unsigned reg) +{ + u32 address = pchip->chip_base_addr + reg; + return readw(address); +} +#else /*CONFIG_OC_LINCAN_DYNAMICIO*/ +/* + * the standard routines for register access cannot be used, + * because they work only with 8-bit peripherals + */ + +extern inline void c_can_write_reg_w(const struct chip_t *pchip, u16 data, unsigned reg) +{ + hms30c7202_write_reg_w(pchip, data, reg); +} + +extern inline u16 c_can_read_reg_w(const struct chip_t *pchip, unsigned reg) +{ + return hms30c7202_read_reg_w(pchip, reg); +} +#endif /*CONFIG_OC_LINCAN_DYNAMICIO*/ + +extern can_spinlock_t c_can_spwlock; // Spin lock for write operations +extern can_spinlock_t c_can_sprlock; // Spin lock for read operations +extern can_spinlock_t c_can_if1lock; // spin lock for the if1 register +extern can_spinlock_t c_can_if2lock; // spin lcok for the if2 register + +int c_can_if1_busycheck(struct chip_t *pchip); +int c_can_if2_busycheck(struct chip_t *pchip); + +int c_can_enable_configuration(struct chip_t *pchip); +int c_can_disable_configuration(struct chip_t *pchip); +int c_can_chip_config(struct chip_t *pchip); +int c_can_baud_rate(struct chip_t *chip, int rate, int clock, + int sjw, int sampl_pt, int flags); +int c_can_mask(struct msgobj_t *pmsgobj, + u32 mask, + u16 usedirbit); +int c_can_use_mask(struct msgobj_t *pmsgobj, + u16 useflag); +int c_can_clear_objects(struct chip_t *pchip); +int c_can_config_irqs(struct chip_t *pchip, + u16 irqs); +int c_can_pre_read_config(struct chip_t *chip, struct msgobj_t *obj); +int c_can_send_msg(struct chip_t *pchip, struct msgobj_t *pmsgobj, + struct canmsg_t *pmsg); +int c_can_remote_request(struct chip_t *pchip, struct msgobj_t *pmsgobj ); +int c_can_set_btregs(struct chip_t *chip, + u16 btr0, + u16 btr1); +int c_can_start_chip(struct chip_t *pchip); +int c_can_stop_chip(struct chip_t *pchip); +int c_can_check_tx_stat(struct chip_t *pchip); + +int c_can_register(struct chipspecops_t *chipspecops); + +void c_can_registerdump(struct chip_t *pchip); + +void c_can_irq_sync_activities(struct chip_t *chip, struct msgobj_t *obj); + +can_irqreturn_t c_can_irq_handler(int irq, void *dev_id, struct pt_regs *regs); + +/* BasicCAN mode address map */ +#define CCCR 0x0000 /* Control Register */ +#define CCSR 0x0004 /* Status Register */ +#define CCEC 0x0008 /* Error Counting Register */ +#define CCBT 0x000C /* Bit Timing Register */ +#define CCINTR 0x0010 /* Interrupt Register */ +#define CCTR 0x0014 /* Test Register */ +#define CCBRPE 0x0018 /* Baud Rate Prescaler Extension Register */ +#define CCCE 0x001C /* CAN Enable Register */ +#define CCTREQ1 0x0100 /* Transmission Request 1 Register */ +#define CCTREQ2 0x0104 /* Transmission Request 2 Register */ +#define CCND1 0x0120 /* New Data 1 Register */ +#define CCND2 0x0124 /* New Data 2 Register */ +#define CCINTP1 0x0140 /* Interrupt Pending 1 Register */ +#define CCINTP2 0x0144 /* Interrupt Pending 2 Register */ + +#define CCIF1CR 0x0020 /* Interface 1 Command Request Register */ +#define CCIF1CM 0x0024 /* IF1 Command Mask Register */ +#define CCIF1M1 0x0028 /* IF1 Mask 1 Register */ +#define CCIF1M2 0x002C /* IF1 Mask 2 Register */ +#define CCIF1A1 0x0030 /* IF1 Arbitration 1 Register */ +#define CCIF1A2 0x0034 /* IF1 Arbitration 2 Register */ +#define CCIF1DMC 0x0038 /* IF1 Message Control Register */ +#define CCIF1DA1 0x003C /* IF1 Data A 1 Register */ +#define CCIF1DA2 0x0040 /* IF1 Data A 2 Register */ +#define CCIF1DB1 0x0044 /* IF1 Data B 1 Register */ +#define CCIF1DB2 0x0048 /* IF1 Data B 2 Register */ + +#define CCIF2CR 0x0080 /* Interface 2 Command Request Register */ +#define CCIF2CM 0x0084 /* IF2 Command Mask Register */ +#define CCIF2M1 0x0088 /* IF2 Mask 1 Register */ +#define CCIF2M2 0x008C /* IF2 Mask 2 Register */ +#define CCIF2A1 0x0090 /* IF2 Arbitration 1 Register */ +#define CCIF2A2 0x0094 /* IF2 Arbitration 2 Register */ +#define CCIF2DMC 0x0098 /* IF2 Message Control Register */ +#define CCIF2DA1 0x009C /* IF2 Data A 1 Register */ +#define CCIF2DA2 0x00A0 /* IF2 Data A 2 Register */ +#define CCIF2DB1 0x00A4 /* IF2 Data B 1 Register */ +#define CCIF2DB2 0x00A8 /* IF2 Data B 2 Register */ + +/* Control register */ +enum c_can_BASIC_CR +{ + CR_INIT = 1, // Internal Initialization Pending + CR_MIE = 1<<1, // Module Interrupt Enable + CR_SIE = 1<<2, // Status-change Interrupt Enable + CR_EIE = 1<<3, // Error Interrupt Enable + CR_DAR = 1<<5, // Disable Automatic Retransmission + CR_CCE = 1<<6, // Configuration Change Enable + CR_TEST = 1<<7 // Test Mode Enable +}; + +/* Status Register */ +enum c_can_BASIC_SR +{ + SR_TXOK = 1<<3, // Transmitted a Message Successfully + SR_RXOK = 1<<4, // Received a Message Successfully + SR_EPASS = 1<<5, // Error Passive + SR_EWARN = 1<<6, // Error Warning Status + SR_BOFF = 1<<7, // Bus Off Status +}; + +/* Status Register Last Error Codes */ +enum c_can_BASIC_SRLEC +{ + SRLEC_NE = 0, // Last Error Code: No Error + SRLEC_SE = 1, // LEC: Stuff Error + SRLEC_FE = 2, // LEC: Form Error + SRLEC_AE = 3, // LEC: Acknowledgement Error + SRLEC_B1 = 4, // LEC: Bit1 Error + SRLEC_B0 = 5, // LEC: Bit0 Error + SRLEC_CR = 6 // LEC: CRC Error +}; + +/* Error Counting Register */ +enum c_can_BASIC_EC +{ + EC_REP = 1<<15 // Receive Error Passive +}; + +/* Interrupt Register */ +enum c_can_BASIC_INT +{ + INT_NOINT = 0, // No Interrupt is pending + INT_STAT = 0x8000 // Status Interrupt +}; + +/* CAN Test Register */ +enum c_can_BASIC_TR +{ + TR_BASIC = 1<<2, // Basic Mode + TR_SLNT = 1<<3, // Silent Mode + TR_LOOPB = 1<<4, // Loop Back Mode + TR_RX = 1<<7 // Receive (CAN_RX Pin) +}; + +/* CAN Test Register TX Control*/ +enum c_can_BASIC_TRTX +{ + TRTX_RST = 0, // Reset value, CAN_TX is controlled by the CAN Core + TRTX_MON = 1, // Sample Point can be monitored at CAN_TX pin + TRTX_DOM = 2, // CAN_TX pin drives a dominant('0') value + TRTX_REC = 3 // CAN_TX pin drives a recessive('1') value +}; + +/* CAN Enable Register */ +enum c_can_BASIC_CE +{ + CE_EN = 1 // CAN Enable Bit +}; + +/* Interface X Command Request Register */ +enum c_can_BASIC_IFXCR +{ + IFXCR_BUSY = 1<<15 // Busy Flag (Write Access only when Busy='0') +}; + +/* Interface X Command Mask Register */ +enum c_can_BASIC_IFXCM +{ + IFXCM_DB = 1, // R/W Data Byte 4-7 + IFXCM_DA = 1<<1, // R/W Data Byte 0-3 + IFXCM_TRND = 1<<2, // Transmit Request (WRRD=1) or Reset New Date Bit (WRRD=0) + IFXCM_CLRINTPND = 1<<3, // Clear Interrupt Pending Bit when reading the Message Object + IFXCM_CNTRL = 1<<4, // Access Interface X Message Control Bits + IFXCM_ARB = 1<<5, // Access Interface X Arbitration + IFXCM_MASK = 1<<6, // Access Interface X Mask Bits + IFXCM_WRRD = 1<<7 // Read/Write (write data from Interface Registers to Message Object if ='1') + // (read data from Message Object to Interface Registers if ='0') +}; + +/* Interface X Mask 2 Register */ +enum c_can_BASIC_IFXMSK2 +{ + IFXMSK2_MDIR = 1<<14, // Mask Message Direction (message direction bit(RTR) used for acceptance filt. or not) + IFXMSK2_MXTD = 1<<15 // Mask Extended Identifier (extended id bit(IDE) used for acceptance filt. or not) +}; + +/* Interface X Arbitration 2 Register */ +enum c_can_BASIC_IFXARB2 +{ + IFXARB2_DIR = 1<<13, // Message Direction (transmit='1') + IFXARB2_XTD = 1<<14, // Use Extended Identifier + IFXARB2_MVAL = 1<<15 // Message Validation +}; + +/* Interface X Message Control Register */ +enum c_can_BASIC_IFXMC +{ + IFXMC_EOB = 1<<7, // End of Buffer (marks last Message Object of FIFO Buffer) + IFXMC_TXRQST = 1<<8, // Transmit Request + IFXMC_RMTEN = 1<<9, // Remote Enable + IFXMC_RXIE = 1<<10, // Receive Interrupt Enable + IFXMC_TXIE = 1<<11, // Transmit Interrupt Enable + IFXMC_UMASK = 1<<12, // Use Identifier Mask + IFXMC_INTPND = 1<<13, // Interrupt Pending + IFXMC_MSGLST = 1<<14, // Message Lost (Only valid for direction = receive) + IFXMC_NEWDAT = 1<<15 // New Data +}; + diff --git a/lincan/include/constants.h b/lincan/include/constants.h index 0dcac8c..7e02330 100644 --- a/lincan/include/constants.h +++ b/lincan/include/constants.h @@ -48,6 +48,8 @@ #define MSGOBJ_IRQ_REQUEST_b 3 #define MSGOBJ_WORKER_WAKE_b 4 #define MSGOBJ_FILTCH_REQUEST_b 5 +#define MSGOBJ_RX_MODE_b 6 +#define MSGOBJ_RX_MODE_EXT_b 7 #define MSGOBJ_OPENED (1<obj_flags) diff --git a/lincan/include/hms30c7202_can.h b/lincan/include/hms30c7202_can.h new file mode 100644 index 0000000..25ce632 --- /dev/null +++ b/lincan/include/hms30c7202_can.h @@ -0,0 +1,28 @@ +/* hms30c7202_can.h - Hynix HMS30c7202 ARM device specific code + * Linux CAN-bus device driver. + * Written by Sebastian Stolzenberg email:stolzi@sebastian-stolzenberg.de + * Based on code from Arnaud Westenberg email:arnaud@wanadoo.nl + * and Ake Hedman, eurosource, akhe@eurosource.se + * 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.2 9 Jul 2003 + */ + +#ifndef __HMS30C7202_CAN__ +# define __HMS30C7202_CAN__ + +int hms30c7202_init_hw_data(struct candevice_t *candev); +int hms30c7202_init_chip_data(struct candevice_t *candev, int chipnr); +int hms30c7202_request_io(struct candevice_t *candev); +int hms30c7202_release_io(struct candevice_t *candev); +int hms30c7202_reset( struct candevice_t *candev); +void hms30c7202_write_reg_w(const struct chip_t *pchip, u16 data, unsigned reg); +u16 hms30c7202_read_reg_w(const struct chip_t *pchip, unsigned reg); + + + +int hms30c7202_init_obj_data(struct chip_t *chip, int objnr); +int hms30c7202_program_irq(struct candevice_t *candev); + +#endif /* __HMS30C7202_CAN__ */ diff --git a/lincan/include/main.h b/lincan/include/main.h index 65d6b2a..cc426b4 100644 --- a/lincan/include/main.h +++ b/lincan/include/main.h @@ -209,6 +209,8 @@ struct chip_t { * %MSGOBJ_TX_REQUEST .. the message object requests TX activation * %MSGOBJ_TX_LOCK .. some IRQ routine or callback on some CPU * is running inside TX activation processing code + * @rx_preconfig_id: place to store RX message identifier for some chip types + * that reuse same object for TX */ struct msgobj_t { unsigned long obj_base_addr; @@ -227,6 +229,8 @@ struct msgobj_t { struct canmsg_t rx_msg; struct chip_t *hostchip; + + unsigned long rx_preconfig_id; atomic_t obj_used; struct list_head obj_users; diff --git a/lincan/src/c_can.c b/lincan/src/c_can.c new file mode 100644 index 0000000..6bef001 --- /dev/null +++ b/lincan/src/c_can.c @@ -0,0 +1,944 @@ +/* c_can.c - Hynix HMS30c7202 ARM generic C_CAN module handling + * Linux CAN-bus device driver. + * Written by Sebastian Stolzenberg email:stolzi@sebastian-stolzenberg.de + * Based on code from Arnaud Westenberg email:arnaud@wanadoo.nl + * and Ake Hedman, eurosource, akhe@eurosource.se + * 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.2 9 Jul 2003 + */ + +#define __NO_VERSION__ + +#include "../include/can.h" +#include "../include/can_sysdep.h" +#include "../include/main.h" +#include "../include/c_can.h" + +extern int stdmask; +extern int extmask; + +can_spinlock_t c_can_spwlock=SPIN_LOCK_UNLOCKED; // Spin lock for write operations +can_spinlock_t c_can_sprlock=SPIN_LOCK_UNLOCKED; // Spin lock for read operations +can_spinlock_t c_can_if1lock=SPIN_LOCK_UNLOCKED; // spin lock for the if1 register +can_spinlock_t c_can_if2lock=SPIN_LOCK_UNLOCKED; // spin lcok for the if2 register + +/** + * c_can_enable_configuration - enable chip configuration mode + * @pchip: pointer to chip state structure + */ +int c_can_enable_configuration(struct chip_t *pchip) +{ + int i=0; + u16 flags; + DEBUGMSG("(c%d)calling c_can_enable_configuration(...)\n", pchip->chip_nr); +/* + DEBUGMSG("Trying disable_irq(...) : "); + //disable IRQ + disable_irq(chip->chip_irq); +*/ + //read Control Register + flags=c_can_read_reg_w(pchip, CCCR); + //set Init-Bit in the Control Register (10 tries) + while ((!(flags & CR_INIT)) && (i<=10)) + { + c_can_write_reg_w(pchip,flags|CR_INIT, CCCR); + udelay(1000); + i++; + flags=c_can_read_reg_w(pchip, CCCR); + } + if (i>=10) + { + CANMSG("Reset error\n"); + //enable_irq(chip->chip_irq); + return -ENODEV; + } + + DEBUGMSG("-> ok\n"); + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int c_can_disable_configuration(struct chip_t *pchip) +{ + int i=0; + u16 flags; + + DEBUGMSG("(c%d)calling c_can_disable_configuration(...)\n", pchip->chip_nr); + //read Control Register + flags=c_can_read_reg_w(pchip, CCCR); + + //reset Init-Bit in the Control Register (10 tries) + while ( (flags & CR_INIT) && (i<=10) ) + { + c_can_write_reg_w( pchip,flags & ~CR_INIT, CCCR); + udelay(1000); //100 microseconds + i++; + flags=c_can_read_reg_w(pchip, CCCR); + } + if (i>=10) + { + CANMSG("Error leaving reset status\n"); + return -ENODEV; + } + + //enable IRQ + //enable_irq(chip->chip_irq); + DEBUGMSG("-> ok\n"); + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int c_can_chip_config(struct chip_t *pchip) +{ + + DEBUGMSG("(c%d)calling c_can_chip_config(...)\n", pchip->chip_nr); + // Validate pointer + if ( NULL == pchip ) return -1; + + if (pchip->baudrate == 0) + pchip->baudrate=1000; + + if (c_can_baud_rate(pchip,pchip->baudrate*1000,pchip->clock,0,75,0)) + { + CANMSG("Error configuring baud rate\n"); + return -ENODEV; + } + /*if (extended){ + if (c_can_extended_mask(pchip,0x0000000,extmask)) { + CANMSG("Error configuring extended mask\n"); + return -ENODEV; + } + }else{ + if (c_can_standard_mask(pchip,0x0000,stdmask)) { + CANMSG("Error configuring standard mask\n"); + return -ENODEV; + } + }*/ + if (c_can_clear_objects(pchip)) + { + CANMSG("Error clearing message objects\n"); + return -ENODEV; + } + if (c_can_config_irqs(pchip, CR_MIE | CR_SIE | CR_EIE)) + { + CANMSG("Error configuring interrupts\n"); + return -ENODEV; + } + + DEBUGMSG("-> Configured successfully\n"); + +#ifdef REGDUMP + c_can_registerdump(pchip); +#endif + + return 0; +} + +/////////////////////////////////////////////////////////////////////// +/* + * Checks if the Busy-Bit in the IF1-Command-Request Register is set + */ +int c_can_if1_busycheck(struct chip_t *pchip) +{ + + int i=0; + unsigned short comreg = 0; + + comreg = c_can_read_reg_w( pchip, CCIF1CR); + while ( (comreg & IFXCR_BUSY) && (i<=10) ) + { + udelay(100); //100 microseconds + i++; + comreg=c_can_read_reg_w( pchip, CCIF1CR); + } + if (i>=10) + { + CANMSG("Error Busy-Bit stays set\n"); + return -ENODEV; + } + + return 0; +} + +/////////////////////////////////////////////////////////////////////// +/* + * Checks if the Busy-Bit in the IF2-Command-Request Register is set + */ +int c_can_if2_busycheck(struct chip_t *pchip) +{ + + int i=0; + unsigned short comreg = 0; + + comreg = c_can_read_reg_w( pchip, CCIF2CR); + while ( (comreg & IFXCR_BUSY) && (i<=10) ) + { + udelay(100); //100 microseconds + i++; + comreg=c_can_read_reg_w( pchip, CCIF2CR); + } + if (i>=10) + { + CANMSG("Error Busy-Bit stays set\n"); + return -ENODEV; + } + + return 0; +} + +/////////////////////////////////////////////////////////////////////// +/* + * Though the C-CAN Chip can handle one mask for each Message Object, this Method defines + * one mask for all MOs. That means every MO gets the same mask. + */ + +/* Set communication parameters. + * param rate baud rate in Hz + * param clock frequency of C-CAN clock in Hz + * param sjw synchronization jump width (0-3) prescaled clock cycles + * param sampl_pt sample point in % (0-100) sets (TSEG1+2)/(TSEG1+TSEG2+3) ratio + * param flags fields BTR1_SAM, OCMODE, OCPOL, OCTP, OCTN, CLK_OFF, CBP + */ +int c_can_baud_rate(struct chip_t *pchip, int rate, int clock, + int sjw, int sampl_pt, int flags) +{ + int best_error = 1000000000, error; + int best_tseg=0, best_brp=0, best_rate=0, brp=0; + int tseg=0, tseg1=0, tseg2=0; + + unsigned short tempCR = 0; + + DEBUGMSG("(c%d)calling c_can_baud_rate(...)\n", pchip->chip_nr); + + if (c_can_enable_configuration(pchip)) + return -ENODEV; + + clock /=2; + + /* tseg even = round down, odd = round up */ + for (tseg=(0+0+2)*2; tseg<=(MAX_TSEG2+MAX_TSEG1+2)*2+1; tseg++) + { + brp = clock/((1+tseg/2)*rate)+tseg%2; + if (brp == 0 || brp > 64) + continue; + error = rate - clock/(brp*(1+tseg/2)); + if (error < 0) + error = -error; + if (error <= best_error) + { + best_error = error; + best_tseg = tseg/2; + best_brp = brp-1; + best_rate = clock/(brp*(1+tseg/2)); + } + } + if (best_error && (rate/best_error < 10)) + { + CANMSG("baud rate %d is not possible with %d Hz clock\n", + rate, 2*clock); + CANMSG("%d bps. brp=%d, best_tseg=%d, tseg1=%d, tseg2=%d\n", + best_rate, best_brp, best_tseg, tseg1, tseg2); + return -EINVAL; + } + tseg2 = best_tseg-(sampl_pt*(best_tseg+1))/100; + if (tseg2 < 0) + tseg2 = 0; + if (tseg2 > MAX_TSEG2) + tseg2 = MAX_TSEG2; + tseg1 = best_tseg-tseg2-2; + if (tseg1 > MAX_TSEG1) + { + tseg1 = MAX_TSEG1; + tseg2 = best_tseg-tseg1-2; + } + + DEBUGMSG("-> Setting %d bps.\n", best_rate); + DEBUGMSG("->brp=%d, best_tseg=%d, tseg1=%d, tseg2=%d, sampl_pt=%d\n", + best_brp, best_tseg, tseg1, tseg2, + (100*(best_tseg-tseg2)/(best_tseg+1))); + + //read Control Register + tempCR = c_can_read_reg_w( pchip, CCCR); + //Configuration Change Enable + c_can_write_reg_w(pchip, tempCR | CR_CCE, CCCR); + c_can_write_reg_w(pchip, ((unsigned short)tseg2)<<12 | ((unsigned short)tseg1)<<8 + | (unsigned short)sjw<<6 | (unsigned short) best_brp, + CCBT); + + if (c_can_disable_configuration(pchip)) + return -ENODEV; + + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int c_can_mask(struct msgobj_t *pmsgobj, + u32 mask, + u16 usedirbit) +{ + unsigned short tempreg = 0; + unsigned short readMaskCM; + unsigned short writeMaskCM; + + DEBUGMSG("(c%dm%d)calling c_can_mask(...)\n", pmsgobj->hostchip->chip_nr, pmsgobj->object); + + readMaskCM = IFXCM_CNTRL | IFXCM_ARB | IFXCM_MASK; + writeMaskCM = IFXCM_CNTRL | IFXCM_ARB | IFXCM_MASK | IFXCM_WRRD; + + spin_lock( &c_can_if1lock ); + + //load Message Object in IF1 + if (c_can_if1_busycheck(pmsgobj->hostchip)) return -ENODEV; + c_can_write_reg_w(pmsgobj->hostchip, readMaskCM, CCIF1CM); + c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF1CR); + + //setting Message Valid Bit to zero + if (c_can_if1_busycheck(pmsgobj->hostchip)) return -ENODEV; + tempreg = c_can_read_reg_w(pmsgobj->hostchip, CCIF1A2); + c_can_write_reg_w(pmsgobj->hostchip, tempreg & ~(IFXARB2_MVAL), CCIF1A2); + c_can_write_reg_w(pmsgobj->hostchip, writeMaskCM, CCIF1CM); + c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF1CR); + + //setting UMask, MsgVal and Mask Register + if (c_can_if1_busycheck(pmsgobj->hostchip)) return -ENODEV; + + //writing acceptance mask for extended or standart mode + if (can_msgobj_test_fl(pmsgobj,RX_MODE_EXT)) + { + if (usedirbit) + c_can_write_reg_w(pmsgobj->hostchip, + (mask>>16 & 0x1FFF) | IFXMSK2_MXTD | IFXMSK2_MDIR, CCIF1M2); + else + c_can_write_reg_w(pmsgobj->hostchip, + (mask>>16 & 0x1FFF) | IFXMSK2_MXTD, CCIF1M2); + c_can_write_reg_w(pmsgobj->hostchip, (mask & 0xFFFF), CCIF1M1); + } + else + { + if (usedirbit) + c_can_write_reg_w(pmsgobj->hostchip, + ((mask<<2) & 0x1FFC) | IFXMSK2_MDIR, CCIF1M2); + else + c_can_write_reg_w(pmsgobj->hostchip, + ((mask<<2) & 0x1FFC), CCIF1M2); + c_can_write_reg_w(pmsgobj->hostchip, 0, CCIF1M1); + } + //seting Message Valid Bit to one + tempreg = c_can_read_reg_w(pmsgobj->hostchip, CCIF1A2); + c_can_write_reg_w(pmsgobj->hostchip, tempreg | IFXARB2_MVAL, CCIF1A2); + //write to chip + c_can_write_reg_w(pmsgobj->hostchip, writeMaskCM, CCIF1CM); + c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF1CR); + + spin_unlock( &c_can_if1lock ); + + DEBUGMSG("-> Setting acceptance mask to 0x%lx\n",(unsigned long)mask); + +#ifdef REGDUMP + c_can_registerdump(pmsgobj->hostchip); +#endif + + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int c_can_use_mask(struct msgobj_t *pmsgobj, + u16 useflag) +{ + unsigned short tempreg = 0; + unsigned short readMaskCM; + unsigned short writeMaskCM; + +#ifdef DEBUG + char *boolstring = "false"; + if (useflag) boolstring = "true"; +#endif + DEBUGMSG("(c%dm%d)calling c_can_use_mask(...)\n", pmsgobj->hostchip->chip_nr, pmsgobj->object); + + readMaskCM = IFXCM_CNTRL | IFXCM_ARB; + writeMaskCM = IFXCM_CNTRL | IFXCM_ARB | IFXCM_WRRD;; + + spin_lock( &c_can_if1lock ); + + //load Message Object in IF1 + if (c_can_if1_busycheck(pmsgobj->hostchip)) return -ENODEV; + c_can_write_reg_w(pmsgobj->hostchip, readMaskCM, CCIF1CM); + c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF1CR); + + //setting Message Valid Bit to zero + if (c_can_if1_busycheck(pmsgobj->hostchip)) return -ENODEV; + tempreg = c_can_read_reg_w(pmsgobj->hostchip, CCIF1A2); + c_can_write_reg_w(pmsgobj->hostchip, tempreg & ~IFXARB2_MVAL, CCIF1A2); + c_can_write_reg_w(pmsgobj->hostchip, writeMaskCM, CCIF1CM); + c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF1CR); + + //setting UMask bit + if (c_can_if1_busycheck(pmsgobj->hostchip)) return -ENODEV; + if ( useflag ) + { + tempreg = c_can_read_reg_w(pmsgobj->hostchip, CCIF1DMC); + c_can_write_reg_w(pmsgobj->hostchip, tempreg | IFXMC_UMASK, CCIF1DMC); + } + else + { + tempreg = c_can_read_reg_w(pmsgobj->hostchip, CCIF1DMC); + c_can_write_reg_w(pmsgobj->hostchip, tempreg & ~IFXMC_UMASK, CCIF1DMC); + } + //seting Message Valid Bit to one + tempreg = c_can_read_reg_w(pmsgobj->hostchip, CCIF1A2); + c_can_write_reg_w(pmsgobj->hostchip, tempreg | IFXARB2_MVAL, CCIF1A2); + //write to chip + c_can_write_reg_w(pmsgobj->hostchip, writeMaskCM, CCIF1CM); + c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF1CR); + + spin_unlock( &c_can_if1lock ); + +#ifdef DEBUG + DEBUGMSG("-> Setting umask bit to %s\n",boolstring); +#endif +#ifdef REGDUMP + c_can_registerdump(pmsgobj->hostchip); +#endif + + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int c_can_clear_objects(struct chip_t *pchip) +{ + unsigned short i = 0; + unsigned short tempreg = 0; + + unsigned short maskCM = IFXCM_ARB; + + DEBUGMSG("(c%d)calling c_can_clear_objects(...)\n", pchip->chip_nr); + + spin_lock( &c_can_if1lock ); + spin_lock( &c_can_if2lock ); + + for (i=0; i<0x10; i++) + { + + //loading Message Objects in IF1 and IF2 + if (c_can_if1_busycheck(pchip)) return -ENODEV; + c_can_write_reg_w(pchip, maskCM, CCIF1CM); + c_can_write_reg_w(pchip, i, CCIF1CR); + if (c_can_if2_busycheck(pchip)) return -ENODEV; + c_can_write_reg_w(pchip, maskCM, CCIF2CM); + c_can_write_reg_w(pchip, i+0x10, CCIF2CR); + + //setting Message Valid Bit to zero + if (c_can_if1_busycheck(pchip)) return -ENODEV; + tempreg = c_can_read_reg_w(pchip, CCIF1A2); + c_can_write_reg_w(pchip, tempreg & ~IFXARB2_MVAL, CCIF1A2); + c_can_write_reg_w(pchip, i, CCIF1CR); + if (c_can_if2_busycheck(pchip)) return -ENODEV; + tempreg = c_can_read_reg_w(pchip, CCIF2A2); + c_can_write_reg_w(pchip, tempreg & ~IFXARB2_MVAL, CCIF2A2); + c_can_write_reg_w(pchip, i+0x10, CCIF2CR); + } + + for (i=0; imax_objects; i++) + { + if (can_msgobj_test_fl(pchip->msgobj[i],OPENED)) + { + // In- and output buffer re-initialization + canqueue_ends_flush_inlist(pchip->msgobj[i]->qends); + canqueue_ends_flush_outlist(pchip->msgobj[i]->qends); + + } + } + + spin_unlock( &c_can_if1lock ); + spin_unlock( &c_can_if2lock ); + + DEBUGMSG("-> Message Objects reset\n"); + + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int c_can_config_irqs(struct chip_t *pchip, + u16 irqs) +{ + u16 tempreg; + + DEBUGMSG("(c%d)calling c_can_config_irqs(...)\n", pchip->chip_nr); + + /* + CANMSG("c_can_config_irqs not implemented\n"); + return -ENOSYS; + */ + + tempreg = c_can_read_reg_w(pchip, CCCR); + //DEBUGMSG("-> CAN Control Register: 0x%.4lx\n",(long)tempreg); + c_can_write_reg_w(pchip, tempreg | (irqs & 0xe), CCCR); + DEBUGMSG("-> Configured hardware interrupt delivery\n"); + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int c_can_pre_read_config(struct chip_t *pchip, struct msgobj_t *pmsgobj) +{ + unsigned short readMaskCM = IFXCM_CNTRL | IFXCM_ARB; + unsigned short writeMaskCM = IFXCM_CNTRL | IFXCM_ARB | IFXCM_WRRD; + unsigned short mcreg = 0; + u32 id=pmsgobj->rx_preconfig_id; + + DEBUGMSG("(c%dm%d)calling c_can_pre_read_config(...)\n", pmsgobj->hostchip->chip_nr, pmsgobj->object); + + spin_lock( &c_can_if1lock ); + + + //loading Message Object in IF1 + if (c_can_if1_busycheck(pmsgobj->hostchip)) return -ENODEV; + c_can_write_reg_w(pmsgobj->hostchip, readMaskCM, CCIF1CM); + c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF1CR); + //setting Message Valid Bit to zero + if (c_can_if1_busycheck(pmsgobj->hostchip)) return -ENODEV; + c_can_write_reg_w(pmsgobj->hostchip, 0, CCIF1A2); + c_can_write_reg_w(pmsgobj->hostchip, writeMaskCM, CCIF1CM); + c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF1CR); + //Configuring Message-Object + if (c_can_if1_busycheck(pmsgobj->hostchip)) return -ENODEV; + mcreg = c_can_read_reg_w(pmsgobj->hostchip, CCIF1CM); + c_can_write_reg_w(pmsgobj->hostchip, + ((mcreg & IFXMC_UMASK) | IFXMC_EOB | IFXMC_RXIE), CCIF1DMC); + //writing arbitration mask for extended or standart mode + if (can_msgobj_test_fl(pmsgobj,RX_MODE_EXT)) + { + c_can_write_reg_w(pmsgobj->hostchip, + IFXARB2_XTD | IFXARB2_MVAL | (id>>16 & 0x1FFF), CCIF1A2); + c_can_write_reg_w(pmsgobj->hostchip, id & 0xFFFF, CCIF1A1); + } + else + { + c_can_write_reg_w(pmsgobj->hostchip, + IFXARB2_MVAL | (id<<2 & 0x1FFC), CCIF1A2); + //c_can_write_reg_w(pmsgobj->hostchip, 0, CCIF1A1); + } + c_can_write_reg_w(pmsgobj->hostchip, writeMaskCM, CCIF1CM); + c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF1CR); + + spin_unlock( &c_can_if1lock ); + + DEBUGMSG("-> Receiving through message object %d with id=%d\n", pmsgobj->object, + id); +#ifdef REGDUMP + c_can_registerdump(pmsgobj->hostchip); +#endif + + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int c_can_pre_write_config(struct chip_t *chip, struct msgobj_t *obj, + struct canmsg_t *msg) +{ + return 0; +} + + /////////////////////////////////////////////////////////////////////// +/* + *Prepare the Chip to send specified Message over specified Messageobject + *In this version the method also sends the message. + */ + +int c_can_send_msg(struct chip_t *pchip, struct msgobj_t *pmsgobj, + struct canmsg_t *pmsg) +{ + unsigned short readMaskCM = IFXCM_CNTRL | IFXCM_ARB | IFXCM_DA | IFXCM_DB; + unsigned short writeMaskCM = IFXCM_CNTRL | IFXCM_ARB | IFXCM_DA | IFXCM_DB| IFXCM_WRRD; + unsigned short writeSendMskCM = IFXCM_CNTRL | IFXCM_ARB | IFXCM_DA | IFXCM_DB| IFXCM_WRRD | IFXCM_TRND; + unsigned short mcreg = 0; + //unsigned short arbreg = 0; + unsigned short dataA1 = 0; + unsigned short dataA2 = 0; + unsigned short dataB1 = 0; + unsigned short dataB2 = 0; + + DEBUGMSG("(c%dm%d)calling c_can_send_msg(...)\n", pmsgobj->hostchip->chip_nr, pmsgobj->object); + + spin_lock( &c_can_if2lock ); + + can_msgobj_clear_fl(pmsgobj,RX_MODE); + + //loading Message Object in IF1 + if (c_can_if2_busycheck(pmsgobj->hostchip)) return -ENODEV; + c_can_write_reg_w(pmsgobj->hostchip, readMaskCM, CCIF2CM); + c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF2CR); + //setting Message Valid Bit to zero + if (c_can_if2_busycheck(pmsgobj->hostchip)) return -ENODEV; + c_can_write_reg_w(pmsgobj->hostchip, 0, CCIF2A2); + c_can_write_reg_w(pmsgobj->hostchip, writeMaskCM, CCIF2CM); + c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF2CR); + //Configuring MO + if (c_can_if2_busycheck(pmsgobj->hostchip)) return -ENODEV; + mcreg = c_can_read_reg_w( pmsgobj->hostchip, CCIF2CM); + //remote enable? + //define Command Mask + c_can_write_reg_w(pmsgobj->hostchip, (mcreg & IFXMC_UMASK) | IFXMC_EOB | IFXMC_TXIE + | IFXMC_RMTEN | IFXMC_NEWDAT | IFXMC_TXRQST | (pmsg->length & 0xF), CCIF2DMC); + //set Arbitration Bits + if (can_msgobj_test_fl(pmsgobj,RX_MODE_EXT)) + { + c_can_write_reg_w(pmsgobj->hostchip, (u16)(pmsg->id), CCIF2A1); + c_can_write_reg_w(pmsgobj->hostchip, IFXARB2_XTD | IFXARB2_MVAL | IFXARB2_DIR + | ((u16)(pmsg->id>>16) & 0x1FFF), CCIF2A2); + } + else + { + c_can_write_reg_w(pmsgobj->hostchip, + (IFXARB2_MVAL | IFXARB2_DIR | ((u16)(pmsg->id<<2) & 0x1FFC)), CCIF2A2); + c_can_write_reg_w(pmsgobj->hostchip, 0, CCIF1A1); + } + //write Data + if (pmsg->length>0) + { + dataA1 = pmsg->data[0] | (u16)pmsg->data[1]<<8; + dataA2 = pmsg->data[2] | (u16)pmsg->data[3]<<8; + dataB1 = pmsg->data[4] | (u16)pmsg->data[5]<<8; + dataB2 = pmsg->data[6] | (u16)pmsg->data[7]<<8; + + c_can_write_reg_w(pmsgobj->hostchip, dataA1, CCIF2DA1); + c_can_write_reg_w(pmsgobj->hostchip, dataA2, CCIF2DA2); + c_can_write_reg_w(pmsgobj->hostchip, dataB1, CCIF2DB1); + c_can_write_reg_w(pmsgobj->hostchip, dataB2, CCIF2DB2); + } + + c_can_write_reg_w(pmsgobj->hostchip, writeSendMskCM, CCIF2CM); + c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF2CR); + + spin_unlock( &c_can_if2lock ); + + DEBUGMSG("-> ok\n"); +#ifdef REGDUMP + c_can_registerdump(pmsgobj->hostchip); +#endif + + return 0; +} + +////////////////////////////////////////////////////////////////////// +int c_can_remote_request(struct chip_t *pchip, struct msgobj_t *pmsgobj ) +{ + unsigned short readMaskCM = IFXCM_CNTRL;// | IFXCM_ARB; + //unsigned short writeMaskCM = IFXCM_CNTRL | IFXCM_ARB | IFXCM_WRRD; + unsigned short mcreg = 0; + + DEBUGMSG("(c%dm%d)calling c_can_remote_request(...)\n", pmsgobj->hostchip->chip_nr, pmsgobj->object); + + //Remote request is only available when the message object is in receiving mode + if (!can_msgobj_test_fl(pmsgobj,RX_MODE)) + { + return 1; + } + + spin_lock( &c_can_if1lock ); + + //loading Message Object in IF1 + if (c_can_if1_busycheck(pmsgobj->hostchip)) return -ENODEV; + c_can_write_reg_w(pmsgobj->hostchip, readMaskCM, CCIF1CM); + c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF1CR); + //setting Transmit-Request-Bit + if (c_can_if1_busycheck(pmsgobj->hostchip)) return -ENODEV; + mcreg = c_can_read_reg_w( pmsgobj->hostchip, CCIF1DMC); + c_can_write_reg_w(pmsgobj->hostchip, mcreg | IFXMC_TXRQST, CCIF1DMC); + + c_can_write_reg_w(pmsgobj->hostchip, pmsgobj->object, CCIF1CR); + + spin_unlock( &c_can_if1lock ); + + DEBUGMSG("-> Sent remote request through message object %d\n", pmsgobj->object); +#ifdef REGDUMP + c_can_registerdump(pmsgobj->hostchip); +#endif + + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int c_can_set_btregs(struct chip_t *pchip, + u16 btr0, + u16 btr1) +{ + unsigned short tempCR = 0; + + DEBUGMSG("(c%d)calling c_can_set_btregs(...)\n", pchip->chip_nr); + + // Validate pointer + if ( NULL == pchip ) return -1; + + if (c_can_enable_configuration(pchip)) + return -ENODEV; + + //read Control Register + tempCR = c_can_read_reg_w(pchip, CCCR); + //Configuration Change Enable + c_can_write_reg_w(pchip, tempCR | CR_CCE, CCCR); + c_can_write_reg_w(pchip, btr0 | (btr1<<8), CCBT); + + if (c_can_disable_configuration(pchip)) + return -ENODEV; + + DEBUGMSG("-> ok\n"); + return 0; +} + +/////////////////////////////////////////////////////////////////////// +/* + * Starts the Chip, by setting the CAN Enable Bit + */ +int c_can_start_chip(struct chip_t *pchip) +{ + u16 flags = 0; + + DEBUGMSG("(c%d)calling c_can_start_chip(...)\n", pchip->chip_nr); + + // Validate pointer + if ( NULL == pchip ) + { + DEBUGMSG("-> Error Chip not available.\n"); + return -1; + } + + // flags = c_can_read_reg_w(pchip, CCCE) | CE_EN; + // c_can_write_reg_w(pchip, flags, CCCE); + // + flags = c_can_read_reg_w(pchip, CCCE) | CE_EN; + c_can_write_reg_w(pchip, flags, CCCE); + + DEBUGMSG("-> ok\n"); +#ifdef REGDUMP + c_can_registerdump(pchip); +#endif + + return 0; +} + +/////////////////////////////////////////////////////////////////////// +/* + * Stops the Chip, by deleting the CAN Enable Bit + */ +int c_can_stop_chip(struct chip_t *pchip) +{ + u16 flags = 0; + + DEBUGMSG("(c%d)calling c_can_stop_chip(...)\n", pchip->chip_nr); + + // Validate pointer + if ( NULL == pchip ) + { + DEBUGMSG("-> Error Chip not available.\n"); + return -1; + } + + flags = c_can_read_reg_w(pchip, CCCE) & ~CE_EN; + c_can_write_reg_w(pchip, flags, CCCE); + + DEBUGMSG("-> ok\n"); + return 0; +} + +/////////////////////////////////////////////////////////////////////// +/* + *Check the TxOK bit of the Status Register and resets it afterwards. + */ +int c_can_check_tx_stat(struct chip_t *pchip) +{ + unsigned long tempstat = 0; + + DEBUGMSG("(c%d)calling c_can_check_tx_stat(...)\n", pchip->chip_nr); + + // Validate pointer + if ( NULL == pchip ) return -1; + + tempstat = c_can_read_reg_w(pchip, CCSR); + + if (tempstat & SR_TXOK) + { + c_can_write_reg_w(pchip, tempstat & ~SR_TXOK, CCSR); + return 0; + } + else + { + return 1; + } +} + + +/////////////////////////////////////////////////////////////////////// +int c_can_wakeup_tx(struct chip_t *chip, struct msgobj_t *obj) +{ + can_preempt_disable(); + + can_msgobj_set_fl(obj,TX_REQUEST); + + /* calls i82527_irq_write_handler synchronized with other invocations + from kernel and IRQ context */ + c_can_irq_sync_activities(chip, obj); + + can_preempt_enable(); + return 0; +} + +/////////////////////////////////////////////////////////////////////// +int c_can_filtch_rq(struct chip_t *chip, struct msgobj_t *obj) +{ + can_preempt_disable(); + + can_msgobj_set_fl(obj,FILTCH_REQUEST); + + /* setups filter synchronized with other invocations from kernel and IRQ context */ + c_can_irq_sync_activities(chip, obj); + + can_preempt_enable(); + return 0; +} + + +/////////////////////////////////////////////////////////////////////// +void c_can_registerdump(struct chip_t *pchip) +{ + CANMSG("------------------------------------\n"); + CANMSG("---------C-CAN Register Dump--------\n"); + CANMSG("------------at 0x%.8lx-----------\n" + ,(unsigned long)pchip->chip_base_addr); + CANMSG("Control Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCCR))); + CANMSG("Status Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCSR))); + CANMSG("Error Counting Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCEC))); + CANMSG("Bit Timing Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCBT))); + CANMSG("Interrupt Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCINTR))); + CANMSG("Test Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCTR))); + CANMSG("Baud Rate Presc. Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCBRPE))); + CANMSG("CAN Enable Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCCE))); + CANMSG("Transm. Req. 1 Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCTREQ1))); + CANMSG("Transm. Req. 2 Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCTREQ2))); + CANMSG("New Data 1 Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCND1))); + CANMSG("New Data 2 Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCND2))); + CANMSG("Interrupt Pend. 1 Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCINTP1))); + CANMSG("Interrupt Pend. 2 Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCINTP2))); + CANMSG("------------------------------------\n"); + CANMSG("IF1 Command Req. Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCIF1CR))); + CANMSG("IF1 Command Mask Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCIF1CM))); + CANMSG("IF1 Mask 1 Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCIF1M1))); + CANMSG("IF1 Mask 2 Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCIF1M2))); + CANMSG("IF1 Arbitration 1 Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCIF1A1))); + CANMSG("IF1 Arbitration 2 Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCIF1A2))); + CANMSG("IF1 Message Control Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCIF1DMC))); + CANMSG("IF1 Data A1 Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCIF1DA1))); + CANMSG("IF1 Data A2 Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCIF1DA2))); + CANMSG("IF1 Data B1 Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCIF1DB1))); + CANMSG("IF1 Data B2 Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCIF1DB2))); + CANMSG("------------------------------------\n"); + CANMSG("IF2 Command Req. Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCIF2CR))); + CANMSG("IF2 Command Mask Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCIF2CM))); + CANMSG("IF2 Mask 1 Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCIF2M1))); + CANMSG("IF2 Mask 2 Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCIF2M2))); + CANMSG("IF2 Arbitration 1 Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCIF2A1))); + CANMSG("IF2 Arbitration 2 Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCIF2A2))); + CANMSG("IF2 Message Control Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCIF2DMC))); + CANMSG("IF2 Data A1 Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCIF2DA1))); + CANMSG("IF2 Data A2 Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCIF2DA2))); + CANMSG("IF2 Data B1 Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCIF2DB1))); + CANMSG("IF2 Data B2 Register: 0x%.4lx\n", + (long)(c_can_read_reg_w( pchip, CCIF2DB2))); + CANMSG("------------------------------------\n"); + CANMSG("------------------------------------\n"); +} + +/////////////////////////////////////////////////////////////////////// + +int c_can_register(struct chipspecops_t *chipspecops) +{ + CANMSG("initializing c_can chip operations\n"); + chipspecops->chip_config=c_can_chip_config; + chipspecops->baud_rate=c_can_baud_rate; + /*chipspecops->standard_mask=c_can_standard_mask; + chipspecops->extended_mask=c_can_extended_mask; + chipspecops->message15_mask=c_can_extended_mask;*/ + chipspecops->clear_objects=c_can_clear_objects; + /*chipspecops->config_irqs=c_can_config_irqs;*/ + chipspecops->pre_read_config=c_can_pre_read_config; + chipspecops->pre_write_config=c_can_pre_write_config; + chipspecops->send_msg=c_can_send_msg; + chipspecops->check_tx_stat=c_can_check_tx_stat; + chipspecops->wakeup_tx=c_can_wakeup_tx; + chipspecops->filtch_rq = c_can_filtch_rq; + chipspecops->remote_request=c_can_remote_request; + chipspecops->enable_configuration=c_can_enable_configuration; + chipspecops->disable_configuration=c_can_disable_configuration; + chipspecops->set_btregs=c_can_set_btregs; + chipspecops->start_chip=c_can_start_chip; + chipspecops->stop_chip=c_can_stop_chip; + chipspecops->irq_handler=c_can_irq_handler; + return 0; +} + +/*int c_can_register(struct chip_t *pchip) +{ + DEBUGMSG("(c%d)call c_can_register\n", pchip->chip_nr); + + // Validate pointer + if ( NULL == pchip ) return -1; + + pchip->chip_config = c_can_chip_config; + pchip->set_baud_rate = c_can_baud_rate; + pchip->set_mask = c_can_mask; + pchip->set_use_mask = c_can_use_mask; + //pchip->set_message15_mask = c_can_extended_mask; + pchip->clear_objects = c_can_clear_objects; + pchip->config_irqs = c_can_config_irqs; + pchip->pre_read_config = c_can_pre_read_config; + //pchip->pre_write_config = c_can_pre_write_config; + pchip->send_msg = c_can_send_msg; + pchip->check_tx_stat = c_can_check_tx_stat; + pchip->remote_request = c_can_remote_request; + pchip->enable_configuration = c_can_enable_configuration; + pchip->disable_configuration = c_can_disable_configuration; + pchip->set_btregs = c_can_set_btregs; + pchip->start_chip = c_can_start_chip; + pchip->stop_chip = c_can_stop_chip; + pchip->register_dump = c_can_registerdump; + + DEBUGMSG("-> ok\n"); + return 0; +} +*/ diff --git a/lincan/src/c_can_irq.c b/lincan/src/c_can_irq.c new file mode 100644 index 0000000..5257d0f --- /dev/null +++ b/lincan/src/c_can_irq.c @@ -0,0 +1,510 @@ +/* c_can_irq.c - Hynix HMS30c7202 ARM IRQ handling code + * Linux CAN-bus device driver. + * Written by Sebastian Stolzenberg email:stolzi@sebastian-stolzenberg.de + * Based on code from Arnaud Westenberg email:arnaud@wanadoo.nl + * and Ake Hedman, eurosource, akhe@eurosource.se + * 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.2 9 Jul 2003 + */ + +#include "../include/can.h" +#include "../include/can_sysdep.h" +#include "../include/main.h" +#include "../include/c_can.h" + +union c_can_data +{ + unsigned short wdata[4]; + unsigned char bdata[8]; +}; + + + +// prototypes +inline void c_can_irq_read_handler( struct chip_t *pchip, int idxobj, u32 msgid ); + +inline void c_can_irq_write_handler( struct chip_t *pchip, int idxobj); + +void c_can_irq_rtr_handler( struct chip_t *pchip, int idxobj, u32 msgid ); + +u16 readMaskCM = IFXCM_ARB | IFXCM_CNTRL | IFXCM_CLRINTPND + | IFXCM_TRND | IFXCM_DA | IFXCM_DB; + +u16 msgLstReadMaskCM = IFXCM_CNTRL; +u16 msgLstWriteMaskCM = IFXCM_CNTRL | IFXCM_WRRD; + +/////////////////////////////////////////////////////////////////////////////// +// c_can_irq_write_handler +// +// Send a message from the output fifo ( if any ). +// + +inline void c_can_irq_write_handler( struct chip_t *pchip, int idxobj) +{ + int cmd; + struct msgobj_t *pmsgobj = pchip->msgobj[idxobj]; + + DEBUGMSG("(c%dm%d)calling c_can_irq_write_handler(...)\n", + pchip->chip_idx, pmsgobj->object); + + if(pmsgobj->tx_slot){ + /* Do local transmitted message distribution if enabled */ + if (processlocal){ + pmsgobj->tx_slot->msg.flags |= MSG_LOCAL; + canque_filter_msg2edges(pmsgobj->qends, &pmsgobj->tx_slot->msg); + } + /* Free transmitted slot */ + canque_free_outslot(pmsgobj->qends, pmsgobj->tx_qedge, pmsgobj->tx_slot); + pmsgobj->tx_slot=NULL; + } + + // Get ready to send next message + spin_lock( &c_can_spwlock ); + + cmd=canque_test_outslot(pmsgobj->qends, &pmsgobj->tx_qedge, &pmsgobj->tx_slot); + if(cmd<0){ + DEBUGMSG("(c%dm%d)Nothin to write\n", + pchip->chip_idx, pmsgobj->object); + spin_unlock( &c_can_spwlock ); + return; + } + + // Send the message + if ( pchip->chipspecops->send_msg( pchip, pmsgobj,&pmsgobj->tx_slot->msg) ) { + pmsgobj->ret = -1; + canque_notify_inends(pmsgobj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_SEND); + canque_free_outslot(pmsgobj->qends, pmsgobj->tx_qedge, pmsgobj->tx_slot); + pmsgobj->tx_slot=NULL; + spin_unlock( &c_can_spwlock ); + DEBUGMSG("(c%dm%d)c_can_irq_handler: Unable to send message\n", + pchip->chip_idx, pmsgobj->object ); + return; + } else { + // Another message sent + #ifdef CAN_WITH_STATISTICS + pchip->stat.cntTxPkt++; + pchip->stat.cntTxData += pmsgobj->tx_slot->length; + #endif /*CAN_WITH_STATISTICS*/ + } + spin_unlock( &c_can_spwlock ); + + // Wake up any waiting writer + return; +} + +/////////////////////////////////////////////////////////////////////////////// +// c_can_irq_read_handler +// +// Message received form the line. Write it in the input fifo-> +// + +inline void c_can_irq_read_handler( struct chip_t *pchip, + int idxobj, u32 msgid ) +{ + int i=0; + u16 bDataAvail=1 ; + u16 msgCntlReg = 0; + union c_can_data readData; + struct msgobj_t *pmsgobj = pchip->msgobj[idxobj]; + + DEBUGMSG("(c%dm%d)calling c_can_irq_read_handler(...)\n", + pchip->chip_idx, pmsgobj->object); + + while ( bDataAvail ) { + + #ifdef CAN_WITH_STATISTICS + pchip->stat.cntRxFifoOvr++; + #endif /*CAN_WITH_STATISTICS*/ + // Message length + msgCntlReg = c_can_read_reg_w( pchip, CCIF1DMC ); + + pmsgobj->rx_msg.length = msgCntlReg & 0x000F; + + // Message id + pmsgobj->rx_msg.id = (u32)msgid; + + // Fetch message bytes + if (pmsgobj->rx_msg.length > 0) + readData.wdata[0] = c_can_read_reg_w(pchip, CCIF1DA1); + if (pmsgobj->rx_msg.length > 2) + readData.wdata[1] = c_can_read_reg_w(pchip, CCIF1DA2); + if (pmsgobj->rx_msg.length > 4) + readData.wdata[2] = c_can_read_reg_w(pchip, CCIF1DB1); + if (pmsgobj->rx_msg.length > 6) + readData.wdata[3] = c_can_read_reg_w(pchip, CCIF1DB2); + + for ( i=0; i < pmsgobj->rx_msg.length; i++ ) { + pmsgobj->rx_msg.data[ i ] = readData.bdata[i]; + } + DEBUGMSG("(c%dm%d)Received Message:\n", + pchip->chip_idx, pmsgobj->object); + DEBUGMSG(" id = %d\n", + pmsgobj->rx_msg.id); + DEBUGMSG(" length = %d\n", + pmsgobj->rx_msg.length); + for ( i=0; i < pmsgobj->rx_msg.length; i++ ) + DEBUGMSG(" data[%d] = 0x%.2x\n", i, pmsgobj->rx_msg.data[i]); + + canque_filter_msg2edges(pmsgobj->qends, &pmsgobj->rx_msg); + + #ifdef CAN_WITH_STATISTICS + // Another received packet + pchip->stat.cntRxPkt++; + + // Add databytes read to statistics block + pchip->stat.cntRxData += pmsgobj->rx_msg.length; + #endif /*CAN_WITH_STATISTICS*/ + + spin_unlock( &c_can_sprlock ); + + // Check if new data arrived + if (c_can_if1_busycheck(pchip)) ; + c_can_write_reg_w(pchip, readMaskCM, CCIF1CM); + c_can_write_reg_w(pchip, idxobj+1, CCIF1CR); + if (c_can_if1_busycheck(pchip)) ; + if ( !( ( bDataAvail = c_can_read_reg_w( pchip, CCIF1DMC ) ) & + IFXMC_NEWDAT ) ) { + break; + } + + if ( bDataAvail & IFXMC_MSGLST ) { + CANMSG("(c%dm%d)c-can fifo full: Message lost!\n", + pchip->chip_idx, pmsgobj->object); + } + + } + // while +} + +void c_can_irq_sync_activities(struct chip_t *chip, struct msgobj_t *obj) +{ + while(!can_msgobj_test_and_set_fl(obj,TX_LOCK)) { + + /*if(can_msgobj_test_and_clear_fl(obj,TX_REQUEST)) { + if(canobj_read_reg(chip,obj,iMSGCTL1)&TXRQ_RES) + i82527_irq_write_handler(chip, obj); + } + + if(!obj->tx_slot) { + if(can_msgobj_test_and_clear_fl(obj,FILTCH_REQUEST)) { + i82527_irq_update_filter(chip, obj); + } + }*/ + /* FIXME: these functionality has to be implemented to start TX */ + + can_msgobj_clear_fl(obj,TX_LOCK); + if(can_msgobj_test_fl(obj,TX_REQUEST)) + continue; + if(can_msgobj_test_fl(obj,FILTCH_REQUEST) && !obj->tx_slot) + continue; + break; + } +} + + +/////////////////////////////////////////////////////////////////////////////// +// c_can_irq_handler +// + +can_irqreturn_t c_can_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + struct rtr_id *rtr_search = hardware_p->rtr_queue; + struct chip_t *pchip = (struct chip_t *)dev_id; + u16 chip_status; + int id0=0, id1=0; + u16 errcount = 0; + u16 irqreg = 0; + u32 msgid = 0; + u16 tempCntlReg = 0; + //#ifdef CAN_DEBUG + // u32 intCntrVAddr = 0; + //#endif + //unsigned short flags = 0; + + //if (pchip->ntype != CAN_CHIPTYPE_C_CAN) { + // DEBUGMSG("\n(c%d)IRQ not for c_can_irq_handler(...)\n", pchip->chip_idx); + // return; + //} + + irqreg = c_can_read_reg_w( pchip, CCINTR ); + + if(!irqreg) { + DEBUGMSG( "\n(c%d)IRQ handler: addr=%.8lx spurious interrupt\n", + pchip->chip_idx, + (long)( pchip->/*v*/base_addr/* + CCSR*/)); + return CAN_IRQ_NONE; + } + + DEBUGMSG( "\n(c%d)IRQ handler: addr=%.8lx irqreg=0x%.4x\n", + pchip->chip_idx, + (long)( pchip->/*v*/base_addr/* + CCSR*/), + irqreg); + + + + #ifdef REGDUMP + c_can_registerdump(pchip); + #endif + +/* +#ifdef CAN_DEBUG + if ( (!( intCntrVAddr = (u32)ioremap( 0x80024000, 0xCD ) ))) { + DEBUGMSG("Failed to map Interrupt Controller IO-memory\n"); + } + else { + + DEBUGMSG( "Mapped Interrupt Controller IO-memory: 0x%lx - 0x%lx to 0x%lx\n", + (unsigned long)0X80024000, + (unsigned long)0X800240CC, + (unsigned long)intCntrVAddr); + } + + DEBUGMSG("Current Interrupt Status Register (ISR): 0x%4.4lx\n", + (long)readl(intCntrVAddr + 4)); + DEBUGMSG("Current Interrupt ID: %d\n", + (int)(readl(intCntrVAddr + 0x90) & 0xF)); + iounmap( (void*)intCntrVAddr); + DEBUGMSG( "Unmapped Interrupt Controller IO-memory: 0x%lx\n", + (unsigned long)intCntrVAddr); +#endif +*/ + while ( irqreg ){ + // Handle change in status register + + if ( irqreg == INT_STAT ) { + chip_status = c_can_read_reg_w( pchip, CCSR ); + DEBUGMSG( "(c%d)Status register: 0x%x\n", + pchip->chip_idx, chip_status ); + + if ( chip_status & SR_EWARN ) { + // There is an abnormal # of errors + #ifdef CAN_WITH_STATISTICS + pchip->stat.cntWarnings++; + #endif /*CAN_WITH_STATISTICS*/ + errcount = c_can_read_reg_w( pchip, CCEC); + DEBUGMSG("(c%d)stat: c_can_irq_handler: Abnormal number of Errors Warning\n" + " txErr=%d, rxErr=%d\n", + pchip->chip_idx, (errcount&0x00ff), ((errcount&0x7f00)>>8)); + + /* + // this code deactivates the chip if the transmiterrorcounter grew above 127 + if ((pchip->stat.cntWarnings > 100) && ((errcount&0x00ff) > 127)) + { + CANMSG("(c%d)to much Errornumber warnings (>100), deactivating chip", + pchip->chip_idx); + pchip->config_irqs(pchip, 0); + pchip->enable_configuration(pchip); + pchip->clear_objects(pchip); + pchip->flags &= ~CHANNEL_CONFIGURED; + return; + }*/ + } + + if ( chip_status & SR_EPASS ) { + // There is an abnormal # of errors + #ifdef CAN_WITH_STATISTICS + pchip->stat.cntErrPassive++; + #endif /*CAN_WITH_STATISTICS*/ + DEBUGMSG("(c%d)stat: c_can_irq_handler: Chip entering Error Passive Mode\n", + pchip->chip_idx); + } + + if ( chip_status & SR_BOFF ) { + // We have a bus off condition + #ifdef CAN_WITH_STATISTICS + pchip->stat.cntBusOff++; + #endif /*CAN_WITH_STATISTICS*/ + //pchip->fifo->tx_in_progress = 0; + //reset init bit + CANMSG("(c%d)stat: c_can_irq_handler: Bus Off\n", + pchip->chip_idx); + /*if (pchip->stat.cntBusOff > 100) + { + CANMSG("(c%d)to much busoff warnings (>100), deactivating chip", + pchip->chip_idx); + pchip->config_irqs(pchip, 0); + pchip->enable_configuration(pchip); + pchip->clear_objects(pchip); + pchip->flags &= ~CHANNEL_CONFIGURED; + return; + } + else*/ + CANMSG("(c%d)try to reconnect", + pchip->chip_idx); + pchip->chipspecops->disable_configuration(pchip); + } + + if (chip_status & SR_TXOK) { + DEBUGMSG("(c%d)stat: Transmitted a Message successfully\n", + pchip->chip_idx); + c_can_write_reg_w(pchip, chip_status & ~SR_TXOK, CCSR); + } + + if (chip_status & SR_RXOK) { + DEBUGMSG("(c%d)stat: Received a Message successfully\n", + pchip->chip_idx); + c_can_write_reg_w(pchip, chip_status & ~SR_RXOK, CCSR); + } + + #ifdef CAN_WITH_STATISTICS + // Errors to statistics + switch( chip_status & 0x07 ) + { + case SRLEC_NE: // No error + break; + case SRLEC_SE: // Stuff error + pchip->stat.cntStuffErr++; + break; + case SRLEC_FE: // Form error + pchip->stat.cntFormErr++; + break; + case SRLEC_AE: // Ack error + pchip->stat.cntAckErr++; + break; + case SRLEC_B1: // Bit 1 error + pchip->stat.cntBit1Err++; + break; + case SRLEC_B0: // Bit 0 error + pchip->stat.cntBit0Err++; + break; + case SRLEC_CR: // CRC error + pchip->stat.cntCrcErr++; + break; + case 7: // unused + break; + } + #endif /*CAN_WITH_STATISTICS*/ + //return; // continue? + } else { + if (irqreg >0 && irqreg <33) { + struct msgobj_t *pmsgobj; + int idxobj; + + //get id + idxobj = irqreg-1; + pmsgobj=pchip->msgobj[idxobj]; + + //DEBUGMSG( "Interrupt handler: addr=%lx devid=%lx irqreq=%x status=0x%x\n", + // (unsigned long)pchip->vbase_addr + iIRQ, + // (unsigned long)dev_id, + // irqreg, + // statreg ); + // + spin_lock( &c_can_if1lock ); + + //Message Lost Check + if (c_can_if1_busycheck(pchip)) ; /*??????????*/ + c_can_write_reg_w(pchip, msgLstReadMaskCM, CCIF1CM); + c_can_write_reg_w(pchip, idxobj+1, CCIF1CR); + + if (c_can_if1_busycheck(pchip)) ; /*??????????*/ + tempCntlReg = c_can_read_reg_w( pchip, CCIF1DMC ); + + if (tempCntlReg & IFXMC_MSGLST) { + CANMSG("(c%dm%d)Chip lost a message\n", + pchip->chip_idx, pmsgobj->object); + #ifdef CAN_WITH_STATISTICS + pchip->stat.cntMsgLst++; + #endif /*CAN_WITH_STATISTICS*/ + + //Reset Message Lost Bit + tempCntlReg = tempCntlReg & (~IFXMC_MSGLST); + c_can_write_reg_w(pchip, tempCntlReg, CCIF1DMC); + c_can_write_reg_w(pchip, msgLstWriteMaskCM, CCIF1CM); + c_can_write_reg_w(pchip, idxobj+1, CCIF1CR); + } + + //transfer Message Object to IF1 Buffer + if (c_can_if1_busycheck(pchip)) ; + c_can_write_reg_w(pchip, readMaskCM, CCIF1CM); + c_can_write_reg_w(pchip, idxobj+1, CCIF1CR); + + if (c_can_if1_busycheck(pchip)) ; + if (c_can_read_reg_w(pchip, CCIF1A2) & IFXARB2_DIR) { + spin_unlock( &c_can_if1lock ); + c_can_irq_write_handler(pchip,idxobj); + } else { + if (can_msgobj_test_fl(pmsgobj,RX_MODE_EXT)) { + id0=c_can_read_reg_w(pchip, CCIF1A1); + id1=(c_can_read_reg_w(pchip, CCIF1A2)&0x1FFF)<<16; + msgid= id0|id1; + } else { + msgid=((c_can_read_reg_w(pchip, CCIF1A2)&0x1FFC)>>2)&0x7FF; + } + spin_unlock( &c_can_if1lock ); + + spin_lock(&hardware_p->rtr_lock); + while ( rtr_search != NULL ) + { + if ( rtr_search->id == msgid ) { + break; + } + rtr_search = rtr_search->next; + } + spin_unlock(&hardware_p->rtr_lock); + + spin_lock( &c_can_if1lock ); + + //transfer Message Object to IF1 Buffer + if (c_can_if1_busycheck(pchip)) ; + c_can_write_reg_w(pchip, readMaskCM, CCIF1CM); + c_can_write_reg_w(pchip, idxobj+1, CCIF1CR); + + if (c_can_if1_busycheck(pchip)) ; + + if ( ( rtr_search != NULL ) && (rtr_search->id == msgid ) ) { + c_can_irq_rtr_handler( pchip, idxobj, msgid ); + } else { + c_can_irq_read_handler( pchip, idxobj, msgid ); + } + spin_unlock( &c_can_if1lock ); + + //} + } + //else + } + //if + } + // Get irq status again + irqreg = c_can_read_reg_w( pchip, CCINTR ); + } + return CAN_IRQ_HANDLED; +} + +/////////////////////////////////////////////////////////////////////////////// +// c_can_irq_rtr_handler +// + +void c_can_irq_rtr_handler( struct chip_t *pchip, int idxobj, u32 msgid ) +{ + short int i=0; + struct rtr_id *prtr_search = hardware_p->rtr_queue; + union c_can_data rtrData; + + spin_lock( &hardware_p->rtr_lock ); + + prtr_search->rtr_message->id = msgid; + prtr_search->rtr_message->length = + ( c_can_read_reg_w( pchip, CCIF1DMC ) & 0x000f); + + // Fetch message bytes + if (prtr_search->rtr_message->length > 0) + rtrData.wdata[0] = c_can_read_reg_w(pchip, CCIF1DA1); + if (prtr_search->rtr_message->length > 2) + rtrData.wdata[1] = c_can_read_reg_w(pchip, CCIF1DA2); + if (prtr_search->rtr_message->length > 4) + rtrData.wdata[2] = c_can_read_reg_w(pchip, CCIF1DB1); + if (prtr_search->rtr_message->length > 6) + rtrData.wdata[3] = c_can_read_reg_w(pchip, CCIF1DB2); + + for ( i=0; irtr_message->length; i++ ) { + prtr_search->rtr_message->data[ i ] = rtrData.bdata[i]; + } + + spin_unlock( &hardware_p->rtr_lock ); + wake_up_interruptible( &prtr_search->rtr_wq ); + return; +} + diff --git a/lincan/src/hms30c7202_can.c b/lincan/src/hms30c7202_can.c new file mode 100644 index 0000000..2bf38aa --- /dev/null +++ b/lincan/src/hms30c7202_can.c @@ -0,0 +1,436 @@ +/* hms30c7202_can.c - Hynix HMS30c7202 ARM device specific code + * Linux CAN-bus device driver. + * Written by Sebastian Stolzenberg email:stolzi@sebastian-stolzenberg.de + * Based on code from Arnaud Westenberg email:arnaud@wanadoo.nl + * and Ake Hedman, eurosource, akhe@eurosource.se + * 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.2 9 Jul 2003 + */ + +#include + +#include "../include/can.h" +#include "../include/can_sysdep.h" +#include "../include/main.h" +#include "../include/c_can.h" +#include "../include/hms30c7202_can.h" + +/* + * 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. + */ +#define IO_RANGE 0x17E + +/** + * hms30c7202_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 hms30c7202_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/template.c + */ +int hms30c7202_request_io(struct candevice_t *candev) +{ + DEBUGMSG("(c%d)calling hms30c7202_request_io(...)\n", pchip->chip_nr); + + if(!can_request_mem_region(candev->io_addr, IO_RANGE, DEVICE_NAME )) { + CANMSG("hmsc30c7202_can failed to request mem region %lx.\n", + (unsigned long)candev->io_addr ); + } + + if (!( candev->dev_base_addr = (long)ioremap( candev->io_addr, IO_RANGE ))) { + DEBUGMSG( "Failed to map IO-memory: 0x%lx - 0x%lx, mapped to 0x%lx\n", + (unsigned long)candev->io_addr, + (unsigned long)candev->io_addr + IO_RANGE - 1, + (unsigned long)candev->dev_base_addr); + can_release_mem_region(candev->io_addr, IO_RANGE); + return -ENODEV; + } else { + + DEBUGMSG( "Mapped IO-memory: 0x%lx - 0x%lx, mapped to 0x%lx\n", + (unsigned long)candev->io_addr, + (unsigned long)candev->io_addr + IO_RANGE - 1, + (unsigned long)candev->dev_base_addr); + + } + + candev->chip[0]->chip_base_addr=candev->dev_base_addr; + + //pchip->write_register(0, pchip->vbase_addr + CCCR); + //DEBUGMSG("C-CAN Control Register : 0x%.4lx\n", + // (unsigned long)(c_can_read_reg_w( pchip->vbase_addr + CCCR))); + candev->chip[0]->chipspecops->start_chip(candev->chip[0]); + //DEBUGMSG("C-CAN Control Register : 0x%.4lx\n", + // (unsigned long)(c_can_read_reg_w( pchip->vbase_addr + CCCR))); + + //DEBUGMSG("hms30c7202_can request i/o, leaving.\n"); + return 0; +} + + +/** + * hms30c7202_release_io - free reserved io memory range + * @candev: pointer to candevice/board which releases io + * + * The function hms30c7202_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/template.c + */ +int hms30c7202_release_io(struct candevice_t *candev) +{ + u16 tempReg; + + //disable IRQ generation + tempReg = hms30c7202_read_reg_w(candev->chip[0], CCCR); + + c_can_config_irqs(candev->chip[0], 0); + + /* // clear all message objects + for (i=1; i<=15; i++) { + ccscan_write_register( + INTPD_RES | + RXIE_RES | + TXIE_RES | + MVAL_RES, + pchip->vbase_addr + + i*0x10 + iMSGCTL0 ); + ccscan_write_register( + NEWD_RES | + MLST_RES | + CPUU_RES | + TXRQ_RES | + RMPD_RES, + pchip->vbase_addr + + i*0x10 + iMSGCTL1 ); + } + */ + // power down HMS30c7202 - C_CAN + candev->chip[0]->chipspecops->stop_chip(candev->chip[0]); + + // release I/O memory mapping + iounmap((void*)candev->dev_base_addr); + + // Release the memory region + can_release_mem_region(candev->io_addr, IO_RANGE); + + return 0; +} + +/** + * hms30c7202_reset - hardware reset routine + * @card: Number of the hardware card. + * + * The function hms30c7202_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/template.c + */ +int hms30c7202_reset( struct candevice_t *candev) +{ + int i=0; + int enableTest=0, disableTest=0; + struct chip_t *pchip = candev->chip[0]; + + enableTest = pchip->chipspecops->enable_configuration(pchip); + disableTest = pchip->chipspecops->disable_configuration(pchip); + if( enableTest || disableTest) { + CANMSG("Reset status timeout!\n"); + CANMSG("Please check your hardware.\n"); + return -ENODEV; + } + + /* Check busoff status */ + + while ( (hms30c7202_read_reg_w(pchip, CCSR) & SR_BOFF) && (i<=15)) { + udelay(20000); + i++; + } + if (i>=15) { + CANMSG("Reset status timeout!\n"); + CANMSG("Please check your hardware.\n"); + return -ENODEV; + } + else + DEBUGMSG("Chip0 reset status ok.\n"); + + //pchip->config_irqs(pchip, CR_MIE | CR_SIE | CR_EIE); + return 0; +} + +#define RESET_ADDR 0x0 +#define NR_C_CAN 1 +#define NR_MSGOBJ 32 + +/** + * hms30c7202_init_hw_data - Initialize hardware cards + * @candev: Pointer to candevice/board structure + * + * The function hms30c7202_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/template.c + */ +int hms30c7202_init_hw_data(struct candevice_t *candev) +/*( struct chip_t *pchip, u16 chip_nr, u16 startminor, u32 baseaddr, u8 irq )*/ +{ + // u32 intCntrVAddr = 0; + u32 gpioVAddr = 0; + u32 tempReg = 0; + u32 baseaddr=candev->io_addr; + + // if ( (!( intCntrVAddr = (u32)ioremap( 0x80024000, 0xCD ) )) + // & (! ( gpioVAddr = (u32)ioremap( 0x80023000, 0xAD ) ))) { + // DEBUGMSG("Failed to map Int and GPIO memory\n"); + // return -EIO; + // } + if ( ! ( gpioVAddr = (u32)ioremap( 0x80023000, 0xAD ) )) { + DEBUGMSG("Failed to map GPIO memory\n"); + return -EIO; + } else { + + // DEBUGMSG( "Mapped Interrupt Controller IO-memory: 0x%lx - 0x%lx to 0x%lx\n", + // (unsigned long)0X80024000, + // (unsigned long)0X800240CC, + // (unsigned long)intCntrVAddr); + DEBUGMSG( "Mapped GPIO IO-memory: 0x%lx - 0x%lx to 0x%lx\n", + (unsigned long)0X80023000, + (unsigned long)0X800240AC, + (unsigned long)gpioVAddr); + } + + if (baseaddr == 0x8002f000) { + // tempReg = readl(intCntrVAddr); + // DEBUGMSG("Read Interrupt Enable Register : 0x%.4lx\n",(long)tempReg); + // DEBUGMSG("Trying to activate CAN0 Interrupt (Bit 18)\n"); + // writel((tempReg | (1<<18)), intCntrVAddr); + // tempReg = readl(intCntrVAddr); + // DEBUGMSG("Read changed Interrupt Enable Register : 0x%.4lx\n",(long)tempReg); + tempReg = readl(gpioVAddr + 0x5C); + DEBUGMSG("Read GPIO-C Enable Register : 0x%.4lx\n",(long)tempReg); + DEBUGMSG("Trying to activate CAN0 (Bit 1 = 0 for CANTx0, Bit 2 = 0 for CANRx0,)\n"); + writel(tempReg & ~0x6, gpioVAddr + 0x5C); + tempReg = readl(gpioVAddr + 0x5C); + DEBUGMSG("Read changed GPIO-C Enable Register : 0x%.4lx\n",(long)tempReg); + tempReg = readl(gpioVAddr + 0x44); + DEBUGMSG("Read GPIO-C Direction Register : 0x%.4lx\n",(long)tempReg); + DEBUGMSG("Trying to set CAN0 directions (Bit 1 = 0 for CANTx0 as OUT, Bit 2 = 1 for CANRx0 as IN,)\n"); + writel((tempReg & ~0x2) | 0x4, gpioVAddr + 0x44); + tempReg = readl(gpioVAddr + 0x44); + DEBUGMSG("Read changed GPIO-C Direction Register : 0x%.4lx\n",(long)tempReg); + } + else if (baseaddr == 0x80030000) { + // tempReg = readl(intCntrVAddr); + // writel((tempReg | (1<<19)), intCntrVAddr); + tempReg = readl(gpioVAddr + 0x9C); + DEBUGMSG("Read GPIO-E Enable Register : 0x%.8lx\n",(long)tempReg); + DEBUGMSG("Trying to activate CAN1 (Bit 22 = 0 for CANRx1, Bit 23 = 0 for CANTx1,)\n"); + writel(tempReg & 0xFF3FFFFF, gpioVAddr + 0x9C); + tempReg = readl(gpioVAddr + 0x9C); + DEBUGMSG("Read changed GPIO-E Enable Register : 0x%.8lx\n",(long)tempReg); + tempReg = readl(gpioVAddr + 0x84); + DEBUGMSG("Read GPIO-E Direction Register : 0x%.8lx\n",(long)tempReg); + DEBUGMSG("Trying to set CAN1 directions (Bit 22 = 1 for CANRx1 as IN, Bit 23 = 0 for CANTx1 as OUT,)\n"); + writel((tempReg & ~(1<<23)) | 1<<22, gpioVAddr + 0x84); + tempReg = readl(gpioVAddr + 0x84); + DEBUGMSG("Read changed GPIO-E Direction Register : 0x%.8lx\n",(long)tempReg); + } + + //DEBUGMSG("Current Interrupt Status Register (ISR): 0x%4.4lx\n", + // (long)readl(intCntrVAddr + 4)); + //DEBUGMSG("Current Interrupt ID: %d\n", + // (int)(readl(intCntrVAddr + 0x90) & 0xF)); + // iounmap( (void*)intCntrVAddr); + iounmap( (void*)gpioVAddr ); + // DEBUGMSG( "Unmapped Interrupt Controller IO-memory: 0x%lx\n", + // (unsigned long)intCntrVAddr); + DEBUGMSG( "Unmapped GPIO IO-memory: 0x%lx\n", + (unsigned long)gpioVAddr); + + // Initialize chip data ( only one chip ) + // pcandev->pchip[ 0 ]->powner = pcandev; + /*pchip->ntype = CAN_CHIPTYPE_C_CAN;*/ + + candev->nr_82527_chips=0; + candev->nr_sja1000_chips=0; + candev->nr_all_chips=NR_C_CAN; + + // Register hardware operations + candev->hwspecops->request_io = hms30c7202_request_io; + candev->hwspecops->release_io = hms30c7202_release_io; + candev->hwspecops->reset = hms30c7202_reset; + /* private register read and write routines used */ + candev->hwspecops->write_register = NULL; /*hms30c7202_write_register;*/ + candev->hwspecops->read_register = NULL; /*hms30c7202_read_register;*/ + + return 0; +} + + +#define CHIP_TYPE "c_can" +/** + * hms30c7202_init_chip_data - Initialize chips + * @candev: Pointer to candevice/board structure + * @chipnr: Number of the CAN chip on the hardware card + * + * The function hms30c7202_init_chip_data() is used to initialize the hardware + * structure containing information about the CAN chips. + * %CHIP_TYPE represents the type of CAN chip. + * 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. + * File: src/template.c + */ +int hms30c7202_init_chip_data(struct candevice_t *candev, int chipnr) +{ + candev->chip[chipnr]->chip_type=CHIP_TYPE; + candev->chip[chipnr]->chip_base_addr=candev->io_addr; + + candev->chip[chipnr]->clock = 16000000; + + candev->chip[chipnr]->max_objects = NR_MSGOBJ; + + /*candev->chip[chipnr]->int_clk_reg = 0x0; + candev->chip[chipnr]->int_bus_reg = 0x0; + candev->chip[chipnr]->sja_cdr_reg = 0x0; + candev->chip[chipnr]->sja_ocr_reg = 0x0;*/ + + // Register chip operations + c_can_register(candev->chip[chipnr]->chipspecops); + + return 0; +} + + +/** + * hms30c7202_init_obj_data - Initialize message buffers + * @chip: Pointer to chip specific structure + * @objnr: Number of the message buffer + * + * The function hms30c7202_init_obj_data() is used to initialize the hardware + * structure containing information about the different message objects on the + * CAN chip. + * The entry @obj_base_addr represents the first memory address of the message + * object. + * Unless the hardware uses a segmented memory map, flags can be set zero. + * Return Value: The function always returns zero + * File: src/template.c + */ +int hms30c7202_init_obj_data(struct chip_t *chip, int objnr) +{ + + DEBUGMSG("(c%d)calling hms30c7202_init_obj_data( ...)\n", pchip->chip_nr); + + /* It seems, that there is no purpose to setup object base address */ + chip->msgobj[objnr]->obj_base_addr=0; + + /*can_msgobj_test_fl(pmsgobj,RX_MODE_EXT);*/ + return 0; +} + +/** + * hms30c7202_write_register - Low level write register routine + * @data: data to be written + * @address: memory address to write to + * + * The function hms30c7202_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/template.c + */ + +void hms30c7202_write_reg_w(const struct chip_t *pchip, u16 data, unsigned reg) +{ + int i; + u32 address = pchip->chip_base_addr + reg; + //unsigned long usecs = 1; + + //DEBUGMSG("Trying to write 0x%u16x to address 0x%lx\n",data,address); + + writew(data,address); + //udelay( usecs ); + for (i=0; i<5; i++); +} + +/** + * hms30c7202_read_register - Low level read register routine + * @address: memory address to read from + * + * The function hms30c7202_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/template.c + */ +u16 hms30c7202_read_reg_w(const struct chip_t *pchip, unsigned reg) +{ + u16 value, i; + u32 address = pchip->chip_base_addr + reg; + //unsigned long usecs = 1; + + //DEBUGMSG("Trying to read from address 0x%lx :",address); + + value = readw(address); + //udelay( usecs ); + for (i=0;i<5;i++); + value = readw(address); + //udelay( usecs ); + for (i=0;i<5;i++); + + //DEBUGMSG("0x%u16x\n",value); + return value; + +} + +/** + * hms30c7202_program_irq - program interrupts + * @candev: Pointer to candevice/board structure + * + * The function hms30c7202_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/template.c + */ +int hms30c7202_program_irq(struct candevice_t *candev) +{ + return 0; +} + +int hms30c7202_register(struct hwspecops_t *hwspecops) +{ + hwspecops->request_io = hms30c7202_request_io; + hwspecops->release_io = hms30c7202_release_io; + hwspecops->reset = hms30c7202_reset; + hwspecops->init_hw_data = hms30c7202_init_hw_data; + hwspecops->init_chip_data = hms30c7202_init_chip_data; + hwspecops->init_obj_data = hms30c7202_init_obj_data; + /* private register read and write routines used */ + hwspecops->write_register = NULL; /*hms30c7202_write_register;*/ + hwspecops->read_register = NULL; /*hms30c7202_read_register;*/ + hwspecops->program_irq = hms30c7202_program_irq; + return 0; +} + diff --git a/lincan/src/i82527.c b/lincan/src/i82527.c index 6897948..03c2dce 100644 --- a/lincan/src/i82527.c +++ b/lincan/src/i82527.c @@ -280,18 +280,29 @@ int i82527_config_irqs(struct chip_t *chip, short irqs) int i82527_pre_read_config(struct chip_t *chip, struct msgobj_t *obj) { - if (extended) { + unsigned long id=obj->rx_preconfig_id; + + can_msgobj_set_fl(obj,RX_MODE); + + if (extended || can_msgobj_test_fl(obj,RX_MODE_EXT)) { + id<<=3; + canobj_write_reg(chip,obj,id,iMSGID3); + canobj_write_reg(chip,obj,id>>8,iMSGID2); + canobj_write_reg(chip,obj,id>>16,iMSGID1); + canobj_write_reg(chip,obj,id>>24,iMSGID0); canobj_write_reg(chip,obj,MCFG_XTD,iMSGCFG); - } - else { + } else { + id<<=5; + canobj_write_reg(chip,obj,id,iMSGID1); + canobj_write_reg(chip,obj,id>>8,iMSGID0); canobj_write_reg(chip,obj,0x00,iMSGCFG); } + canobj_write_reg(chip,obj,(NEWD_RES|MLST_RES|TXRQ_RES|RMPD_RES), iMSGCTL1); canobj_write_reg(chip,obj,(MVAL_SET|TXIE_RES|RXIE_SET|INTPD_RES),iMSGCTL0); DEBUGMSG("i82527_pre_read_config: configured obj at 0x%08lx\n",obj->obj_base_addr); - return 0; } @@ -304,6 +315,8 @@ int i82527_pre_write_config(struct chip_t *chip, struct msgobj_t *obj, len = msg->length; if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH; + can_msgobj_clear_fl(obj,RX_MODE); + canobj_write_reg(chip,obj,(MVAL_SET|TXIE_SET|RXIE_RES|INTPD_RES),iMSGCTL0); canobj_write_reg(chip,obj,(RMPD_RES|TXRQ_RES|CPUU_SET|NEWD_RES),iMSGCTL1); @@ -549,33 +562,21 @@ static inline void i82527_irq_update_filter(struct chip_t *chip, struct msgobj_t *obj) { struct canfilt_t filt; - unsigned long id; if(canqueue_ends_filt_conjuction(obj->qends, &filt)) { + obj->rx_preconfig_id=filt.id; canobj_write_reg(chip,obj,(MVAL_RES|TXIE_RES|RXIE_RES|INTPD_RES),iMSGCTL0); if(obj->object == 15) { i82527_message15_mask(chip,filt.id,filt.mask); } - if (filt.flags&MSG_EXT) { - id=filt.id<<3; - canobj_write_reg(chip,obj,id,iMSGID3); - canobj_write_reg(chip,obj,id>>8,iMSGID2); - canobj_write_reg(chip,obj,id>>16,iMSGID1); - canobj_write_reg(chip,obj,id>>24,iMSGID0); - canobj_write_reg(chip,obj,MCFG_XTD,iMSGCFG); - } - else { - id=filt.id<<5; - canobj_write_reg(chip,obj,id,iMSGID1); - canobj_write_reg(chip,obj,id>>8,iMSGID0); - canobj_write_reg(chip,obj,0x00,iMSGCFG); - } + if (filt.flags&MSG_EXT) + can_msgobj_set_fl(obj,RX_MODE_EXT); + else + can_msgobj_clear_fl(obj,RX_MODE_EXT); - canobj_write_reg(chip,obj,(NEWD_RES|MLST_RES|TXRQ_RES|RMPD_RES), iMSGCTL1); - canobj_write_reg(chip,obj,(MVAL_SET|TXIE_RES|RXIE_SET|INTPD_RES),iMSGCTL0); + i82527_pre_read_config(chip, obj); CANMSG("i82527_irq_update_filter: obj at 0x%08lx\n",obj->obj_base_addr); - } } @@ -717,8 +718,6 @@ int i82527_filtch_rq(struct chip_t *chip, struct msgobj_t *obj) can_preempt_enable(); return 0; - - return 0; } int i82527_register(struct chipspecops_t *chipspecops) diff --git a/lincan/src/pcm3680.c b/lincan/src/pcm3680.c index cfe5856..2d17861 100644 --- a/lincan/src/pcm3680.c +++ b/lincan/src/pcm3680.c @@ -54,7 +54,7 @@ int pcm3680_request_io(struct candevice_t *candev) } /** - * template_elease_io - free reserved io memory range + * template_release_io - free reserved io memory range * @candev: pointer to candevice/board which releases io * * The function template_release_io() is used to free reserved io-memory. diff --git a/lincan/src/unican.c b/lincan/src/unican.c index 488d8e1..66466d6 100644 --- a/lincan/src/unican.c +++ b/lincan/src/unican.c @@ -918,7 +918,7 @@ int unican_pci_init_chip_data(struct candevice_t *candev, int chipnr) { int ret; candev->chip[chipnr]->chip_irq=candev->sysdevptr.pcidev->irq; - ret = unican_pci_init_chip_data(candev, chipnr); + ret = unican_init_chip_data(candev, chipnr); candev->chip[chipnr]->flags |= CHIP_IRQ_PCI; return ret; } -- 2.39.2