|
5 | 5 | */ |
6 | 6 |
|
7 | 7 | #include <drivers/can.h> |
| 8 | +#include <kernel.h> |
| 9 | +#include <soc.h> |
| 10 | +#include <stm32_ll_rcc.h> |
| 11 | +#include "can_stm32fd.h" |
| 12 | +#include <pinmux/stm32/pinmux_stm32.h> |
8 | 13 |
|
9 | | -u32_t can_mcan_get_core_clock(struct device *dev) |
10 | | -{ |
11 | | - u32_t core_clock = LL_RCC_GetFDCANClockFreq(LL_RCC_FDCAN_CLKSOURCE); |
12 | | - u32_t dbrp, nbrp; |
| 14 | +#include <logging/log.h> |
| 15 | +LOG_MODULE_DECLARE(can_driver, CONFIG_CAN_LOG_LEVEL); |
13 | 16 |
|
14 | | -#if CONFIG_CAN_CKDIV != 0 |
15 | | - core_clock /= CONFIG_CAN_CKDIV * 2; |
| 17 | +#if CONFIG_CAN_STM32_CLOCK_DIVISOR != 1 && CONFIG_CAN_STM32_CLOCK_DIVISOR & 0x01 |
| 18 | +#error CAN_STM32_CLOCK_DIVISOR invalid.\ |
| 19 | +Allowed values are 1 or 2 * n, where n <= 15 |
16 | 20 | #endif |
17 | 21 |
|
18 | | -__weak void can_mcan_clock_enable() |
| 22 | +#define DT_DRV_COMPAT st_stm32_fdcan |
| 23 | + |
| 24 | +int can_stm32fd_get_core_clock(const struct device *dev, uint32_t *rate) |
| 25 | +{ |
| 26 | + ARG_UNUSED(dev); |
| 27 | + int rate_tmp; |
| 28 | + |
| 29 | + rate_tmp = LL_RCC_GetFDCANClockFreq(LL_RCC_FDCAN_CLKSOURCE); |
| 30 | + |
| 31 | + if (rate_tmp == LL_RCC_PERIPH_FREQUENCY_NO) { |
| 32 | + LOG_ERR("Can't read core clock"); |
| 33 | + return -EIO; |
| 34 | + } |
| 35 | + |
| 36 | + *rate = rate_tmp / CONFIG_CAN_STM32_CLOCK_DIVISOR; |
| 37 | + |
| 38 | + return 0; |
| 39 | +} |
| 40 | + |
| 41 | +void can_stm32fd_clock_enable(void) |
19 | 42 | { |
20 | 43 | LL_RCC_SetFDCANClockSource(LL_RCC_FDCAN_CLKSOURCE_PCLK1); |
21 | 44 | __HAL_RCC_FDCAN_CLK_ENABLE(); |
22 | 45 |
|
23 | | - FDCAN_CONFIG->CKDIV = CONFIG_CAN_CKDIV; |
| 46 | + FDCAN_CONFIG->CKDIV = CONFIG_CAN_STM32_CLOCK_DIVISOR >> 1; |
| 47 | +} |
| 48 | + |
| 49 | +void can_stm32fd_register_state_change_isr(const struct device *dev, |
| 50 | + can_state_change_isr_t isr) |
| 51 | +{ |
| 52 | + struct can_stm32fd_data *data = DEV_DATA(dev); |
| 53 | + |
| 54 | + data->mcan_data.state_change_isr = isr; |
| 55 | +} |
| 56 | + |
| 57 | +static int can_stm32fd_init(const struct device *dev) |
| 58 | +{ |
| 59 | + const struct can_stm32fd_config *cfg = DEV_CFG(dev); |
| 60 | + const struct can_mcan_config *mcan_cfg = &cfg->mcan_cfg; |
| 61 | + struct can_mcan_data *mcan_data = &DEV_DATA(dev)->mcan_data; |
| 62 | + struct can_mcan_msg_sram *msg_ram = cfg->msg_sram; |
| 63 | + int ret; |
| 64 | + |
| 65 | + /* Configure dt provided device signals when available */ |
| 66 | + ret = stm32_dt_pinctrl_configure(cfg->pinctrl, |
| 67 | + ARRAY_SIZE(cfg->pinctrl), |
| 68 | + (uint32_t)mcan_cfg->can); |
| 69 | + if (ret < 0) { |
| 70 | + LOG_ERR("CAN pinctrl setup failed (%d)", ret); |
| 71 | + return ret; |
| 72 | + } |
| 73 | + |
| 74 | + can_stm32fd_clock_enable(); |
| 75 | + ret = can_mcan_init(dev, mcan_cfg, msg_ram, mcan_data); |
| 76 | + if (ret) { |
| 77 | + return ret; |
| 78 | + } |
| 79 | + |
| 80 | + cfg->config_irq(); |
| 81 | + |
| 82 | + return ret; |
| 83 | +} |
| 84 | + |
| 85 | +enum can_state can_stm32fd_get_state(const struct device *dev, |
| 86 | + struct can_bus_err_cnt *err_cnt) |
| 87 | +{ |
| 88 | + const struct can_stm32fd_config *cfg = DEV_CFG(dev); |
| 89 | + const struct can_mcan_config *mcan_cfg = &cfg->mcan_cfg; |
| 90 | + |
| 91 | + return can_mcan_get_state(mcan_cfg, err_cnt); |
| 92 | +} |
| 93 | + |
| 94 | +int can_stm32fd_send(const struct device *dev, const struct zcan_frame *frame, |
| 95 | + k_timeout_t timeout, can_tx_callback_t callback, |
| 96 | + void *callback_arg) |
| 97 | +{ |
| 98 | + const struct can_stm32fd_config *cfg = DEV_CFG(dev); |
| 99 | + const struct can_mcan_config *mcan_cfg = &cfg->mcan_cfg; |
| 100 | + struct can_mcan_data *mcan_data = &DEV_DATA(dev)->mcan_data; |
| 101 | + struct can_mcan_msg_sram *msg_ram = cfg->msg_sram; |
| 102 | + |
| 103 | + return can_mcan_send(mcan_cfg, mcan_data, msg_ram, frame, timeout, |
| 104 | + callback, callback_arg); |
| 105 | +} |
| 106 | + |
| 107 | +int can_stm32fd_attach_isr(const struct device *dev, can_rx_callback_t isr, |
| 108 | + void *cb_arg, const struct zcan_filter *filter) |
| 109 | +{ |
| 110 | + const struct can_stm32fd_config *cfg = DEV_CFG(dev); |
| 111 | + struct can_mcan_data *mcan_data = &DEV_DATA(dev)->mcan_data; |
| 112 | + struct can_mcan_msg_sram *msg_ram = cfg->msg_sram; |
| 113 | + |
| 114 | + return can_mcan_attach_isr(mcan_data, msg_ram, isr, cb_arg, filter); |
| 115 | +} |
| 116 | + |
| 117 | +void can_stm32fd_detach(const struct device *dev, int filter_nr) |
| 118 | +{ |
| 119 | + const struct can_stm32fd_config *cfg = DEV_CFG(dev); |
| 120 | + struct can_mcan_data *mcan_data = &DEV_DATA(dev)->mcan_data; |
| 121 | + struct can_mcan_msg_sram *msg_ram = cfg->msg_sram; |
| 122 | + |
| 123 | + can_mcan_detach(mcan_data, msg_ram, filter_nr); |
24 | 124 | } |
| 125 | + |
| 126 | +int can_stm32fd_set_mode(const struct device *dev, enum can_mode mode) |
| 127 | +{ |
| 128 | + const struct can_stm32fd_config *cfg = DEV_CFG(dev); |
| 129 | + const struct can_mcan_config *mcan_cfg = &cfg->mcan_cfg; |
| 130 | + |
| 131 | + return can_mcan_set_mode(mcan_cfg, mode); |
| 132 | +} |
| 133 | + |
| 134 | +int can_stm32fd_set_timing(const struct device *dev, |
| 135 | + const struct can_timing *timing, |
| 136 | + const struct can_timing *timing_data) |
| 137 | +{ |
| 138 | + const struct can_stm32fd_config *cfg = DEV_CFG(dev); |
| 139 | + const struct can_mcan_config *mcan_cfg = &cfg->mcan_cfg; |
| 140 | + |
| 141 | + return can_mcan_set_timing(mcan_cfg, timing, timing_data); |
| 142 | +} |
| 143 | + |
| 144 | +void can_stm32fd_line_0_isr(void *arg) |
| 145 | +{ |
| 146 | + struct device *dev = (struct device *)arg; |
| 147 | + const struct can_stm32fd_config *cfg = DEV_CFG(dev); |
| 148 | + const struct can_mcan_config *mcan_cfg = &cfg->mcan_cfg; |
| 149 | + struct can_stm32fd_data *data = DEV_DATA(dev); |
| 150 | + struct can_mcan_data *mcan_data = &data->mcan_data; |
| 151 | + struct can_mcan_msg_sram *msg_ram = cfg->msg_sram; |
| 152 | + |
| 153 | + can_mcan_line_0_isr(mcan_cfg, msg_ram, mcan_data); |
| 154 | +} |
| 155 | + |
| 156 | +void can_stm32fd_line_1_isr(void *arg) |
| 157 | +{ |
| 158 | + struct device *dev = (struct device *)arg; |
| 159 | + const struct can_stm32fd_config *cfg = DEV_CFG(dev); |
| 160 | + const struct can_mcan_config *mcan_cfg = &cfg->mcan_cfg; |
| 161 | + struct can_mcan_data *mcan_data = &DEV_DATA(dev)->mcan_data; |
| 162 | + struct can_mcan_msg_sram *msg_ram = cfg->msg_sram; |
| 163 | + |
| 164 | + can_mcan_line_1_isr(mcan_cfg, msg_ram, mcan_data); |
| 165 | +} |
| 166 | + |
| 167 | +static const struct can_driver_api can_api_funcs = { |
| 168 | + .set_mode = can_stm32fd_set_mode, |
| 169 | + .set_timing = can_stm32fd_set_timing, |
| 170 | + .send = can_stm32fd_send, |
| 171 | + .attach_isr = can_stm32fd_attach_isr, |
| 172 | + .detach = can_stm32fd_detach, |
| 173 | + .get_state = can_stm32fd_get_state, |
| 174 | +#ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY |
| 175 | + .recover = can_mcan_recover, |
| 176 | +#endif |
| 177 | + .get_core_clock = can_stm32fd_get_core_clock, |
| 178 | + .register_state_change_isr = can_stm32fd_register_state_change_isr, |
| 179 | + .timing_min = { |
| 180 | + .sjw = 0x7f, |
| 181 | + .prop_seg = 0x00, |
| 182 | + .phase_seg1 = 0x01, |
| 183 | + .phase_seg2 = 0x01, |
| 184 | + .prescaler = 0x01 |
| 185 | + }, |
| 186 | + .timing_max = { |
| 187 | + .sjw = 0x7f, |
| 188 | + .prop_seg = 0x00, |
| 189 | + .phase_seg1 = 0x100, |
| 190 | + .phase_seg2 = 0x80, |
| 191 | + .prescaler = 0x200 |
| 192 | + }, |
| 193 | +#ifdef CONFIG_CAN_FD_MODE |
| 194 | + .timing_min_data = { |
| 195 | + .sjw = 0x01, |
| 196 | + .prop_seg = 0x01, |
| 197 | + .phase_seg1 = 0x01, |
| 198 | + .phase_seg2 = 0x01, |
| 199 | + .prescaler = 0x01 |
| 200 | + }, |
| 201 | + .timing_max_data = { |
| 202 | + .sjw = 0x10, |
| 203 | + .prop_seg = 0x00, |
| 204 | + .phase_seg1 = 0x20, |
| 205 | + .phase_seg2 = 0x10, |
| 206 | + .prescaler = 0x20 |
| 207 | + } |
| 208 | +#endif |
| 209 | +}; |
| 210 | + |
| 211 | +#define CAN_STM32FD_IRQ_CFG_FUNCTION(inst) \ |
| 212 | +static void config_can_##inst##_irq(void) \ |
| 213 | +{ \ |
| 214 | + LOG_DBG("Enable CAN" #inst " IRQ"); \ |
| 215 | + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, line_0, irq), \ |
| 216 | + DT_INST_IRQ_BY_NAME(inst, line_0, priority), \ |
| 217 | + can_stm32fd_line_0_isr, DEVICE_DT_INST_GET(inst), 0); \ |
| 218 | + irq_enable(DT_INST_IRQ_BY_NAME(inst, line_0, irq)); \ |
| 219 | + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, line_1, irq), \ |
| 220 | + DT_INST_IRQ_BY_NAME(inst, line_1, priority), \ |
| 221 | + can_stm32fd_line_1_isr, DEVICE_DT_INST_GET(inst), 0); \ |
| 222 | + irq_enable(DT_INST_IRQ_BY_NAME(inst, line_1, irq)); \ |
| 223 | +} |
| 224 | + |
| 225 | +#ifdef CONFIG_CAN_FD_MODE |
| 226 | + |
| 227 | +#define CAN_STM32FD_CFG_INST(inst) \ |
| 228 | +static const struct can_stm32fd_config can_stm32fd_cfg_##inst = { \ |
| 229 | + .msg_sram = (struct can_mcan_msg_sram *) \ |
| 230 | + DT_INST_REG_ADDR_BY_NAME(inst, message_ram), \ |
| 231 | + .config_irq = config_can_##inst##_irq, \ |
| 232 | + .mcan_cfg = { \ |
| 233 | + .can = (struct can_mcan_reg *) \ |
| 234 | + DT_INST_REG_ADDR_BY_NAME(inst, m_can), \ |
| 235 | + .bus_speed = DT_INST_PROP(inst, bus_speed), \ |
| 236 | + .sjw = DT_INST_PROP(inst, sjw), \ |
| 237 | + .sample_point = DT_INST_PROP_OR(inst, sample_point, 0), \ |
| 238 | + .prop_ts1 = DT_INST_PROP_OR(inst, prop_seg, 0) + \ |
| 239 | + DT_INST_PROP_OR(inst, phase_seg1, 0), \ |
| 240 | + .ts2 = DT_INST_PROP_OR(inst, phase_seg2, 0), \ |
| 241 | + .bus_speed_data = DT_INST_PROP(inst, bus_speed_data), \ |
| 242 | + .sjw_data = DT_INST_PROP(inst, sjw_data), \ |
| 243 | + .sample_point_data = \ |
| 244 | + DT_INST_PROP_OR(inst, sample_point_data, 0), \ |
| 245 | + .prop_ts1_data = DT_INST_PROP_OR(inst, prop_seg_data, 0) + \ |
| 246 | + DT_INST_PROP_OR(inst, phase_seg1_data, 0), \ |
| 247 | + .ts2_data = DT_INST_PROP_OR(inst, phase_seg2_data, 0), \ |
| 248 | + }, \ |
| 249 | + .pinctrl = ST_STM32_DT_INST_PINCTRL(inst, 0), \ |
| 250 | +}; |
| 251 | + |
| 252 | +#else /* CONFIG_CAN_FD_MODE */ |
| 253 | + |
| 254 | +#define CAN_STM32FD_CFG_INST(inst) \ |
| 255 | +static const struct can_stm32fd_config can_stm32fd_cfg_##inst = { \ |
| 256 | + .msg_sram = (struct can_mcan_msg_sram *) \ |
| 257 | + DT_INST_REG_ADDR_BY_NAME(inst, message_ram), \ |
| 258 | + .config_irq = config_can_##inst##_irq, \ |
| 259 | + .mcan_cfg = { \ |
| 260 | + .can = (struct can_mcan_reg *) \ |
| 261 | + DT_INST_REG_ADDR_BY_NAME(inst, m_can), \ |
| 262 | + .bus_speed = DT_INST_PROP(inst, bus_speed), \ |
| 263 | + .sjw = DT_INST_PROP(inst, sjw), \ |
| 264 | + .sample_point = DT_INST_PROP_OR(inst, sample_point, 0), \ |
| 265 | + .prop_ts1 = DT_INST_PROP_OR(inst, prop_seg, 0) + \ |
| 266 | + DT_INST_PROP_OR(inst, phase_seg1, 0), \ |
| 267 | + .ts2 = DT_INST_PROP_OR(inst, phase_seg2, 0), \ |
| 268 | + }, \ |
| 269 | + .pinctrl = ST_STM32_DT_INST_PINCTRL(inst, 0), \ |
| 270 | +}; |
| 271 | + |
| 272 | +#endif /* CONFIG_CAN_FD_MODE */ |
| 273 | + |
| 274 | +#define CAN_STM32FD_DATA_INST(inst) \ |
| 275 | +static struct can_stm32fd_data can_stm32fd_dev_data_##inst; |
| 276 | + |
| 277 | +#define CAN_STM32FD_DEVICE_INST(inst) \ |
| 278 | +DEVICE_DT_INST_DEFINE(inst, &can_stm32fd_init, device_pm_control_nop, \ |
| 279 | + &can_stm32fd_dev_data_##inst, &can_stm32fd_cfg_##inst, \ |
| 280 | + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ |
| 281 | + &can_api_funcs); |
| 282 | + |
| 283 | +#define CAN_STM32FD_INST(inst) \ |
| 284 | +CAN_STM32FD_IRQ_CFG_FUNCTION(inst) \ |
| 285 | +CAN_STM32FD_CFG_INST(inst) \ |
| 286 | +CAN_STM32FD_DATA_INST(inst) \ |
| 287 | +CAN_STM32FD_DEVICE_INST(inst) |
| 288 | + |
| 289 | +DT_INST_FOREACH_STATUS_OKAY(CAN_STM32FD_INST) |
0 commit comments