drivers: can: mcan: enable transmitter delay compensation when possible
Enable Transmitter Delay Compensation whenever the data phase timing
parameters allow it.
Fixes: #70447
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
(cherry picked from commit bfad7bc00e734010d059d5ba7eb4cd2187eb1c8d)
diff --git a/drivers/can/can_mcan.c b/drivers/can/can_mcan.c
index a0ae16e..f1df659 100644
--- a/drivers/can/can_mcan.c
+++ b/drivers/can/can_mcan.c
@@ -225,8 +225,10 @@
#ifdef CONFIG_CAN_FD_MODE
int can_mcan_set_timing_data(const struct device *dev, const struct can_timing *timing_data)
{
+ const uint8_t tdco_max = FIELD_GET(CAN_MCAN_TDCR_TDCO, CAN_MCAN_TDCR_TDCO);
struct can_mcan_data *data = dev->data;
uint32_t dbtp = 0U;
+ uint8_t tdco;
int err;
if (data->started) {
@@ -240,6 +242,23 @@
FIELD_PREP(CAN_MCAN_DBTP_DTSEG2, timing_data->phase_seg2 - 1UL) |
FIELD_PREP(CAN_MCAN_DBTP_DBRP, timing_data->prescaler - 1UL);
+ if (timing_data->prescaler == 1U || timing_data->prescaler == 2U) {
+ /* TDC can only be enabled if DBRP = { 0, 1 } */
+ dbtp |= CAN_MCAN_DBTP_TDC;
+
+ /* Set TDC offset for correct location of the Secondary Sample Point (SSP) */
+ tdco = CAN_CALC_TDCO(timing_data, 0U, tdco_max);
+ LOG_DBG("TDC enabled, using TDCO %u", tdco);
+
+ err = can_mcan_write_reg(dev, CAN_MCAN_TDCR, FIELD_PREP(CAN_MCAN_TDCR_TDCO, tdco));
+ if (err != 0) {
+ goto unlock;
+ }
+ } else {
+ LOG_DBG("TDC cannot be enabled, prescaler value %u too high",
+ timing_data->prescaler);
+ }
+
err = can_mcan_write_reg(dev, CAN_MCAN_DBTP, dbtp);
if (err != 0) {
goto unlock;