diff --git a/drivers/can/can_mcan.c b/drivers/can/can_mcan.c index 60c7cdf1ebd..99385274497 100644 --- a/drivers/can/can_mcan.c +++ b/drivers/can/can_mcan.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "can_mcan.h" #include "can_mcan_int.h" #include @@ -212,9 +213,23 @@ int can_mcan_set_mode(const struct can_mcan_config *cfg, enum can_mode mode) struct can_mcan_reg *can = cfg->can; int ret; + if (cfg->phy != NULL) { + ret = can_transceiver_enable(cfg->phy); + if (ret != 0) { + LOG_ERR("failed to enable CAN transceiver (err %d)", ret); + return ret; + } + } + ret = can_enter_init_mode(can, K_MSEC(CAN_INIT_TIMEOUT)); if (ret) { LOG_ERR("Failed to enter init mode"); + + if (cfg->phy != NULL) { + /* Attempt to disable the CAN transceiver in case of error */ + (void)can_transceiver_disable(cfg->phy); + } + return -EIO; } @@ -252,6 +267,11 @@ int can_mcan_set_mode(const struct can_mcan_config *cfg, enum can_mode mode) ret = can_leave_init_mode(can, K_MSEC(CAN_INIT_TIMEOUT)); if (ret) { LOG_ERR("Failed to leave init mode"); + + if (cfg->phy != NULL) { + /* Attempt to disable the CAN transceiver in case of error */ + (void)can_transceiver_disable(cfg->phy); + } } return 0; @@ -275,16 +295,31 @@ int can_mcan_init(const struct device *dev, const struct can_mcan_config *cfg, k_sem_init(&data->tx_fin_sem[i], 0, 1); } + if (cfg->phy != NULL) { + if (!device_is_ready(cfg->phy)) { + LOG_ERR("CAN transceiver not ready"); + return -ENODEV; + } + + ret = can_transceiver_enable(cfg->phy); + if (ret != 0) { + LOG_ERR("failed to enable CAN transceiver (err %d)", ret); + return -EIO; + } + } + ret = can_exit_sleep_mode(can); if (ret) { LOG_ERR("Failed to exit sleep mode"); - return -EIO; + ret = -EIO; + goto done; } ret = can_enter_init_mode(can, K_MSEC(CAN_INIT_TIMEOUT)); if (ret) { LOG_ERR("Failed to enter init mode"); - return -EIO; + ret = -EIO; + goto done; } /* Configuration Change Enable */ @@ -376,7 +411,8 @@ int can_mcan_init(const struct device *dev, const struct can_mcan_config *cfg, cfg->sample_point); if (ret == -EINVAL) { LOG_ERR("Can't find timing for given param"); - return -EIO; + ret = -EIO; + goto done; } LOG_DBG("Presc: %d, TS1: %d, TS2: %d", timing.prescaler, timing.phase_seg1, timing.phase_seg2); @@ -397,7 +433,8 @@ int can_mcan_init(const struct device *dev, const struct can_mcan_config *cfg, cfg->sample_point_data); if (ret == -EINVAL) { LOG_ERR("Can't find timing for given dataphase param"); - return -EIO; + ret = -EIO; + goto done; } LOG_DBG("Sample-point err data phase: %d", ret); @@ -441,10 +478,17 @@ int can_mcan_init(const struct device *dev, const struct can_mcan_config *cfg, ret = can_leave_init_mode(can, K_MSEC(CAN_INIT_TIMEOUT)); if (ret) { LOG_ERR("Failed to leave init mode"); - return -EIO; + ret = -EIO; + goto done; } - return 0; +done: + if (ret != 0 && cfg->phy != NULL) { + /* Attempt to disable the CAN transceiver in case of error */ + (void)can_transceiver_disable(cfg->phy); + } + + return ret; } static void can_mcan_state_change_handler(const struct can_mcan_config *cfg, diff --git a/drivers/can/can_mcan.h b/drivers/can/can_mcan.h index 35d3afaece6..c06ced48f93 100644 --- a/drivers/can/can_mcan.h +++ b/drivers/can/can_mcan.h @@ -200,6 +200,8 @@ struct can_mcan_config { uint8_t ts2_data; uint8_t tx_delay_comp_offset; #endif + const struct device *phy; + uint32_t max_bitrate; }; struct can_mcan_reg; diff --git a/drivers/can/can_mcux_mcan.c b/drivers/can/can_mcux_mcan.c index be67b441273..57ffadfd86b 100644 --- a/drivers/can/can_mcux_mcan.c +++ b/drivers/can/can_mcux_mcan.c @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -98,6 +99,15 @@ static int mcux_mcan_get_core_clock(const struct device *dev, uint32_t *rate) rate); } +int mcux_mcan_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) +{ + const struct mcux_mcan_config *config = dev->config; + + *max_bitrate = config->mcan.max_bitrate; + + return 0; +} + static void mcux_mcan_line_0_isr(const struct device *dev) { const struct mcux_mcan_config *config = dev->config; @@ -149,6 +159,7 @@ static const struct can_driver_api mcux_mcan_driver_api = { .get_state = mcux_mcan_get_state, .set_state_change_callback = mcux_mcan_set_state_change_callback, .get_core_clock = mcux_mcan_get_core_clock, + .get_max_bitrate = mcux_mcan_get_max_bitrate, /* * MCUX MCAN timing limits are specified in the "Nominal bit timing and * prescaler register (NBTP)" table in the SoC reference manual. @@ -215,7 +226,9 @@ static const struct can_driver_api mcux_mcan_driver_api = { DT_INST_PROP_OR(n, phase_seg1_data, 0), \ .ts2_data = DT_INST_PROP_OR(n, phase_seg2_data, 0), \ .tx_delay_comp_offset = \ - DT_INST_PROP(n, tx_delay_comp_offset) \ + DT_INST_PROP(n, tx_delay_comp_offset), \ + .phy = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(n, phys)), \ + .max_bitrate = DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(n, 5000000), \ } #else /* CONFIG_CAN_FD_MODE */ #define MCUX_MCAN_MCAN_INIT(n) \ @@ -227,6 +240,8 @@ static const struct can_driver_api mcux_mcan_driver_api = { .prop_ts1 = DT_INST_PROP_OR(n, prop_seg, 0) + \ DT_INST_PROP_OR(n, phase_seg1, 0), \ .ts2 = DT_INST_PROP_OR(n, phase_seg2, 0), \ + .phy = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(n, phys)), \ + .max_bitrate = DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(n, 1000000), \ } #endif /* !CONFIG_CAN_FD_MODE */ diff --git a/drivers/can/can_sam.c b/drivers/can/can_sam.c index 2b9331a52e4..8e744190390 100644 --- a/drivers/can/can_sam.c +++ b/drivers/can/can_sam.c @@ -7,6 +7,7 @@ #include "can_mcan.h" #include +#include #include #include #include @@ -129,6 +130,15 @@ static int can_sam_set_timing(const struct device *dev, const struct can_timing return can_mcan_set_timing(mcan_cfg, timing, timing_data); } +int can_sam_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) +{ + const struct can_sam_config *cfg = dev->config; + + *max_bitrate = cfg->mcan_cfg.max_bitrate; + + return 0; +} + static void can_sam_line_0_isr(const struct device *dev) { const struct can_sam_config *cfg = dev->config; @@ -162,6 +172,7 @@ static const struct can_driver_api can_api_funcs = { .recover = can_mcan_recover, #endif .get_core_clock = can_sam_get_core_clock, + .get_max_bitrate = can_sam_get_max_bitrate, .set_state_change_callback = can_sam_set_state_change_callback, .timing_min = { .sjw = 0x1, @@ -223,7 +234,9 @@ static void config_can_##inst##_irq(void) .prop_ts1_data = DT_INST_PROP_OR(inst, prop_seg_data, 0) + \ DT_INST_PROP_OR(inst, phase_seg1_data, 0), \ .ts2_data = DT_INST_PROP_OR(inst, phase_seg2_data, 0), \ - .tx_delay_comp_offset = DT_INST_PROP(inst, tx_delay_comp_offset) \ + .tx_delay_comp_offset = DT_INST_PROP(inst, tx_delay_comp_offset), \ + .phy = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(inst, phys)), \ + .max_bitrate = DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(inst, 5000000), \ } #else /* CONFIG_CAN_FD_MODE */ #define CAN_SAM_MCAN_CFG(inst) \ @@ -233,6 +246,8 @@ static void config_can_##inst##_irq(void) .sample_point = DT_INST_PROP_OR(inst, sample_point, 0), \ .prop_ts1 = DT_INST_PROP_OR(inst, prop_seg, 0) + DT_INST_PROP_OR(inst, phase_seg1, 0), \ .ts2 = DT_INST_PROP_OR(inst, phase_seg2, 0), \ + .phy = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(inst, phys)), \ + .max_bitrate = DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(inst, 1000000), \ } #endif /* CONFIG_CAN_FD_MODE */ diff --git a/drivers/can/can_stm32fd.c b/drivers/can/can_stm32fd.c index 0677b967162..35231571f66 100644 --- a/drivers/can/can_stm32fd.c +++ b/drivers/can/can_stm32fd.c @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -153,6 +154,15 @@ static int can_stm32fd_set_timing(const struct device *dev, return can_mcan_set_timing(mcan_cfg, timing, timing_data); } +int can_stm32fd_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) +{ + const struct can_stm32fd_config *cfg = dev->config; + + *max_bitrate = cfg->mcan.max_bitrate; + + return 0; +} + static void can_stm32fd_line_0_isr(void *arg) { struct device *dev = (struct device *)arg; @@ -188,6 +198,7 @@ static const struct can_driver_api can_api_funcs = { .recover = can_mcan_recover, #endif .get_core_clock = can_stm32fd_get_core_clock, + .get_max_bitrate = can_stm32fd_get_max_bitrate, .get_max_filters = can_stm32fd_get_max_filters, .set_state_change_callback = can_stm32fd_set_state_change_callback, .timing_min = { @@ -263,7 +274,10 @@ static const struct can_stm32fd_config can_stm32fd_cfg_##inst = { \ DT_INST_PROP_OR(inst, phase_seg1_data, 0), \ .ts2_data = DT_INST_PROP_OR(inst, phase_seg2_data, 0), \ .tx_delay_comp_offset = \ - DT_INST_PROP(inst, tx_delay_comp_offset) \ + DT_INST_PROP(inst, tx_delay_comp_offset), \ + .phy = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(inst, phys)), \ + .max_bitrate = \ + DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(inst, 5000000), \ }, \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ }; @@ -287,6 +301,9 @@ static const struct can_stm32fd_config can_stm32fd_cfg_##inst = { \ .prop_ts1 = DT_INST_PROP_OR(inst, prop_seg, 0) + \ DT_INST_PROP_OR(inst, phase_seg1, 0), \ .ts2 = DT_INST_PROP_OR(inst, phase_seg2, 0), \ + .phy = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(inst, phys)), \ + .max_bitrate = \ + DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(inst, 1000000), \ }, \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ }; diff --git a/drivers/can/can_stm32h7.c b/drivers/can/can_stm32h7.c index ee3fb71bbf6..cd9a47395ab 100644 --- a/drivers/can/can_stm32h7.c +++ b/drivers/can/can_stm32h7.c @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -178,6 +179,15 @@ static int can_stm32h7_set_timing(const struct device *dev, return can_mcan_set_timing(&cfg->mcan_cfg, timing, timing_data); } +int mcux_stm32h7_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate) +{ + const struct mcux_stm32h7_config *cfg = dev->config; + + *max_bitrate = cfg->mcan.max_bitrate; + + return 0; +} + static void can_stm32h7_line_0_isr(const struct device *dev) { const struct can_stm32h7_config *cfg = dev->config; @@ -205,6 +215,7 @@ static const struct can_driver_api can_api_funcs = { .recover = can_mcan_recover, #endif .get_core_clock = can_stm32h7_get_core_clock, + .get_max_bitrate = can_stm32h7_get_max_bitrate, .get_max_filters = can_stm32h7_get_max_filters, .set_state_change_callback = can_stm32h7_set_state_change_cb, /* Timing limits are per the STM32H7 Reference Manual (RM0433 Rev 7), @@ -265,7 +276,9 @@ static const struct can_driver_api can_api_funcs = { DT_INST_PROP_OR(n, phase_seg1_data, 0), \ .ts2_data = DT_INST_PROP_OR(n, phase_seg2_data, 0), \ .tx_delay_comp_offset = \ - DT_INST_PROP(n, tx_delay_comp_offset) \ + DT_INST_PROP(n, tx_delay_comp_offset), \ + .phy = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(n, phys)), \ + .max_bitrate = DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(n, 5000000), \ } #else /* CONFIG_CAN_FD_MODE */ #define CAN_STM32H7_MCAN_MCAN_INIT(n) \ @@ -277,6 +290,8 @@ static const struct can_driver_api can_api_funcs = { .prop_ts1 = DT_INST_PROP_OR(n, prop_seg, 0) + \ DT_INST_PROP_OR(n, phase_seg1, 0), \ .ts2 = DT_INST_PROP_OR(n, phase_seg2, 0), \ + .phy = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(n, phys)), \ + .max_bitrate = DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(n, 1000000), \ } #endif /* !CONFIG_CAN_FD_MODE */