From f2a039e8bbb4c7d52ddb23f90c52e3ccd2cb3eed Mon Sep 17 00:00:00 2001 From: Aymeric Aillet Date: Mon, 13 Jun 2022 18:02:47 +0200 Subject: [PATCH] drivers/can/rcar: Fix setting bit timing Fix issue #45169. With this CAN controller, changing bit timing has to be done in controller reset mode, resetting some registers to their default values. TCR register, that is enabling loopback mode is one of these. Because of this reset, the controller switch back from loopback to normal mode without the test suite being notified, preventing receiving sent frames afterwards. To fix this issue, we are now storing useful registers values before switching to reset mode and restoring these values in halt mode before going back in operation mode. Signed-off-by: Aymeric Aillet --- drivers/can/can_rcar.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/drivers/can/can_rcar.c b/drivers/can/can_rcar.c index ddac1fc27af..34822cca3d7 100644 --- a/drivers/can/can_rcar.c +++ b/drivers/can/can_rcar.c @@ -658,16 +658,45 @@ static int can_rcar_set_timing(const struct device *dev, struct can_rcar_data *data = dev->data; int ret = 0; + struct reg_backup { + uint32_t address; + uint8_t value; + }; + + struct reg_backup regs[3] = { { RCAR_CAN_TCR, 0 }, { RCAR_CAN_TFCR, 0 } + , { RCAR_CAN_RFCR, 0 } }; + k_mutex_lock(&data->inst_mutex, K_FOREVER); - /* Changing bittiming should be done in reset mode */ + /* Changing bittiming should be done in reset mode. + * Switching to reset mode is resetting loopback mode (TCR), + * transmit and receive FIFOs (TFCR and RFCR). + * Storing these reg values to restore them once back in halt mode. + */ + for (int i = 0; i < 3; i++) { + regs[i].value = sys_read8(config->reg_addr + regs[i].address); + } + + /* Switching to reset mode */ ret = can_rcar_enter_reset_mode(config, true); if (ret != 0) { goto unlock; } + /* Setting bit timing */ can_rcar_set_bittiming(config, timing); + /* Restoring registers must be done in halt mode */ + ret = can_rcar_enter_halt_mode(config); + if (ret) { + goto unlock; + } + + /* Restoring registers */ + for (int i = 0; i < 3; i++) { + sys_write8(regs[i].value, config->reg_addr + regs[i].address); + } + /* Go back to operation mode */ ret = can_rcar_enter_operation_mode(config);