This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TCAN4550: TCAN4550

Part Number: TCAN4550

Tool/software:

Hi,

We are using TCAN4450 module is integrated in IMX8DXL processor. The TCAN module is successfully initialized but unable to send the data(TX) and RX is happenening is correctly.
When we are trying to send the message (TX) from the processor, observed TCAN panic.

Below is the dts configuration.

&lpspi3 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lpspi3>;
fsl,spi-num-chipselects = <1>;
spi-max-frequency = <6000000>;
cs-gpios = <&lsio_gpio0 16 GPIO_ACTIVE_HIGH>;
status = "okay";


tcan4x5x1: tcan4x5x@0 {
compatible = "ti,tcan4x5x";
reg = <0>;
pinctrl-names = "default";
#address-cells = <1>;
#size-cells = <1>;
spi-max-frequency = <4000000>;
bosch,mram-cfg = <0x0 3 2 28 10 0 20 12>; 
clocks = <&hclk>, <&cclk>;
clock-names = "hclk", "cclk";
interrupt-parent = <&lsio_gpio3>;
interrupts = <18 IRQ_TYPE_EDGE_FALLING>;
data-ready-gpios = <&lsio_gpio3 18 GPIO_ACTIVE_HIGH>;
reset-gpios = <&exp2 11 GPIO_ACTIVE_HIGH>;
iw-tcan-prop;
wakeup-source;
status = "okay";

};
};

And below is the PANIC when trying to send the data

root@imx8dxl-iwg46s:~# insmod /run/media/mmcblk0p1/tcan4x5x.ko
[ 25.051965] inside probe-----------
[ 25.409155] tcan4x5x spi3.0: m_can device registered (irq=215, version=32)
[ 25.419456] tcan4x5x spi3.0 can3: TCAN4X5X successfully initialized.
root@imx8dxl-iwg46s:~#
root@imx8dxl-iwg46s:~# ip link set can3 up type can bitr[ 33.851928] can-3v3: disabling
[ 33.855019] vref_1v8: disabling
[ 33.858219] usb_otg1_vbus: disabling
ate 250000
[ 36.234793] IPv6: ADDRCONF(NETDEV_CHANGE): can3: link becomes ready
root@imx8dxl-iwg46s:~# cansend can3 123#aabbccddee
[ 42.931517] begining-----
[ 42.934202] handler begining---------------------
[ 42.938970] 11th bit identifier
[ 42.938977] else part of version----------------
[ 42.946910] BUG: scheduling while atomic: cansend/447/0x00000203
[ 42.952990] Modules linked in: tcan4x5x
[ 42.956893] CPU: 1 PID: 447 Comm: cansend Not tainted 5.15.52+gf266012f09d6 #129
[ 42.964318] Hardware name: iW-RainboW-G46M-i.MX8DXL OSM (DT)
[ 42.969983] Call trace:
[ 42.972429] dump_backtrace+0x0/0x1a0
[ 42.976116] show_stack+0x1c/0x70
[ 42.979451] dump_stack_lvl+0x68/0x84
[ 42.983124] dump_stack+0x1c/0x38
[ 42.986454] __schedule_bug+0x60/0x80
[ 42.990126] __schedule+0x658/0x710
[ 42.993627] schedule+0x74/0x110
[ 42.996869] schedule_timeout+0x80/0xf0
[ 43.000716] wait_for_completion_timeout+0x80/0x10c
[ 43.005607] fsl_lpspi_transfer_one+0x4c8/0x6e0
[ 43.010153] spi_transfer_one_message+0x174/0x1d0
[ 43.014868] __spi_pump_messages.constprop.0+0x264/0x50c
[ 43.020195] __spi_sync+0x18c/0x1c0
[ 43.023694] spi_write_then_read+0xf8/0x1e0
[ 43.027890] tcan4x5x_regmap_read+0x3c/0x64 [tcan4x5x]
[ 43.033051] _regmap_raw_read+0xd8/0x17c
[ 43.036986] _regmap_bus_read+0x48/0x80
[ 43.040835] _regmap_read+0x64/0xf0
[ 43.044338] regmap_read+0x50/0x80
[ 43.047752] tcan4x5x_read_reg+0x34/0x60 [tcan4x5x]
[ 43.052652] m_can_tx_handler+0x298/0x89c
[ 43.056672] m_can_start_xmit+0xac/0x14c
[ 43.060610] dev_hard_start_xmit+0xd8/0x160
[ 43.064803] sch_direct_xmit+0xe8/0x36c
[ 43.068652] __dev_queue_xmit+0x524/0xb6c
[ 43.072677] dev_queue_xmit+0x18/0x24
[ 43.076351] can_send+0xc0/0x260
[ 43.079592] raw_sendmsg+0x140/0x30c
[ 43.083180] sock_write_iter+0xa4/0x110
[ 43.087028] new_sync_write+0x174/0x184
[ 43.090877] vfs_write+0x230/0x29c
[ 43.094291] ksys_write+0xdc/0xf4
[ 43.097618] __arm64_sys_write+0x20/0x2c
[ 43.101554] invoke_syscall+0x48/0x114
[ 43.105313] el0_svc_common.constprop.0+0xd4/0xfc
[ 43.110033] do_el0_svc+0x2c/0x94
[ 43.113361] el0_svc+0x28/0x80
[ 43.116427] el0t_64_sync_handler+0xa8/0x130
[ 43.120707] el0t_64_sync+0x1a0/0x1a4
[ 43.124997] putidx 0000 0000 0000 0000 0000 0000 0000 0000
[ 43.132847] M_CAN_TXFQS0000 0000 0000 0000 0000 0000 0000 1100
[ 43.139491] M_CAN_FIFO_ID,------------0011 0010 0001 0101 0000 0011 0010 0000
[ 43.147313] After---- M_CAN_FIFO_ID,------------0011 0010 0001 0101 0000 0011 0010 0000
[ 43.155643] before fifo write----------------------------
[ 43.161333] after fifo write-----------------------------
[ 43.166784] inside for loop fifo write-------------------------
[ 43.172771] inside for loop fifo write-------------------------
[ 43.178959] beg of delay-------------------------------
[ 43.184270] end of delay--------------------------
[ 43.189777] not full------------
[ 43.193134] ------------[ cut here ]------------
[ 43.193139] WARNING: CPU: 0 PID: 447 at kernel/softirq.c:362 __local_bh_enable_ip+0xac/0xbc
[ 43.193164] Modules linked in:
[ 43.193168] tcan4x5x
[ 43.209194]
[ 43.209202] CPU: 0 PID: 447 Comm: cansend Tainted: G W 5.15.52+gf266012f09d6 #129
[ 43.209213] Hardware name: iW-RainboW-G46M-i.MX8DXL OSM (DT)
[ 43.209218] pstate: 00000005 (nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[ 43.209227] pc : __local_bh_enable_ip+0xac/0xbc
[ 43.209240] lr : __dev_queue_xmit+0x424/0xb6c
[ 43.209250] sp : ffff80000af5bb20
[ 43.209253] x29: ffff80000af5bb20 x28: ffff000005f38000 x27: 0000000000000000
[ 43.209268] x26: ffff000005c59028 x25: ffff000005b91000 x24: 0000000000000010
[ 43.209283] x23: ffff000005b91000 x22: ffff000005e99e00 x21: ffff000005b90400
[ 43.209300] x20: 0000000000000000 x19: ffff000005c59000 x18: 0000000000000003
[ 43.209314] x17: 0000000000001aeb x16: 0000000000000113 x15: 000000b4caf04ccf
[ 43.209329] x14: 0000000000000245 x13: 0000000000000000 x12: 0000000000000000
[ 43.209343] x11: 0000000000000002 x10: 0000000000000990 x9 : ffff80000af5b7a0
[ 43.209359] x8 : ffff000005f389f0 x7 : ffff000005b90540 x6 : ffff000005b90780
[ 43.209378] x5 : 000000000000000a x4 : 000000000000000a x3 : ffff000005b904d8
[ 43.209391] x2 : 0000000000000000 x1 : 0000000000000200 x0 : 00000000fffffffe
[ 43.209409] Call trace:
[ 43.209414] __local_bh_enable_ip+0xac/0xbc
[ 43.209425] __dev_queue_xmit+0x424/0xb6c
[ 43.209435] dev_queue_xmit+0x18/0x24
[ 43.209445] can_send+0xc0/0x260
[ 43.209456] raw_sendmsg+0x140/0x30c
[ 43.209465] sock_write_iter+0xa4/0x110
[ 43.209480] new_sync_write+0x174/0x184
[ 43.209494] vfs_write+0x230/0x29c
[ 43.209505] ksys_write+0xdc/0xf4
[ 43.209518] __arm64_sys_write+0x20/0x2c
[ 43.209529] invoke_syscall+0x48/0x114
[ 43.209540] el0_svc_common.constprop.0+0xd4/0xfc
[ 43.209554] do_el0_svc+0x2c/0x94
[ 43.209567] el0_svc+0x28/0x80
[ 43.209578] el0t_64_sync_handler+0xa8/0x130
[ 43.209586] el0t_64_sync+0x1a0/0x1a4
[ 43.209595] ---[ end trace 1101eba41d86a994 ]---
[ 43.209712] Unable to handle kernel paging request at virtual address 0000ffff84049df0
[ 43.209726] Mem abort info:
[ 43.209728] ESR = 0x82000007
[ 43.209731] EC = 0x20: IABT (lower EL), IL = 32 bits
[ 43.209737] SET = 0, FnV = 0
[ 43.209741] EA = 0, S1PTW = 0
[ 43.209744] FSC = 0x07: level 3 translation fault
[ 43.209749] user pgtable: 4k pages, 48-bit VAs, pgdp=0000000094a20000
[ 43.209755] [0000ffff84049df0] pgd=0800000085ee3003, p4d=0800000085ee3003, pud=0800000085c1d003, pmd=0800000085c25003, pte=0000000000000000
[ 43.209776] Internal error: Oops: 82000007 [#1] PREEMPT SMP
[ 43.209782] Modules linked in: tcan4x5x
[ 43.209790] CPU: 0 PID: 447 Comm: cansend Tainted: G W 5.15.52+gf266012f09d6 #129
[ 43.209799] Hardware name: iW-RainboW-G46M-i.MX8DXL OSM (DT)
[ 43.209803] pstate: 20000000 (nzCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[ 43.209812] pc : 0000ffff84049df0
[ 43.209815] lr : 0000ffff83fd06d0
[ 43.209817] sp : 0000ffffd6ba8250
[ 43.209820] x29: 0000ffffd6ba8250 x28: 0000ffff8417c350 x27: 0000aaaad3e13b88
[ 43.209834] x26: 0000ffffd6ba82d0 x25: 0000000000000000 x24: 0000ffff8417aaf8
[ 43.209850] x23: 0000ffff8412c000 x22: 0000000000000004 x21: 0000ffff8412c748
[ 43.209864] x20: 0000aaaad3e14008 x19: 0000ffff8412c728 x18: fffffffffffff000
[ 43.209881] x17: 0000000000000000 x16: 0000000000000000 x15: 0000ffff84175da0
[ 43.209894] x14: 0000ffff8417c000 x13: 0000ffff8417bb60 x12: 0000ffff841740b0
[ 43.209909] x11: 0000ffffd6ba82c0 x10: 0000210000000000 x9 : 0000ffffd6ba82bf
[ 43.209924] x8 : 0000000000000020 x7 : 0000ffff8417c930 x6 : 0000ffff8417c350
[ 43.209939] x5 : 000000000000017f x4 : 0000ffff8417bab0 x3 : 0000000000000000
[ 43.209953] x2 : 0000ffff8412cb60 x1 : 0000000000000001 x0 : 0000aaaad3e14008
[ 43.546303] ---[ end trace 1101eba41d86a995 ]---
[ 43.546310] Kernel panic - not syncing: Oops: Fatal exception in interrupt
[ 43.546316] SMP: stopping secondary CPUs
[ 43.546324] Kernel Offset: disabled
[ 43.546327] CPU features: 0x00000001,20000846
[ 43.546333] Memory Limit: none
[ 43.572634] ---[ end Kernel panic - not syncing: Oops: Fatal exception in interrupt ]---

  • Hello Tanushree,

    If I understand you correctly, the TCAN4550 is getting initialized correctly and can receive CAN messages, but has an issue when trying to transmit a message.  Is that correct?

    I'm not sure about what "Kernel panic" is and my expertise is with the TCAN4550 device and not with Linux so I can help you with register configuration and hardware related questions.  

    However, my first thoughts are that you may have a memory allocation in the TCAN4550's MRAM that could be causing issues.  The TCAN4550 only has 2Kb of MRAM that you need to configure for your application.  All of the TX and RX buffers, SID and XID filters, and event FIFO messages must fit within the 2Kb limit. I don't know how many bytes of data you are configuring for your TX and RX buffers which will determine how much memory is needed for those elements.  But just based on the number of elements in your configuration, you are almost certainly exceeding the 2Kb limit. 

    bosch,mram-cfg = <0x0 3 2 28 10 0 20 12>; 

    Please review the m_can.yaml (Link) for a description of this MRAM configuration.

    Please note that there is no error checking on the memory allocation within MRAM.  Also note that the memory address wraps around automatically if you try to access a location beyond the max address.  Therefore, it is possible for you to overwrite memory cells within your configuration and you need to calculate and verify your memory allocation will not exceed the max limit in order to prevent and overwrite.

    The number of elements that MCAN can be configured to support exceeds the physical memory in the TCAN4550, so you will not be able to allocate the maximum number of elements for each type.  Please verify your MRAM memory allocation requirements and adjust the number of elements in your configuration if necessary.

    If you can read back the final register values from the device after initialization I can review them for possible errors at the device level if you feel your MRAM allocation is correct.

    Regards,

    Jonathan

  • Hello Jonathan,

    Yes, your understood correctly.

    With the same configuration and m_can file is working in the IMX6ULL. but in IMX8DXL it is not working. In m_can_xmit function queue work function is calling but we are removing the queue work function and we are directly calling the m_can_tx_handler function.

    Below is the m_can.c and tcan4x5x.c file. The same changes is working in the IMX6 processor. This changes is for CANFD optimization.

    0410.tcan4x5x.c
    // SPDX-License-Identifier: GPL-2.0
    // SPI to CAN driver for the Texas Instruments TCAN4x5x
    // Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/
    
    #include <linux/regmap.h>
    #include <linux/spi/spi.h>
    
    #include <linux/regulator/consumer.h>
    #include <linux/gpio/consumer.h>
    
    #include "m_can.h"
    
    #define DEVICE_NAME "tcan4x5x"
    #define TCAN4X5X_EXT_CLK_DEF 40000000
    
    #define TCAN4X5X_DEV_ID0 0x00
    #define TCAN4X5X_DEV_ID1 0x04
    #define TCAN4X5X_REV 0x08
    #define TCAN4X5X_STATUS 0x0C
    #define TCAN4X5X_ERROR_STATUS 0x10
    #define TCAN4X5X_CONTROL 0x14
    
    #define TCAN4X5X_CONFIG 0x800
    #define TCAN4X5X_TS_PRESCALE 0x804
    #define TCAN4X5X_TEST_REG 0x808
    #define TCAN4X5X_INT_FLAGS 0x820
    #define TCAN4X5X_MCAN_INT_REG 0x824
    #define TCAN4X5X_INT_EN 0x830
    
    /* Interrupt bits */
    #define TCAN4X5X_CANBUSTERMOPEN_INT_EN BIT(30)
    #define TCAN4X5X_CANHCANL_INT_EN BIT(29)
    #define TCAN4X5X_CANHBAT_INT_EN BIT(28)
    #define TCAN4X5X_CANLGND_INT_EN BIT(27)
    #define TCAN4X5X_CANBUSOPEN_INT_EN BIT(26)
    #define TCAN4X5X_CANBUSGND_INT_EN BIT(25)
    #define TCAN4X5X_CANBUSBAT_INT_EN BIT(24)
    #define TCAN4X5X_UVSUP_INT_EN BIT(22)
    #define TCAN4X5X_UVIO_INT_EN BIT(21)
    #define TCAN4X5X_TSD_INT_EN BIT(19)
    #define TCAN4X5X_ECCERR_INT_EN BIT(16)
    #define TCAN4X5X_CANINT_INT_EN BIT(15)
    #define TCAN4X5X_LWU_INT_EN BIT(14)
    #define TCAN4X5X_CANSLNT_INT_EN BIT(10)
    #define TCAN4X5X_CANDOM_INT_EN BIT(8)
    #define TCAN4X5X_CANBUS_ERR_INT_EN BIT(5)
    #define TCAN4X5X_BUS_FAULT BIT(4)
    #define TCAN4X5X_MCAN_INT BIT(1)
    #define TCAN4X5X_ENABLE_TCAN_INT \
    	(TCAN4X5X_MCAN_INT | TCAN4X5X_BUS_FAULT | \
    	 TCAN4X5X_CANBUS_ERR_INT_EN | TCAN4X5X_CANINT_INT_EN)
    
    /* MCAN Interrupt bits */
    #define TCAN4X5X_MCAN_IR_ARA BIT(29)
    #define TCAN4X5X_MCAN_IR_PED BIT(28)
    #define TCAN4X5X_MCAN_IR_PEA BIT(27)
    #define TCAN4X5X_MCAN_IR_WD BIT(26)
    #define TCAN4X5X_MCAN_IR_BO BIT(25)
    #define TCAN4X5X_MCAN_IR_EW BIT(24)
    #define TCAN4X5X_MCAN_IR_EP BIT(23)
    #define TCAN4X5X_MCAN_IR_ELO BIT(22)
    #define TCAN4X5X_MCAN_IR_BEU BIT(21)
    #define TCAN4X5X_MCAN_IR_BEC BIT(20)
    #define TCAN4X5X_MCAN_IR_DRX BIT(19)
    #define TCAN4X5X_MCAN_IR_TOO BIT(18)
    #define TCAN4X5X_MCAN_IR_MRAF BIT(17)
    #define TCAN4X5X_MCAN_IR_TSW BIT(16)
    #define TCAN4X5X_MCAN_IR_TEFL BIT(15)
    #define TCAN4X5X_MCAN_IR_TEFF BIT(14)
    #define TCAN4X5X_MCAN_IR_TEFW BIT(13)
    #define TCAN4X5X_MCAN_IR_TEFN BIT(12)
    #define TCAN4X5X_MCAN_IR_TFE BIT(11)
    #define TCAN4X5X_MCAN_IR_TCF BIT(10)
    #define TCAN4X5X_MCAN_IR_TC BIT(9)
    #define TCAN4X5X_MCAN_IR_HPM BIT(8)
    #define TCAN4X5X_MCAN_IR_RF1L BIT(7)
    #define TCAN4X5X_MCAN_IR_RF1F BIT(6)
    #define TCAN4X5X_MCAN_IR_RF1W BIT(5)
    #define TCAN4X5X_MCAN_IR_RF1N BIT(4)
    #define TCAN4X5X_MCAN_IR_RF0L BIT(3)
    #define TCAN4X5X_MCAN_IR_RF0F BIT(2)
    #define TCAN4X5X_MCAN_IR_RF0W BIT(1)
    #define TCAN4X5X_MCAN_IR_RF0N BIT(0)
    #define TCAN4X5X_RESET_GPIO 75
    
    
    
    //#ifdef CONFIG_MX6ULL_IWG26I
    #define TCAN4X5X_ENABLE_MCAN_INT \
    	(TCAN4X5X_MCAN_IR_TC | TCAN4X5X_MCAN_IR_RF0F | \
    		 TCAN4X5X_MCAN_IR_RF1F | TCAN4X5X_MCAN_IR_RF0W | \
    	 TCAN4X5X_MCAN_IR_RF1W)
    //#else
     /* CONFIG_MX6ULL_IWG26I */
    //#define TCAN4X5X_ENABLE_MCAN_INT \
    //	(TCAN4X5X_MCAN_IR_TC | TCAN4X5X_MCAN_IR_RF0N | \
    //	 TCAN4X5X_MCAN_IR_RF1N | TCAN4X5X_MCAN_IR_RF0F | \
    //	 TCAN4X5X_MCAN_IR_RF1F)
    //#endif 
    /* CONFIG_MX6ULL_IWG26I */
    
    #define CTRL_REG	0x1018
    #define CTRL_INIT_BIT	BIT(0)
    #define CTRL_CCE_BIT	BIT(1)
    #define RX_FIFO0_CONFIGURATION_REG	0x10A0
    #define RX_FIFO0_WATERMARK_BIT	BIT(24)
    
    
    
    
    #define TCAN4X5X_MRAM_START 0x8000
    #define TCAN4X5X_MCAN_OFFSET 0x1000
    #define TCAN4X5X_MAX_REGISTER 0x8fff
    
    #define TCAN4X5X_CLEAR_ALL_INT 0xffffffff
    #define TCAN4X5X_SET_ALL_INT 0xffffffff
    
    #define TCAN4X5X_WRITE_CMD (0x61 << 24)
    #define TCAN4X5X_READ_CMD (0x41 << 24)
    
    #define TCAN4X5X_MODE_SEL_MASK (BIT(7) | BIT(6))
    #define WDT_ENABLE (BIT(3) | BIT(4))
    #define WDT_ENABLE_BIT BIT(3)
    #define WDT_CLK (BIT(27) | BIT(28))
    #define WDT_CLK_BIT BIT(27)
    #define WDT_RESET (BIT(18) | BIT(19))
    #define WDT_RESET_BIT BIT(18)
    #define WDT_TIM (BIT(28) | BIT(29))
    #define WDT_TIM_BIT BIT(29)
    #define TCAN4X5X_MODE_SLEEP 0x00
    #define TCAN4X5X_MODE_STANDBY BIT(6)
    #define TCAN4X5X_MODE_NORMAL BIT(7)
    
    #define TCAN4X5X_SW_RESET BIT(2)
    
    #define TCAN4X5X_MCAN_CONFIGURED BIT(5)
    #define TCAN4X5X_WATCHDOG_EN BIT(3)
    #define TCAN4X5X_WD_60_MS_TIMER 0
    #define TCAN4X5X_WD_600_MS_TIMER BIT(28)
    #define TCAN4X5X_WD_3_S_TIMER BIT(29)
    #define TCAN4X5X_WD_6_S_TIMER (BIT(28) | BIT(29))
    
    bool iw_tcan_prop = false; /* Flag added for Rugged Telematics Device */
    int iw_rxf0_reg_val; /* Variable to store the RX FIFO 0 Configuration register */
    struct tcan4x5x_priv {
    	struct regmap *regmap;
    	struct spi_device *spi;
    
    	struct m_can_classdev *mcan_dev;
    
    	struct gpio_desc *reset_gpio;
    	struct gpio_desc *device_wake_gpio;
    	struct gpio_desc *device_state_gpio;
    	struct regulator *power;
    
    	/* Register based ip */
    	int mram_start;
    	int reg_offset;
    };
    
    static struct can_bittiming_const tcan4x5x_bittiming_const = {
    	.name = DEVICE_NAME,
    	.tseg1_min = 2,
    	.tseg1_max = 31,
    	.tseg2_min = 2,
    	.tseg2_max = 16,
    	.sjw_max = 16,
    	.brp_min = 1,
    	.brp_max = 32,
    	.brp_inc = 1,
    };
    
    static struct can_bittiming_const tcan4x5x_data_bittiming_const = {
    	.name = DEVICE_NAME,
    	.tseg1_min = 1,
    	.tseg1_max = 32,
    	.tseg2_min = 1,
    	.tseg2_max = 16,
    	.sjw_max = 16,
    	.brp_min = 1,
    	.brp_max = 32,
    	.brp_inc = 1,
    };
    
    static void tcan4x5x_check_wake(struct tcan4x5x_priv *priv)
    {
    	int wake_state = 0;
    
    	if (priv->device_state_gpio)
    		wake_state = gpiod_get_value(priv->device_state_gpio);
    
    	if (priv->device_wake_gpio && wake_state) {
    		gpiod_set_value(priv->device_wake_gpio, 0);
    		usleep_range(5, 50);
    		gpiod_set_value(priv->device_wake_gpio, 1);
    	}
    }
    
    static int tcan4x5x_reset(struct tcan4x5x_priv *priv)
    {
    	int ret = 0;
    
    	if (priv->reset_gpio) {
    		gpiod_set_value(priv->reset_gpio, 1);
    
    		/* tpulse_width minimum 30us */
    		usleep_range(30, 100);
    		gpiod_set_value(priv->reset_gpio, 0);
    	} else {
    		ret = regmap_write(priv->regmap, TCAN4X5X_CONFIG,
    				TCAN4X5X_SW_RESET);
    		if (ret)
    			return ret;
    	}
    
    	usleep_range(700, 1000);
    
    	return ret;
    }
    
    static int regmap_spi_gather_write(void *context, const void *reg,
    		size_t reg_len, const void *val,
    		size_t val_len)
    {
    	struct device *dev = context;
    	struct spi_device *spi = to_spi_device(dev);
    	struct spi_message m;
    	u32 addr;
    	struct spi_transfer t[2] = {
    		{ .tx_buf = &addr, .len = reg_len, .cs_change = 0,},
    		{ .tx_buf = val, .len = val_len, },
    	};
    
    	addr = TCAN4X5X_WRITE_CMD | (*((u16 *)reg) << 8) | val_len >> 2;
    
    	spi_message_init(&m);
    	spi_message_add_tail(&t[0], &m);
    	spi_message_add_tail(&t[1], &m);
    
    	return spi_sync(spi, &m);
    }
    
    static int tcan4x5x_regmap_write(void *context, const void *data, size_t count)
    {
    	u16 *reg = (u16 *)(data);
    	const u32 *val = data + 4;
    
    	return regmap_spi_gather_write(context, reg, 4, val, count - 4);
    }
    
    static int regmap_spi_async_write(void *context,
    		const void *reg, size_t reg_len,
    		const void *val, size_t val_len,
    		struct regmap_async *a)
    {
    	return -ENOTSUPP;
    }
    
    static struct regmap_async *regmap_spi_async_alloc(void)
    {
    	return NULL;
    }
    
    static int tcan4x5x_regmap_read(void *context,
    		const void *reg, size_t reg_size,
    		void *val, size_t val_size)
    {
    	struct device *dev = context;
    	struct spi_device *spi = to_spi_device(dev);
    
    	u32 addr = TCAN4X5X_READ_CMD | (*((u16 *)reg) << 8) | val_size >> 2;
    
    	return spi_write_then_read(spi, &addr, reg_size, (u32 *)val, val_size);
    }
    
    static struct regmap_bus tcan4x5x_bus = {
    	.write = tcan4x5x_regmap_write,
    	.gather_write = regmap_spi_gather_write,
    	.async_write = regmap_spi_async_write,
    	.async_alloc = regmap_spi_async_alloc,
    	.read = tcan4x5x_regmap_read,
    	.read_flag_mask = 0x00,
    	.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
    	.val_format_endian_default = REGMAP_ENDIAN_NATIVE,
    };
    
    static u32 tcan4x5x_read_reg(struct m_can_classdev *cdev, int reg)
    {
    	struct tcan4x5x_priv *priv = cdev->device_data;
    	u32 val;
    
    	regmap_read(priv->regmap, priv->reg_offset + reg, &val);
    
    	return val;
    }
    
    static u32 tcan4x5x_read_fifo(struct m_can_classdev *cdev, int addr_offset)
    {
    	struct tcan4x5x_priv *priv = cdev->device_data;
    	u32 val;
    
    	regmap_read(priv->regmap, priv->mram_start + addr_offset, &val);
    
    	return val;
    }
    
    static int tcan4x5x_write_reg(struct m_can_classdev *cdev, int reg, int val)
    {
    	struct tcan4x5x_priv *priv = cdev->device_data;
    
    	return regmap_write(priv->regmap, priv->reg_offset + reg, val);
    }
    
    static int tcan4x5x_write_fifo(struct m_can_classdev *cdev,
    		int addr_offset, int val)
    {
    	struct tcan4x5x_priv *priv = cdev->device_data;
    
    	return regmap_write(priv->regmap, priv->mram_start + addr_offset, val);
    }
    
    static int tcan4x5x_power_enable(struct regulator *reg, int enable)
    {
    	if (IS_ERR_OR_NULL(reg))
    		return 0;
    
    	if (enable)
    		return regulator_enable(reg);
    	else
    		return regulator_disable(reg);
    }
    
    static int tcan4x5x_write_tcan_reg(struct m_can_classdev *cdev,
    		int reg, int val)
    {
    	struct tcan4x5x_priv *priv = cdev->device_data;
    
    	return regmap_write(priv->regmap, reg, val);
    }
    
    static int tcan4x5x_clear_interrupts(struct m_can_classdev *cdev)
    {
    	int ret;
    	struct tcan4x5x_priv *tcan4x5x = cdev->device_data;
    	ret = tcan4x5x_write_tcan_reg(cdev, TCAN4X5X_STATUS,
    			TCAN4X5X_CLEAR_ALL_INT);
    	if (ret)
    		return ret;
    
    	ret = tcan4x5x_write_tcan_reg(cdev, TCAN4X5X_MCAN_INT_REG,
    			TCAN4X5X_ENABLE_MCAN_INT);
    	if (ret)
    		return ret;
    
    	ret = tcan4x5x_write_tcan_reg(cdev, TCAN4X5X_INT_FLAGS,
    			TCAN4X5X_CLEAR_ALL_INT);
    	if (ret)
    		return ret;
    
    	ret = tcan4x5x_write_tcan_reg(cdev, TCAN4X5X_ERROR_STATUS,
    			TCAN4X5X_CLEAR_ALL_INT);
    	if (ret)
    		return ret;
    	/* Watchdog reset */
    	ret = regmap_update_bits(tcan4x5x->regmap, TCAN4X5X_CONFIG,
    			WDT_RESET, WDT_RESET_BIT);
    	if (ret)
    		return ret;
    
    	return ret;
    }
    
    static int tcan4x5x_init(struct m_can_classdev *cdev)
    {
    	struct tcan4x5x_priv *tcan4x5x = cdev->device_data;
    	int ret;
    
    	tcan4x5x_check_wake(tcan4x5x);
    	printk("tcan init----\n");
    
    	ret = tcan4x5x_write_tcan_reg(cdev, TCAN4X5X_INT_EN,
    			TCAN4X5X_ENABLE_TCAN_INT);
    	if (ret)
    		return ret;
    	ret = regmap_update_bits(tcan4x5x->regmap, TCAN4X5X_CONFIG,
    			WDT_CLK, WDT_CLK_BIT);
    	if (ret)
    		return ret;
    	ret = regmap_update_bits(tcan4x5x->regmap, TCAN4X5X_CONFIG,
    			WDT_ENABLE, WDT_ENABLE_BIT);
    	if (ret)
    		return ret;
    	ret = tcan4x5x_clear_interrupts(cdev);
    	if (ret)
    		return ret;
    	ret = regmap_update_bits(tcan4x5x->regmap, TCAN4X5X_CONFIG,
    			TCAN4X5X_MODE_SEL_MASK, TCAN4X5X_MODE_NORMAL);
    	if (ret)
    		return ret;
    	/* Zero out the MCAN buffers */
    	m_can_init_ram(cdev);
    
    	return ret;
    }
    
    static int tcan4x5x_parse_config(struct m_can_classdev *cdev)
    {
    	struct tcan4x5x_priv *tcan4x5x = cdev->device_data;
    	int ret;
    	printk("tcan parse config----------\n");
    
    	if (!iw_tcan_prop)
    	{
    		tcan4x5x->device_wake_gpio = devm_gpiod_get(cdev->dev, "device-wake",
    				GPIOD_OUT_HIGH);
    		if (IS_ERR(tcan4x5x->device_wake_gpio)) {
    			dev_err(cdev->dev, "device-wake gpio not defined\n");
    			return -EINVAL;
    		}
    	}
    
    	tcan4x5x->reset_gpio = devm_gpiod_get_optional(cdev->dev, "reset",
    			GPIOD_OUT_LOW);
    	if (IS_ERR(tcan4x5x->reset_gpio))
    		tcan4x5x->reset_gpio = NULL;
    
    	if (!iw_tcan_prop)
    	{
    		ret = tcan4x5x_reset(tcan4x5x);
    		if (ret)
    			return ret;
    	}
    
    	tcan4x5x->device_state_gpio = devm_gpiod_get_optional(cdev->dev,
    			"device-state",
    			GPIOD_IN);
    	if (IS_ERR(tcan4x5x->device_state_gpio))
    		tcan4x5x->device_state_gpio = NULL;
    
    	tcan4x5x->power = devm_regulator_get_optional(cdev->dev,
    			"vsup");
    	if (PTR_ERR(tcan4x5x->power) == -EPROBE_DEFER)
    		return -EPROBE_DEFER;
    
    	return 0;
    }
    
    static const struct regmap_config tcan4x5x_regmap = {
    	.reg_bits = 32,
    	.val_bits = 32,
    	.cache_type = REGCACHE_NONE,
    	.max_register = TCAN4X5X_MAX_REGISTER,
    };
    
    static struct m_can_ops tcan4x5x_ops = {
    	.init = tcan4x5x_init,
    	.read_reg = tcan4x5x_read_reg,
    	.write_reg = tcan4x5x_write_reg,
    	.write_fifo = tcan4x5x_write_fifo,
    	.read_fifo = tcan4x5x_read_fifo,
    	.clear_interrupts = tcan4x5x_clear_interrupts,
    };
    
    /*
    * Added for the reset of TCAN4X5X chip
    */
    static int tcan4x5x_wakeup_mode( void )
    {
    	usleep_range(10, 50);
    	gpio_request(TCAN4X5X_RESET_GPIO, "TCAN_ON");
    	gpio_direction_output(TCAN4X5X_RESET_GPIO, 0);
    	gpio_set_value(TCAN4X5X_RESET_GPIO, 0);
    	usleep_range(1, 50);
    
    	gpio_request(TCAN4X5X_RESET_GPIO, "TCAN_ON");
    	gpio_direction_output(TCAN4X5X_RESET_GPIO, 0);
    	gpio_set_value(TCAN4X5X_RESET_GPIO, 1);
    	usleep_range(1, 50);
    
    	gpio_request(TCAN4X5X_RESET_GPIO, "TCAN_ON");
    	gpio_direction_output(TCAN4X5X_RESET_GPIO, 0);
    	gpio_set_value(TCAN4X5X_RESET_GPIO, 0);
    	usleep_range(1, 50);
    
    	return 0;
    }
    
    static int tcan4x5x_can_probe(struct spi_device *spi)
    {
    	struct tcan4x5x_priv *priv;
    	struct m_can_classdev *mcan_class;
    	int freq, ret;
    	printk("tcan probe---------\n");
    
    	/* For finding the TCAN node */
    	struct device_node *tcan_node;
    	tcan_node = of_find_compatible_node(NULL, NULL, "ti,tcan4x5x");
    	if (!tcan_node) {
    		printk("%s : can't find TCAN node\n", __func__);
    		return -EINVAL;
    	}
    
    	/* For finding the iWave flag defined in Device Tree */
    	if (of_get_property(tcan_node, "iw-tcan-prop", NULL))
    	{
    		iw_tcan_prop = true;
    		m_can_set_iw_mcan_prop_flag();
    		tcan4x5x_wakeup_mode( );
    		msleep(100);
    	}
    
    	mcan_class = m_can_class_allocate_dev(&spi->dev);
    	if (!mcan_class)
    		return -ENOMEM;
    
    	priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
    	if (!priv)
    		return -ENOMEM;
    
    	mcan_class->device_data = priv;
    
    	m_can_class_get_clocks(mcan_class);
    	if (IS_ERR(mcan_class->cclk)) {
    		dev_err(&spi->dev, "no CAN clock source defined\n");
    		freq = TCAN4X5X_EXT_CLK_DEF;
    	} else {
    		freq = clk_get_rate(mcan_class->cclk);
    	}
    
    	/* Sanity check */
    	if (freq < 20000000 || freq > TCAN4X5X_EXT_CLK_DEF)
    		return -ERANGE;
    
    	priv->reg_offset = TCAN4X5X_MCAN_OFFSET;
    	priv->mram_start = TCAN4X5X_MRAM_START;
    	priv->spi = spi;
    	priv->mcan_dev = mcan_class;
    
    	mcan_class->pm_clock_support = 0;
    	mcan_class->can.clock.freq = freq;
    	mcan_class->dev = &spi->dev;
    	mcan_class->ops = &tcan4x5x_ops;
    	mcan_class->is_peripheral = true;
    	mcan_class->bit_timing = &tcan4x5x_bittiming_const;
    	mcan_class->data_timing = &tcan4x5x_data_bittiming_const;
    	mcan_class->net->irq = spi->irq;
    
    	spi_set_drvdata(spi, priv);
    
    	ret = tcan4x5x_parse_config(mcan_class);
    	if (ret)
    		goto out_clk;
    
    	/* Configure the SPI bus */
    	spi->bits_per_word = 32;
    	ret = spi_setup(spi);
    	if (ret)
    		goto out_clk;
    
    	priv->regmap = devm_regmap_init(&spi->dev, &tcan4x5x_bus,
    			&spi->dev, &tcan4x5x_regmap);
    
    	tcan4x5x_power_enable(priv->power, 1);
    
    	ret = tcan4x5x_init(mcan_class);
    	if (ret)
    		goto out_power;
    
    	ret = m_can_class_register(mcan_class);
    	if (ret)
    		goto out_power;
    
    	if (of_get_property(tcan_node, "wakeup-source", NULL))
            {
                    device_init_wakeup(mcan_class->dev, true);
            }
    
    	netdev_info(mcan_class->net, "TCAN4X5X successfully initialized.\n");
    	return 0;
    
    out_power:
    	tcan4x5x_power_enable(priv->power, 0);
    out_clk:
    	if (!IS_ERR(mcan_class->cclk)) {
    		clk_disable_unprepare(mcan_class->cclk);
    		clk_disable_unprepare(mcan_class->hclk);
    	}
    
    	dev_err(&spi->dev, "Probe failed, err=%d\n", ret);
    	return ret;
    }
    
    static int tcan4x5x_sleep_mode( struct tcan4x5x_priv *priv )
    {
    	struct tcan4x5x_priv *tcan4x5x =
    		(struct tcan4x5x_priv *)priv;
    	int ret;
    	ret = regmap_update_bits(tcan4x5x->regmap, TCAN4X5X_CONFIG,
    			TCAN4X5X_MODE_SEL_MASK, TCAN4X5X_MODE_SLEEP );
    	return ret;
    }
    
    static int tcan4x5x_can_remove(struct spi_device *spi)
    {
    	struct tcan4x5x_priv *priv = spi_get_drvdata(spi);
    
    	printk("tcan remove------\n");
    	if (iw_tcan_prop)
    	{
    		tcan4x5x_sleep_mode( priv );
    	}
    	tcan4x5x_power_enable(priv->power, 0);
    
    	m_can_class_unregister(priv->mcan_dev);
    
    	return 0;
    }
    
    static int tcan4x5x_suspend(struct device *device)
    {
            int err = 0, ret = 0;
            struct tcan4x5x_priv *priv = spi_get_drvdata(to_spi_device(device));
            struct net_device *dev = priv->mcan_dev->net;
    	
    	printk("tcan suspend-------\n");
            if (netif_running(dev))
            {
                    if (device_may_wakeup(device))
                    {
    			iw_rxf0_reg_val = 0;
                            /* 
                             * For modifying the watermark level for CAN, the INIT and \
                             * CCE bits should be high. Those are Write protected bits. \
                             * */
                            err = regmap_update_bits(priv->regmap, CTRL_REG, CTRL_INIT_BIT, CTRL_INIT_BIT);
                            if (err)
                                    return err;
    
                            err = regmap_update_bits(priv->regmap, CTRL_REG, CTRL_CCE_BIT, CTRL_CCE_BIT);
                            if (err)
                                    return err;
    
                            /* 
                             * Reading the current value of RX FIFO 0 register and \
                             * stores it in iw_rxf0_reg_val to revert it back. \
                             * */
                            regmap_read(priv->regmap, RX_FIFO0_CONFIGURATION_REG, &iw_rxf0_reg_val);
    
                            /* Modify the watermark level as 1 in RX FIFO 0 CONF Register. */
                            err = iw_rxf0_reg_val & 0x80FFFFFF;
                            err |= 1 << 24;
                            ret = regmap_write(priv->regmap, RX_FIFO0_CONFIGURATION_REG, err);
                            if (ret)
                                    return ret;
    
                            /* Disable the periodic Watchdog interrupt in RX FIFO 0 CONF Register. */
                            err = regmap_update_bits(priv->regmap, TCAN4X5X_CONFIG, TCAN4X5X_WATCHDOG_EN, !TCAN4X5X_WATCHDOG_EN);
                            if (err)
                                    return err;
    
                            /* Disabling the INIT and CCE bits after changing the Watermark level. */
                            err = regmap_update_bits(priv->regmap, CTRL_REG, CTRL_CCE_BIT, !CTRL_CCE_BIT);
                            if (err)
                                    return err;
    
                            err = regmap_update_bits(priv->regmap, CTRL_REG, CTRL_INIT_BIT, !CTRL_INIT_BIT);
                            if (err)
                                    return err;
    
                            /* Enable the IRQ wakeup */
                            err = enable_irq_wake(priv->mcan_dev->net->irq);
    			                  if(err)
                                    return err;
    
                            err = m_can_class_suspend(device);
                              if(err)
                              return err;
                    }
            }
    
            return err;
    }
    static int tcan4x5x_resume(struct device *device)
    {
            int err = 0;
            struct tcan4x5x_priv *priv = spi_get_drvdata(to_spi_device(device));
            struct net_device *dev = priv->mcan_dev->net;
    	
    	printk("tcan resume---------\n");
            if (netif_running(dev))
            {
                    if (device_may_wakeup(device))
                    {
                            /* Disable the RX interrupts */
                            m_can_disable_rx_irq(priv->mcan_dev);
    
                            /* Disable the IRQ wakeup */
                            err = disable_irq_wake(priv->mcan_dev->net->irq);
                            if(err)
                                    return err;
    
                            if (priv->mcan_dev->ops->clear_interrupts)
                            {
                                    priv->mcan_dev->ops->clear_interrupts(priv->mcan_dev);
                            }
                            if (priv->mcan_dev->ops->clear_interrupts_tx)
                            {
                                    priv->mcan_dev->ops->clear_interrupts_tx(priv->mcan_dev);
                            }
    
                            err = m_can_rx_clear(dev);
                            if(err)
                                    return err;
    
                            /* 
                             * For modifying the watermark level for CAN, the INIT and \
                             * CCE bits should be high. Those are Write protected bits. \
                             * */
                            err = regmap_update_bits(priv->regmap, CTRL_REG, CTRL_INIT_BIT, CTRL_INIT_BIT);
                            if (err)
                                    return err;
    
                            err = regmap_update_bits(priv->regmap, CTRL_REG, CTRL_CCE_BIT, CTRL_CCE_BIT);
                            if (err)
                                    return err;
    
                            err = regmap_update_bits(priv->regmap, TCAN4X5X_CONFIG, WDT_RESET, WDT_RESET_BIT);
                            if (err)
                                    return err;
    
                            err = regmap_update_bits(priv->regmap, TCAN4X5X_CONFIG, TCAN4X5X_WATCHDOG_EN, TCAN4X5X_WATCHDOG_EN);
                            if (err)
                                    return err;
    
    			         /* 
                             * Reverting back the value of RX FIFO 0 register which was \
                             * stored in iw_rxf0_reg_val. This will reverts the Watermark \
                             * value to the previous value. \
                             * */
                            err = regmap_write(priv->regmap, RX_FIFO0_CONFIGURATION_REG, iw_rxf0_reg_val);
                            if (err)
                                    return err;
    
                            err = regmap_update_bits(priv->regmap, CTRL_REG, CTRL_CCE_BIT, !CTRL_CCE_BIT);
                            if (err)
                                    return err;
    
                            err = regmap_update_bits(priv->regmap, CTRL_REG, CTRL_INIT_BIT, !CTRL_INIT_BIT);
                            if (err)
                                    return err;
    
                            err = m_can_class_resume(device);
                            if(err)
                                    return err;
    
                            /* Enable the RX interrupts */
                            m_can_enable_rx_irq(priv->mcan_dev);
                    }
            }
    
            return err;
    }
    
    static const struct dev_pm_ops tcan4x5x_pm_ops = {
    	SET_SYSTEM_SLEEP_PM_OPS(tcan4x5x_suspend, tcan4x5x_resume)
    };
    
    
    static const struct of_device_id tcan4x5x_of_match[] = {
    	{ .compatible = "ti,tcan4x5x", },
    	{ }
    };
    MODULE_DEVICE_TABLE(of, tcan4x5x_of_match);
    
    static const struct spi_device_id tcan4x5x_id_table[] = {
    	{
    		.name		= "tcan4x5x",
    		.driver_data	= 0,
    	},
    	{ }
    };
    MODULE_DEVICE_TABLE(spi, tcan4x5x_id_table);
    
    static struct spi_driver tcan4x5x_can_driver = {
    	.driver = {
    		.name = DEVICE_NAME,
    		.of_match_table = tcan4x5x_of_match,
    		.pm = NULL,
    		.pm = &tcan4x5x_pm_ops,
    	},
    	.id_table = tcan4x5x_id_table,
    	.probe = tcan4x5x_can_probe,
    	.remove = tcan4x5x_can_remove,
    };
    module_spi_driver(tcan4x5x_can_driver);
    
    MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
    MODULE_DESCRIPTION("Texas Instruments TCAN4x5x CAN driver");
    MODULE_LICENSE("GPL v2");
    

    m_can.c
    // SPDX-License-Identifier: GPL-2.0
    // CAN bus driver for Bosch M_CAN controller
    // Copyright (C) 2014 Freescale Semiconductor, Inc.
    //      Dong Aisheng <b29396@freescale.com>
    // Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/
    
    /* Bosch M_CAN user manual can be obtained from:
     * http://www.bosch-semiconductors.de/media/pdf_1/ipmodules_1/m_can/
     * mcan_users_manual_v302.pdf
     */
    
    #include <linux/interrupt.h>
    #include <linux/io.h>
    #include <linux/kernel.h>
    #include <linux/module.h>
    #include <linux/netdevice.h>
    #include <linux/of.h>
    #include <linux/of_device.h>
    #include <linux/platform_device.h>
    #include <linux/pm_runtime.h>
    #include <linux/iopoll.h>
    #include <linux/can/dev.h>
    #include <linux/pinctrl/consumer.h>
    
    #include "m_can.h"
    bool iw_mcan_prop = false; /* Flag added for Rugged Telematics Device */
    int iw_ie_reg = 0;
    bool mode = false;         /* Flag added for determining when tcan has to go to standby mode */
    bool FD_mode = false;
    #if 0
    int m_can_rx_clear(struct net_device *dev)
    {
            struct m_can_classdev *cdev = netdev_priv(dev);
            m_can_disable_all_interrupts(cdev);
            m_can_rx_peripheral(dev);
    
            return 0;
    }
    EXPORT_SYMBOL_GPL(m_can_rx_clear);
    #endif
    
    
    
    
    /* registers definition */
    enum m_can_reg {
    	M_CAN_CREL	= 0x0,
    	M_CAN_ENDN	= 0x4,
    	M_CAN_CUST	= 0x8,
    	M_CAN_DBTP	= 0xc,
    	M_CAN_TEST	= 0x10,
    	M_CAN_RWD	= 0x14,
    	M_CAN_CCCR	= 0x18,
    	M_CAN_NBTP	= 0x1c,
    	M_CAN_TSCC	= 0x20,
    	M_CAN_TSCV	= 0x24,
    	M_CAN_TOCC	= 0x28,
    	M_CAN_TOCV	= 0x2c,
    	M_CAN_ECR	= 0x40,
    	M_CAN_PSR	= 0x44,
    	/* TDCR Register only available for version >=3.1.x */
    	M_CAN_TDCR	= 0x48,
    	M_CAN_IR	= 0x50,
    	M_CAN_IE	= 0x54,
    	M_CAN_ILS	= 0x58,
    	M_CAN_ILE	= 0x5c,
    	M_CAN_GFC	= 0x80,
    	M_CAN_SIDFC	= 0x84,
    	M_CAN_XIDFC	= 0x88,
    	M_CAN_XIDAM	= 0x90,
    	M_CAN_HPMS	= 0x94,
    	M_CAN_NDAT1	= 0x98,
    	M_CAN_NDAT2	= 0x9c,
    	M_CAN_RXF0C	= 0xa0,
    	M_CAN_RXF0S	= 0xa4,
    	M_CAN_RXF0A	= 0xa8,
    	M_CAN_RXBC	= 0xac,
    	M_CAN_RXF1C	= 0xb0,
    	M_CAN_RXF1S	= 0xb4,
    	M_CAN_RXF1A	= 0xb8,
    	M_CAN_RXESC	= 0xbc,
    	M_CAN_TXBC	= 0xc0,
    	M_CAN_TXFQS	= 0xc4,
    	M_CAN_TXESC	= 0xc8,
    	M_CAN_TXBRP	= 0xcc,
    	M_CAN_TXBAR	= 0xd0,
    	M_CAN_TXBCR	= 0xd4,
    	M_CAN_TXBTO	= 0xd8,
    	M_CAN_TXBCF	= 0xdc,
    	M_CAN_TXBTIE	= 0xe0,
    	M_CAN_TXBCIE	= 0xe4,
    	M_CAN_TXEFC	= 0xf0,
    	M_CAN_TXEFS	= 0xf4,
    	M_CAN_TXEFA	= 0xf8,
    };
    /*Transmission delay */
    volatile int Tx_DELAY = 0;
    /* napi related */
    #define M_CAN_NAPI_WEIGHT	64
    
    /* message ram configuration data length */
    #define MRAM_CFG_LEN	8
    
    /* Core Release Register (CREL) */
    #define CREL_REL_SHIFT		28
    #define CREL_REL_MASK		(0xF << CREL_REL_SHIFT)
    #define CREL_STEP_SHIFT		24
    #define CREL_STEP_MASK		(0xF << CREL_STEP_SHIFT)
    #define CREL_SUBSTEP_SHIFT	20
    #define CREL_SUBSTEP_MASK	(0xF << CREL_SUBSTEP_SHIFT)
    
    /* Data Bit Timing & Prescaler Register (DBTP) */
    #define DBTP_TDC		BIT(23)
    #define DBTP_DBRP_SHIFT		16
    #define DBTP_DBRP_MASK		(0x1f << DBTP_DBRP_SHIFT)
    #define DBTP_DTSEG1_SHIFT	8
    #define DBTP_DTSEG1_MASK	(0x1f << DBTP_DTSEG1_SHIFT)
    #define DBTP_DTSEG2_SHIFT	4
    #define DBTP_DTSEG2_MASK	(0xf << DBTP_DTSEG2_SHIFT)
    #define DBTP_DSJW_SHIFT		0
    #define DBTP_DSJW_MASK		(0xf << DBTP_DSJW_SHIFT)
    
    /* Transmitter Delay Compensation Register (TDCR) */
    #define TDCR_TDCO_SHIFT		8
    #define TDCR_TDCO_MASK		(0x7F << TDCR_TDCO_SHIFT)
    #define TDCR_TDCF_SHIFT		0
    #define TDCR_TDCF_MASK		(0x7F << TDCR_TDCF_SHIFT)
    
    /* Test Register (TEST) */
    #define TEST_LBCK		BIT(4)
    
    /* CC Control Register(CCCR) */
    #define CCCR_CMR_MASK		0x3
    #define CCCR_CMR_SHIFT		10
    #define CCCR_CMR_CANFD		0x1
    #define CCCR_CMR_CANFD_BRS	0x2
    #define CCCR_CMR_CAN		0x3
    #define CCCR_CME_MASK		0x3
    #define CCCR_CME_SHIFT		8
    #define CCCR_CME_CAN		0
    #define CCCR_CME_CANFD		0x1
    #define CCCR_CME_CANFD_BRS	0x2
    #define CCCR_TXP		BIT(14)
    #define CCCR_TEST		BIT(7)
    #define CCCR_MON		BIT(5)
    #define CCCR_CSR		BIT(4)
    #define CCCR_CSA		BIT(3)
    #define CCCR_ASM		BIT(2)
    #define CCCR_CCE		BIT(1)
    #define CCCR_INIT		BIT(0)
    #define CCCR_CANFD		0x10
    /* for version >=3.1.x */
    #define CCCR_EFBI		BIT(13)
    #define CCCR_PXHD		BIT(12)
    #define CCCR_BRSE               BIT(9)
    #define CCCR_FDOE               BIT(8)
    /* only for version >=3.2.x */
    #define CCCR_NISO		BIT(15)
    
    /* Nominal Bit Timing & Prescaler Register (NBTP) */
    #define NBTP_NSJW_SHIFT		25
    #define NBTP_NSJW_MASK		(0x7f << NBTP_NSJW_SHIFT)
    #define NBTP_NBRP_SHIFT		16
    #define NBTP_NBRP_MASK		(0x1ff << NBTP_NBRP_SHIFT)
    #define NBTP_NTSEG1_SHIFT	8
    #define NBTP_NTSEG1_MASK	(0xff << NBTP_NTSEG1_SHIFT)
    #define NBTP_NTSEG2_SHIFT	0
    #define NBTP_NTSEG2_MASK	(0x7f << NBTP_NTSEG2_SHIFT)
    
    /* Error Counter Register(ECR) */
    #define ECR_RP			BIT(15)
    #define ECR_REC_SHIFT		8
    #define ECR_REC_MASK		(0x7f << ECR_REC_SHIFT)
    #define ECR_TEC_SHIFT		0
    #define ECR_TEC_MASK		0xff
    
    /* Protocol Status Register(PSR) */
    #define PSR_BO		BIT(7)
    #define PSR_EW		BIT(6)
    #define PSR_EP		BIT(5)
    #define PSR_LEC_MASK	0x7
    
    /* Interrupt Register(IR) */
    #define IR_ALL_INT	0xffffffff
    
    /* Renamed bits for versions > 3.1.x */
    #define IR_ARA		BIT(29)
    #define IR_PED		BIT(28)
    #define IR_PEA		BIT(27)
    
    /* Bits for version 3.0.x */
    #define IR_STE		BIT(31)
    #define IR_FOE		BIT(30)
    #define IR_ACKE		BIT(29)
    #define IR_BE		BIT(28)
    #define IR_CRCE		BIT(27)
    #define IR_WDI		BIT(26)
    #define IR_BO		BIT(25)
    #define IR_EW		BIT(24)
    #define IR_EP		BIT(23)
    #define IR_ELO		BIT(22)
    #define IR_BEU		BIT(21)
    #define IR_BEC		BIT(20)
    #define IR_DRX		BIT(19)
    #define IR_TOO		BIT(18)
    #define IR_MRAF		BIT(17)
    #define IR_TSW		BIT(16)
    #define IR_TEFL		BIT(15)
    #define IR_TEFF		BIT(14)
    #define IR_TEFW		BIT(13)
    #define IR_TEFN		BIT(12)
    #define IR_TFE		BIT(11)
    #define IR_TCF		BIT(10)
    #define IR_TC		BIT(9)
    #define IR_HPM		BIT(8)
    #define IR_RF1L		BIT(7)
    #define IR_RF1F		BIT(6)
    #define IR_RF1W		BIT(5)
    #define IR_RF1N		BIT(4)
    #define IR_RF0L		BIT(3)
    #define IR_RF0F		BIT(2)
    #define IR_RF0W		BIT(1)
    #define IR_RF0N		BIT(0)
    #define IR_ERR_STATE	(IR_BO | IR_EW | IR_EP)
    
    /* Interrupts for version 3.0.x */
    #define IR_ERR_LEC_30X	(IR_STE	| IR_FOE | IR_ACKE | IR_BE | IR_CRCE)
    #define IR_ERR_BUS_30X	(IR_ERR_LEC_30X | IR_WDI | IR_ELO | IR_BEU | \
    		IR_BEC | IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | \
    		IR_RF1L | IR_RF0L)
    #define IR_ERR_ALL_30X	(IR_ERR_STATE | IR_ERR_BUS_30X)
    /* Interrupts for version >= 3.1.x */
    //#ifdef CONFIG_MX6ULL_IWG26I
    #define IR_ERR_LEC_31X	(IR_PED | IR_PEA | IR_RF0N | IR_RF1N )
    //#else
     /* CONFIG_MX6ULL_IWG26I */
    //#define IR_ERR_LEC_31X	(IR_PED | IR_PEA)
    //#endif
     /* CONFIG_MX6ULL_IWG26I */
    #define IR_ERR_BUS_31X      (IR_ERR_LEC_31X | IR_WDI | IR_ELO | IR_BEU | \
    		IR_BEC | IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | \
    		IR_RF1L | IR_RF0L)
    #define IR_ERR_ALL_31X	(IR_ERR_STATE | IR_ERR_BUS_31X)
    
    /* Interrupt Line Select (ILS) */
    #define ILS_ALL_INT0	0x0
    #define ILS_ALL_INT1	0xFFFFFFFF
    
    /* Interrupt Line Enable (ILE) */
    #define ILE_EINT1	BIT(1)
    #define ILE_EINT0	BIT(0)
    
    /* Rx FIFO 0/1 Configuration (RXF0C/RXF1C) */
    #define RXFC_FWM_SHIFT	24
    #define RXFC_FWM_MASK	(0x7f << RXFC_FWM_SHIFT)
    #define RXFC_FS_SHIFT	16
    #define RXFC_FS_MASK	(0x7f << RXFC_FS_SHIFT)
    
    /* Rx FIFO 0/1 Status (RXF0S/RXF1S) */
    #define RXFS_RFL	BIT(25)
    #define RXFS_FF		BIT(24)
    #define RXFS_FPI_SHIFT	16
    #define RXFS_FPI_MASK	0x3f0000
    #define RXFS_FGI_SHIFT	8
    #define RXFS_FGI_MASK	0x3f00
    #define RXFS_FFL_MASK	0x7f
    #define RXFS_FFL_MASK_ELEMENTS	0x7f
    
    /* Rx Buffer / FIFO Element Size Configuration (RXESC) */
    #define M_CAN_RXESC_8BYTES	0x0
    #define M_CAN_RXESC_64BYTES	0x777
    
    /* Tx Buffer Configuration(TXBC) */
    #define TXBC_NDTB_SHIFT		16
    #define TXBC_NDTB_MASK		(0x3f << TXBC_NDTB_SHIFT)
    #define TXBC_TFQS_SHIFT		24
    #define TXBC_TFQS_MASK		(0x3f << TXBC_TFQS_SHIFT)
    
    /* Tx FIFO/Queue Status (TXFQS) */
    #define TXFQS_TFQF		BIT(21)
    #define TXFQS_TFQPI_SHIFT	16
    #define TXFQS_TFQPI_MASK	(0x1f << TXFQS_TFQPI_SHIFT)
    #define TXFQS_TFGI_SHIFT	8
    #define TXFQS_TFGI_MASK		(0x1f << TXFQS_TFGI_SHIFT)
    #define TXFQS_TFFL_SHIFT	0
    #define TXFQS_TFFL_MASK		(0x3f << TXFQS_TFFL_SHIFT)
    
    /* Tx Buffer Element Size Configuration(TXESC) */
    #define TXESC_TBDS_8BYTES	0x0
    #define TXESC_TBDS_64BYTES	0x7
    
    /* Tx Event FIFO Configuration (TXEFC) */
    #define TXEFC_EFS_SHIFT		16
    #define TXEFC_EFS_MASK		(0x3f << TXEFC_EFS_SHIFT)
    
    /* Tx Event FIFO Status (TXEFS) */
    #define TXEFS_TEFL		BIT(25)
    #define TXEFS_EFF		BIT(24)
    #define TXEFS_EFGI_SHIFT	8
    #define	TXEFS_EFGI_MASK		(0x1f << TXEFS_EFGI_SHIFT)
    #define TXEFS_EFFL_SHIFT	0
    #define TXEFS_EFFL_MASK		(0x3f << TXEFS_EFFL_SHIFT)
    
    /* Tx Event FIFO Acknowledge (TXEFA) */
    #define TXEFA_EFAI_SHIFT	0
    #define TXEFA_EFAI_MASK		(0x1f << TXEFA_EFAI_SHIFT)
    
    /* Message RAM Configuration (in bytes) */
    #define SIDF_ELEMENT_SIZE	4
    #define XIDF_ELEMENT_SIZE	8
    #define RXF0_ELEMENT_SIZE	72
    #define RXF1_ELEMENT_SIZE	72
    #define RXB_ELEMENT_SIZE	72
    #define TXE_ELEMENT_SIZE	8
    #define TXB_ELEMENT_SIZE	72
    
    /* Message RAM Elements */
    #define M_CAN_FIFO_ID		0x0
    #define M_CAN_FIFO_DLC		0x4
    #define M_CAN_FIFO_DATA(n)	(0x8 + ((n) << 2))
    
    /* Rx Buffer Element */
    /* R0 */
    #define RX_BUF_ESI		BIT(31)
    #define RX_BUF_XTD		BIT(30)
    #define RX_BUF_RTR		BIT(29)
    /* R1 */
    #define RX_BUF_ANMF		BIT(31)
    #define RX_BUF_FDF		BIT(21)
    #define RX_BUF_BRS		BIT(20)
    
    /* Tx Buffer Element */
    /* T0 */
    #define TX_BUF_ESI		BIT(31)
    #define TX_BUF_XTD		BIT(30)
    #define TX_BUF_RTR		BIT(29)
    /* T1 */
    #define TX_BUF_EFC		BIT(23)
    #define TX_BUF_FDF		BIT(21)
    #define TX_BUF_BRS		BIT(20)
    #define TX_BUF_MM_SHIFT		24
    #define TX_BUF_MM_MASK		(0xff << TX_BUF_MM_SHIFT)
    
    /* Tx event FIFO Element */
    /* E1 */
    #define TX_EVENT_MM_SHIFT	TX_BUF_MM_SHIFT
    #define TX_EVENT_MM_MASK	(0xff << TX_EVENT_MM_SHIFT)
    
    #define IR_ALL_INT_CUSTOM_NO_TX (IR_ALL_INT & ~(IR_TEFL | IR_TEFF | IR_TEFN | IR_TCF | IR_TC | IR_TFE | IR_TEFW | IR_PED))
    
    static inline u32 m_can_read(struct m_can_classdev *cdev, enum m_can_reg reg)
    {
    	return cdev->ops->read_reg(cdev, reg);
    }
    
    static inline void m_can_write(struct m_can_classdev *cdev, enum m_can_reg reg,
    		u32 val)
    {
    	cdev->ops->write_reg(cdev, reg, val);
    }
    
    static u32 m_can_fifo_read(struct m_can_classdev *cdev,
    		u32 fgi, unsigned int offset)
    {
    	u32 addr_offset = cdev->mcfg[MRAM_RXF0].off + fgi * RXF0_ELEMENT_SIZE +
    		offset;
    
    	return cdev->ops->read_fifo(cdev, addr_offset);
    }
    
    static void m_can_fifo_write(struct m_can_classdev *cdev,
    		u32 fpi, unsigned int offset, u32 val)
    {
    	u32 addr_offset = cdev->mcfg[MRAM_TXB].off + fpi * TXB_ELEMENT_SIZE +
    		offset;
    
    	cdev->ops->write_fifo(cdev, addr_offset, val);
    }
    
    static inline void m_can_fifo_write_no_off(struct m_can_classdev *cdev,
    		u32 fpi, u32 val)
    {
    	cdev->ops->write_fifo(cdev, fpi, val);
    }
    
    static u32 m_can_txe_fifo_read(struct m_can_classdev *cdev, u32 fgi, u32 offset)
    {
    	u32 addr_offset = cdev->mcfg[MRAM_TXE].off + fgi * TXE_ELEMENT_SIZE +
    		offset;
    
    	return cdev->ops->read_fifo(cdev, addr_offset);
    }
    
    static inline bool m_can_tx_fifo_full(struct m_can_classdev *cdev)
    {
    	return !!(m_can_read(cdev, M_CAN_TXFQS) & TXFQS_TFQF);
    }
    
    void m_can_config_endisable(struct m_can_classdev *cdev, bool enable)
    {
    	u32 cccr = m_can_read(cdev, M_CAN_CCCR);
    	u32 timeout = 10;
    	u32 val = 0;
    
    	/* Clear the Clock stop request if it was set */
    	if (cccr & CCCR_CSR)
    		cccr &= ~CCCR_CSR;
    		
    	if (enable) {
    		/* Clear the Clock stop request if it was set */
    		if (cccr & CCCR_CSR)
    			cccr &= ~CCCR_CSR;
    
    		/* enable m_can configuration */
    		m_can_write(cdev, M_CAN_CCCR, cccr | CCCR_INIT);
    		udelay(5);
    		/* CCCR.CCE can only be set/reset while CCCR.INIT = '1' */
    		m_can_write(cdev, M_CAN_CCCR, cccr | CCCR_INIT | CCCR_CCE);
    	} else {
    		m_can_write(cdev, M_CAN_CCCR, cccr & ~(CCCR_INIT | CCCR_CCE));
    	}
    	/* there's a delay for module initialization */
    	if (enable)
    		val = CCCR_INIT | CCCR_CCE;
    
    	while ((m_can_read(cdev, M_CAN_CCCR) & (CCCR_INIT | CCCR_CCE)) != val) {
    		if (timeout == 0) {
    			netdev_warn(cdev->net, "Failed to init module\n");
    			return;
    		}
    		timeout--;
    		udelay(1);
    	}
    }
    
    static inline void m_can_enable_all_interrupts(struct m_can_classdev *cdev)
    {
    	/* Only interrupt line 0 is used in this driver */
    	m_can_write(cdev, M_CAN_ILE, ILE_EINT0);
    }
    
    static inline void m_can_disable_all_interrupts(struct m_can_classdev *cdev)
    {
    	m_can_write(cdev, M_CAN_ILE, 0x0);
    }
    
    #if 0
    int m_can_rx_clear(struct net_device *dev)
    {
            struct m_can_classdev *cdev = netdev_priv(dev);
            m_can_disable_all_interrupts(cdev);
            m_can_rx_peripheral(dev);
    
            return 0;
    }
    EXPORT_SYMBOL_GPL(m_can_rx_clear);
    #endif
    static void m_can_clean(struct net_device *net)
    {
    	struct m_can_classdev *cdev = netdev_priv(net);
    
    	if (cdev->tx_skb) {
    		int putidx = 0;
    
    		net->stats.tx_errors++;
    		if (cdev->version > 30)
    			putidx = ((m_can_read(cdev, M_CAN_TXFQS) &
    						TXFQS_TFQPI_MASK) >> TXFQS_TFQPI_SHIFT);
    		cdev->tx_skb = NULL;
    	}
    }
    
    static void m_can_read_fifo(struct net_device *dev, u32 rxfs)
    {
    	struct net_device_stats *stats = &dev->stats;
    	struct m_can_classdev *cdev = netdev_priv(dev);
    	struct canfd_frame *cf;
    	struct sk_buff *skb;
    	u32 id, fgi, dlc;
    	int i;
    
    	/* calculate the fifo get index for where to read data */
    	fgi = (rxfs & RXFS_FGI_MASK) >> RXFS_FGI_SHIFT;
    	dlc = m_can_fifo_read(cdev, fgi, M_CAN_FIFO_DLC);
    	if (dlc & RX_BUF_FDF)
    		skb = alloc_canfd_skb(dev, &cf);
    	else
    		skb = alloc_can_skb(dev, (struct can_frame **)&cf);
    	if (!skb) {
    		stats->rx_dropped++;
    		return;
    	}
    
    	if (dlc & RX_BUF_FDF)
    		cf->len = can_fd_dlc2len((dlc >> 16) & 0x0F);
    	else
    		cf->len = can_cc_dlc2len((dlc >> 16) & 0x0F);
    
    	id = m_can_fifo_read(cdev, fgi, M_CAN_FIFO_ID);
    	if (id & RX_BUF_XTD)
    		cf->can_id = (id & CAN_EFF_MASK) | CAN_EFF_FLAG;
    	else
    		cf->can_id = (id >> 18) & CAN_SFF_MASK;
    
    	if (id & RX_BUF_ESI) {
    		cf->flags |= CANFD_ESI;
    		netdev_dbg(dev, "ESI Error\n");
    	}
    
    	if (!(dlc & RX_BUF_FDF) && (id & RX_BUF_RTR)) {
    		cf->can_id |= CAN_RTR_FLAG;
    	} else {
    		if (dlc & RX_BUF_BRS)
    			cf->flags |= CANFD_BRS;
    
    		for (i = 0; i < cf->len; i += 4)
    			*(u32 *)(cf->data + i) =
    				m_can_fifo_read(cdev, fgi,
    						M_CAN_FIFO_DATA(i / 4));
    	}
    
    	/* acknowledge rx fifo 0 */
    	m_can_write(cdev, M_CAN_RXF0A, fgi);
    
    	stats->rx_packets++;
    	stats->rx_bytes += cf->len;
    
    	netif_receive_skb(skb);
    }
    
    static int m_can_do_rx_poll(struct net_device *dev, int quota)
    {
    	struct m_can_classdev *cdev = netdev_priv(dev);
    	u32 pkts = 0;
    	u32 rxfs;
    
    	rxfs = m_can_read(cdev, M_CAN_RXF0S);
    	if (!(rxfs & RXFS_FFL_MASK)) {
    		netdev_dbg(dev, "no messages in fifo0\n");
    		return 0;
    	}
    
    	if(iw_mcan_prop)
    	{
    		quota = rxfs & RXFS_FFL_MASK_ELEMENTS;
    	}
    
    	while ((rxfs & RXFS_FFL_MASK) && (quota > 0)) {
    		if (rxfs & RXFS_RFL)
    			netdev_warn(dev, "Rx FIFO 0 Message Lost\n");
    
    		m_can_read_fifo(dev, rxfs);
    
    		quota--;
    		pkts++;
    		rxfs = m_can_read(cdev, M_CAN_RXF0S);
    	}
    
    	if (pkts)
    		can_led_event(dev, CAN_LED_EVENT_RX);
    
    	return pkts;
    }
    
    static int m_can_handle_lost_msg(struct net_device *dev)
    {
    	struct net_device_stats *stats = &dev->stats;
    	struct sk_buff *skb;
    	struct can_frame *frame;
    
    	netdev_err(dev, "msg lost in rxf0\n");
    
    	stats->rx_errors++;
    	stats->rx_over_errors++;
    
    	skb = alloc_can_err_skb(dev, &frame);
    	if (unlikely(!skb))
    		return 0;
    
    	frame->can_id |= CAN_ERR_CRTL;
    	frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
    
    	netif_receive_skb(skb);
    
    	return 1;
    }
    
    static int m_can_handle_lec_err(struct net_device *dev,
    		enum m_can_lec_type lec_type)
    {
    	struct m_can_classdev *cdev = netdev_priv(dev);
    	struct net_device_stats *stats = &dev->stats;
    	struct can_frame *cf;
    	struct sk_buff *skb;
    
    	cdev->can.can_stats.bus_error++;
    	stats->rx_errors++;
    
    	/* propagate the error condition to the CAN stack */
    	skb = alloc_can_err_skb(dev, &cf);
    	if (unlikely(!skb))
    		return 0;
    
    	/* check for 'last error code' which tells us the
    	 * type of the last error to occur on the CAN bus
    	 */
    	cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
    
    	switch (lec_type) {
    		case LEC_STUFF_ERROR:
    			netdev_dbg(dev, "stuff error\n");
    			cf->data[2] |= CAN_ERR_PROT_STUFF;
    			break;
    		case LEC_FORM_ERROR:
    			netdev_dbg(dev, "form error\n");
    			cf->data[2] |= CAN_ERR_PROT_FORM;
    			break;
    		case LEC_ACK_ERROR:
    			netdev_dbg(dev, "ack error\n");
    			cf->data[3] = CAN_ERR_PROT_LOC_ACK;
    			break;
    		case LEC_BIT1_ERROR:
    			netdev_dbg(dev, "bit1 error\n");
    			cf->data[2] |= CAN_ERR_PROT_BIT1;
    			break;
    		case LEC_BIT0_ERROR:
    			netdev_dbg(dev, "bit0 error\n");
    			cf->data[2] |= CAN_ERR_PROT_BIT0;
    			break;
    		case LEC_CRC_ERROR:
    			netdev_dbg(dev, "CRC error\n");
    			cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
    			break;
    		default:
    			break;
    	}
    
    	stats->rx_packets++;
    	stats->rx_bytes += cf->can_dlc;
    	netif_receive_skb(skb);
    
    	return 1;
    }
    
    static int __m_can_get_berr_counter(const struct net_device *dev,
    		struct can_berr_counter *bec)
    {
    	struct m_can_classdev *cdev = netdev_priv(dev);
    	unsigned int ecr;
    
    	ecr = m_can_read(cdev, M_CAN_ECR);
    	bec->rxerr = (ecr & ECR_REC_MASK) >> ECR_REC_SHIFT;
    	bec->txerr = (ecr & ECR_TEC_MASK) >> ECR_TEC_SHIFT;
    
    	return 0;
    }
    
    static int m_can_clk_start(struct m_can_classdev *cdev)
    {
    	int err;
    
    	if (cdev->pm_clock_support == 0)
    		return 0;
    
    	err = pm_runtime_get_sync(cdev->dev);
    	if (err < 0) {
    		pm_runtime_put_noidle(cdev->dev);
    		return err;
    	}
    
    	return 0;
    }
    
    static void m_can_clk_stop(struct m_can_classdev *cdev)
    {
    	if (cdev->pm_clock_support)
    		pm_runtime_put_sync(cdev->dev);
    }
    
    static int m_can_get_berr_counter(const struct net_device *dev,
    		struct can_berr_counter *bec)
    {
    	struct m_can_classdev *cdev = netdev_priv(dev);
    	int err;
    
    	err = m_can_clk_start(cdev);
    	if (err)
    		return err;
    
    	__m_can_get_berr_counter(dev, bec);
    
    	m_can_clk_stop(cdev);
    
    	return 0;
    }
    
    static int m_can_handle_state_change(struct net_device *dev,
    		enum can_state new_state)
    {
    	struct m_can_classdev *cdev = netdev_priv(dev);
    	struct net_device_stats *stats = &dev->stats;
    	struct can_frame *cf;
    	struct sk_buff *skb;
    	struct can_berr_counter bec;
    	unsigned int ecr;
    
    	switch (new_state) {
    		case CAN_STATE_ERROR_ACTIVE:
    			/* error warning state */
    			cdev->can.can_stats.error_warning++;
    			cdev->can.state = CAN_STATE_ERROR_WARNING;
    			break;
    		case CAN_STATE_ERROR_PASSIVE:
    			/* error passive state */
    			cdev->can.can_stats.error_passive++;
    			cdev->can.state = CAN_STATE_ERROR_PASSIVE;
    			break;
    		case CAN_STATE_BUS_OFF:
    			/* bus-off state */
    			cdev->can.state = CAN_STATE_BUS_OFF;
    			m_can_disable_all_interrupts(cdev);
    			cdev->can.can_stats.bus_off++;
    			can_bus_off(dev);
    			break;
    		default:
    			break;
    	}
    
    	/* propagate the error condition to the CAN stack */
    	skb = alloc_can_err_skb(dev, &cf);
    	if (unlikely(!skb))
    		return 0;
    
    	__m_can_get_berr_counter(dev, &bec);
    
    	switch (new_state) {
    		case CAN_STATE_ERROR_ACTIVE:
    			/* error warning state */
    			cf->can_id |= CAN_ERR_CRTL;
    			cf->data[1] = (bec.txerr > bec.rxerr) ?
    				CAN_ERR_CRTL_TX_WARNING :
    				CAN_ERR_CRTL_RX_WARNING;
    			cf->data[6] = bec.txerr;
    			cf->data[7] = bec.rxerr;
    			break;
    		case CAN_STATE_ERROR_PASSIVE:
    			/* error passive state */
    			cf->can_id |= CAN_ERR_CRTL;
    			ecr = m_can_read(cdev, M_CAN_ECR);
    			if (ecr & ECR_RP)
    				cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
    			if (bec.txerr > 127)
    				cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
    			cf->data[6] = bec.txerr;
    			cf->data[7] = bec.rxerr;
    			break;
    		case CAN_STATE_BUS_OFF:
    			/* bus-off state */
    			cf->can_id |= CAN_ERR_BUSOFF;
    			break;
    		default:
    			break;
    	}
    
    	stats->rx_packets++;
    	stats->rx_bytes += cf->can_dlc;
    	netif_receive_skb(skb);
    
    	return 1;
    }
    
    static int m_can_handle_state_errors(struct net_device *dev, u32 psr)
    {
    	struct m_can_classdev *cdev = netdev_priv(dev);
    	int work_done = 0;
    
    	if (psr & PSR_EW && cdev->can.state != CAN_STATE_ERROR_WARNING) {
    		netdev_dbg(dev, "entered error warning state\n");
    		work_done += m_can_handle_state_change(dev,
    				CAN_STATE_ERROR_WARNING);
    	}
    
    	if (psr & PSR_EP && cdev->can.state != CAN_STATE_ERROR_PASSIVE) {
    		netdev_dbg(dev, "entered error passive state\n");
    		work_done += m_can_handle_state_change(dev,
    				CAN_STATE_ERROR_PASSIVE);
    	}
    
    	if (psr & PSR_BO && cdev->can.state != CAN_STATE_BUS_OFF) {
    		netdev_dbg(dev, "entered error bus off state\n");
    		work_done += m_can_handle_state_change(dev,
    				CAN_STATE_BUS_OFF);
    	}
    
    	return work_done;
    }
    
    static void m_can_handle_other_err(struct net_device *dev, u32 irqstatus)
    {
    	if (irqstatus & IR_WDI)
    		netdev_err(dev, "Message RAM Watchdog event due to missing READY\n");
    	if (irqstatus & IR_ELO)
    		netdev_err(dev, "Error Logging Overflow\n");
    	if (irqstatus & IR_BEU)
    		netdev_err(dev, "Bit Error Uncorrected\n");
    	if (irqstatus & IR_BEC)
    		netdev_err(dev, "Bit Error Corrected\n");
    	if (irqstatus & IR_TOO)
    		netdev_err(dev, "Timeout reached\n");
    	if (irqstatus & IR_MRAF)
    		netdev_err(dev, "Message RAM access failure occurred\n");
    }
    
    static inline bool is_lec_err(u32 psr)
    {
    	psr &= LEC_UNUSED;
    
    	return psr && (psr != LEC_UNUSED);
    }
    
    static int m_can_handle_bus_errors(struct net_device *dev, u32 irqstatus,
    		u32 psr)
    {
    	struct m_can_classdev *cdev = netdev_priv(dev);
    	int work_done = 0;
    
    	if (irqstatus & IR_RF0L)
    		work_done += m_can_handle_lost_msg(dev);
    
    	/* handle lec errors on the bus */
    	if ((cdev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) &&
    			is_lec_err(psr))
    		work_done += m_can_handle_lec_err(dev, psr & LEC_UNUSED);
    
    	/* other unproccessed error interrupts */
    	m_can_handle_other_err(dev, irqstatus);
    
    	return work_done;
    }
    
    static int m_can_rx_handler_rx(struct net_device *dev, int quota)
    {
    	int work_done = 0;
    	work_done += m_can_do_rx_poll(dev, (quota - work_done));
    	return work_done;
    		
    }
    
    static int m_can_rx_handler(struct net_device *dev, int quota)
    {
    	struct m_can_classdev *cdev = netdev_priv(dev);
    	int work_done = 0;
    	u32 irqstatus, psr;
    	irqstatus = cdev->irqstatus | m_can_read(cdev, M_CAN_IR);
    	if (!irqstatus)
    		goto end;
    	/* Errata workaround for issue "Needless activation of MRAF irq"
    	 * During frame reception while the MCAN is in Error Passive state
    	 * and the Receive Error Counter has the value MCAN_ECR.REC = 127,
    	 * it may happen that MCAN_IR.MRAF is set although there was no
    	 * Message RAM access failure.
    	 * If MCAN_IR.MRAF is enabled, an interrupt to the Host CPU is generated
    	 * The Message RAM Access Failure interrupt routine needs to check
    	 * whether MCAN_ECR.RP = ’1’ and MCAN_ECR.REC = 127.
    	 * In this case, reset MCAN_IR.MRAF. No further action is required.
    	 */
    	if (cdev->version <= 31 && irqstatus & IR_MRAF &&
    			m_can_read(cdev, M_CAN_ECR) & ECR_RP) {
    		struct can_berr_counter bec;
    
    		__m_can_get_berr_counter(dev, &bec);
    		if (bec.rxerr == 127) {
    			m_can_write(cdev, M_CAN_IR, IR_MRAF);
    			irqstatus &= ~IR_MRAF;
    		}
    	}
    
    	psr = m_can_read(cdev, M_CAN_PSR);
    
    	if (irqstatus & IR_ERR_STATE)
    		work_done += m_can_handle_state_errors(dev, psr);
    	if(iw_mcan_prop)
    	{
    		/* changes bus size from 30X to 31X*/
    		if (irqstatus & IR_ERR_BUS_31X)
    			work_done += m_can_handle_bus_errors(dev, irqstatus, psr);
    
    		if (irqstatus & IR_RF0W)
    			work_done += m_can_do_rx_poll(dev, (quota - work_done));
    	}
    	else /* iw_mcan_prop */
    	{
    		if (irqstatus & IR_ERR_BUS_30X)
    			work_done += m_can_handle_bus_errors(dev, irqstatus, psr);
    
    		if (irqstatus & IR_RF0N)
    			work_done += m_can_do_rx_poll(dev, (quota - work_done));
    	} /* iw_mcan_prop */
    end:
    	return work_done;
    }
    
    static int m_can_rx_peripheral(struct net_device *dev)
    {
    	struct m_can_classdev *cdev = netdev_priv(dev);
    
    	m_can_rx_handler(dev, 1);
    
    	m_can_enable_all_interrupts(cdev);
    
    	return 0;
    }
    
    int m_can_rx_clear(struct net_device *dev)
    {
            struct m_can_classdev *cdev = netdev_priv(dev);
            m_can_disable_all_interrupts(cdev);
            m_can_rx_peripheral(dev);
    
            return 0;
    }
    EXPORT_SYMBOL_GPL(m_can_rx_clear);
    
    static int m_can_poll(struct napi_struct *napi, int quota)
    {
    	struct net_device *dev = napi->dev;
    	struct m_can_classdev *cdev = netdev_priv(dev);
    	int work_done;
    
    	work_done = m_can_rx_handler(dev, quota);
    	if (work_done < quota) {
    		napi_complete_done(napi, work_done);
    		m_can_enable_all_interrupts(cdev);
    	}
    
    	return work_done;
    }
    
    
    /* Set the "iw_mcan_prop" flag to execute iWave specific change */
    void m_can_set_iw_mcan_prop_flag( void )
    {
            iw_mcan_prop = true;
    }
    EXPORT_SYMBOL_GPL(m_can_set_iw_mcan_prop_flag);
    
    static void m_can_echo_tx_event(struct net_device *dev)
    {
    	u32 fgi = 0;
    	unsigned int msg_mark;
    
    	struct m_can_classdev *cdev = netdev_priv(dev);
    	struct net_device_stats *stats = &dev->stats;
    
    	fgi = (m_can_read(cdev, M_CAN_TXEFS) & TXEFS_EFGI_MASK)
    		>> TXEFS_EFGI_SHIFT;
    
    	/* get message marker */
    	msg_mark = (m_can_txe_fifo_read(cdev, fgi, 4) &
    			TX_EVENT_MM_MASK) >> TX_EVENT_MM_SHIFT;
    
    	/* ack txe element */
    	m_can_write(cdev, M_CAN_TXEFA, (TXEFA_EFAI_MASK &
    				(fgi << TXEFA_EFAI_SHIFT)));
    
    	/* update stats */
    	stats->tx_bytes += can_get_echo_skb(dev, msg_mark, NULL);
    	stats->tx_packets++;
    }
    
    static int m_can_rx_peripheral_rx(struct net_device *dev)
    {
    	struct m_can_classdev *cdev = netdev_priv(dev);
    
    	m_can_rx_handler_rx(dev, 1);
    
    	m_can_enable_all_interrupts(cdev);
    	return 0;
    }
    
    static irqreturn_t m_can_isr(int irq, void *dev_id)
    {
    	struct net_device *dev = (struct net_device *)dev_id;
    	struct m_can_classdev *cdev = netdev_priv(dev);
    	struct net_device_stats *stats = &dev->stats;
    	u32 ir;
    	ir = m_can_read(cdev, M_CAN_IR);
    	/* ACK all irqs */
    	if (ir & IR_ALL_INT_CUSTOM_NO_TX)
    		m_can_write(cdev, M_CAN_IR, ir);
    
    	cdev->ops->clear_interrupts(cdev);
    	
    	/* schedule NAPI in case of
    	 * - rx IRQ
    	 * - state change IRQ
    	 * - bus error IRQ and bus error reporting
    	 */
    	if(ir == 0x0 || (ir & IR_RF0N)) /* Watchdog interrupt */
    	{
    		m_can_disable_all_interrupts(cdev);
    		m_can_rx_peripheral_rx(dev);
    		return IRQ_HANDLED;
    	}
    	
    	if(iw_mcan_prop)
    	{
    		if ((ir & IR_RF0W) || (ir & IR_RF0N) || (ir & IR_ERR_ALL_30X)) {
    			cdev->irqstatus = ir;
    			m_can_disable_all_interrupts(cdev);
    			if (!cdev->is_peripheral)
    				napi_schedule(&cdev->napi);
    			else
    				m_can_rx_peripheral(dev);
    		}
    	}
    	else /* iw_mcan_prop */
    	{
    		if ((ir & IR_RF0N) || (ir & IR_ERR_ALL_30X)) {
    			cdev->irqstatus = ir;
    			m_can_disable_all_interrupts(cdev);
    			if (!cdev->is_peripheral)
    				napi_schedule(&cdev->napi);
    			else
    				m_can_rx_peripheral(dev);
    		}
    	} /* iw_mcan_prop */
    	/*if (cdev->version == 30) {
    		if (ir & IR_TC) {
    			/  Transmission Complete Interrupt /
    			stats->tx_bytes += can_get_echo_skb(dev, 0, NULL);
    			stats->tx_packets++;
    			can_led_event(dev, CAN_LED_EVENT_TX);
    			netif_wake_queue(dev);
    		}
    	} else  {
    		if (ir & IR_TFE) 
    		{
    			netif_wake_queue(dev);
    		}
    	}*/
    	return IRQ_HANDLED;
    }
    
    static const struct can_bittiming_const m_can_bittiming_const_30X = {
    	.name = KBUILD_MODNAME,
    	.tseg1_min = 2,		/* Time segment 1 = prop_seg + phase_seg1 */
    	.tseg1_max = 64,
    	.tseg2_min = 1,		/* Time segment 2 = phase_seg2 */
    	.tseg2_max = 16,
    	.sjw_max = 16,
    	.brp_min = 1,
    	.brp_max = 1024,
    	.brp_inc = 1,
    };
    
    static const struct can_bittiming_const m_can_data_bittiming_const_30X = {
    	.name = KBUILD_MODNAME,
    	.tseg1_min = 2,		/* Time segment 1 = prop_seg + phase_seg1 */
    	.tseg1_max = 16,
    	.tseg2_min = 1,		/* Time segment 2 = phase_seg2 */
    	.tseg2_max = 8,
    	.sjw_max = 4,
    	.brp_min = 1,
    	.brp_max = 32,
    	.brp_inc = 1,
    };
    
    static const struct can_bittiming_const m_can_bittiming_const_31X = {
    	.name = KBUILD_MODNAME,
    	.tseg1_min = 2,		/* Time segment 1 = prop_seg + phase_seg1 */
    	.tseg1_max = 256,
    	.tseg2_min = 1,		/* Time segment 2 = phase_seg2 */
    	.tseg2_max = 128,
    	.sjw_max = 128,
    	.brp_min = 1,
    	.brp_max = 512,
    	.brp_inc = 1,
    };
    
    static const struct can_bittiming_const m_can_data_bittiming_const_31X = {
    	.name = KBUILD_MODNAME,
    	.tseg1_min = 1,		/* Time segment 1 = prop_seg + phase_seg1 */
    	.tseg1_max = 32,
    	.tseg2_min = 1,		/* Time segment 2 = phase_seg2 */
    	.tseg2_max = 16,
    	.sjw_max = 16,
    	.brp_min = 1,
    	.brp_max = 32,
    	.brp_inc = 1,
    };
    
    static int m_can_set_bittiming(struct net_device *dev)
    {
    	struct m_can_classdev *cdev = netdev_priv(dev);
    	const struct can_bittiming *bt = &cdev->can.bittiming;
    	const struct can_bittiming *dbt = &cdev->can.data_bittiming;
    	u16 brp, sjw, tseg1, tseg2;
    	u32 reg_btp;
    
    	brp = bt->brp - 1;
    	sjw = bt->sjw - 1;
    	tseg1 = bt->prop_seg + bt->phase_seg1 - 1;
    	tseg2 = bt->phase_seg2 - 1;
    	reg_btp = (brp << NBTP_NBRP_SHIFT) | (sjw << NBTP_NSJW_SHIFT) |
    		(tseg1 << NBTP_NTSEG1_SHIFT) | (tseg2 << NBTP_NTSEG2_SHIFT);
    	m_can_write(cdev, M_CAN_NBTP, reg_btp);
    	Tx_DELAY = 0;
    
    	if (cdev->can.ctrlmode & CAN_CTRLMODE_FD) {
    		reg_btp = 0;
    		brp = dbt->brp - 1;
    		sjw = dbt->sjw - 1;
    		tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1;
    		tseg2 = dbt->phase_seg2 - 1;
    		FD_mode = true;
    
    		/* TDC is only needed for bitrates beyond 2.5 MBit/s.
    		 * This is mentioned in the "Bit Time Requirements for CAN FD"
    		 * paper presented at the International CAN Conference 2013
    		 */
    		if (dbt->bitrate > 1000000) {
    			u32 tdco, ssp;
    
    			/* Use the same value of secondary sampling point
    			 * as the data sampling point
    			 */
    			ssp = dbt->sample_point;
    
    			/* Equation based on Bosch's M_CAN User Manual's
    			 * Transmitter Delay Compensation Section
    			 */
    			tdco = (cdev->can.clock.freq / 1000) *
    				ssp / dbt->bitrate;
    			/* Max valid TDCO value is 127 */
    			if (tdco > 127) {
    				netdev_warn(dev, "TDCO value of %u is beyond maximum. Using maximum possible value\n",
    						tdco);
    				tdco = 127;
    			}
    
    			reg_btp |= DBTP_TDC;
    			m_can_write(cdev, M_CAN_TDCR,
    					tdco << TDCR_TDCO_SHIFT);
    		}
    
    		reg_btp |= (brp << DBTP_DBRP_SHIFT) |
    			(sjw << DBTP_DSJW_SHIFT) |
    			(tseg1 << DBTP_DTSEG1_SHIFT) |
    			(tseg2 << DBTP_DTSEG2_SHIFT);
    
    		m_can_write(cdev, M_CAN_DBTP, reg_btp);
    	}
    	else
    	{
    		switch (bt->bitrate)
    		{
    			case 1000000:
    				Tx_DELAY = 0;
    				break;
    		}
    	}
    
    	return 0;
    }
    
    
    /* Configure M_CAN chip:
     * - set rx buffer/fifo element size
     * - configure rx fifo
     * - accept non-matching frame into fifo 0
     * - configure tx buffer
     *		- >= v3.1.x: TX FIFO is used
     * - configure mode
     * - setup bittiming
     */
    static void m_can_chip_config(struct net_device *dev)
    {
    	struct m_can_classdev *cdev = netdev_priv(dev);
    	u32 cccr, test;
    	int k;
    
    	/* RX Buffer/FIFO Element Size 64 bytes data field */
    	m_can_write(cdev, M_CAN_RXESC, M_CAN_RXESC_64BYTES);
    
    	/* Accept Non-matching Frames Into FIFO 0 */
    	m_can_write(cdev, M_CAN_GFC, 0x0);
    
    	if (cdev->version == 30) {
    		/* only support one Tx Buffer currently */
    		m_can_write(cdev, M_CAN_TXBC, (1 << TXBC_NDTB_SHIFT) |
    				cdev->mcfg[MRAM_TXB].off);
    	} else {
    		/* TX FIFO is used for newer IP Core versions */
    		m_can_write(cdev, M_CAN_TXBC,
    				(cdev->mcfg[MRAM_TXB].num << TXBC_TFQS_SHIFT) |
    				(cdev->mcfg[MRAM_TXB].off));
    	}
    
    	/* support 64 bytes payload */
    	m_can_write(cdev, M_CAN_TXESC, TXESC_TBDS_64BYTES);
    
    	/* TX Event FIFO */
    	if (cdev->version == 30) {
    		m_can_write(cdev, M_CAN_TXEFC, (1 << TXEFC_EFS_SHIFT) |
    				cdev->mcfg[MRAM_TXE].off);
    	} else {
    		/* Full TX Event FIFO is used */
    		m_can_write(cdev, M_CAN_TXEFC,
    				((cdev->mcfg[MRAM_TXE].num << TXEFC_EFS_SHIFT)
    				 & TXEFC_EFS_MASK) |
    				cdev->mcfg[MRAM_TXE].off);
    	}
    	
    	if (iw_mcan_prop)
    	{
    		/* rx fifo configuration, blocking mode, fifo size 1 */
    		m_can_write(cdev, M_CAN_RXF0C,
    				(cdev->mcfg[MRAM_RXF0].num << RXFC_FS_SHIFT) |
    				cdev->mcfg[MRAM_RXF0].off | 0x9A000000 /*| 0x81200000*/);
    		//Added by iwave
    		k = cdev->mcfg[MRAM_RXF0].num << RXFC_FS_SHIFT | cdev->mcfg[MRAM_RXF0].off ;
    
    		m_can_write(cdev, M_CAN_RXF1C,
    				(cdev->mcfg[MRAM_RXF1].num << RXFC_FS_SHIFT) |
    				cdev->mcfg[MRAM_RXF1].off | 0x8C000000 /*| 0x81200000 */);
    	}
    	else /* iw_mcan_prop */
    	{
    		/* rx fifo configuration, blocking mode, fifo size 1 */
    		m_can_write(cdev, M_CAN_RXF0C,
    				(cdev->mcfg[MRAM_RXF0].num << RXFC_FS_SHIFT) |
    				cdev->mcfg[MRAM_RXF0].off);
    
    		m_can_write(cdev, M_CAN_RXF1C,
    				(cdev->mcfg[MRAM_RXF1].num << RXFC_FS_SHIFT) |
    				cdev->mcfg[MRAM_RXF1].off);
    	} /* iw_mcan_prop */
    	
    	cccr = m_can_read(cdev, M_CAN_CCCR);
    	test = m_can_read(cdev, M_CAN_TEST);
    	test &= ~TEST_LBCK;
    	if (cdev->version == 30) {
    		/* Version 3.0.x */
    
    		cccr &= ~(CCCR_TEST | CCCR_MON |
    				(CCCR_CMR_MASK << CCCR_CMR_SHIFT) |
    				(CCCR_CME_MASK << CCCR_CME_SHIFT));
    
    		if (cdev->can.ctrlmode & CAN_CTRLMODE_FD)
    			cccr |= CCCR_CME_CANFD_BRS << CCCR_CME_SHIFT;
    
    	} else {
    		/* Version 3.1.x or 3.2.x */
    		cccr &= ~(CCCR_TEST | CCCR_MON | CCCR_BRSE | CCCR_FDOE |
    				CCCR_NISO);
    
    		/* Only 3.2.x has NISO Bit implemented */
    		if (cdev->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO)
    			cccr |= CCCR_NISO;
    
    		if (cdev->can.ctrlmode & CAN_CTRLMODE_FD)
    			cccr |= (CCCR_BRSE | CCCR_FDOE);
    	}
    
    	/* Enable Monitoring (all versions) */
    	if (cdev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
    		cccr |= CCCR_MON;
    
    	/* Write config */
    	m_can_write(cdev, M_CAN_CCCR, cccr);
    	m_can_write(cdev, M_CAN_TEST, test);
    
    	/* Enable interrupts */
    	m_can_write(cdev, M_CAN_IR, IR_ALL_INT);
    	if (!(cdev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING))
    		if (cdev->version == 30)
    			m_can_write(cdev, M_CAN_IE, IR_ALL_INT &
    					~(IR_ERR_LEC_30X));
    		else
    			m_can_write(cdev, M_CAN_IE, IR_ALL_INT_CUSTOM_NO_TX &
    					~(IR_ERR_LEC_31X));
    	else
    		m_can_write(cdev, M_CAN_IE, IR_ALL_INT_CUSTOM_NO_TX);
    
    	/* route all interrupts to INT0 */
    	m_can_write(cdev, M_CAN_ILS, ILS_ALL_INT0);
    
    	/* set bittiming params */
    	m_can_set_bittiming(dev);
    	
    	m_can_config_endisable(cdev, false);
    	mode=true;
    
    	if (cdev->ops->init)
    		cdev->ops->init(cdev);
    }
    
    static void m_can_start(struct net_device *dev)
    {
    	struct m_can_classdev *cdev = netdev_priv(dev);
    
    	/* basic m_can configuration */
    	m_can_chip_config(dev);
    
    	cdev->can.state = CAN_STATE_ERROR_ACTIVE;
    
    	m_can_enable_all_interrupts(cdev);
    }
    
    static int m_can_set_mode(struct net_device *dev, enum can_mode mode)
    {
    	switch (mode) {
    		case CAN_MODE_START:
    			m_can_clean(dev);
    			m_can_start(dev);
    			netif_wake_queue(dev);
    			break;
    		default:
    			return -EOPNOTSUPP;
    	}
    
    	return 0;
    }
    
    /* Checks core release number of M_CAN
     * returns 0 if an unsupported device is detected
     * else it returns the release and step coded as:
     * return value = 10 * <release> + 1 * <step>
     */
    static int m_can_check_core_release(struct m_can_classdev *cdev)
    {
    	u32 crel_reg;
    	u8 rel;
    	u8 step;
    	int res;
    
    	/* Read Core Release Version and split into version number
    	 * Example: Version 3.2.1 => rel = 3; step = 2; substep = 1;
    	 */
    	crel_reg = m_can_read(cdev, M_CAN_CREL);
    	rel = (u8)((crel_reg & CREL_REL_MASK) >> CREL_REL_SHIFT);
    	step = (u8)((crel_reg & CREL_STEP_MASK) >> CREL_STEP_SHIFT);
    
    	if (rel == 3) {
    		/* M_CAN v3.x.y: create return value */
    		res = 30 + step;
    	} else {
    		/* Unsupported M_CAN version */
    		res = 0;
    	}
    
    	return res;
    }
    
    /* Selectable Non ISO support only in version 3.2.x
     * This function checks if the bit is writable.
     */
    static bool m_can_niso_supported(struct m_can_classdev *cdev)
    {
    	u32 cccr_reg, cccr_poll = 0;
    	int niso_timeout = -ETIMEDOUT;
    	int i;
    
    	cccr_reg = m_can_read(cdev, M_CAN_CCCR);
    	cccr_reg |= CCCR_NISO;
    	m_can_write(cdev, M_CAN_CCCR, cccr_reg);
    
    	for (i = 0; i <= 10; i++) {
    		cccr_poll = m_can_read(cdev, M_CAN_CCCR);
    		if (cccr_poll == cccr_reg) {
    			niso_timeout = 0;
    			break;
    		}
    
    		usleep_range(1, 5);
    	}
    
    	/* Clear NISO */
    	cccr_reg &= ~(CCCR_NISO);
    	m_can_write(cdev, M_CAN_CCCR, cccr_reg | CCCR_FDOE | CCCR_BRSE);
    
    
    	/* return false if time out (-ETIMEDOUT), else return true */
    	return !niso_timeout;
    }
    
    static int m_can_dev_setup(struct m_can_classdev *m_can_dev)
    {
    	struct net_device *dev = m_can_dev->net;
    	int m_can_version;
    
    	m_can_version = m_can_check_core_release(m_can_dev);
    	/* return if unsupported version */
    	if (!m_can_version) {
    		dev_err(m_can_dev->dev, "Unsupported version number: %2d",
    				m_can_version);
    		return -EINVAL;
    	}
    
    	if (!m_can_dev->is_peripheral)
    		netif_napi_add(dev, &m_can_dev->napi,
    				m_can_poll, M_CAN_NAPI_WEIGHT);
    
    	/* Shared properties of all M_CAN versions */
    	m_can_dev->version = m_can_version;
    	m_can_dev->can.do_set_mode = m_can_set_mode;
    	m_can_dev->can.do_get_berr_counter = m_can_get_berr_counter;
    
    	/* Set M_CAN supported operations */
    	m_can_dev->can.ctrlmode_supported = /*CAN_CTRLMODE_LOOPBACK |*/
    		CAN_CTRLMODE_LISTENONLY |
    		CAN_CTRLMODE_BERR_REPORTING |
    		CAN_CTRLMODE_FD;
    
    	/* Set properties depending on M_CAN version */
    	switch (m_can_dev->version) {
    		case 30:
    			/* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.0.x */
    			can_set_static_ctrlmode(dev, CAN_CTRLMODE_FD_NON_ISO);
    			m_can_dev->can.bittiming_const = m_can_dev->bit_timing ?
    				m_can_dev->bit_timing : &m_can_bittiming_const_30X;
    
    			m_can_dev->can.data_bittiming_const = m_can_dev->data_timing ?
    				m_can_dev->data_timing :
    				&m_can_data_bittiming_const_30X;
    			break;
    		case 31:
    			/* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.1.x */
    			can_set_static_ctrlmode(dev, CAN_CTRLMODE_FD_NON_ISO);
    			m_can_dev->can.bittiming_const = m_can_dev->bit_timing ?
    				m_can_dev->bit_timing : &m_can_bittiming_const_31X;
    
    			m_can_dev->can.data_bittiming_const = m_can_dev->data_timing ?
    				m_can_dev->data_timing :
    				&m_can_data_bittiming_const_31X;
    			break;
    		case 32:
    			m_can_dev->can.bittiming_const = m_can_dev->bit_timing ?
    				m_can_dev->bit_timing : &m_can_bittiming_const_31X;
    
    			m_can_dev->can.data_bittiming_const = m_can_dev->data_timing ?
    				m_can_dev->data_timing :
    				&m_can_data_bittiming_const_31X;
    			m_can_dev->can.ctrlmode_supported |=
    				(m_can_niso_supported(m_can_dev)
    				 ? CAN_CTRLMODE_FD_NON_ISO
    				 : 0);
    			break;
    		default:
    			dev_err(m_can_dev->dev, "Unsupported version number: %2d",
    					m_can_dev->version);
    			return -EINVAL;
    	}
    
    	if (m_can_dev->ops->init)
    		m_can_dev->ops->init(m_can_dev);
    
    	return 0;
    }
    
    static void m_can_stop(struct net_device *dev)
    {
    	struct m_can_classdev *cdev = netdev_priv(dev);
    
    	/* disable all interrupts */
    	m_can_disable_all_interrupts(cdev);
    
    	/* set the state as STOPPED */
    	cdev->can.state = CAN_STATE_STOPPED;
    }
    
    static int m_can_close(struct net_device *dev)
    {
    	struct m_can_classdev *cdev = netdev_priv(dev);
    
    	netif_stop_queue(dev);
    
    	if (!cdev->is_peripheral)
    		napi_disable(&cdev->napi);
    
    	m_can_stop(dev);
    	m_can_clk_stop(cdev);
    	free_irq(dev->irq, dev);
    
    	if (cdev->is_peripheral) {
    		cdev->tx_skb = NULL;
    		destroy_workqueue(cdev->tx_wq);
    		cdev->tx_wq = NULL;
    	}
    
    	close_candev(dev);
    	can_led_event(dev, CAN_LED_EVENT_STOP);
    
    	return 0;
    }
    
    static int m_can_next_echo_skb_occupied(struct net_device *dev, int putidx)
    {
    	struct m_can_classdev *cdev = netdev_priv(dev);
    	/*get wrap around for loopback skb index */
    	unsigned int wrap = cdev->can.echo_skb_max;
    	int next_idx;
    	/* calculate next index */
    	next_idx = (++putidx >= wrap ? 0 : putidx);
    
    	/* check if occupied */
    	return !!cdev->can.echo_skb[next_idx];
    }
    void printBinary(unsigned int num);
    void printBinary(unsigned int num) {
        int i;
        for (i = 31; i >= 0; i--) {
            printk(KERN_CONT "%d", (num >> i) & 1);
            if (i % 4 == 0) // add space for better readability
                printk(KERN_CONT " ");
        }
        printk(KERN_CONT "\n");
    }
    
    static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev)
    {
    	struct canfd_frame *cf = (struct canfd_frame *)cdev->tx_skb->data;
    	struct net_device *dev = cdev->net;
    	struct sk_buff *skb = cdev->tx_skb;
    	const struct can_bittiming *bt = &cdev->can.bittiming;
    	const struct can_bittiming *dbt = &cdev->can.data_bittiming;
    	u32 id, cccr, fdflags;
    	int i;
    	int putidx;
    	bool FD_29_bit;
    	printk("handler begining---------------------\n");	
    	/* Generate ID field for TX buffer Element */
    	/* Common to all supported M_CAN versions */
    	   if (!cdev || !skb) {
    	        printk(KERN_ERR "Invalid parameters\n");
            	return NETDEV_TX_BUSY;
    	   }
    	if (cf->can_id & CAN_EFF_FLAG) { /* 29 bit identifier */
    		id = cf->can_id & CAN_EFF_MASK;
    		id |= TX_BUF_XTD;
    		if(FD_mode == false && bt->bitrate !=1000000)
    		{
    			switch (bt->bitrate)
    			{
    				case 250000:
    					Tx_DELAY = 350;
    					break;
    				case 500000:
    					Tx_DELAY = 80;
    					break;
    			}
    		}
    		else
    		{
    			FD_29_bit = true;
    		}
    	} else { /* 11 bit identifier */
    		id = ((cf->can_id & CAN_SFF_MASK) << 18);
    		printk("11th bit identifier");
    		if(FD_mode == false && bt->bitrate !=1000000)
    		{
    			switch (bt->bitrate)
    			{
    				case 250000:
    					Tx_DELAY = 270;
    					break;
    				case 500000:
    					Tx_DELAY = 40;
    					break;
    			}
    		}
    		else
    		{
    			FD_29_bit = false;
    		}
    	}
    
    	if (cf->can_id & CAN_RTR_FLAG)
    		printk("inside RTR FLAG------------\n");
    		id |= TX_BUF_RTR;
    
    	if (cdev->version == 30) {
    		netif_stop_queue(dev);
    		printk("inside cdev version------------------\n");
    
    		/* message ram configuration */
    		m_can_fifo_write(cdev, 0, M_CAN_FIFO_ID, id);
    		m_can_fifo_write(cdev, 0, M_CAN_FIFO_DLC,
    				can_fd_len2dlc(cf->len) << 16);
    
    		for (i = 0; i < cf->len; i += 4)
    			m_can_fifo_write(cdev, 0,
    					M_CAN_FIFO_DATA(i / 4),
    					*(u32 *)(cf->data + i));
    			printk("inside can fifo write--------------------\n");
    
    		can_put_echo_skb(skb, dev, 0,0);
    
    		if (cdev->can.ctrlmode & CAN_CTRLMODE_FD) {
    			cccr = m_can_read(cdev, M_CAN_CCCR);
    			cccr &= ~(CCCR_CMR_MASK << CCCR_CMR_SHIFT);
    			if (can_is_canfd_skb(skb)) {
    				if (cf->flags & CANFD_BRS)
    					cccr |= CCCR_CMR_CANFD_BRS <<
    						CCCR_CMR_SHIFT;
    				else
    					cccr |= CCCR_CMR_CANFD <<
    						CCCR_CMR_SHIFT;
    			} else {
    				cccr |= CCCR_CMR_CAN << CCCR_CMR_SHIFT;
    			}
    			m_can_write(cdev, M_CAN_CCCR, cccr);
    		}
    		m_can_write(cdev, M_CAN_TXBTIE, 0x1);
    		m_can_write(cdev, M_CAN_TXBAR, 0x1);
    		/* End of xmit function for version 3.0.x */
    	} else {
    		/* Transmit routine for version >= v3.1.x */
    		/* get put index for frame */
    		printk("else part of version----------------\n");
    		putidx = ((m_can_read(cdev, M_CAN_TXFQS) & TXFQS_TFQPI_MASK)
    				>> TXFQS_TFQPI_SHIFT);
    
    		printk("putidx " );			// to print refgister name
    		printBinary(putidx);	
    		
    		int errcr;
    		errcr = m_can_read(cdev, M_CAN_TXFQS);  //to read register
    		printk("M_CAN_TXFQS" );			// to print refgister name
    		printBinary(errcr);
    
    		errcr = m_can_read(cdev, M_CAN_FIFO_ID);  //to read register
                    printk("M_CAN_FIFO_ID,------------" );                 // to print refgister name
                    printBinary(errcr);
    
    		/* Write ID Field to FIFO Element */
    		m_can_fifo_write(cdev, putidx, M_CAN_FIFO_ID, id);
    
    		 errcr = m_can_read(cdev, M_CAN_FIFO_ID);  //to read register
                    printk("After---- M_CAN_FIFO_ID,------------" );                 // to print refgister name
                    printBinary(errcr);
    
    
    		/* get CAN FD configuration of frame */
    		fdflags = 0;
    		if (can_is_canfd_skb(skb)) {
    			printk("CANfd configuration frame\n");
    			fdflags |= TX_BUF_FDF;
    			if (cf->flags & CANFD_BRS)
    				fdflags |= TX_BUF_BRS;
    		}
    
    		/* Construct DLC Field. Also contains CAN-FD configuration
    		 * use put index of fifo as message marker
    		 * it is used in TX interrupt for
    		 * sending the correct echo frame
    		 */
    		printk("before fifo write----------------------------\n");
    		m_can_fifo_write(cdev, putidx, M_CAN_FIFO_DLC,
    				((putidx << TX_BUF_MM_SHIFT) &
    				 TX_BUF_MM_MASK) |
    				(can_fd_len2dlc(cf->len) << 16) |
    				fdflags | TX_BUF_EFC);
    		printk("after fifo write-----------------------------\n");
    
    		for (i = 0; i < cf->len; i += 4)
    			printk("inside for loop fifo write-------------------------\n");
    			m_can_fifo_write(cdev, putidx, M_CAN_FIFO_DATA(i / 4),
    					*(u32 *)(cf->data + i));
    		printk("beg of delay-------------------------------\n");
    		if(FD_mode == true && (dbt->bitrate <= 1000000 || bt->bitrate <= 250000))
    		{
    	
    			if(FD_29_bit == true)
    			{
    				printk("inside delay---------------\n");
    				if(i==64)
    				{
    					switch(bt->bitrate)
    					{
    						case 250000:
    							switch(dbt->bitrate)
    							{
    								case 250000:
    									Tx_DELAY = 1960;
    									break;
    								case 500000:
    									Tx_DELAY = 840;
    									break;
    								case 1000000:
    									Tx_DELAY = 270;
    									break;
    							}
    							break;
    						case 500000:
    							switch(dbt->bitrate)
    							{
    								case 500000:
    									Tx_DELAY = 740;
    									break;
    								case 1000000:
    									Tx_DELAY = 170;
    									break;
    							}
    							break;
    						case 1000000:
    							switch(dbt->bitrate)
    							{
    								case 1000000:
    									Tx_DELAY = 120;
    									break;
    							}
    							break;
    					}
    				}
    				else
    				{
    					switch(bt->bitrate)
    					{
    						case 250000:
    							switch(dbt->bitrate)
    							{
    								case 250000:
    									Tx_DELAY = 400;
    									break;
    								case 500000:
    									Tx_DELAY = 200;
    									break;
    								case 1000000:
    									Tx_DELAY = 100;
    									break;
    								case 2000000:
    									Tx_DELAY = 60;
    									break;
    								case 4000000:
    									Tx_DELAY = 30;
    									break;
    								case 5000000:
    									Tx_DELAY = 40;
    									break;
    								default:
    									Tx_DELAY = 45;
    									break;
    							}
    							break;
    						case 500000:
    							switch(dbt->bitrate)
    							{
    								case 500000:
    									Tx_DELAY = 110;
    									break;
    								case 1000000:
    									Tx_DELAY = 10;
    									break;
    							}
    							break;
    						case 1000000:
    							switch(dbt->bitrate)
    							{
    								case 1000000:
    									Tx_DELAY = 0;
    									break;
    							}
    							break;
    					}
    				}
    			}
    			else
    			{
    				if(i==64)
    				{
    					switch(bt->bitrate)
    					{
    						case 250000:
    							switch(dbt->bitrate)
    							{
    								case 250000:
    									Tx_DELAY = 1880;
    									break;
    								case 500000:
    									Tx_DELAY = 760;
    									break;
    								case 1000000:
    									Tx_DELAY = 190;
    									break;
    							}
    							break;
    						case 500000:
    							switch(dbt->bitrate)
    							{
    								case 500000:
    									Tx_DELAY = 700;
    									break;
    								case 1000000:
    									Tx_DELAY = 140;
    									break;
    							}
    							break;
    						case 1000000:
    							switch(dbt->bitrate)
    							{
    								case 1000000:
    									Tx_DELAY = 110;
    									break;
    							}
    							break;
    					}
    				}
    				else
    				{
    					switch(bt->bitrate)
    					{
    						case 250000:
    							switch(dbt->bitrate)
    							{
    								case 250000:
    									Tx_DELAY = 330;
    									break;
    								case 500000:
    									Tx_DELAY = 120;
    									break;
    								case 1000000:
    									Tx_DELAY = 25;
    									break;
    							}
    							break;
    						case 500000:
    							switch(dbt->bitrate)
    							{
    								case 500000:
    									Tx_DELAY = 70;
    									break;
    								case 1000000:
    									Tx_DELAY = 0;
    									break;
    							}
    							break;
    						case 1000000:
    							switch(dbt->bitrate)
    							{
    								case 1000000:
    									Tx_DELAY = 0;
    									break;
    							}
    							break;
    					}
    				}
    			}
    		}
    		printk("end of delay--------------------------\n");
    		/* Push loopback echo.
    		 * Will be looped back on TX interrupt based on message marker
    		 */
    		can_put_echo_skb(skb, dev, putidx,0);
    
    		/* Enable TX FIFO element to start transfer  */
    		m_can_write(cdev, M_CAN_TXBAR, (1 << putidx));
    		if (m_can_tx_fifo_full(cdev) )
    		{
    			printk("already full------------------\n");
    			netif_wake_queue(dev);
    			//Don't start the network and enable Transmit FIFO enable interrupt
    			m_can_write(cdev, M_CAN_IE, IR_ALL_INT_CUSTOM_NO_TX);
    		}
    		else
    		{
    			netif_wake_queue(dev);
    			printk("not full------------\n");
    		}
    		cdev->tx_skb = NULL;
    	}
    	
    	return NETDEV_TX_OK;
    }
    
    static void m_can_tx_work_queue(struct work_struct *ws)
    {
    	struct m_can_classdev *cdev = container_of(ws, struct m_can_classdev,
    			tx_work);
    
    	m_can_tx_handler(cdev);
    	cdev->tx_skb = NULL;
    }
    
    static netdev_tx_t m_can_start_xmit(struct sk_buff *skb,
    		struct net_device *dev)
    {
    	struct m_can_classdev *cdev = netdev_priv(dev);
    
    	if (cdev->is_peripheral) {
    		if (cdev->tx_skb) {
    			//netdev_err(dev, "hard_xmit called while tx busy\n");
    			return NETDEV_TX_BUSY;
    		}
    
    		if (cdev->can.state == CAN_STATE_BUS_OFF) {
    			m_can_clean(dev);
    		} else {
    			/* Need to stop the queue to avoid numerous requests
    			 * from being sent.  Suggested improvement is to create
    			 * a queueing mechanism that will queue the skbs and
    			 * process them in order.
    			 */
    			printk("begining-----\n");
    			udelay(Tx_DELAY);
    			cdev->tx_skb = skb;
    			netif_stop_queue(cdev->net);
    //			queue_work(cdev->tx_wq, &cdev->tx_work);
    			return m_can_tx_handler(cdev);
    			printk("ending----------\n");
    		}
    	} else {
    		cdev->tx_skb = skb;
    		return m_can_tx_handler(cdev);
    	}
    
    	return NETDEV_TX_OK;
    }
    
    static int m_can_open(struct net_device *dev)
    {
    	struct m_can_classdev *cdev = netdev_priv(dev);
    	int err;
    
    	err = m_can_clk_start(cdev);
    	if (err)
    		return err;
    	/* open the can device */
    	err = open_candev(dev);
    	if (err) {
    		netdev_err(dev, "failed to open can device\n");
    		goto exit_disable_clks;
    	}
    	/* register interrupt handler */
    	if (cdev->is_peripheral) {
    		cdev->tx_skb = NULL;
    		cdev->tx_wq = alloc_workqueue("mcan_wq",
    				WQ_FREEZABLE | WQ_MEM_RECLAIM, 0);
    		if (!cdev->tx_wq) {
    			err = -ENOMEM;
    			goto out_wq_fail;
    		}
    
    		INIT_WORK(&cdev->tx_work, m_can_tx_work_queue);
    
    		err = request_threaded_irq(dev->irq, NULL, m_can_isr,
    				IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
    				dev->name, dev);
    	} else {
    		err = request_irq(dev->irq, m_can_isr, IRQF_SHARED, dev->name,
    				dev);
    	}
    
    	if (err < 0) {
    		netdev_err(dev, "failed to request interrupt\n");
    		goto exit_irq_fail;
    	}
    
    	/* start the m_can controller */
    	m_can_start(dev);
    
    	can_led_event(dev, CAN_LED_EVENT_OPEN);
    
    	if (!cdev->is_peripheral)
    		napi_enable(&cdev->napi);
    
    	netif_start_queue(dev);
    
    	return 0;
    
    exit_irq_fail:
    	if (cdev->is_peripheral)
    		destroy_workqueue(cdev->tx_wq);
    out_wq_fail:
    	close_candev(dev);
    exit_disable_clks:
    	m_can_clk_stop(cdev);
    	return err;
    }
    
    static const struct net_device_ops m_can_netdev_ops = {
    	.ndo_open = m_can_open,
    	.ndo_stop = m_can_close,
    	.ndo_start_xmit = m_can_start_xmit,
    	.ndo_change_mtu = can_change_mtu,
    };
    
    static int register_m_can_dev(struct net_device *dev)
    {
    	//dev->flags |= IFF_ECHO;	/* we support local echo 
    	dev->netdev_ops = &m_can_netdev_ops;
    
    	return register_candev(dev);
    }
    
    static void m_can_of_parse_mram(struct m_can_classdev *cdev,
    		const u32 *mram_config_vals)
    {
    	cdev->mcfg[MRAM_SIDF].off = mram_config_vals[0];
    	cdev->mcfg[MRAM_SIDF].num = mram_config_vals[1];
    	cdev->mcfg[MRAM_XIDF].off = cdev->mcfg[MRAM_SIDF].off +
    		cdev->mcfg[MRAM_SIDF].num * SIDF_ELEMENT_SIZE;
    	cdev->mcfg[MRAM_XIDF].num = mram_config_vals[2];
    	cdev->mcfg[MRAM_RXF0].off = cdev->mcfg[MRAM_XIDF].off +
    		cdev->mcfg[MRAM_XIDF].num * XIDF_ELEMENT_SIZE;
    	cdev->mcfg[MRAM_RXF0].num = mram_config_vals[3] &
    		(RXFC_FS_MASK >> RXFC_FS_SHIFT);
    	cdev->mcfg[MRAM_RXF1].off = cdev->mcfg[MRAM_RXF0].off +
    		cdev->mcfg[MRAM_RXF0].num * RXF0_ELEMENT_SIZE;
    	cdev->mcfg[MRAM_RXF1].num = mram_config_vals[4] &
    		(RXFC_FS_MASK >> RXFC_FS_SHIFT);
    	cdev->mcfg[MRAM_RXB].off = cdev->mcfg[MRAM_RXF1].off +
    		cdev->mcfg[MRAM_RXF1].num * RXF1_ELEMENT_SIZE;
    	cdev->mcfg[MRAM_RXB].num = mram_config_vals[5];
    	cdev->mcfg[MRAM_TXE].off = cdev->mcfg[MRAM_RXB].off +
    		cdev->mcfg[MRAM_RXB].num * RXB_ELEMENT_SIZE;
    	cdev->mcfg[MRAM_TXE].num = mram_config_vals[6];
    	cdev->mcfg[MRAM_TXB].off = cdev->mcfg[MRAM_TXE].off +
    		cdev->mcfg[MRAM_TXE].num * TXE_ELEMENT_SIZE;
    	cdev->mcfg[MRAM_TXB].num = mram_config_vals[7] &
    		(TXBC_NDTB_MASK >> TXBC_NDTB_SHIFT);
    
    	dev_dbg(cdev->dev,
    			"sidf 0x%x %d xidf 0x%x %d rxf0 0x%x %d rxf1 0x%x %d rxb 0x%x %d txe 0x%x %d txb 0x%x %d\n",
    			cdev->mcfg[MRAM_SIDF].off, cdev->mcfg[MRAM_SIDF].num,
    			cdev->mcfg[MRAM_XIDF].off, cdev->mcfg[MRAM_XIDF].num,
    			cdev->mcfg[MRAM_RXF0].off, cdev->mcfg[MRAM_RXF0].num,
    			cdev->mcfg[MRAM_RXF1].off, cdev->mcfg[MRAM_RXF1].num,
    			cdev->mcfg[MRAM_RXB].off, cdev->mcfg[MRAM_RXB].num,
    			cdev->mcfg[MRAM_TXE].off, cdev->mcfg[MRAM_TXE].num,
    			cdev->mcfg[MRAM_TXB].off, cdev->mcfg[MRAM_TXB].num);
    }
    
    void m_can_init_ram(struct m_can_classdev *cdev)
    {
    	int end, i, start;
    	/* initialize the entire Message RAM in use to avoid possible
    	 * ECC/parity checksum errors when reading an uninitialized buffer
    	 */
    	if(mode==false)
    	{
    		m_can_config_endisable(cdev, true);
    	}
    	if(mode==true)
    	{
    		mode=false;
    	}
    	start = cdev->mcfg[MRAM_SIDF].off;
    	end = cdev->mcfg[MRAM_TXB].off +
    		cdev->mcfg[MRAM_TXB].num * TXB_ELEMENT_SIZE;
    
    	for (i = start; i < end; i += 4)
    		m_can_fifo_write_no_off(cdev, i, 0x0);	
    }
    EXPORT_SYMBOL_GPL(m_can_init_ram);
    
    int m_can_class_get_clocks(struct m_can_classdev *m_can_dev)
    {
    	int ret = 0;
    
    	m_can_dev->hclk = devm_clk_get(m_can_dev->dev, "hclk");
    	m_can_dev->cclk = devm_clk_get(m_can_dev->dev, "cclk");
    
    	if (IS_ERR(m_can_dev->cclk)) {
    		dev_err(m_can_dev->dev, "no clock found\n");
    		ret = -ENODEV;
    	}
    
    	return ret;
    }
    EXPORT_SYMBOL_GPL(m_can_class_get_clocks);
    
    struct m_can_classdev *m_can_class_allocate_dev(struct device *dev)
    {
    	struct m_can_classdev *class_dev = NULL;
    	u32 mram_config_vals[MRAM_CFG_LEN];
    	struct net_device *net_dev;
    	u32 tx_fifo_size;
    	int ret;
    
    	ret = fwnode_property_read_u32_array(dev_fwnode(dev),
    			"bosch,mram-cfg",
    			mram_config_vals,
    			sizeof(mram_config_vals) / 4);
    	if (ret) {
    		dev_err(dev, "Could not get Message RAM configuration.");
    		goto out;
    	}
    
    	/* Get TX FIFO size
    	 * Defines the total amount of echo buffers for loopback
    	 */
    	tx_fifo_size = mram_config_vals[7];
    
    	/* allocate the m_can device */
    	net_dev = alloc_candev(sizeof(*class_dev), tx_fifo_size);
    	if (!net_dev) {
    		dev_err(dev, "Failed to allocate CAN device");
    		goto out;
    	}
    
    	class_dev = netdev_priv(net_dev);
    	if (!class_dev) {
    		dev_err(dev, "Failed to init netdev cdevate");
    		goto out;
    	}
    
    	class_dev->net = net_dev;
    	class_dev->dev = dev;
    	SET_NETDEV_DEV(net_dev, dev);
    
    	m_can_of_parse_mram(class_dev, mram_config_vals);
    out:
    	return class_dev;
    }
    EXPORT_SYMBOL_GPL(m_can_class_allocate_dev);
    
    int m_can_class_register(struct m_can_classdev *m_can_dev)
    {
    	int ret;
    
    	if (m_can_dev->pm_clock_support) {
    		pm_runtime_enable(m_can_dev->dev);
    		ret = m_can_clk_start(m_can_dev);
    		if (ret)
    			goto pm_runtime_fail;
    	}
    
    	ret = m_can_dev_setup(m_can_dev);
    	if (ret)
    		goto clk_disable;
    
    	ret = register_m_can_dev(m_can_dev->net);
    	if (ret) {
    		dev_err(m_can_dev->dev, "registering %s failed (err=%d)\n",
    				m_can_dev->net->name, ret);
    		goto clk_disable;
    	}
    
    	devm_can_led_init(m_can_dev->net);
    
    	of_can_transceiver(m_can_dev->net);
    
    	dev_info(m_can_dev->dev, "%s device registered (irq=%d, version=%d)\n",
    			KBUILD_MODNAME, m_can_dev->net->irq, m_can_dev->version);
    
    	/* Probe finished
    	 * Stop clocks. They will be reactivated once the M_CAN device is opened
    	 */
    clk_disable:
    	m_can_clk_stop(m_can_dev);
    pm_runtime_fail:
    	if (ret) {
    		if (m_can_dev->pm_clock_support)
    			pm_runtime_disable(m_can_dev->dev);
    		free_candev(m_can_dev->net);
    	}
    
    	return ret;
    }
    EXPORT_SYMBOL_GPL(m_can_class_register);
    
    int m_can_class_suspend(struct device *dev)
    {
    	struct net_device *ndev = dev_get_drvdata(dev);
    	struct m_can_classdev *cdev = netdev_priv(ndev);
    
    	if (netif_running(ndev)) {
    		netif_stop_queue(ndev);
    		netif_device_detach(ndev);
    		m_can_stop(ndev);
    		m_can_clk_stop(cdev);
    	}
    
    	pinctrl_pm_select_sleep_state(dev);
    
    	cdev->can.state = CAN_STATE_SLEEPING;
    
    	return 0;
    }
    EXPORT_SYMBOL_GPL(m_can_class_suspend);
    
    int m_can_class_resume(struct device *dev)
    {
    	struct net_device *ndev = dev_get_drvdata(dev);
    	struct m_can_classdev *cdev = netdev_priv(ndev);
    
    	pinctrl_pm_select_default_state(dev);
    
    	cdev->can.state = CAN_STATE_ERROR_ACTIVE;
    
    	if (netif_running(ndev)) {
    		int ret;
    
    		ret = m_can_clk_start(cdev);
    		if (ret)
    			return ret;
    
    		m_can_init_ram(cdev);
    		m_can_start(ndev);
    		netif_device_attach(ndev);
    		netif_start_queue(ndev);
    	}
    
    	return 0;
    }
    EXPORT_SYMBOL_GPL(m_can_class_resume);
    
    void m_can_class_unregister(struct m_can_classdev *m_can_dev)
    {
    	unregister_candev(m_can_dev->net);
    
    	m_can_clk_stop(m_can_dev);
    
    	free_candev(m_can_dev->net);
    }
    EXPORT_SYMBOL_GPL(m_can_class_unregister);
    
    void m_can_disable_rx_irq(struct m_can_classdev *m_can_dev)
    {
            iw_ie_reg = m_can_read(m_can_dev, M_CAN_IE);
            m_can_write(m_can_dev, M_CAN_IE, iw_ie_reg & 0xFFFFFE00);
    }
    EXPORT_SYMBOL_GPL(m_can_disable_rx_irq);
    
    void m_can_enable_rx_irq(struct m_can_classdev *m_can_dev)
    {
            m_can_write(m_can_dev, M_CAN_IE, iw_ie_reg);
    }
    EXPORT_SYMBOL_GPL(m_can_enable_rx_irq);
    
    MODULE_AUTHOR("Dong Aisheng <b29396@freescale.com>");
    MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
    MODULE_LICENSE("GPL v2");
    MODULE_DESCRIPTION("CAN bus driver for Bosch M_CAN controller");
    

  • Hello Tanushree,

    If the TCAN4550 is working with your code on the IMX6 processor, then it is likely not a TCAN4550 register configuration issue and instead related to some difference between the IMX6 and the IMX8DXL processors.  I don't have experience with either of these so I don't know how to help you with a processor issue.

    If there are any interrupt or status bits being set in the TCAN4550 registers that you can monitor during your issues, I could try to offer some insight at a functional level.  But I can only support you by working with the register values in the device to verify the configuration is correct and what any interrupt and status bits are indicating.

    Because I'm not a Linux expert, and I'm not familiar with either of these two processors, I won't be able to tell you why the code works on one processor and not the other.

    Regards,

    Jonathan