--- /dev/null
+/* 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
+};
+
#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<<MSGOBJ_OPENED_b)
#define MSGOBJ_TX_REQUEST (1<<MSGOBJ_TX_REQUEST_b)
#define MSGOBJ_IRQ_REQUEST (1<<MSGOBJ_IRQ_REQUEST_b)
#define MSGOBJ_WORKER_WAKE (1<<MSGOBJ_WORKER_WAKE_b)
#define MSGOBJ_FILTCH_REQUEST (1<<MSGOBJ_FILTCH_REQUEST_b)
+#define MSGOBJ_RX_MODE (1<<MSGOBJ_RX_MODE_b)
+#define MSGOBJ_RX_MODE_EXT (1<<MSGOBJ_RX_MODE_EXT_b)
#define can_msgobj_test_fl(obj,obj_fl) \
test_bit(MSGOBJ_##obj_fl##_b,&(obj)->obj_flags)
--- /dev/null
+/* hms30c7202_can.h - Hynix HMS30c7202 ARM device specific code\r
+ * Linux CAN-bus device driver.\r
+ * Written by Sebastian Stolzenberg email:stolzi@sebastian-stolzenberg.de\r
+ * Based on code from Arnaud Westenberg email:arnaud@wanadoo.nl\r
+ * and Ake Hedman, eurosource, akhe@eurosource.se\r
+ * Rewritten for new CAN queues by Pavel Pisa - OCERA team member\r
+ * email:pisa@cmp.felk.cvut.cz\r
+ * This software is released under the GPL-License.\r
+ * Version lincan-0.2 9 Jul 2003\r
+ */\r
+\r
+#ifndef __HMS30C7202_CAN__\r
+# define __HMS30C7202_CAN__\r
+\r
+int hms30c7202_init_hw_data(struct candevice_t *candev);\r
+int hms30c7202_init_chip_data(struct candevice_t *candev, int chipnr);\r
+int hms30c7202_request_io(struct candevice_t *candev);\r
+int hms30c7202_release_io(struct candevice_t *candev);\r
+int hms30c7202_reset( struct candevice_t *candev);\r
+void hms30c7202_write_reg_w(const struct chip_t *pchip, u16 data, unsigned reg);\r
+u16 hms30c7202_read_reg_w(const struct chip_t *pchip, unsigned reg);\r
+\r
+\r
+\r
+int hms30c7202_init_obj_data(struct chip_t *chip, int objnr);\r
+int hms30c7202_program_irq(struct candevice_t *candev);\r
+\r
+#endif /* __HMS30C7202_CAN__ */\r
* %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;
struct canmsg_t rx_msg;
struct chip_t *hostchip;
+
+ unsigned long rx_preconfig_id;
atomic_t obj_used;
struct list_head obj_users;
--- /dev/null
+/* 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; i<pchip->max_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;
+}
+*/
--- /dev/null
+/* 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; i<prtr_search->rtr_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;
+}
+
--- /dev/null
+/* 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 <linux/delay.h>
+
+#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;
+}
+
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;
}
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);
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);
-
}
}
can_preempt_enable();
return 0;
-
- return 0;
}
int i82527_register(struct chipspecops_t *chipspecops)
}
/**
- * 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.
{
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;
}