Skip to content

Commit

Permalink
drivers/can/rcar: Fix setting bit timing
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
aaillet authored and fabiobaltieri committed Jul 1, 2022
1 parent 1c3c799 commit f2a039e
Showing 1 changed file with 30 additions and 1 deletion.
31 changes: 30 additions & 1 deletion drivers/can/can_rcar.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit f2a039e

Please sign in to comment.