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 <aymeric.aillet@iot.bzh>
This commit is contained in:
parent
1c3c79979e
commit
f2a039e8bb
1 changed files with 30 additions and 1 deletions
|
@ -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);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue