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: Dynamic Bitrate / Mode Switching Issue with TCAN (m_can driver)

Part Number: TCAN4550

We encountered an issue with the TCAN device during dynamic switching of CAN modes and bitrates.

Initially, the CAN interface is configured in High-Speed (HS) mode with a bitrate of 500 kbps. After deinitializing the interface, we reconfigure it to CAN-FD mode with a nominal bitrate of 1 Mbps and a data bitrate of 3 Mbps. However, in this scenario:

    *CAN-FD data (64 bytes) transmission does not work.
    *Classic CAN communication at 1 Mbps also fails
    *Classic CAN communication at 500 kbps is working, even though the interface is reinitialized with the updated configuration.

Upon investigation, we observed that dynamic switching is not functioning correctly with the tcan4x5x driver. Reviewing the driver and register behavior revealed that the initialization bits (INIT and CCE) in the MCAN_CCCR register are set only once during driver load. Since these bits are not re-enabled during runtime reconfiguration, dynamic switching of modes and bitrates is not supported by default.

To address this issue, we modified the m_can.c driver as shown below:

diff -aruN A/drivers/net/can/m_can/m_can.c B/drivers/net/can/m_can/m_can.c
--- A/drivers/net/can/m_can/m_can.c    2026-03-17 11:17:38.166965563 +0530
+++ B/drivers/net/can/m_can/m_can.c    2026-04-01 18:20:24.215708731 +0530
@@ -1253,6 +1253,7 @@
         cccr &= ~(CCCR_TEST | CCCR_MON | CCCR_BRSE | CCCR_FDOE |
                 CCCR_NISO);
 
+        cccr = (CCCR_INIT | CCCR_CCE ) ;
         /* Only 3.2.x has NISO Bit implemented */
         if (cdev->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO)
             cccr |= CCCR_NISO;
@@ -1265,6 +1266,8 @@
     if (cdev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
         cccr |= CCCR_MON;
 
+    m_can_write(cdev, M_CAN_CCCR, CCCR_INIT);
+    m_can_write(cdev, M_CAN_CCCR, (CCCR_INIT | CCCR_CCE ) );
     /* Write config */
     m_can_write(cdev, M_CAN_CCCR, cccr);
     m_can_write(cdev, M_CAN_TEST, test);


With these changes, dynamic switching between CAN modes and bitrates is now working as expected.

We would appreciate your review of this modification and confirmation that it will not introduce any unintended side effects.

Additionally, we would like to understand why this functionality is not enabled by default in the driver. Is there a specific design constraint or hardware limitation that prevents dynamic reconfiguration without explicitly re-entering INIT/CCE mode?

  • Hi Akash,

    I have assigned this question to our TCAN4550 expert. He is out of office today, but he should get you a response soon. 

    Best,

    Ethan

  • Hello Akash,

    All devices on a CAN bus must be configured with the same data rate settings to avoid communication errors.  Therefore dynamic switching of bit rates for a single node would result in communication errors if all of the other nodes did not switch to the new bit rates at the same time.  I assume this is why the driver only initializes the bit rates during the first initialization because dynamically switching bit rates is not common because the bit rate configuration is usually per-determined.

    If you want to change the bit rate configuration, then you will have to set both the CCCR_INIT and CCCR_CCE bits to "1" prior to changing any of the MCAN configuration bits including the Nominal and Data bit rate configuration registers.  Once this is done you will need to set the CCCR_INIT (and optionally the CCCR_CCE) bits back to "0" to take the MCAN controller out of the protected state and re-initialize it for CAN bus communication.

    I will note that primarily this is a device level support forum and not an Linux support forum.  My expertise is with the TCAN4550 device and I am happy to help with any device level questions relating to the configuration or use of the device features.  The Linux driver has been up-streamed into the Linux Kernel and is not something I directly support.

    Regards,

    Jonathan