#include "../include/can_sysdep.h"
#include "../include/main.h"
#include "../include/mscan.h"
-#include "../include/mpc5200.h"
-
-#define myDEBUG 1 /* enable debug for MPC5200 with MSCAN only */
-
-#if myDEBUG
- #define DEBUGMSG(fmt,args...) can_printk(KERN_ERR "lincan (debug): " fmt,##args)
-#endif
+//#include "../include/mpc5200.h"
#define MSCAN_MAX_TRANSMIT_WAIT_LOOPS 20
-#define MSCAN_MAX_SETTING_WAIT_LOOPS 25 /* maximal loop count while checking Chip reply to action */
+#define MSCAN_MAX_SETTING_WAIT_LOOPS 25 /* maximal loop count while checking Chip reply to action ~ 5 ms */
#define MSCAN_MAX_IRQ_WAIT_LOOPS 25
+CAN_DEFINE_SPINLOCK(mscan_prewr_lock);
void mscan_irq_read_handler(struct canchip_t *chip, struct msgobj_t *obj);
void mscan_irq_write_handler(struct canchip_t *chip, struct msgobj_t *obj);
void mscan_setup_ctrl_regs(struct canmsg_t * msg, uint16_t * ctrl0, uint16_t * ctrl1, uint16_t * ctrl2);
void mscan_msg_from_rxbuffer(struct canchip_t * chip, struct canmsg_t * msg);
-void mscan_setup_txbuffer(struct canchip_t * chip, struct canmsg_t * msg, int buffer);
+void mscan_setup_txbuffer(struct canchip_t * chip, struct canmsg_t * msg);
void mscan_notifyRXends(struct msgobj_t * obj, int what);
int mscan_check_txbuff_stat(struct canchip_t *chip, int buffer);
static int mscan_init_mode_active(struct canchip_t *chip);
static int mscan_sleep_mode_active(struct canchip_t *chip);
+static int mscan_enter_init_mode(struct canchip_t * chip);
+static int mscan_enter_sleep_mode(struct canchip_t * chip);
+
static reg_t mscan_get_flags(struct canchip_t * chip, reg_t flags, unsigned reg_addr);
static void mscan_set_flags(struct canchip_t * chip, reg_t flags, unsigned reg_addr);
static void mscan_clear_flags(struct canchip_t * chip, reg_t flags, unsigned reg_addr);
+static uint16_t mscan_get_irq_flags(struct canchip_t * chip);
static void mscan_clear_buffer(struct canchip_t * chip, unsigned start_addr);
+static int mscan_abort_msg(struct canchip_t * chip, reg_t buffer_mask);
+
+#if MPC5200_DBG
+ static void dump_regs(struct canchip_t * chip)
+ {
+ CANMSG("MSCAN reg dump\n");
+ CANMSG("CTL0 0x%02x\tCTL1 0x%02x\tBTR0 0x%02x\tBTR1 0x%02x\n",
+ mscan_get_flags(chip, 0xff, MSCAN_CTL0),
+ mscan_get_flags(chip, 0xff, MSCAN_CTL1),
+ mscan_get_flags(chip, 0xff, MSCAN_BTR0),
+ mscan_get_flags(chip, 0xff, MSCAN_BTR1));
+
+ CANMSG("RFLG 0x%02x\tRIER 0x%02x\tTFLG 0x%02x\tTIER 0x%02x\n",
+ mscan_get_flags(chip, 0xff, MSCAN_RFLG),
+ mscan_get_flags(chip, 0xff, MSCAN_RIER),
+ mscan_get_flags(chip, 0xff, MSCAN_TFLG),
+ mscan_get_flags(chip, 0xff, MSCAN_TIER));
+
+ CANMSG("TARQ 0x%02x\tTAAK 0x%02x\tTBSEL 0x%02x\tIDAC 0x%02x\n",
+ mscan_get_flags(chip, 0xff, MSCAN_TARQ),
+ mscan_get_flags(chip, 0xff, MSCAN_TAAK),
+ mscan_get_flags(chip, 0xff, MSCAN_TBSEL),
+ mscan_get_flags(chip, 0xff, MSCAN_IDAC));
+
+ CANMSG("RXERR 0x%02x\tTXERR 0x%02x\n",
+ mscan_get_flags(chip, 0xff, MSCAN_RXERR),
+ mscan_get_flags(chip, 0xff, MSCAN_TXERR));
+
+ }
+
+ static void dump_buff(struct canchip_t * chip, unsigned offset_addr)
+ {
+ volatile struct mscan_msg_buffer * buff = (struct mscan_msg_buffer *)(chip->chip_base_addr + offset_addr);
+
+ CANMSG("MSCAN buffer dump\n");
+
+ /* structural access */
+ CANMSG("Data0 0x%02x Data1 0x%02x Data2 0x%02x Data3 0x%02x Data4 0x%02x Data5 0x%02x Data6 0x%02x Data7 0x%02x\n",
+ buff->data_0, buff->data_1, buff->data_2, buff->data_3, buff->data_4, buff->data_5, buff->data_6, buff->data_7);
+ CANMSG("Data Len %d\tPriority 0x%02x\n",
+ buff->data_len, buff->local_prio);
+ CANMSG("IDR0 0x%02x\tIDR1 0x%02x\tIDR2 0x%02x\tIDR3 0x%02x\n",
+ buff->id_0, buff->id_1, buff->id_2, buff->id_3);
+
+ }
+
+ static void dump_filter(struct canchip_t * chip)
+ {
+ volatile struct mscan_flt_regs * flt = (struct mscan_flt_regs *)(chip->chip_base_addr + MSCAN_IDAR0);
+
+ CANMSG("MSCAN Acceptance filter dump\n");
+
+ CANMSG("IDAC 0x%02x\n", mscan_get_flags(chip, MSCAN_IDAC_IDAM | MSCAN_IDAC_IDHIT, MSCAN_IDAC));
+
+ CANMSG("IDAR0 0x%02x\tIDAR1 0x%02x\tIDAR2 0x%02x\tIDAR3 0x%02x\n",
+ flt->acp_id_0, flt->acp_id_1, flt->acp_id_2, flt->acp_id_3);
+ CANMSG("IDMR0 0x%02x\tIDMR1 0x%02x\tIDMR2 0x%02x\tIDMR3 0x%02x\n",
+ flt->acp_mask_0, flt->acp_mask_1, flt->acp_mask_2, flt->acp_mask_3);
+
+ CANMSG("IDAR4 0x%02x\tIDAR5 0x%02x\tIDAR6 0x%02x\tIDAR7 0x%02x\n",
+ flt->acp_id_4, flt->acp_id_5, flt->acp_id_6, flt->acp_id_7);
+ CANMSG("IDMR4 0x%02x\tIDMR5 0x%02x\tIDMR6 0x%02x\tIDMR7 0x%02x\n",
+ flt->acp_mask_4, flt->acp_mask_5, flt->acp_mask_6, flt->acp_mask_7);
+ }
+#endif /* MPC5200_DBG */
+
+
+/* macro for standardized CAN Bus Status change report */
+#define MSCAN_STAT_CHANGE(msg,idx) CANMSG("MSCAN chip %d %s\n", idx, msg)
/* Enable folowing IRQs
- * MSCAN_TIER_TXE - Transmit Empty Interrupt
+ * MSCAN_TIER_TXE - Transmit Empty Interrupt - Set and Cleared during TX proccess not during init
* MSCAN_RIER_RXFIE - Receive Buffer Full
+ * MSCAN_RIER_RSTATE - Receiver Status Change Enable: 0-Never, 1-BusOff, 2-BusOff+RxErr, 3-All
+ * MSCAN_RIER_TSTATE - Transmitter Status Change Enable: 0-Never, 1-BusOff, 2-BusOff+TxErr, 3-All
* MSCAN_RIER_OVRIE - Overrun
* MSCAN_RIER_CSCIE - CAN Status Change
*/
-uint16_t mscan_IRQs = (MSCAN_TIER_TXE << 8) | MSCAN_RIER_RXFIE | MSCAN_RIER_OVRIE | MSCAN_RIER_CSCIE; /* TX interrupt flag is held shifter */
+uint16_t mscan_IRQs = MSCAN_RIER_RXFIE |
+ MSCAN_RIER_RSTATE | MSCAN_RIER_TSTATE |
+ MSCAN_RIER_OVRIE | MSCAN_RIER_CSCIE; /* TX interrupt flag is held shifted */
/* 1 - enable interrupt, 0 - interrupt is masked */
+/* used to distinguish which direction (TX/RX) caused Can Bus State change interrupt */
+reg_t rxstat = 0;
+reg_t txstat = 0;
+
+/* initial acceptance filter settings */
+#define INIT_STD_ID 0x0000
+#define INIT_STD_MASK 0x0fff /* accept all messages - 11 mask bits and LSB is RTR */
+
+
/* ************************************************************************************************************************************* */
DEBUGMSG("Configuring chip...\n");
- if (!(err = mscan_enable_configuration(chip)))
+ if ((err = mscan_enable_configuration(chip)))
return err;
if (!chip->baudrate)
chip->baudrate=1000000; /* default baudrate set to 1Mbit */
- if (!(err = mscan_baud_rate(chip, chip->baudrate, chip->clock, 0, 750, 0)))
+ if ((err = mscan_baud_rate(chip, chip->baudrate, chip->clock, 0, 750, 0)))
return err;
- if (!(err = mscan_disable_configuration(chip)))
+ if ((err = mscan_disable_configuration(chip)))
return err;
/* IRQ mask could be set only when NOT in INIT mode */
- if (!(err = mscan_config_irqs(chip, mscan_IRQs)))
+ if ((err = mscan_config_irqs(chip, mscan_IRQs)))
return err;
return 0;
int mscan_enable_configuration(struct canchip_t *chip)
{
/* Do not clear buffers here, they may contain valid data ! */
- int i = 0;
- DEBUGMSG("Enabling configuration...\n");
+ DEBUGMSG("config ENABLE\n");
if (mscan_init_mode_active(chip)) /* chip is already in config mode */
- return 0;
+ {
+ DEBUGMSG("config ENABLE ... already in INIT mode\n");
+ goto econf_exit_ok;
+ }
/* Disable interrupt */
can_disable_irq(chip->chip_irq);
/* Sleep mode - disable CAN activity after completing current operation */
- mscan_set_flags(chip, MSCAN_CTL0_SLPRQ, MSCAN_CTL0);
-
- /* Waits until chip enters Sleep mode - finishes current TX/RX operation */
- while (!mscan_get_flags(chip, MSCAN_CTL1_SLPAK, MSCAN_CTL1) && i++ < MSCAN_MAX_SETTING_WAIT_LOOPS)
- udelay(200);
-
- if (i >= MSCAN_MAX_SETTING_WAIT_LOOPS) {
- CANMSG("Error entering Sleep mode (enable configuration) \n");
- can_enable_irq(chip->chip_irq);
- return -EBUSY;
- }
-
+ /* if controler not synced to bus, skip sleep mode */
+ if (!mscan_sleep_mode_active(chip) &&
+ mscan_get_flags(chip, MSCAN_CTL0_SYNCH, MSCAN_CTL0))
+ if (mscan_enter_sleep_mode(chip))
+ {
+ /* cannot enter sleep mode */
+ DUMPREGS(chip);
+ DEBUGMSG("Forcig INIT\n");
+ }
+
/* now we can enter Init mode */
- mscan_set_flags(chip, MSCAN_CTL0_INITRQ, MSCAN_CTL0);
-
- i = 0;
- /* Waits until chip enters Init mode */
- while (!mscan_get_flags(chip, MSCAN_CTL1_INITAK, MSCAN_CTL1) && i++ < MSCAN_MAX_SETTING_WAIT_LOOPS)
- udelay(200);
-
- if (i >= MSCAN_MAX_SETTING_WAIT_LOOPS) {
- CANMSG("Error entering Init mode (enable configuration) \n");
- can_enable_irq(chip->chip_irq);
- return -EBUSY;
- }
-
+ if(mscan_enter_init_mode(chip))
+ goto econf_exit_busy;
+econf_exit_ok:
+ /* DEBUGMSG("config ENABLE ... OK\n"); */
return 0;
+
+econf_exit_busy:
+ /* DEBUGMSG("config ENABLE ... failed !\n"); */
+ can_enable_irq(chip->chip_irq);
+ return -EBUSY;
}
int mscan_disable_configuration(struct canchip_t *chip)
/* Do not clear buffers here, they may contain valid data ! */
int i = 0;
- DEBUGMSG("Disabling configuration mode...\n");
+ DEBUGMSG("config DISABLE\n");
if (!mscan_init_mode_active(chip) && !mscan_sleep_mode_active(chip)) /* chip is already in normal mode */
+ {
+ DEBUGMSG("config DISABLE ... not in INIT mode\n");
return 0;
+ }
/* disable Init mode */
udelay(200);
if (i >= MSCAN_MAX_SETTING_WAIT_LOOPS) {
- CANMSG("Error leaving Init mode (disable configuration) \n");
+ DEBUGMSG("Error leaving Init mode (disable configuration) \n");
return -EBUSY;
}
udelay(200);
if (i >= MSCAN_MAX_SETTING_WAIT_LOOPS) {
- CANMSG("Error leaving Sleep mode (disable configuration) \n");
+ DEBUGMSG("Error leaving Sleep mode (disable configuration) \n");
return -EBUSY;
}
/* Enable interrupt */
can_enable_irq(chip->chip_irq);
+ /* DEBUGMSG("config DISABLE ... OK\n"); */
+
return 0;
}
reg_t btr0, btr1;
- DEBUGMSG("Seting Baud rate...\n");
-
/* Use CIA recommended sample points */
if (!sampl_pt)
{
DEBUGMSG("Setting %lu bps.\n", best_rate);
- /* all values has offset -1 */
- brp--; tseg1--; tseg2--;
+ /* all values has offset -1 in MSCAN memory */
+ best_brp--; tseg1--; tseg2--;
- btr0 = (brp & MSCAN_BTR0_BRP) | ((sjw << 6) & MSCAN_BTR0_SJW);
+ btr0 = (best_brp & MSCAN_BTR0_BRP) | ((sjw << 6) & MSCAN_BTR0_SJW);
btr1 = (tseg1 & MSCAN_BTR1_TSEG1) | ((tseg2 << 4) & MSCAN_BTR1_TSEG2);
mscan_set_btregs(chip, btr0, btr1);
btr1 &= ~MSCAN_BTR1_SAMP; /* use one-point sample, not three smaples per bit */
+ DEBUGMSG("BTR0 0x%02x BTR1 0x%02x\n", btr0, btr1);
+
can_write_reg(chip, btr0, MSCAN_BTR0);
can_write_reg(chip, btr1, MSCAN_BTR1);
/* DEBUGMSG("Attaching to chip %d.\n", chip->chip_idx); */
reg_t ctl1;
+
/* Clear all TX and RX buffers */
if (mscan_clear_objects(chip))
return -ENODEV;
+
/* Transmitt Abort Request Register (TARQ) is clean after INIT mode - no need to clear it explicitly */
/* Control Register 0 (CTL0) is clean after INIT too (excepts fro WUPE, SLRQ and INITRQ) */
/* MSCAN_CTL1_WUPM | WakeUp mode not used */
/* MSCAN_CTL1_SLPAK | ReadOnly */
/* MSCAN_CTL1_INITAK | ReadOnly */
-
+
can_write_reg(chip, ctl1, MSCAN_CTL1);
+
+ /* set filter to accept all STD messages */
+ if (mscan_standard_mask(chip, INIT_STD_ID, INIT_STD_MASK))
+ {
+ DEBUGMSG("Failed to set initial filter ID: %d Mask: 0x%04x\n", INIT_STD_ID, INIT_STD_MASK);
+ }
+
/* set Baudrate and Interrupts */
if (mscan_chip_config(chip))
return -ENODEV;
if (mscan_disable_configuration(chip))
return -ENODEV;
- /* Enable interrupt */
- can_enable_irq(chip->chip_irq);
+ /* Enable interrupt - called in mpc5200_request_io */
+ /* can_enable_irq(chip->chip_irq); */
+
+ DEBUGMSG("Successfully attached to chip [%02d].\n", chip->chip_idx);
- CANMSG("Successfully attached to chip [%02d].\n", chip->chip_idx);
return 0;
}
int mscan_release_chip(struct canchip_t *chip)
{
- mscan_stop_chip(chip); /* we are in INIT mode */
+ /* IRQ unmapped in lincan driver core */
can_disable_irq(chip->chip_irq);
- mscan_clear_objects(chip);
+ mscan_clear_objects(chip); /* Cannot be called in INIT mode */
+
+
+ mscan_stop_chip(chip); /* we are in INIT mode */
/* disable chip */
mscan_clear_flags(chip, MSCAN_CTL1_CANE, MSCAN_CTL1);
/* we use two 32-bit acceptance filters */
- mscan_set_flags(chip, 0x30, MSCAN_IDAC);
+ mscan_clear_flags(chip, MSCAN_IDAC_IDAM, MSCAN_IDAC);
idr0 = (reg_t)((code & 0x0ff0) >> 4); /* 8 most significant bits */
- idr1 = (reg_t)((code & 0x000f) << 4); /* 3 last bits, RTR as MSB, IDE=0 doesnt have to be set explicitly */
+ idr1 = (reg_t)((code & 0x000f) << 4); /* 3 last bits, RTR as LSB, IDE=0 doesnt have to be set explicitly */
mr0 = (reg_t)((mask & 0x0ff0) >> 4);
- mr1 = (reg_t)((mask & 0x000f) << 4);
+ mr1 = (reg_t)(((mask & 0x000f) << 4) & 0xf0); /* to be sure IDE=0 */
can_write_reg(chip, idr0, MSCAN_IDAR0);
can_write_reg(chip, mr0, MSCAN_IDMR0);
can_write_reg(chip, mr1, MSCAN_IDMR1);
+ /* use same filtering settings for second filter */
+ can_write_reg(chip, idr0, MSCAN_IDAR4);
+ can_write_reg(chip, idr1, MSCAN_IDAR5);
+
+ can_write_reg(chip, mr0, MSCAN_IDMR4);
+ can_write_reg(chip, mr1, MSCAN_IDMR5);
+
+
DEBUGMSG("Set standard_mask [id:0x%04x RTR=%d, m:0x%04x RTR=%d]\n", code >> 1, code & 0x0001, mask >> 1, mask & 0x0001);
+ DUMPFLT(chip);
+
return 0;
}
/* we use two 32-bit acceptance filters */
- mscan_set_flags(chip, 0x30, MSCAN_IDAC);
+ mscan_clear_flags(chip, MSCAN_IDAC_IDAM, MSCAN_IDAC);
idr0 = (reg_t)((code & 0x7fa00000) >> 22); /* EXT_ID {29:21} */
can_write_reg(chip, mr2, MSCAN_IDMR2);
can_write_reg(chip, mr3, MSCAN_IDMR3);
+ /* use same filtering settings for second filter */
+ can_write_reg(chip, idr0, MSCAN_IDAR4);
+ can_write_reg(chip, idr1, MSCAN_IDAR5);
+ can_write_reg(chip, idr2, MSCAN_IDAR6);
+ can_write_reg(chip, idr3, MSCAN_IDAR7);
+
+ can_write_reg(chip, mr0, MSCAN_IDMR4);
+ can_write_reg(chip, mr1, MSCAN_IDMR5);
+ can_write_reg(chip, mr2, MSCAN_IDMR6);
+ can_write_reg(chip, mr3, MSCAN_IDMR7);
+
+
DEBUGMSG("Set extended_mask [id:0x%08x RTR=%lu, m:0x%08x RTR=%lu]\n", (uint32_t)(code >> 1), code & 0x00000001, (uint32_t)(mask >> 1), mask & 0x00000001);
+ DUMPFLT(chip);
return 0;
}
int mscan_pre_read_config(struct canchip_t *chip, struct msgobj_t *obj)
{
- DEBUGMSG("Pre read config\n");
+ DEBUGRX("Pre read config\n");
/* MSCAN has only one buffer, which is already initialized */
int mscan_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj, struct canmsg_t *msg)
{
reg_t txf;
+ reg_t bf;
int buff_no;
- DEBUGMSG("Pre write config\n");
-
+ can_spin_lock(&mscan_prewr_lock);
can_preempt_disable();
+ DEBUGTX("Pre write config\n");
/* find free buffer */
txf = mscan_get_flags(chip, MSCAN_TFLG_TXE, MSCAN_TFLG);
- for (buff_no = 0; buff_no < 3 && (txf ^ (0x01 << buff_no)); buff_no++) { }
+ for (buff_no = 0; buff_no < 3 && !(txf & (0x01 << buff_no)); buff_no++) { }
if (buff_no >= 3)
- return -ENODEV; /* no free buffer found */
+ {
+ DEBUGTX("no free buffer found [0x%02x]\n", txf);
+ goto pwrite_exit_fail; /* no free buffer found */
+ }
- mscan_setup_txbuffer(chip, msg, buff_no);
- /* clear TX Buffer Empty flag (by writing '1') to initiate trasmition */
- mscan_set_flags(chip, (reg_t)(0x01 << buff_no), MSCAN_TFLG);
+ /* Select buffer */
+ bf = (reg_t)(0x01 << buff_no);
+ can_write_reg(chip, bf & MSCAN_TBSEL_TX, MSCAN_TBSEL);
- can_preempt_enable();
+ DEBUGTX("Buffer %d\n", buff_no);
+
+ mscan_setup_txbuffer(chip, msg);
+ /* store buffer flag into canmsg_t->cob for future
+ * use in send_msg
+ * canmsg_t->cob is not used according to Lincan documentation */
+ msg->cob = bf;
+
+
+ can_preempt_enable();
+ can_spin_unlock(&mscan_prewr_lock);
return 0;
+
+pwrite_exit_fail:
+ can_preempt_enable();
+ can_spin_unlock(&mscan_prewr_lock);
+ return -ENODEV; /* no free buffer found */
}
int mscan_send_msg(struct canchip_t *chip, struct msgobj_t *obj, struct canmsg_t *msg)
{
- DEBUGMSG("Send Message\n");
+ DEBUGTX("Send Message\n");
- /* nothing to do here - message is already set to transmit in pre_write_config */
+ /* turn on IRQ for this buffer */
+ can_write_reg(chip, msg->cob, MSCAN_TIER);
+
+ /* clear TX Buffer Empty flag (by writing '1') to initiate trasmition */
+ can_write_reg(chip, msg->cob, MSCAN_TFLG);
return 0;
}
int mscan_remote_request(struct canchip_t *chip, struct msgobj_t *obj)
{
- CANMSG("mscan_remote_request not implemented\n");
+ DEBUGMSG("mscan_remote_request not implemented\n");
return -ENOSYS;
}
int mscan_irq_handler(int irq, struct canchip_t *chip)
{
/*
- MSCAN_RFLG_WUPIF - WakeUp Interrupt Flag - rw
- MSCAN_RFLG_CSCIF - CAN Status Change Interrupt Flag - rw
- MSCAN_RFLG_RSTAT - Receiver Status Bits: 0-RxOK, 1-RxWRN, 2-RxERR, 3-BusOff - ro
- MSCAN_RFLG_TSTAT - Transmitter Status Bits: 0-TxOK, 1-TxWRN, 2-TxErr, 3-BusOff - ro
- MSCAN_RFLG_OVRIF - Overrun Interrupt Flag - rw
- MSCAN_RFLG_RXF - Receive Buffer Full - rw
+ MSCAN_RFLG_CSCIF - CAN Status Change Interrupt Flag
+ MSCAN_RFLG_RSTAT - Receiver Status Bits: 0-RxOK, 1-RxWRN, 2-RxERR, 3-BusOff
+ MSCAN_RFLG_TSTAT - Transmitter Status Bits: 0-TxOK, 1-TxWRN, 2-TxErr, 3-BusOff
+ MSCAN_RFLG_OVRIF - Overrun Interrupt Flag
+ MSCAN_RFLG_RXF - Receive Buffer Full
MSCAN_TFLG_TXE - Transmitter Buffer Empty */
/* get IRQs */
- uint16_t irq_reg;
+ uint16_t irq_reg, tx_irq;
+ reg_t irq_rstat, irq_tstat;
short loop_cnt = MSCAN_MAX_IRQ_WAIT_LOOPS;
- irq_reg = (mscan_get_flags(chip, (reg_t)((mscan_IRQs >> 8) & 0xff), MSCAN_TFLG) << 8) |
- (mscan_get_flags(chip, (reg_t)(mscan_IRQs & 0xff), MSCAN_RFLG));
- DEBUGMSG("irq: %d", irq);
- DEBUGMSG("IRQ Handler: MSCAN_IRR: 0x%04x\n", irq_reg);
+ tx_irq = (MSCAN_TFLG_TXE << 8); /* to spare few tacts in IRQ loop */
+
+ irq_reg = mscan_get_irq_flags(chip);
+ DEBUGMSG("IRQ Handler chip %d (%d)\n", chip->chip_idx, irq);
+
do {
+ if(!loop_cnt--)
+ goto irqhnd_exit_stuck;
- if(!loop_cnt--) {
- CANMSG("mscan_irq_handler IRQ %d stuck\n", irq);
- return CANCHIP_IRQ_STUCK;
- }
+ DEBUGMSG("IRR: 0x%04x\n", irq_reg);
/* Received message */
if (irq_reg & MSCAN_RFLG_RXF)
{
- DEBUGMSG("Received message");
+ DEBUGRX("Received message\n");
mscan_irq_read_handler(chip, chip->msgobj[0]);
/* RXPR flag for this msgobj is cleared during irq_read_handler*/
mscan_set_flags(chip, MSCAN_RFLG_RXF, MSCAN_RFLG);
}
- /* Receive bus off/error/warning */
- if (irq_reg & MSCAN_RFLG_RSTAT)
+
+ /* Can Status change - due to RX/TX error counters */
+ if(irq_reg & MSCAN_RFLG_CSCIF)
{
- switch (((irq_reg & MSCAN_RFLG_RSTAT) >> 4) & 0x03)
- {
- case 3: /* Bus off */
- CANMSG("Error: entering RX BUS OFF state");
+ irq_rstat = (irq_reg >> 4) & 0x03;
+ irq_tstat = (irq_reg >> 2) & 0x03;
- chip->msgobj[0]->ret=-1;
- /* notify RX */
- mscan_notifyRXends(chip->msgobj[0], CANQUEUE_NOTIFY_ERROR);
- break;
-
- case 2: /* bus - error passive */
- CANMSG("Warning: entering ERROR PASSIVE state REC: %d\n", (reg_t)can_read_reg(chip, MSCAN_RXERR));
- /* Show warning only */
- break;
-
- case 1: /* bus - warning */
- CANMSG("Bus Warning: REC: %d\n", (reg_t)can_read_reg(chip, MSCAN_RXERR));
- /* Show warning only */
- break;
+ /* Receive bus off/error/warning */
+ if (irq_rstat ^ rxstat) /* check whether RSTAT changed */
+ {
+ switch (irq_rstat)
+ {
+ case 3: /* Bus off */
+ MSCAN_STAT_CHANGE("RX: BUS OFF", chip->chip_idx);
+
+ chip->msgobj[0]->ret=-1;
+
+ /* notify RX */
+ mscan_notifyRXends(chip->msgobj[0], CANQUEUE_NOTIFY_ERROR);
+ break;
+
+ case 2: /* bus - error passive */
+ MSCAN_STAT_CHANGE("RX: ERROR PASSIVE", chip->chip_idx);
+ /* Show warning only */
+ break;
+
+ case 1: /* bus - warning */
+ MSCAN_STAT_CHANGE("RX: Bus Warning", chip->chip_idx);
+ /* Show warning only */
+ break;
+
+ case 0: /* bus - OK */
+ MSCAN_STAT_CHANGE("RX: Bus OK", chip->chip_idx);
+ /* Show warning only */
+ break;
+ }
+ rxstat = irq_rstat; /* update static RX status field */
}
-
- /* reset flag */
- mscan_set_flags(chip, MSCAN_RFLG_RSTAT, MSCAN_RFLG);
- }
-
- /* Transmit bus off/error/warning */
- if (irq_reg & MSCAN_RFLG_TSTAT)
- {
- switch (((irq_reg & MSCAN_RFLG_TSTAT) >> 1) & 0x03)
+
+ /* Transmit bus off/error/warning */
+ if (irq_tstat ^ txstat)
{
- case 3: /* Bus off */
- CANMSG("Error: entering TX BUS OFF state");
-
- /* notify TX end */
- if(chip->msgobj[0]->tx_slot)
- canque_notify_inends(chip->msgobj[0]->tx_qedge, CANQUEUE_NOTIFY_ERROR);
- break;
-
- case 2: /* bus - error passive */
- CANMSG("Warning: entering ERROR PASSIVE state TEC: %d\n", (reg_t)can_read_reg(chip, MSCAN_TXERR));
- /* Show warning only */
- break;
-
- case 1: /* bus - warning */
- CANMSG("Bus Warning: TEC: %d\n", (reg_t)can_read_reg(chip, MSCAN_TXERR));
- /* Show warning only */
- break;
+ switch (irq_tstat)
+ {
+ case 3: /* Bus off */
+ MSCAN_STAT_CHANGE("TX: BUS OFF", chip->chip_idx);
+
+ /* notify TX end */
+ if(chip->msgobj[0]->tx_slot)
+ canque_notify_inends(chip->msgobj[0]->tx_qedge, CANQUEUE_NOTIFY_ERROR);
+ break;
+
+ case 2: /* bus - error passive */
+ MSCAN_STAT_CHANGE("TX: ERROR PASSIVE", chip->chip_idx);
+ /* Show warning only */
+ break;
+
+ case 1: /* bus - warning */
+ MSCAN_STAT_CHANGE("TX: Bus Warning", chip->chip_idx);
+ /* Show warning only */
+ break;
+
+ case 0: /* bus - OK */
+ MSCAN_STAT_CHANGE("TX: Bus OK", chip->chip_idx);
+ /* Show warning only */
+ break;
+ }
+ txstat = irq_tstat; /* update static TX status field */
}
-
+
/* reset flag */
- mscan_set_flags(chip, MSCAN_RFLG_TSTAT, MSCAN_RFLG);
+ mscan_set_flags(chip, MSCAN_RFLG_CSCIF, MSCAN_RFLG);
}
/* Message Overrun/Overwritten */
}
/* Mailbox empty - after message was sent */
- if ((irq_reg >> 8) & MSCAN_TFLG_TXE)
+ if (irq_reg & tx_irq)
{
- /* Clear TXACK flag */
- mscan_set_flags(chip, MSCAN_TFLG_TXE, MSCAN_TFLG);
+ DEBUGTX("Buffer empty interrupt\n");
+
+ /* clear propriate TXE IRE Enabled flag */
+ can_spin_lock(mscan_prewr_lock);
+ mscan_clear_flags(chip, (irq_reg >> 8) & MSCAN_TIER_TXE, MSCAN_TIER);
+ can_spin_unlock(mscan_prewr_lock);
+
- /* sends message */
- mscan_wakeup_tx(chip, chip->msgobj[0]);
+ /* sends message */
+ mscan_wakeup_tx(chip, chip->msgobj[0]);
}
- irq_reg = (mscan_get_flags(chip, (reg_t)((mscan_IRQs >> 8) & 0xff), MSCAN_TFLG) << 8) |
- (mscan_get_flags(chip, (reg_t)(mscan_IRQs & 0xff), MSCAN_RFLG));
- } while(irq_reg & mscan_IRQs);
+ irq_reg = mscan_get_irq_flags(chip);
+
+ /* omit RSTAT and TSTAT - they're used only in CSCIF handler */
+ } while(irq_reg &
+ mscan_IRQs &
+ ~(MSCAN_RFLG_RSTAT | MSCAN_RFLG_TSTAT));
+
return CANCHIP_IRQ_HANDLED;
+
+irqhnd_exit_stuck:
+ DEBUGMSG("mscan_irq_handler IRQ %d stuck\n", irq);
+ return CANCHIP_IRQ_STUCK;
}
int mscan_irq_accept(int irq, struct canchip_t *chip)
{
- CANMSG("mscan_irq_accept NOT IMPLEMENTED\n");
+ DEBUGMSG("mscan_irq_accept NOT IMPLEMENTED\n");
return -ENOSYS;
}
int mscan_config_irqs(struct canchip_t *chip, short irqs)
{
int err;
- reg_t tier, rier;
+ reg_t rier, tier;
+
+ DEBUGMSG("config IRQs\n");
if (mscan_init_mode_active(chip))
{
- CANMSG("MSCAN: Setting Up IRQs while INIT active \n");
+ DEBUGMSG("MSCAN: Setting Up IRQs while INIT active \n");
return -EBUSY;
}
- tier = (reg_t)((irqs >> 8) & 0x00ff & ~MSCAN_TIER_RSVD);
rier = (reg_t)(irqs & 0x00ff);
+ tier = (reg_t)((irqs >> 8) & 0x00ff);
- if(!(err = mscan_clear_irq_flags(chip)))
+ if((err = mscan_clear_irq_flags(chip)))
return err;
can_write_reg(chip, rier, MSCAN_RIER);
can_write_reg(chip, tier, MSCAN_TIER);
- CANMSG("IRQ Mask set [0x%02x]\n", irqs);
+ DEBUGMSG("IRQ Mask set [rier: 0x%02x]\n", rier);
return 0;
}
int mscan_check_txbuff_stat(struct canchip_t *chip, int buffer)
{
/* Transmition is complete return 0 - no error */
- reg_t txf = mscan_get_flags(chip, MSCAN_TFLG_TXE, MSCAN_TFLG);
+ reg_t txf = mscan_get_flags(chip, MSCAN_TFLG_TXE & (0x01 << buffer), MSCAN_TFLG);
return (txf ^ (0x01 << buffer));
}
int mscan_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj)
{
- DEBUGMSG("WakeUP TX\n");
-
can_preempt_disable();
+ DEBUGMSG("WakeUP TX\n");
- can_msgobj_set_fl(obj,TX_REQUEST);
- if(!can_msgobj_test_and_set_fl(obj,TX_LOCK) &&
- (!mscan_check_txbuff_stat(chip, 0) ||
- !mscan_check_txbuff_stat(chip, 1) ||
- !mscan_check_txbuff_stat(chip, 2)))
- { /* enable transmition only if MB is empty */
- can_msgobj_clear_fl(obj,TX_REQUEST);
-
- mscan_irq_write_handler(chip, obj);
-
- can_msgobj_clear_fl(obj,TX_LOCK);
- }
- else
- can_msgobj_clear_fl(obj,TX_REQUEST);
+ can_msgobj_set_fl(obj, TX_REQUEST);
+ while(!can_msgobj_test_and_set_fl(obj, TX_LOCK)) {
+ can_msgobj_clear_fl(obj, TX_REQUEST);
+
+ /* enable transmition only if any TX buffer is empty */
+ if (mscan_get_flags(chip, MSCAN_TFLG_TXE, MSCAN_TFLG))
+ mscan_irq_write_handler(chip, obj);
+ else
+ {
+ can_msgobj_clear_fl(obj, TX_LOCK);
+ break;
+ }
+
+
+ can_msgobj_clear_fl(obj, TX_LOCK);
+
+ if(!can_msgobj_test_fl(obj, TX_REQUEST))
+ break;
+ }
can_preempt_enable();
-/* DEBUGMSG("WakeUP TX - END\n"); */
+ DEBUGMSG("WakeUP TX - END\n");
return 0;
}
uint32_t mask;
-#if myDEBUG
+#if MPC5200_DBG
int num = canqueue_ends_filt_conjuction(obj->qends, &filter);
#else
canqueue_ends_filt_conjuction(obj->qends, &filter);
if (!mscan_get_flags(chip, MSCAN_RFLG_RXF, MSCAN_RFLG))
{
obj->ret=-1;
+ DEBUGRX("Receive buffer empty\n");
return;
}
{
int cmd;
+ DEBUGTX("Irq write handler\n");
+
if(obj->tx_slot){
/* Do local transmitted message distribution if enabled */
if (processlocal){
int mscan_reset_chip(struct canchip_t * chip)
{
+ DEBUGMSG("chip reset \n");
+
/* reset chip by turning MSCAN off and on in INIT mode */
if (mscan_enable_configuration(chip))
return -ENODEV;
if (mscan_disable_configuration(chip))
return -ENODEV;
+ /* Abort all pending messages */
+ mscan_abort_msg(chip, MSCAN_TARQ_ABTRQ);
+
+ DEBUGMSG("chip reset DONE\n");
+
return 0;
}
/* mscan_clear_irq_flags should be called only when not in INIT mode */
int mscan_clear_irq_flags(struct canchip_t *chip)
{
- reg_t rflg, tflg;
+ /* do not clear TXE flags -> it forces chip to send messages in buffers */
+ reg_t rflg;
if (mscan_init_mode_active(chip))
{
- CANMSG("MSCAN: Clearing IRQs while INIT active \n");
+ DEBUGMSG("MSCAN: Clearing IRQs while INIT active \n");
return -EBUSY;
}
rflg = MSCAN_RFLG_WUPIF | MSCAN_RFLG_CSCIF | MSCAN_RFLG_RSTAT |
MSCAN_RFLG_TSTAT | MSCAN_RFLG_OVRIF | MSCAN_RFLG_RXF;
- tflg = MSCAN_TFLG_TXE;
/* reset flags by writing '1' */
can_write_reg(chip, rflg, MSCAN_RFLG);
- can_write_reg(chip, tflg, MSCAN_TFLG);
return 0;
}
/* Fill message content to one transmit buffers */
/* Note: Check whether buffer is empy has to be done before calling this function */
-void mscan_setup_txbuffer(struct canchip_t * chip, struct canmsg_t * msg, int buffer)
+void mscan_setup_txbuffer(struct canchip_t * chip, struct canmsg_t * msg)
{
- volatile struct mscan_msg_buffer * txb = (struct mscan_msg_buffer *)MSCAN_TXFG;
+ volatile struct mscan_msg_buffer * txb = (struct mscan_msg_buffer *)(chip->chip_base_addr + MSCAN_TXFG);
reg_t rtr;
- /* Select buffer */
- mscan_set_flags(chip, (0x01 << buffer) & MSCAN_TBSEL_TX, MSCAN_TBSEL);
-
if (msg->flags & MSG_RTR)
rtr = 0x01;
/* data length */
txb->data_len = (reg_t)(msg->length & 0x1f);
+
+ DUMPBUFF(chip, MSCAN_TXFG);
}
/* Fill message content from receive buffer */
void mscan_msg_from_rxbuffer(struct canchip_t * chip, struct canmsg_t * msg)
{
- volatile struct mscan_msg_buffer * rxb = (struct mscan_msg_buffer *)MSCAN_RXFG;
+ struct mscan_msg_buffer * rxb = (struct mscan_msg_buffer *)(chip->chip_base_addr + MSCAN_RXFG);
/* retrieve Can mesage ID */
msg->flags = 0; /* clear all */
/* check buffer IDE flag */
if (mscan_get_flags(chip, (reg_t)0x08, MSCAN_RXFG + MSCAN_MSGBUFF_ID1)) /* 0x08 - IDE flag in ID1 */
{
+ DEBUGMSG("Ext ID\n");
/* Extended ID */
msg->id = (((uint32_t)rxb->id_0 << 21) & 0x3fa00000) |
(((uint32_t)rxb->id_1 << 18) & 0x00380000) |
}
else
{
+ DEBUGMSG("std ID\n");
/* Standard ID */
- msg->id = (((uint32_t)rxb->id_0 << 3) & 0x000001f8) |
+ msg->id = (((uint32_t)rxb->id_0 << 3) & 0x000007f8) |
(((uint32_t)rxb->id_1 >> 5) & 0x00000007);
/* RTR flag */
/* updates the TSEG1 and TSEG2 according to overall TSEG and Sample Point (0-1000) */
static int mscan_update_samplept(int sampl_pt, int tseg, int *tseg1, int *tseg2)
{
+ /* tseg = tseg1 + tseg2, its NOT tsegall !
+ * difference between tseg and tsegall is:
+ * tsegall = tseg + 1
+ */
+
*tseg2 = tseg + 1 - (sampl_pt * (tseg + 1)) / 1000;
if (*tseg2 < MSCAN_TSEG2_MIN)
*tseg2 = MSCAN_TSEG2_MIN;
*tseg1 = MSCAN_TSEG1_MAX;
*tseg2 = tseg - *tseg1;
}
- return 1000 * (tseg + 1 - *tseg2) / (tseg + 1);
+ return 1000 * (*tseg1 + 1) / (tseg + 1);
}
static int mscan_init_mode_active(struct canchip_t *chip)
{
/* Init request AND Init ACK */
- DEBUGMSG(" is Init active?\n");
+ /* DEBUGMSG(" is Init active?\n"); */
return mscan_get_flags(chip, MSCAN_CTL0_INITRQ, MSCAN_CTL0) &&
mscan_get_flags(chip, MSCAN_CTL1_INITAK, MSCAN_CTL1);
}
mscan_get_flags(chip, MSCAN_CTL1_SLPAK, MSCAN_CTL1);
}
+static int mscan_enter_init_mode(struct canchip_t * chip)
+{
+ int i = MSCAN_MAX_SETTING_WAIT_LOOPS + 1;
+
+ mscan_set_flags(chip, MSCAN_CTL0_INITRQ, MSCAN_CTL0);
+
+ /* Waits until chip enters Init mode */
+ while (!mscan_get_flags(chip, MSCAN_CTL1_INITAK, MSCAN_CTL1) && --i)
+ udelay(200);
+
+ if (!i)
+ {
+ DEBUGMSG("Error entering Init mode (enable configuration) \n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+static int mscan_enter_sleep_mode(struct canchip_t * chip)
+{
+ int i = MSCAN_MAX_SETTING_WAIT_LOOPS + 1;
+
+ if (mscan_sleep_mode_active(chip))
+ {
+ DEBUGMSG("Already in sleep mode or not synced to Bus\n");
+ return 0;
+ }
+
+ /* DEBUGMSG("isSynced: 0x%02x\n",mscan_get_flags(chip, MSCAN_CTL0_SYNCH, MSCAN_CTL0)); */
+
+ mscan_set_flags(chip, MSCAN_CTL0_SLPRQ, MSCAN_CTL0);
+
+ /* Waits until chip enters Sleep mode - finishes current TX/RX operation */
+ while (!mscan_get_flags(chip, MSCAN_CTL1_SLPAK, MSCAN_CTL1) && --i)
+ udelay(200);
+
+ if (!i)
+ {
+ DEBUGMSG("Error entering Sleep mode (enable configuration) \n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+
static reg_t mscan_get_flags(struct canchip_t * chip, reg_t flags, unsigned reg_addr)
{
- DEBUGMSG(" get flags [%u]\n", reg_addr);
+ /* DEBUGMSG(" get flags [%u]\n", reg_addr); */
return (reg_t)can_read_reg(chip, reg_addr) & flags;
}
static void mscan_set_flags(struct canchip_t * chip, reg_t flags, unsigned reg_addr)
reg_t r = can_read_reg(chip, reg_addr);
can_write_reg(chip, r & ~flags, reg_addr);
}
+static uint16_t mscan_get_irq_flags(struct canchip_t * chip)
+{
+ /* Transmit Buffer Empty only if enabled */
+ return ((mscan_get_flags(chip, MSCAN_TIER_TXE, MSCAN_TIER) &
+ mscan_get_flags(chip, MSCAN_TFLG_TXE, MSCAN_TFLG)) << 8) |
+ (mscan_get_flags(chip, (reg_t)(mscan_IRQs & 0xff), MSCAN_RFLG));
+}
static void mscan_clear_buffer(struct canchip_t * chip, unsigned start_addr)
for (addr = start_addr; addr < 26; addr++)
can_write_reg(chip, 0x00, addr);
}
+
+static int mscan_abort_msg(struct canchip_t * chip, reg_t buffer_mask)
+{
+ reg_t m;
+ int i = MSCAN_MAX_SETTING_WAIT_LOOPS + 1;
+
+ /* check input */
+ m = buffer_mask & MSCAN_TARQ_ABTRQ;
+
+ /* It's not neccessary to abort empy message */
+ m &= (~mscan_get_flags(chip, MSCAN_TFLG_TXE, MSCAN_TFLG));
+
+ if(!m)
+ {
+ DEBUGMSG("nothing to abort\n");
+ goto abortmsg_exit_ok;
+ }
+
+
+ /* set TARQ - Transmitt Abort Request */
+ mscan_set_flags(chip, m, MSCAN_TARQ);
+
+
+ /* Waits until chip acknowleges abortition */
+ while (mscan_get_flags(chip, MSCAN_TAAK_ABTAK, MSCAN_TAAK) != m && --i)
+ udelay(200);
+
+ if (!i)
+ {
+ DEBUGMSG("Error waiting for Message Abort [requested: 0x%02x]\n", m);
+ goto abortmsg_exit_fail;
+ }
+
+
+abortmsg_exit_ok:
+ return 0;
+
+abortmsg_exit_fail:
+ return -ENODEV;
+}
+