--- /dev/null
+/**************************************************************************/
+/* File: mscan.h - Freescale MPC5200 MSCAN controller support */
+/* */
+/* LinCAN - (Not only) Linux CAN bus driver */
+/* Copyright (C) 2002-2009 DCE FEE CTU Prague <http://dce.felk.cvut.cz> */
+/* Copyright (C) 2002-2009 Pavel Pisa <pisa@cmp.felk.cvut.cz> */
+/* Copyright (C) 2007-2008 Martin Petera <peterm4@fel.cvut.cz> */
+/* Funded by OCERA and FRESCOR IST projects */
+/* Based on CAN driver code by Arnaud Westenberg <arnaud@wanadoo.nl> */
+/* */
+/* LinCAN is free software; you can redistribute it and/or modify it */
+/* under terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2, or (at your option) any */
+/* later version. LinCAN is distributed in the hope that it will be */
+/* useful, but WITHOUT ANY WARRANTY; without even the implied warranty */
+/* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
+/* General Public License for more details. You should have received a */
+/* copy of the GNU General Public License along with LinCAN; see file */
+/* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, */
+/* Cambridge, MA 02139, USA. */
+/* */
+/* To allow use of LinCAN in the compact embedded systems firmware */
+/* and RT-executives (RTEMS for example), main authors agree with next */
+/* special exception: */
+/* */
+/* Including LinCAN header files in a file, instantiating LinCAN generics */
+/* or templates, or linking other files with LinCAN objects to produce */
+/* an application image/executable, does not by itself cause the */
+/* resulting application image/executable to be covered by */
+/* the GNU General Public License. */
+/* This exception does not however invalidate any other reasons */
+/* why the executable file might be covered by the GNU Public License. */
+/* Publication of enhanced or derived LinCAN files is required although. */
+/**************************************************************************/
+
+#ifndef LINCAN_MSCAN_H
+#define LINCAN_MSCAN_H
+
+
+
+#define MPC5200_DBG 0
+
+/* Debug - coarse approach */
+#if MPC5200_DBG
+ /* standard LinCAN core debug - used only for MPC5200 driver part */
+ #define DEBUGMSG(fmt,args...) can_printk(KERN_ERR "lincan (debug): " fmt,##args)
+
+ /* dump specific parts of chip memory */
+ #define DUMPREGS(canchip) dump_regs(canchip)
+ #define DUMPBUFF(canchip, offset) dump_buff(canchip, offset)
+ #define DUMPFLT(canchip) dump_filter(canchip)
+
+ /* Debug Tx Rx operations */
+ #define DEBUGTX(fmt,args...) can_printk(KERN_ERR "lincan (debug): " fmt,##args)
+ #define DEBUGRX(fmt,args...) can_printk(KERN_ERR "lincan (debug): " fmt,##args)
+#else
+ #define DUMPREGS(canchip)
+ #define DUMPBUFF(canchip, offset)
+ #define DUMPFLT(canchip)
+ #define DEBUGTX(fmt,args...)
+ #define DEBUGRX(fmt,args...)
+#endif /* MPC5200_DBG */
+
+
+
+
+/* MSCAN register size */
+#define reg_t uint8_t
+
+
+/* Determine which clock source to use */
+/* 0 - use IP Bus clock */
+/* 1 - use SYS_XTAL_IN frequency */
+#define MPC5200_CLKSRC 1
+
+#if MPC5200_CLKSRC
+ #define MPC5200_CLK_FREQ (MPC5200_SHARK_SYS_XTAL_FREQ/12) /* 33MHz */
+#else
+ #define MPC5200_CLK_FREQ (MPC5200_SHARK_IPB_FREQ/4) /* 33MHz */
+#endif
+
+
+int mscan_chip_config(struct canchip_t *chip);
+int mscan_enable_configuration(struct canchip_t *chip);
+int mscan_disable_configuration(struct canchip_t *chip);
+
+int mscan_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw, int sampl_pt, int flags);
+int mscan_set_btregs(struct canchip_t *chip, unsigned short bcr0, unsigned short bcr1);
+
+int mscan_start_chip(struct canchip_t *chip);
+int mscan_stop_chip(struct canchip_t *chip);
+int mscan_attach_to_chip(struct canchip_t *chip);
+int mscan_release_chip(struct canchip_t *chip);
+
+int mscan_standard_mask(struct canchip_t *chip, unsigned short code, unsigned short mask);
+int mscan_extended_mask(struct canchip_t *chip, unsigned long code, unsigned long mask);
+/* int mscan_message15_mask(int irq, struct canchip_t *chip); */
+
+int mscan_pre_read_config(struct canchip_t *chip, struct msgobj_t *obj);
+int mscan_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj, struct canmsg_t *msg);
+int mscan_send_msg(struct canchip_t *chip, struct msgobj_t *obj, struct canmsg_t *msg);
+int mscan_remote_request(struct canchip_t *chip, struct msgobj_t *obj);
+
+int mscan_irq_handler(int irq, struct canchip_t *chip);
+/* int mscan_irq_accept(int irq, struct canchip_t *chip); */
+int mscan_config_irqs(struct canchip_t *chip, short irqs);
+
+int mscan_clear_objects(struct canchip_t *chip);
+int mscan_check_tx_stat(struct canchip_t *chip);
+int mscan_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj);
+int mscan_filtch_rq(struct canchip_t *chip, struct msgobj_t * obj);
+
+int mscan_register(struct chipspecops_t *chipspecops);
+int mscan_fill_chipspecops(struct canchip_t *chip);
+
+int mscan_reset_chip(struct canchip_t * chip);
+
+extern inline void can_write_reg_w(const struct canchip_t *pchip, uint16_t data, unsigned reg)
+{
+ can_ioptr_t address = pchip->chip_base_addr + reg;
+ #ifndef CONFIG_OC_LINCAN_DYNAMICIO
+ writew(data,address);
+ #else /*CONFIG_OC_LINCAN_DYNAMICIO*/
+ pchip->write_register(data, address);
+ #endif /*CONFIG_OC_LINCAN_DYNAMICIO*/
+}
+
+extern inline uint16_t can_read_reg_w(const struct canchip_t *pchip, unsigned reg)
+{
+ can_ioptr_t address = pchip->chip_base_addr + reg;
+ #ifndef CONFIG_OC_LINCAN_DYNAMICIO
+ return readw(address);
+ #else /*CONFIG_OC_LINCAN_DYNAMICIO*/
+ return pchip->read_register(address);
+ #endif /*CONFIG_OC_LINCAN_DYNAMICIO*/
+}
+
+
+/* BasicCAN mode address map */
+#define MSCAN_CTL0 0x00 /* Control Register 0 */
+#define MSCAN_CTL1 0x01 /* Control Register 1 */
+#define MSCAN_BTR0 0x04 /* Bus Timing Register 0 */
+#define MSCAN_BTR1 0x05 /* Bus Timing Register 1 */
+#define MSCAN_RFLG 0x08 /* Receive Flag Register */
+#define MSCAN_RIER 0x09 /* Receiver Interrupt Enable Register */
+#define MSCAN_TFLG 0x0c /* Transmitter Flag Register */
+#define MSCAN_TIER 0x0d /* Transmitter Interrupt Enable Register */
+#define MSCAN_TARQ 0x10 /* Transmitter Message Abort Request Register */
+#define MSCAN_TAAK 0x11 /* Transmitter Message Abort Acknowledge Register */
+#define MSCAN_TBSEL 0x14 /* Transmitter Buffer Selection */
+#define MSCAN_IDAC 0x15 /* Identifier Acceptance Control Register */
+/* Reserved 0x18, 0x19 */
+#define MSCAN_RXERR 0x1c /* Receive Error Counter Register */
+#define MSCAN_TXERR 0x1d /* Transmitt Error Counter Register */
+
+/* Acceptance Filters */
+#define MSCAN_IDAR0 0x20 /* Identifier Acceptance Register 0 */
+#define MSCAN_IDAR1 0x21 /* Identifier Acceptance Register 1 */
+#define MSCAN_IDAR2 0x24 /* Identifier Acceptance Register 2 */
+#define MSCAN_IDAR3 0x25 /* Identifier Acceptance Register 3 */
+#define MSCAN_IDMR0 0x28 /* Identifier Mask Register 0 */
+#define MSCAN_IDMR1 0x29 /* Identifier Mask Register 1 */
+#define MSCAN_IDMR2 0x2c /* Identifier Mask Register 2 */
+#define MSCAN_IDMR3 0x2d /* Identifier Mask Register 3 */
+
+#define MSCAN_IDAR4 0x30 /* Identifier Acceptance Register 4 */
+#define MSCAN_IDAR5 0x31 /* Identifier Acceptance Register 5 */
+#define MSCAN_IDAR6 0x34 /* Identifier Acceptance Register 6 */
+#define MSCAN_IDAR7 0x35 /* Identifier Acceptance Register 7 */
+#define MSCAN_IDMR4 0x38 /* Identifier Mask Register 4 */
+#define MSCAN_IDMR5 0x39 /* Identifier Mask Register 5 */
+#define MSCAN_IDMR6 0x3c /* Identifier Mask Register 6 */
+#define MSCAN_IDMR7 0x3d /* Identifier Mask Register 7 */
+
+/* Buffers */
+#define MSCAN_RXFG 0x40 /* Foregroung Receive Buffer 0x40-0x5f */
+#define MSCAN_TXFG 0x60 /* Foregroung Receive Buffer 0x60-0x7f */
+
+
+/* BaudRate minimal and maximal TSEG values */
+#define MSCAN_TSEG1_MIN 4 /* means 1 Tq clock cycle */
+#define MSCAN_TSEG1_MAX 16 /* means 16 Tq clock cycles */
+#define MSCAN_TSEG2_MIN 2 /* means 1 Tq clock cycle */
+#define MSCAN_TSEG2_MAX 8 /* means 8 Tq clock cycles */
+#define MSCAN_TSEG_MIN (MSCAN_TSEG1_MIN + MSCAN_TSEG2_MIN)
+#define MSCAN_TSEG_MAX (MSCAN_TSEG1_MAX + MSCAN_TSEG2_MAX)
+
+#define MSCAN_BRP_MIN 1
+#define MSCAN_BRP_MAX 64
+
+enum mscan_ctl0 {
+ MSCAN_CTL0_RXFRM = 1 << 7, /* Received Frame Flag - rw */
+ MSCAN_CTL0_RXACT = 1 << 6, /* Receiver Active Status - ro */
+ MSCAN_CTL0_CSWAI = 1 << 5, /* CAN Stops in Wait Mode - rw */
+ MSCAN_CTL0_SYNCH = 1 << 4, /* Synchronized Status - ro */
+ MSCAN_CTL0_TIME = 1 << 3, /* Timer Enable - rw */
+ MSCAN_CTL0_WUPE = 1 << 2, /* WakeUp Enable - rw */
+ MSCAN_CTL0_SLPRQ = 1 << 1, /* Sleep Request - rw */
+ MSCAN_CTL0_INITRQ = 1 << 0, /* Initialization Mode Request - rw */
+};
+
+enum mscan_ctl1 {
+ MSCAN_CTL1_CANE = 1 << 7, /* MSCAN Enable rw */
+ MSCAN_CTL1_CLKSRC = 1 << 6, /* MSCAN Clock Source rw */
+ MSCAN_CTL1_LOOPB = 1 << 5, /* Loob-Back Self Test Mode rw */
+ MSCAN_CTL1_LISTEN = 1 << 4, /* Listen-Only Mode rw */
+ MSCAN_CTL1_WUPM = 1 << 2, /* WakeUp Mode rw */
+ MSCAN_CTL1_SLPAK = 1 << 1, /* Sleep Mode Acknowledge - ro */
+ MSCAN_CTL1_INITAK = 1 << 0, /* Initialization Mode Acknowledge - ro */
+
+ MSCAN_CTL1_RSVD = 1 << 3, /* Reserved */
+};
+
+enum mscan_btr0 {
+ MSCAN_BTR0_SJW = 0xa0, /* Synchronization Jump Width: 0 to 3 (1 to 4 Tq) */
+ MSCAN_BTR0_BRP = 0x3f, /* Baud Rate Prescaler: 0 to 63 (1 to 64) */
+};
+
+enum mscan_btr1 {
+ MSCAN_BTR1_SAMP = 1 << 7, /* Sampling: 0-One sample, 1-Three samples per bit */
+ MSCAN_BTR1_TSEG2 = 0x70, /* TSEG2: 3 bits */
+ MSCAN_BTR1_TSEG1 = 0x0f, /* TSEG1: 4 bits */
+};
+
+/* Interupt & Interrupt Enable Registers */
+enum mscan_rflg {
+ MSCAN_RFLG_WUPIF = 1 << 7, /* WakeUp Interrupt Flag - rw */
+ MSCAN_RFLG_CSCIF = 1 << 6, /* CAN Status Change Interrupt Flag - rw */
+ MSCAN_RFLG_RSTAT = 0x30, /* Receiver Status Bits: 0-RxOK, 1-RxWRN, 2-RxERR, 3-BusOff - ro */
+ MSCAN_RFLG_TSTAT = 0x0c, /* Transmitter Status Bits: 0-TxOK, 1-TxWRN, 2-TxErr, 3-BusOff - ro */
+ MSCAN_RFLG_OVRIF = 1 << 1, /* Overrun Interrupt Flag - rw */
+ MSCAN_RFLG_RXF = 1 << 0, /* Receive Buffer Full - rw */
+};
+
+enum mscan_rier {
+ MSCAN_RIER_WUPIE = 1 << 7, /* WakeUp Interrupt Enable - rw */
+ MSCAN_RIER_CSCIE = 1 << 6, /* CAN Status Change Interrupt Enable - rw */
+ MSCAN_RIER_RSTATE = 0x30, /* Receiver Status Change Enable: 0-Never, 1-BusOff, 2-BusOff+RxErr, 3-All - rw */
+ MSCAN_RIER_TSTATE = 0x0c, /* Transmitter Status Change Enable: 0-Never, 1-BusOff, 2-BusOff+TxErr, 3-All - rw */
+ MSCAN_RIER_OVRIE = 1 << 1, /* Overrun Interrupt Enable - rw */
+ MSCAN_RIER_RXFIE = 1 << 0, /* Receive Buffer Full Interrupt Enable - rw */
+};
+
+enum mscan_tflg {
+ MSCAN_TFLG_TXE = 0x07, /* Transmitter Buffer Empty */
+
+ MSCAN_TFLG_RSVD = 0xf8, /* Reserved */
+};
+
+enum mscan_tier {
+ MSCAN_TIER_TXE = 0x07, /* Transmitter Empty Interrupt Enable */
+
+ MSCAN_TIER_RSVD = 0xf8, /* Reserved */
+};
+/* IRQ end */
+
+enum mscan_tarq {
+ MSCAN_TARQ_ABTRQ = 0x07, /* Abort Request */
+
+ MSCAN_TARQ_RSVD = 0xf8, /* Reserved */
+};
+
+enum mscan_taak {
+ MSCAN_TAAK_ABTAK = 0x07, /* Abort Acknowledge */
+
+ MSCAN_TAAK_RSVD = 0xf8, /* Reserved */
+};
+
+enum mscan_tbsel {
+ MSCAN_TBSEL_TX = 0x07, /* Transmitt Buffer Select - prioritize lower */
+
+ MSCAN_TBSEL_RSVD = 0xf8, /* Reserved */
+};
+
+enum mscan_idac {
+ MSCAN_IDAC_IDAM = 0x30, /* Identifier Acceptance Mode: 0-Two 32bit, 1-Four 16-bit. 2-Eight 8bit, 3-Closed */
+ MSCAN_IDAC_IDHIT = 0x07, /* Identifier Acceptance Hit Indicator */
+
+ MSCAN_IDAC_RSVD = 0xa8, /* Reserved */
+};
+
+/* Message Buffer Organization */
+#define MSCAN_MSGBUFF_ID0 0x00 /* Identifier Register 0 */
+#define MSCAN_MSGBUFF_ID1 0x01 /* Identifier Register 1 */
+#define MSCAN_MSGBUFF_ID2 0x04 /* Identifier Register 2 */
+#define MSCAN_MSGBUFF_ID3 0x05 /* Identifier Register 3 */
+
+#define MSCAN_MSGBUFF_DATA0 0x08 /* Data Segment Register 0 */
+#define MSCAN_MSGBUFF_DATA1 0x09 /* Data Segment Register 1 */
+#define MSCAN_MSGBUFF_DATA2 0x0c /* Data Segment Register 2 */
+#define MSCAN_MSGBUFF_DATA3 0x0d /* Data Segment Register 3 */
+#define MSCAN_MSGBUFF_DATA4 0x10 /* Data Segment Register 4 */
+#define MSCAN_MSGBUFF_DATA5 0x11 /* Data Segment Register 5 */
+#define MSCAN_MSGBUFF_DATA6 0x14 /* Data Segment Register 6 */
+#define MSCAN_MSGBUFF_DATA7 0x15 /* Data Segment Register 7 */
+
+#define MSCAN_MSGBUFF_DLEN 0x18 /* Data Length Register */
+#define MSCAN_MSGBUFF_TXPRIO 0x19 /* Transmitt Buffer Priority - Not Applicable for Rx buffers */
+#define MSCAN_MSGBUFF_TSH 0x1c /* Time Stamp Register High */
+#define MSCAN_MSGBUFF_TSL 0x1d /* Time Stamp Register Low */
+
+struct mscan_msg_buffer{
+
+ uint8_t id_0; /* CAN identifier: ID_EXT {28:21} OR ID_STD {10:3} */
+ uint8_t id_1; /* CAN identifier: ID_EXT {20:18},SRR,IDE,ID_EXT{17:15} OR ID_STD{2:0},RTR,IDE, reserved */
+ uint16_t spacer_0; /* spacer for compatibility */
+ uint8_t id_2; /* CAN identifier: IDE_EXT{14:7} OR reserved for ID_STD */
+ uint8_t id_3; /* CAN identifier: ID_EXT{6:0},RTR OR reserved for ID_STD */
+ uint16_t spacer_1; /* spacer for compatibility */
+ uint8_t data_0; /* CAN data byte 0 */
+ uint8_t data_1; /* CAN data byte 1 */
+ uint16_t spacer_2; /* spacer for compatibility */
+ uint8_t data_2; /* CAN data byte 2 */
+ uint8_t data_3; /* CAN data byte 3 */
+ uint16_t spacer_3; /* spacer for compatibility */
+ uint8_t data_4; /* CAN data byte 4 */
+ uint8_t data_5; /* CAN data byte 5 */
+ uint16_t spacer_4; /* spacer for compatibility */
+ uint8_t data_6; /* CAN data byte 6 */
+ uint8_t data_7; /* CAN data byte 7 */
+ uint16_t spacer_5; /* spacer for compatibility */
+ uint8_t data_len; /* CAN data length: 0xf0 reserved, DLC{3:0} */
+ uint8_t local_prio; /* MSCAN TX local priority - unused fro TX buffer */
+ uint16_t spacer_6; /* spacer for compatibility */
+ uint8_t timestamp_h; /* local timestamp - High byte - Read Only */
+ uint8_t timestamp_l; /* local timestamp - Low byte - Read Only */
+};
+
+/* structure for memory layout of acceptance
+ * filter registers
+ */
+struct mscan_flt_regs{
+ uint8_t acp_id_0;
+ uint8_t acp_id_1;
+ uint16_t spacer_0;
+
+ uint8_t acp_id_2;
+ uint8_t acp_id_3;
+ uint16_t spacer_1;
+
+ uint8_t acp_mask_0;
+ uint8_t acp_mask_1;
+ uint16_t spacer_2;
+
+ uint8_t acp_mask_2;
+ uint8_t acp_mask_3;
+ uint16_t spacer_3;
+
+ uint8_t acp_id_4;
+ uint8_t acp_id_5;
+ uint16_t spacer_4;
+
+ uint8_t acp_id_6;
+ uint8_t acp_id_7;
+ uint16_t spacer_5;
+
+ uint8_t acp_mask_4;
+ uint8_t acp_mask_5;
+ uint16_t spacer_6;
+
+ uint8_t acp_mask_6;
+ uint8_t acp_mask_7;
+};
+
+#endif /* LINCAN_MSCAN_H */
--- /dev/null
+/**************************************************************************/
+/* File: mscan.c - Freescale MPC5200 MSCAN controller support */
+/* */
+/* LinCAN - (Not only) Linux CAN bus driver */
+/* Copyright (C) 2002-2009 DCE FEE CTU Prague <http://dce.felk.cvut.cz> */
+/* Copyright (C) 2002-2009 Pavel Pisa <pisa@cmp.felk.cvut.cz> */
+/* Copyright (C) 2007-2008 Martin Petera <peterm4@fel.cvut.cz> */
+/* Funded by OCERA and FRESCOR IST projects */
+/* Based on CAN driver code by Arnaud Westenberg <arnaud@wanadoo.nl> */
+/* */
+/* LinCAN is free software; you can redistribute it and/or modify it */
+/* under terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2, or (at your option) any */
+/* later version. LinCAN is distributed in the hope that it will be */
+/* useful, but WITHOUT ANY WARRANTY; without even the implied warranty */
+/* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
+/* General Public License for more details. You should have received a */
+/* copy of the GNU General Public License along with LinCAN; see file */
+/* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, */
+/* Cambridge, MA 02139, USA. */
+/* */
+/* To allow use of LinCAN in the compact embedded systems firmware */
+/* and RT-executives (RTEMS for example), main authors agree with next */
+/* special exception: */
+/* */
+/* Including LinCAN header files in a file, instantiating LinCAN generics */
+/* or templates, or linking other files with LinCAN objects to produce */
+/* an application image/executable, does not by itself cause the */
+/* resulting application image/executable to be covered by */
+/* the GNU General Public License. */
+/* This exception does not however invalidate any other reasons */
+/* why the executable file might be covered by the GNU Public License. */
+/* Publication of enhanced or derived LinCAN files is required although. */
+/**************************************************************************/
+
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
+#include "../include/main.h"
+#include "../include/mscan.h"
+//#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 ~ 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);
+
+int mscan_clear_irq_flags(struct canchip_t *chip);
+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);
+
+void mscan_notifyRXends(struct msgobj_t * obj, int what);
+int mscan_check_txbuff_stat(struct canchip_t *chip, int buffer);
+
+static int mscan_update_samplept(int sampl_pt, int tseg, int *tseg1, int *tseg2);
+
+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 - 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_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 */
+
+
+
+/* ************************************************************************************************************************************* */
+
+
+int mscan_chip_config(struct canchip_t *chip)
+{
+ /* Do not clear buffers here, they may contain valid data ! */
+ int err;
+
+ DEBUGMSG("Configuring chip...\n");
+
+ 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)))
+ return err;
+
+ 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)))
+ return err;
+
+ return 0;
+}
+
+/* enter initialization AND sleep mode */
+int mscan_enable_configuration(struct canchip_t *chip)
+{
+ /* Do not clear buffers here, they may contain valid data ! */
+
+ DEBUGMSG("config ENABLE\n");
+
+ if (mscan_init_mode_active(chip)) /* chip is already in config mode */
+ {
+ 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 */
+ /* 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 */
+ 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("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 */
+ mscan_clear_flags(chip, MSCAN_CTL0_INITRQ, MSCAN_CTL0);
+
+ /* Waits until chip leaves Sleep 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) {
+ DEBUGMSG("Error leaving Init mode (disable configuration) \n");
+ return -EBUSY;
+ }
+
+
+ /* disable Sleep mode */
+ mscan_clear_flags(chip, MSCAN_CTL0_SLPRQ, MSCAN_CTL0);
+
+ i = 0;
+ /* Waits until chip leaves Init mode */
+ 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) {
+ 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;
+}
+
+
+/* ************************************************************************************************************************************* */
+
+
+int mscan_baud_rate(struct canchip_t *chip, int bitrate, int clock, int sjw, int sampl_pt, int flags)
+{
+ /* Set communication parameters.
+ * param rate baud rate in Hz
+ * param clock frequency of mscan clock in Hz
+ * param sjw synchronization jump width (0-3) prescaled clock cycles
+ * param sampl_pt sample point (0-1000) sets (TSEG1 + 1)/(TSEG1 + TSEG2 + 2) ratio
+ * flags not used
+ */
+
+
+ /* rate = clock / ((tseg1 + tseg2 + 1) * brp ) */
+
+ long rate, best_rate = 0;
+ long best_error = 1000000000, error = 0;
+ int best_tseg = 0, best_brp = 0, brp = 0;
+ int tsegall, tseg = 0, tseg1 = 0, tseg2 = 0;
+ int spt = 0, spt_error = best_error;
+ reg_t btr0, btr1;
+
+
+ /* Use CIA recommended sample points */
+ if (!sampl_pt)
+ {
+ if (bitrate > 800000)
+ sampl_pt = 750;
+ else if (bitrate > 500000)
+ sampl_pt = 800;
+ else
+ sampl_pt = 875;
+ }
+
+ /* tseg even = round down, odd = round up */
+ for (tseg = MSCAN_TSEG_MAX * 2 + 1; tseg >= MSCAN_TSEG_MIN * 2; tseg--)
+ {
+ tsegall = 1 + tseg / 2;
+ /* Compute all possible tseg choices (tseg=tseg1+tseg2) */
+ brp = clock / (tsegall * bitrate) + tseg % 2;
+
+ if ((brp < MSCAN_BRP_MIN) || (brp > MSCAN_BRP_MAX))
+ continue;
+
+ /* tseg brp biterror */
+ rate = clock / (brp * tsegall);
+ error = bitrate - rate;
+
+ if (error < 0)
+ error = -error;
+ if (error > best_error)
+ continue;
+ best_error = error;
+
+ if (error == 0) {
+ spt = mscan_update_samplept(sampl_pt, tseg / 2, &tseg1, &tseg2);
+ error = sampl_pt - spt;
+
+ if (error < 0)
+ error = -error;
+ if (error > spt_error)
+ continue;
+ spt_error = error;
+ }
+
+ best_tseg = tseg / 2;
+ best_brp = brp;
+ best_rate = rate;
+ if (error == 0)
+ break;
+ }
+
+ if (best_error) {
+ /* Error in one-tenth of a percent */
+ error = (best_error * 1000) / bitrate;
+ DEBUGMSG("Baudrate error %lu\n", error);
+ }
+
+
+ /* recompute with best values */
+ spt = mscan_update_samplept(sampl_pt, best_tseg, &tseg1, &tseg2);
+
+ DEBUGMSG("Setting %lu bps.\n", best_rate);
+
+ /* all values has offset -1 in MSCAN memory */
+ best_brp--; tseg1--; tseg2--;
+
+ 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);
+
+ mscan_disable_configuration(chip);
+
+/* DEBUGMSG("Baud rate set successfully\n"); */
+ return 0;
+}
+
+int mscan_set_btregs(struct canchip_t *chip, unsigned short bcr0, unsigned short bcr1)
+{
+/* DEBUGMSG("Seting BCR0 and BCR1.\n"); */
+ reg_t btr0, btr1;
+
+ btr0 = (reg_t)bcr0;
+ btr1 = (reg_t)bcr1;
+
+ 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("BCR0 and BCR1 successfully set.\n"); */
+ return 0;
+}
+
+
+/* ************************************************************************************************************************************* */
+
+
+int mscan_start_chip(struct canchip_t *chip)
+{
+/* DEBUGMSG("Starting chip %d...\n", chip->chip_idx); */
+
+ /* Stop chip turns chip to Sleep&Init mode - traffic on CAN bus is ignored after completing curent operation.
+ * Start chip only turn chip back from Sleep&Init state - using disable_config
+ */
+ mscan_disable_configuration(chip);
+
+ DEBUGMSG("Chip [%d] started\n", chip->chip_idx);
+ return 0;
+}
+
+int mscan_stop_chip(struct canchip_t *chip)
+{
+/* DEBUGMSG("Stopping chip %d...\n", chip->chip_idx); */
+
+ /* Stop chip turns chip to Sleep&Init mode - traffic on CAN bus is ignored after completing curent operation.
+ * - using enable_config
+ */
+ mscan_enable_configuration(chip);
+
+ DEBUGMSG("Chip [%d] stopped\n", chip->chip_idx);
+ return 0;
+}
+
+int mscan_attach_to_chip(struct canchip_t *chip)
+{
+/* 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) */
+
+ /* initialize chip by entering Sleep & Init mode */
+ if (mscan_enable_configuration(chip))
+ return -ENODEV;
+
+ /* reset Control Register 1 (CTL1) */
+ ctl1 = MSCAN_CTL1_CANE |
+ (MPC5200_CLKSRC ? MSCAN_CTL1_CLKSRC : 0x00) ;
+ /* MSCAN_CTL1_LOOPB | LoopBack mode not used */
+ /* MSCAN_CTL1_LISTEN | Listen-Only mode not used */
+ /* 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;
+
+ /* not neccessary, but just to be sure */
+ if (mscan_disable_configuration(chip))
+ return -ENODEV;
+
+ /* Enable interrupt - called in mpc5200_request_io */
+ /* can_enable_irq(chip->chip_irq); */
+
+ DEBUGMSG("Successfully attached to chip [%02d].\n", chip->chip_idx);
+
+ return 0;
+}
+
+int mscan_release_chip(struct canchip_t *chip)
+{
+ /* IRQ unmapped in lincan driver core */
+ can_disable_irq(chip->chip_irq);
+
+ 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);
+
+ DEBUGMSG("Chip released [%02d]\n", chip->chip_idx);
+ return 0;
+}
+
+
+/* ************************************************************************************************************************************* */
+
+/* has to be called in Init & Sleep mode */
+int mscan_standard_mask(struct canchip_t *chip, unsigned short code, unsigned short mask)
+{
+ /* code - contains 11bit ID and as LSB the RTR flag */
+ /* code - contains 11bit mask and RTR mask as LSB */
+
+ reg_t idr0, idr1, mr0, mr1; /* ID register 0,1, Mask register 0, 1 */
+
+ if (code & 0x1ffff800)
+ return mscan_extended_mask(chip, code, mask);
+
+
+ /* we use two 32-bit acceptance filters */
+ 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 LSB, IDE=0 doesnt have to be set explicitly */
+ mr0 = (reg_t)((mask & 0x0ff0) >> 4);
+ mr1 = (reg_t)(((mask & 0x000f) << 4) & 0xf0); /* to be sure IDE=0 */
+
+
+ can_write_reg(chip, idr0, MSCAN_IDAR0);
+ can_write_reg(chip, idr1, MSCAN_IDAR1);
+
+ 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;
+}
+
+/* has to be called in Init & Sleep mode */
+int mscan_extended_mask(struct canchip_t *chip, unsigned long code, unsigned long mask)
+{
+ /* code - contains 11bit ID and as LSB the RTR flag */
+ /* code - contains 11bit mask and RTR mask as LSB */
+
+ reg_t idr0, idr1, idr2, idr3; /* ID registers 0,1,2,3 */
+ reg_t mr0, mr1, mr2, mr3; /* Mask registers 0,1,2,3 */
+
+
+ /* we use two 32-bit acceptance filters */
+ mscan_clear_flags(chip, MSCAN_IDAC_IDAM, MSCAN_IDAC);
+
+
+ idr0 = (reg_t)((code & 0x7fa00000) >> 22); /* EXT_ID {29:21} */
+
+ idr1 = (reg_t)((code & 0x00380000) >> 14); /* EXT_ID {20:18} */
+ idr1|= 0x18; /* SRR and IDE */
+ idr1|= (reg_t)((code & 0x00070000) >> 16); /* EXT_ID {17:15} */
+
+ idr2 = (reg_t)((code & 0x0000ff00) >> 8); /* EXT_ID {14:7} */
+ idr3 = (reg_t) (code & 0x000000ff); /* EXT_ID {6:0} and RTR */
+
+
+ mr0 = (reg_t)((mask & 0x7fa00000) >> 22); /* EXT_ID {29:21} */
+
+ mr1 = (reg_t)((mask & 0x00380000) >> 14); /* EXT_ID {20:18} */
+ /* SRR=0 and IDE=0 - do not ignore */
+ mr1|= (reg_t)((mask & 0x00070000) >> 16); /* EXT_ID {17:15} */
+
+ mr2 = (reg_t)((mask & 0x0000ff00) >> 8); /* EXT_ID {14:7} */
+ mr3 = (reg_t) (mask & 0x000000ff); /* EXT_ID {6:0} and RTR */
+
+
+ can_write_reg(chip, idr0, MSCAN_IDAR0);
+ can_write_reg(chip, idr1, MSCAN_IDAR1);
+ can_write_reg(chip, idr2, MSCAN_IDAR2);
+ can_write_reg(chip, idr3, MSCAN_IDAR3);
+
+ can_write_reg(chip, mr0, MSCAN_IDMR0);
+ can_write_reg(chip, mr1, MSCAN_IDMR1);
+ 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)
+{
+ DEBUGRX("Pre read config\n");
+
+ /* MSCAN has only one buffer, which is already initialized */
+
+ return 0;
+}
+
+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;
+
+ 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++) { }
+
+ if (buff_no >= 3)
+ {
+ DEBUGTX("no free buffer found [0x%02x]\n", txf);
+ goto pwrite_exit_fail; /* no free buffer found */
+ }
+
+
+ /* Select buffer */
+ bf = (reg_t)(0x01 << buff_no);
+ can_write_reg(chip, bf & MSCAN_TBSEL_TX, MSCAN_TBSEL);
+
+ 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)
+{
+ DEBUGTX("Send Message\n");
+
+ /* 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)
+{
+ DEBUGMSG("mscan_remote_request not implemented\n");
+ return -ENOSYS;
+}
+
+
+/* ************************************************************************************************************************************* */
+
+
+int mscan_irq_handler(int irq, struct canchip_t *chip)
+{
+/*
+ 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, tx_irq;
+ reg_t irq_rstat, irq_tstat;
+ short loop_cnt = MSCAN_MAX_IRQ_WAIT_LOOPS;
+
+ 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;
+
+ DEBUGMSG("IRR: 0x%04x\n", irq_reg);
+
+ /* Received message */
+ if (irq_reg & MSCAN_RFLG_RXF)
+ {
+ DEBUGRX("Received message\n");
+
+ mscan_irq_read_handler(chip, chip->msgobj[0]);
+ /* RXPR flag for this msgobj is cleared during irq_read_handler*/
+
+ /* reset flag */
+ mscan_set_flags(chip, MSCAN_RFLG_RXF, MSCAN_RFLG);
+ }
+
+
+ /* Can Status change - due to RX/TX error counters */
+ if(irq_reg & MSCAN_RFLG_CSCIF)
+ {
+ irq_rstat = (irq_reg >> 4) & 0x03;
+ irq_tstat = (irq_reg >> 2) & 0x03;
+
+
+ /* 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 */
+ }
+
+ /* Transmit bus off/error/warning */
+ if (irq_tstat ^ txstat)
+ {
+ 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_CSCIF, MSCAN_RFLG);
+ }
+
+ /* Message Overrun/Overwritten */
+ if (irq_reg & MSCAN_RFLG_OVRIF)
+ {
+ CANMSG("Error: MESSAGE OVERRUN/OVERWRITTEN");
+
+ /* notify only injured RXqueue-end */
+ mscan_notifyRXends(chip->msgobj[0], CANQUEUE_NOTIFY_ERROR);
+
+ /* reset flag */
+ mscan_set_flags(chip, MSCAN_RFLG_OVRIF, MSCAN_RFLG);
+ }
+
+ /* Mailbox empty - after message was sent */
+ if (irq_reg & tx_irq)
+ {
+ 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]);
+ }
+
+ 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)
+{
+ DEBUGMSG("mscan_irq_accept NOT IMPLEMENTED\n");
+ return -ENOSYS;
+}
+
+int mscan_config_irqs(struct canchip_t *chip, short irqs)
+{
+ int err;
+ reg_t rier, tier;
+
+ DEBUGMSG("config IRQs\n");
+
+ if (mscan_init_mode_active(chip))
+ {
+ DEBUGMSG("MSCAN: Setting Up IRQs while INIT active \n");
+ return -EBUSY;
+ }
+
+ rier = (reg_t)(irqs & 0x00ff);
+ tier = (reg_t)((irqs >> 8) & 0x00ff);
+
+ if((err = mscan_clear_irq_flags(chip)))
+ return err;
+
+ can_write_reg(chip, rier, MSCAN_RIER);
+ can_write_reg(chip, tier, MSCAN_TIER);
+
+ DEBUGMSG("IRQ Mask set [rier: 0x%02x]\n", rier);
+ return 0;
+}
+
+
+/* ************************************************************************************************************************************* */
+
+
+int mscan_clear_objects(struct canchip_t *chip)
+{
+ /* clear RX buffer */
+ mscan_clear_buffer(chip, MSCAN_RXFG);
+
+ /* clear TX buffers, need to set CANTBSEL register */
+ can_write_reg(chip, 0x01, MSCAN_TBSEL);
+ mscan_clear_buffer(chip, MSCAN_TXFG);
+
+ can_write_reg(chip, 0x02, MSCAN_TBSEL);
+ mscan_clear_buffer(chip, MSCAN_TXFG);
+
+ can_write_reg(chip, 0x04, MSCAN_TBSEL);
+ mscan_clear_buffer(chip, MSCAN_TXFG);
+
+ return 0;
+}
+
+int mscan_check_tx_stat(struct canchip_t *chip)
+{
+/* DEBUGMSG("Check TX stat\n"); */
+ /* If Transmition is complete return 0 - no error */
+ if (mscan_get_flags(chip, MSCAN_TFLG_TXE, MSCAN_TFLG) == MSCAN_TFLG_TXE) /* all buffers empty */
+ return 0;
+ else
+ return 1;
+}
+
+/* Note: this checks TX status of particular buffer */
+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 & (0x01 << buffer), MSCAN_TFLG);
+ return (txf ^ (0x01 << buffer));
+}
+
+int mscan_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj)
+{
+ can_preempt_disable();
+ DEBUGMSG("WakeUP TX\n");
+
+ 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");
+ return 0;
+}
+
+int mscan_filtch_rq(struct canchip_t *chip, struct msgobj_t * obj)
+{
+ struct canfilt_t filter;
+ uint32_t mask;
+
+
+#if MPC5200_DBG
+ int num = canqueue_ends_filt_conjuction(obj->qends, &filter);
+#else
+ canqueue_ends_filt_conjuction(obj->qends, &filter);
+#endif
+
+ DEBUGMSG("CNT: %d ID: 0x%08x MASK: 0x%08x\n", num, (uint32_t) (filter.id) & 0x1fffffff, (uint32_t) (~filter.mask) & 0x1fffffff);
+
+ /* MSCAN uses oposite logic (compared to IP) for LAFM: 1-ignore bit, 0-use bit as mask */
+ mask = (~filter.mask) << 1;
+
+ /* RTR is LSB of mask */
+ if (filter.flags & MSG_RTR)
+ mask |= 0x00000001;
+
+ if (filter.flags & MSG_EXT) /* Extended ID */
+ return mscan_extended_mask(chip, filter.id, mask);
+ else /* Standard ID */
+ return mscan_standard_mask(chip, filter.id, mask);
+}
+
+
+/* ************************************************************************************************************************************* */
+
+
+void mscan_irq_read_handler(struct canchip_t *chip, struct msgobj_t *obj)
+{
+ /* check RX Flag */
+ if (!mscan_get_flags(chip, MSCAN_RFLG_RXF, MSCAN_RFLG))
+ {
+ obj->ret=-1;
+ DEBUGRX("Receive buffer empty\n");
+ return;
+ }
+
+ mscan_msg_from_rxbuffer(chip, &(obj->rx_msg));
+
+ /* fill CAN message timestamp */
+ can_filltimestamp(&obj->rx_msg.timestamp);
+
+ canque_filter_msg2edges(obj->qends, &obj->rx_msg);
+}
+
+void mscan_irq_write_handler(struct canchip_t *chip, struct msgobj_t *obj)
+{
+ int cmd;
+
+ DEBUGTX("Irq write handler\n");
+
+ if(obj->tx_slot){
+ /* Do local transmitted message distribution if enabled */
+ if (processlocal){
+ /* fill CAN message timestamp */
+ can_filltimestamp(&obj->tx_slot->msg.timestamp);
+
+ obj->tx_slot->msg.flags |= MSG_LOCAL;
+ canque_filter_msg2edges(obj->qends, &obj->tx_slot->msg);
+ }
+ /* Free transmitted slot */
+ canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
+ obj->tx_slot=NULL;
+ }
+
+ cmd = canque_test_outslot(obj->qends, &obj->tx_qedge, &obj->tx_slot);
+ if(cmd < 0)
+ return;
+
+ if (chip->chipspecops->pre_write_config(chip, obj, &obj->tx_slot->msg)) {
+ obj->ret = -1;
+ canque_notify_inends(obj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_PREP);
+ canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
+ obj->tx_slot = NULL;
+ return;
+ }
+ if (chip->chipspecops->send_msg(chip, obj, &obj->tx_slot->msg)) {
+ obj->ret = -1;
+ canque_notify_inends(obj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_SEND);
+ canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
+ obj->tx_slot = NULL;
+ return;
+ }
+}
+
+
+/* ************************************************************************************************************************************* */
+
+
+int mscan_register(struct chipspecops_t *chipspecops)
+{
+ chipspecops->chip_config = mscan_chip_config;
+ chipspecops->enable_configuration = mscan_enable_configuration;
+ chipspecops->disable_configuration = mscan_disable_configuration;
+
+ chipspecops->baud_rate = mscan_baud_rate;
+ chipspecops->set_btregs = mscan_set_btregs;
+
+ chipspecops->start_chip = mscan_start_chip;
+ chipspecops->stop_chip = mscan_stop_chip;
+ chipspecops->attach_to_chip = mscan_attach_to_chip;
+ chipspecops->release_chip = mscan_release_chip;
+
+ chipspecops->standard_mask = mscan_standard_mask;
+ chipspecops->extended_mask = mscan_extended_mask;
+ chipspecops->message15_mask = NULL; /* mscan_message15_mask; */
+
+ chipspecops->pre_read_config = mscan_pre_read_config;
+ chipspecops->pre_write_config = mscan_pre_write_config;
+ chipspecops->send_msg = mscan_send_msg;
+ chipspecops->remote_request = mscan_remote_request;
+
+ chipspecops->irq_handler = mscan_irq_handler;
+ chipspecops->irq_accept = NULL; /* mscan_irq_accept; */
+ chipspecops->config_irqs = mscan_config_irqs;
+
+ chipspecops->clear_objects = mscan_clear_objects;
+ chipspecops->check_tx_stat = mscan_check_tx_stat;
+ chipspecops->wakeup_tx = mscan_wakeup_tx;
+ chipspecops->filtch_rq = mscan_filtch_rq;
+ return 0;
+}
+
+int mscan_fill_chipspecops(struct canchip_t *chip)
+{
+ chip->chip_type = "mscan";
+ chip->max_objects = 1;
+ chip->write_register = chip->hostdevice->hwspecops->write_register;
+ chip->read_register = chip->hostdevice->hwspecops->read_register;
+
+ /*
+ chip->flags;
+ chip->baudrate;
+ chip->msgobj;
+ chip->chip_data;
+ chip->chip_lock;
+
+ chip->sja_cdr_reg;
+ chip->sja_ocr_reg;
+ chip->int_cpu_reg;
+ chip->int_clk_reg;
+ chip->int_bus_reg;
+
+ #ifdef CAN_WITH_RTL
+ chip->worker_thread;
+ chip->pend_flags;
+ #endif
+ */
+
+ mscan_register(chip->chipspecops);
+ return 0;
+}
+
+
+/* ************************************************************************************************************************************* */
+
+
+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;
+
+ mscan_clear_flags(chip, MSCAN_CTL1_CANE, MSCAN_CTL1);
+ mscan_set_flags(chip, MSCAN_CTL1_CANE, MSCAN_CTL1);
+
+ 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)
+{
+ /* do not clear TXE flags -> it forces chip to send messages in buffers */
+ reg_t rflg;
+
+ if (mscan_init_mode_active(chip))
+ {
+ DEBUGMSG("MSCAN: Clearing IRQs while INIT active \n");
+ return -EBUSY;
+ }
+
+ DEBUGMSG("Clearing IRQ flags...\n");
+
+ rflg = MSCAN_RFLG_WUPIF | MSCAN_RFLG_CSCIF | MSCAN_RFLG_RSTAT |
+ MSCAN_RFLG_TSTAT | MSCAN_RFLG_OVRIF | MSCAN_RFLG_RXF;
+
+ /* reset flags by writing '1' */
+ can_write_reg(chip, rflg, MSCAN_RFLG);
+
+ return 0;
+}
+
+
+/* ************************************************************************************************************************************* */
+
+
+void mscan_notifyRXends(struct msgobj_t * obj, int what)
+{
+ struct canque_edge_t * edge;
+ canque_for_each_inedge(obj->qends, edge){
+ canque_notify_outends(edge, what);
+ }
+}
+
+/* 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)
+{
+ volatile struct mscan_msg_buffer * txb = (struct mscan_msg_buffer *)(chip->chip_base_addr + MSCAN_TXFG);
+ reg_t rtr;
+
+
+ if (msg->flags & MSG_RTR)
+ rtr = 0x01;
+ else
+ rtr = 0x00;
+
+ /* set Can mesage ID and local priority */
+ if (msg->flags & MSG_EXT)
+ {
+ /* Extended ID */
+ txb->id_0 = (reg_t)((msg->id >> 21) & 0x000000ff);
+ txb->id_1 = (reg_t)(
+ ((msg->id >> 18) & 0x000000e0) |
+ 0x00000018 | /* SRR & IDE */
+ ((msg->id >> 15) & 0x00000003));
+ txb->id_2 = (reg_t)((msg->id >> 7) & 0x000000ff);
+ txb->id_3 = (reg_t)(((msg->id << 1) & 0x000000fe) | rtr);
+
+ /* local priority is 7 MSB bits followed by IDE flag */
+ txb->local_prio = (reg_t)((txb->id_0 & 0xfe) | 0x01); /* IDE=1 */
+ }
+ else
+ {
+ /* Standard ID */
+ txb->id_0 = (reg_t)((msg->id >> 3) & 0x000000ff);
+ txb->id_1 = (reg_t)(((msg->id << 5) & 0x000000e0) | (rtr << 4)); /* IDE=0 */
+ txb->id_2 = 0x00;
+ txb->id_3 = 0x00;
+
+ /* local priority are 7 MSB bits folowed by IDE flag */
+ txb->local_prio = (reg_t)(txb->id_0 & 0xfe); /* IDE=0 */
+ }
+
+ /* set data */
+ switch (msg->length)
+ {
+ case 8: txb->data_7 = msg->data[7];
+ case 7: txb->data_6 = msg->data[6];
+ case 6: txb->data_5 = msg->data[5];
+ case 5: txb->data_4 = msg->data[4];
+ case 4: txb->data_3 = msg->data[3];
+ case 3: txb->data_2 = msg->data[2];
+ case 2: txb->data_1 = msg->data[1];
+ case 1: txb->data_0 = msg->data[0];
+ }
+
+ /* 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)
+{
+ 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) |
+ (((uint32_t)rxb->id_1 << 15) & 0x00070000) |
+ (((uint32_t)rxb->id_2 << 7 ) & 0x0000ff00) |
+ (((uint32_t)rxb->id_3 >> 1 ) & 0x000000ff);
+
+ /* RTR flag */
+ if (rxb->id_3 & 0x01)
+ msg->flags |= MSG_RTR;
+
+ /* EXT flag */
+ msg->flags |= MSG_EXT;
+ }
+ else
+ {
+ DEBUGMSG("std ID\n");
+ /* Standard ID */
+ msg->id = (((uint32_t)rxb->id_0 << 3) & 0x000007f8) |
+ (((uint32_t)rxb->id_1 >> 5) & 0x00000007);
+
+ /* RTR flag */
+ if (rxb->id_1 & 0x08)
+ msg->flags |= MSG_RTR;
+
+ /* no EXT flag is set here */
+ }
+
+ /* retrieve data */
+ switch (rxb->data_len)
+ {
+ case 8: msg->data[7] = rxb->data_7;
+ case 7: msg->data[6] = rxb->data_6;
+ case 6: msg->data[5] = rxb->data_5;
+ case 5: msg->data[4] = rxb->data_4;
+ case 4: msg->data[3] = rxb->data_3;
+ case 3: msg->data[2] = rxb->data_2;
+ case 2: msg->data[1] = rxb->data_1;
+ case 1: msg->data[0] = rxb->data_0;
+ }
+
+ /* data length */
+ msg->length = (reg_t)(rxb->data_len & 0x1f);
+}
+/* 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;
+ if (*tseg2 > MSCAN_TSEG2_MAX)
+ *tseg2 = MSCAN_TSEG2_MAX;
+ *tseg1 = tseg - *tseg2;
+ if (*tseg1 > MSCAN_TSEG1_MAX) {
+ *tseg1 = MSCAN_TSEG1_MAX;
+ *tseg2 = tseg - *tseg1;
+ }
+ 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"); */
+ return mscan_get_flags(chip, MSCAN_CTL0_INITRQ, MSCAN_CTL0) &&
+ mscan_get_flags(chip, MSCAN_CTL1_INITAK, MSCAN_CTL1);
+}
+static int mscan_sleep_mode_active(struct canchip_t *chip)
+{
+ /* Sleep Request AND Sleep Ack */
+ return mscan_get_flags(chip, MSCAN_CTL0_SLPRQ, MSCAN_CTL0) &&
+ 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); */
+ 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 void mscan_clear_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)
+{
+ /* clear 25 registers of buffer, others are reset to 0-no need to clean them */
+ unsigned 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;
+}
+