Initial MPC5200 support contribution
authorMartin Petera <martin.petera@gmail.com>
Wed, 2 Dec 2009 16:18:40 +0000 (17:18 +0100)
committerMartin Petera <martin.petera@gmail.com>
Wed, 2 Dec 2009 16:18:40 +0000 (17:18 +0100)
lincan/include/mpc5200.h [new file with mode: 0644]
lincan/include/mscan.h [new file with mode: 0644]
lincan/src/mpc5200.c [new file with mode: 0644]
lincan/src/mscan.c [new file with mode: 0644]

diff --git a/lincan/include/mpc5200.h b/lincan/include/mpc5200.h
new file mode 100644 (file)
index 0000000..d63ffbd
--- /dev/null
@@ -0,0 +1,76 @@
+/**************************************************************************/
+/* File: mpc5200.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.  */
+/**************************************************************************/
+
+#define NR_82527       0
+#define NR_SJA1000     0
+#define NR_MSCAN       2                               /* this isnt used in Lincan core */
+#define NR_ALL         2
+
+#define MPC5200_CAN_IRQ                17              /* IRQ 17, 18 according to shark.dts */
+#define MPC5200_CAN_CHIP_OFFSET                0x80
+
+#define IO_RANGE                       0x80
+
+
+/* Clock frequency - used for baudrate */
+// TODO: zjistit frekvence IPB a SYS_XTAL
+#define MPC5200_SHARK_SYS_XTAL_FREQ    32768000        /* 32768k xtal */
+#define MPC5200_SHARK_IPB_FREQ         3300000         /* derived from XTAL by dividing */
+
+/* Determine which clock source to use */
+/* 0 - use IP Bus clock                */
+/* 1 - use SYS_XTAL_IN frequency       */
+#define MPC5200_CLKSRC         1               
+
+#ifndef MPC5200_CLKSRC
+       #define MPC5200_CLK_FREQ        MPC5200_SHARK_SYS_XTAL_FREQ
+#else
+       #define MPC5200_CLK_FREQ        MPC5200_SHARK_IPB_FREQ
+#endif
+
+
+
+/* static CAN_DEFINE_SPINLOCK(mpc5200_port_lock); */
+
+int mpc5200_request_io(struct candevice_t *candev);
+int mpc5200_release_io(struct candevice_t *candev);
+int mpc5200_reset(struct candevice_t *candev); 
+int mpc5200_init_hw_data(struct candevice_t *candev);
+int mpc5200_init_chip_data(struct candevice_t *candev, int chipnr);
+int mpc5200_init_obj_data(struct canchip_t *chip, int objnr);
+int mpc5200_program_irq(struct candevice_t *candev);
+void mpc5200_write_register(unsigned data, can_ioptr_t address);
+unsigned mpc5200_read_register(can_ioptr_t address);
+
diff --git a/lincan/include/mscan.h b/lincan/include/mscan.h
new file mode 100644 (file)
index 0000000..0daf98c
--- /dev/null
@@ -0,0 +1,283 @@
+/**************************************************************************/
+/* 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.  */
+/**************************************************************************/
+
+
+#define reg_t uint8_t
+
+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_TARG     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        = 0x0a,                 /* 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       = 0x0a,                 /* 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 */
+};
diff --git a/lincan/src/mpc5200.c b/lincan/src/mpc5200.c
new file mode 100644 (file)
index 0000000..10d23a1
--- /dev/null
@@ -0,0 +1,137 @@
+/**************************************************************************/
+/* File: mpc5200.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/mpc5200.h"
+#include "../include/mscan.h"
+
+int mpc5200_request_io(struct candevice_t *candev)
+{
+       if (!can_request_io_region(candev->io_addr, candev->nr_all_chips * IO_RANGE, DEVICE_NAME)) {
+               CANMSG("Unable to open port: 0x%lx\n",candev->io_addr);
+               return -ENODEV;
+       }
+
+       DEBUGMSG("Registered IO-memory: 0x%lx - 0x%lx\n", candev->io_addr, candev->io_addr + candev->nr_all_chips * IO_RANGE - 1);
+       return 0;
+}
+
+int mpc5200_release_io(struct candevice_t *candev)
+{
+       can_release_io_region(candev->io_addr, candev->nr_all_chips * IO_RANGE);
+
+       return 0;
+}
+
+int mpc5200_reset(struct candevice_t *candev)
+{
+       int i; 
+       DEBUGMSG("Resetting MSCAN chips ...\n");
+
+       for (i = 0; i < candev->nr_all_chips; i++)
+       {
+           /* !!! Assuming this card has ONLY MSCAN chips !!! */
+           if (mscan_reset_chip(candev->chip[i])) return -ENODEV;
+       }
+
+       return 0;
+}
+
+int mpc5200_init_hw_data(struct candevice_t *candev) 
+{
+       /* candev->res_addr = RESET_ADDR; */
+       candev->nr_82527_chips = NR_82527;
+       candev->nr_sja1000_chips = NR_SJA1000;
+       candev->nr_all_chips = NR_ALL;
+       /* candev->flags |= CANDEV_PROGRAMMABLE_IRQ; */
+
+       return 0;
+}
+int mpc5200_init_chip_data(struct candevice_t *candev, int chipnr)
+{
+       mscan_fill_chipspecops(candev->chip[chipnr]);
+
+       candev->chip[chipnr]->chip_base_addr = can_ioport2ioptr(candev->io_addr) + chipnr * MPC5200_CAN_CHIP_OFFSET; /* one chip with 2 interfaces */
+       candev->chip[chipnr]->clock = MPC5200_CLK_FREQ;
+       candev->chip[chipnr]->chip_irq = MPC5200_CAN_IRQ + chipnr;
+       candev->chip[chipnr]->hostdevice = candev;
+
+       return 0;
+}
+
+int mpc5200_init_obj_data(struct canchip_t *chip, int objnr)
+{
+       /* we have only two chips with only one mailbox each */
+       chip->msgobj[objnr]->obj_base_addr = (can_ioptr_t) MSCAN_CTL0 + MPC5200_CAN_CHIP_OFFSET * objnr;
+
+       return 0;
+}
+
+int mpc5200_program_irq(struct candevice_t *candev)
+{
+       /* we  don't use programmable interrupt on MPC5200 */ 
+       return 0;
+}
+
+
+void mpc5200_write_register(unsigned data, can_ioptr_t address)
+{
+       /* address is an absolute address */
+       DEBUGMSG("write register\n");
+       writeb(data, address);          /* regs in PowerPC (5200) are one-byte length */
+}
+
+unsigned mpc5200_read_register(can_ioptr_t address)
+{
+       /* address is an absolute address */
+       DEBUGMSG("read register\n");
+       return readb(address);          /* regs in PowerPC (5200) are one-byte length */
+}
+
+int mpc5200_register(struct hwspecops_t *hwspecops)
+{
+       hwspecops->request_io = mpc5200_request_io;
+       hwspecops->release_io = mpc5200_release_io;
+       hwspecops->reset = mpc5200_reset;
+       hwspecops->init_hw_data = mpc5200_init_hw_data;
+       hwspecops->init_chip_data = mpc5200_init_chip_data;
+       hwspecops->init_obj_data = mpc5200_init_obj_data;
+       hwspecops->program_irq = mpc5200_program_irq;
+       hwspecops->write_register = mpc5200_write_register;
+       hwspecops->read_register = mpc5200_read_register;
+       return 0;
+}
diff --git a/lincan/src/mscan.c b/lincan/src/mscan.c
new file mode 100644 (file)
index 0000000..65b648a
--- /dev/null
@@ -0,0 +1,1155 @@
+/**************************************************************************/
+/* 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 myDEBUG 1              /* enable debug for MPC5200 with MSCAN only */
+
+#if myDEBUG
+       #define DEBUGMSG(fmt,args...) can_printk(KERN_ERR "lincan (debug): " fmt,##args)
+#endif
+
+
+#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_IRQ_WAIT_LOOPS 25
+
+
+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, int buffer);
+
+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 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 void mscan_clear_buffer(struct canchip_t * chip, unsigned start_addr);
+
+/* Enable folowing IRQs
+ * MSCAN_TIER_TXE - Transmit Empty Interrupt
+ * MSCAN_RIER_RXFIE - Receive Buffer Full
+ * 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 */
+/* 1 - enable interrupt, 0 - interrupt is masked */
+
+
+/* ************************************************************************************************************************************* */
+
+
+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 ! */
+       int i = 0;
+
+       DEBUGMSG("Enabling configuration...\n");
+
+       if (mscan_init_mode_active(chip))       /* chip is already in config mode */
+               return 0;
+
+       /* 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;
+       }
+
+
+       /* 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;
+       }
+
+
+       return 0;
+}
+
+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");
+
+       if (!mscan_init_mode_active(chip) && !mscan_sleep_mode_active(chip))    /* chip is already in normal mode */
+               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) {
+               CANMSG("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) {
+               CANMSG("Error leaving Sleep mode (disable configuration) \n");
+               return -EBUSY;
+       }
+
+
+       /* Enable interrupt */
+       can_enable_irq(chip->chip_irq);
+
+       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;
+
+
+       DEBUGMSG("Seting Baud rate...\n");
+
+        /* 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 */
+       brp--; tseg1--; tseg2--;
+
+       btr0 = (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 */
+
+       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 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 */
+       can_enable_irq(chip->chip_irq);
+
+       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 */
+       can_disable_irq(chip->chip_irq);
+       
+       mscan_clear_objects(chip);
+
+       /* 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_set_flags(chip, 0x30, 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 */
+       mr0 =  (reg_t)((mask & 0x0ff0) >> 4);
+       mr1 =  (reg_t)((mask & 0x000f) << 4);
+
+
+       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);
+
+       DEBUGMSG("Set standard_mask [id:0x%04x RTR=%d, m:0x%04x RTR=%d]\n", code >> 1, code & 0x0001, mask >> 1, mask & 0x0001);
+       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_set_flags(chip, 0x30, 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);
+
+       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);
+    
+        return 0;
+}
+
+
+/* ************************************************************************************************************************************* */
+
+
+int mscan_pre_read_config(struct canchip_t *chip, struct msgobj_t *obj)
+{
+       DEBUGMSG("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;
+       int buff_no;
+
+       DEBUGMSG("Pre write config\n");
+
+       can_preempt_disable();
+       
+       /* 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)
+               return -ENODEV;         /* 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);
+
+       can_preempt_enable();
+
+       return 0;
+}
+
+int mscan_send_msg(struct canchip_t *chip, struct msgobj_t *obj, struct canmsg_t *msg)
+{
+       DEBUGMSG("Send Message\n");
+       
+       /* nothing to do here - message is already set to transmit in pre_write_config */
+       
+       return 0;
+}
+
+int mscan_remote_request(struct canchip_t *chip, struct msgobj_t *obj)
+{
+       CANMSG("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_TFLG_TXE   - Transmitter Buffer Empty */
+
+       /* get IRQs */
+       uint16_t irq_reg;
+       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); 
+
+       do {
+
+               if(!loop_cnt--) {
+                       CANMSG("mscan_irq_handler IRQ %d stuck\n", irq);
+                       return CANCHIP_IRQ_STUCK;
+               }
+
+               /* Received message */
+               if (irq_reg & MSCAN_RFLG_RXF)
+               {
+                       DEBUGMSG("Received message");
+
+                       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);
+               }
+
+               /* Receive bus off/error/warning */
+               if (irq_reg & MSCAN_RFLG_RSTAT)
+               {
+                       switch (((irq_reg & MSCAN_RFLG_RSTAT) >> 4) & 0x03)
+                       {
+                               case 3: /* Bus off */
+                                       CANMSG("Error: entering RX BUS OFF state");
+
+                                       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;
+                       }
+                       
+                       /* 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)
+                       {
+                               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;
+                       }
+                       
+                       /* reset flag */
+                       mscan_set_flags(chip, MSCAN_RFLG_TSTAT, 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 >> 8) & MSCAN_TFLG_TXE)
+               {
+                   /* Clear TXACK flag */                  
+                   mscan_set_flags(chip, MSCAN_TFLG_TXE, MSCAN_TFLG);
+
+                   /* 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);
+
+       return CANCHIP_IRQ_HANDLED;
+}
+
+int mscan_irq_accept(int irq, struct canchip_t *chip)
+{
+       CANMSG("mscan_irq_accept NOT IMPLEMENTED\n");
+       return -ENOSYS;
+}
+
+int mscan_config_irqs(struct canchip_t *chip, short irqs)
+{
+       int err;
+       reg_t tier, rier;
+
+       if (mscan_init_mode_active(chip))
+       {
+               CANMSG("MSCAN: Setting Up IRQs while INIT active \n");
+               return -EBUSY;
+       }
+
+       tier = (reg_t)((irqs >> 8) & 0x00ff & ~MSCAN_TIER_RSVD);
+       rier = (reg_t)(irqs & 0x00ff);
+
+       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);
+       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, 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();
+       
+       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_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 myDEBUG
+       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;
+               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;
+
+       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)
+{
+       /* 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;
+
+       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;
+
+       if (mscan_init_mode_active(chip))
+       {
+               CANMSG("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;
+       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;
+}
+
+
+/* ************************************************************************************************************************************* */
+
+
+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, int buffer)
+{
+       volatile struct mscan_msg_buffer * txb = (struct mscan_msg_buffer *)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;
+       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);
+}
+
+/* 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;
+
+       /* 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 */
+       {
+               /* 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
+       {
+               /* Standard ID */
+               msg->id =       (((uint32_t)rxb->id_0 << 3) & 0x000001f8) |
+                               (((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)
+{
+        *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 * (tseg + 1 - *tseg2) / (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 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 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);
+}