drivers: can: mcan: add transceiver support
Add support for CAN transceivers to the Bosch M_CAN CAN drivers. Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
This commit is contained in:
parent
000661db21
commit
d8e88b61eb
6 changed files with 118 additions and 10 deletions
|
@ -8,6 +8,7 @@
|
|||
#include <string.h>
|
||||
#include <kernel.h>
|
||||
#include <drivers/can.h>
|
||||
#include <drivers/can/transceiver.h>
|
||||
#include "can_mcan.h"
|
||||
#include "can_mcan_int.h"
|
||||
#include <logging/log.h>
|
||||
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <device.h>
|
||||
#include <drivers/can.h>
|
||||
#include <drivers/can/transceiver.h>
|
||||
#include <drivers/clock_control.h>
|
||||
#include <logging/log.h>
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "can_mcan.h"
|
||||
|
||||
#include <drivers/can.h>
|
||||
#include <drivers/can/transceiver.h>
|
||||
#include <soc.h>
|
||||
#include <kernel.h>
|
||||
#include <logging/log.h>
|
||||
|
@ -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 */
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <drivers/can.h>
|
||||
#include <drivers/can/transceiver.h>
|
||||
#include <drivers/pinctrl.h>
|
||||
#include <kernel.h>
|
||||
#include <soc.h>
|
||||
|
@ -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), \
|
||||
};
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <drivers/can.h>
|
||||
#include <drivers/can/transceiver.h>
|
||||
#include <drivers/clock_control/stm32_clock_control.h>
|
||||
#include <drivers/clock_control.h>
|
||||
#include <drivers/pinctrl.h>
|
||||
|
@ -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 */
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue