Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 1 | /* |
Henrik Brix Andersen | 5b3712a | 2022-04-19 13:46:30 +0200 | [diff] [blame] | 2 | * Copyright (c) 2022 Vestas Wind Systems A/S |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 3 | * Copyright (c) 2022 Blue Clover |
| 4 | * |
| 5 | * SPDX-License-Identifier: Apache-2.0 |
| 6 | */ |
| 7 | |
Gerard Marull-Paretas | fb60aab | 2022-05-06 10:25:46 +0200 | [diff] [blame] | 8 | #include <zephyr/drivers/can.h> |
| 9 | #include <zephyr/drivers/clock_control/stm32_clock_control.h> |
| 10 | #include <zephyr/drivers/clock_control.h> |
| 11 | #include <zephyr/drivers/pinctrl.h> |
| 12 | #include <zephyr/kernel.h> |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 13 | #include <stm32_ll_rcc.h> |
Gerard Marull-Paretas | fb60aab | 2022-05-06 10:25:46 +0200 | [diff] [blame] | 14 | #include <zephyr/logging/log.h> |
Gerard Marull-Paretas | 178bdc4 | 2022-10-17 10:24:11 +0200 | [diff] [blame] | 15 | #include <zephyr/irq.h> |
Henrik Brix Andersen | de45e8e | 2022-02-22 12:06:54 +0100 | [diff] [blame] | 16 | |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 17 | #include "can_mcan.h" |
| 18 | |
Henrik Brix Andersen | de45e8e | 2022-02-22 12:06:54 +0100 | [diff] [blame] | 19 | LOG_MODULE_REGISTER(can_stm32h7, CONFIG_CAN_LOG_LEVEL); |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 20 | |
| 21 | #define DT_DRV_COMPAT st_stm32h7_fdcan |
| 22 | |
| 23 | struct can_stm32h7_config { |
Henrik Brix Andersen | bbfc1f9 | 2023-05-04 11:14:31 +0200 | [diff] [blame] | 24 | mm_reg_t base; |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 25 | void (*config_irq)(void); |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 26 | const struct pinctrl_dev_config *pcfg; |
| 27 | struct stm32_pclken pclken; |
| 28 | }; |
| 29 | |
Henrik Brix Andersen | bbfc1f9 | 2023-05-04 11:14:31 +0200 | [diff] [blame] | 30 | static int can_stm32h7_read_reg(const struct device *dev, uint16_t reg, uint32_t *val) |
| 31 | { |
| 32 | const struct can_mcan_config *mcan_config = dev->config; |
| 33 | const struct can_stm32h7_config *stm32h7_config = mcan_config->custom; |
| 34 | |
| 35 | return can_mcan_sys_read_reg(stm32h7_config->base, reg, val); |
| 36 | } |
| 37 | |
| 38 | static int can_stm32h7_write_reg(const struct device *dev, uint16_t reg, uint32_t val) |
| 39 | { |
| 40 | const struct can_mcan_config *mcan_config = dev->config; |
| 41 | const struct can_stm32h7_config *stm32h7_config = mcan_config->custom; |
| 42 | |
| 43 | return can_mcan_sys_write_reg(stm32h7_config->base, reg, val); |
| 44 | } |
| 45 | |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 46 | static int can_stm32h7_get_core_clock(const struct device *dev, uint32_t *rate) |
| 47 | { |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 48 | const uint32_t rate_tmp = LL_RCC_GetFDCANClockFreq(LL_RCC_FDCAN_CLKSOURCE); |
| 49 | |
Henrik Brix Andersen | 5b3712a | 2022-04-19 13:46:30 +0200 | [diff] [blame] | 50 | ARG_UNUSED(dev); |
| 51 | |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 52 | if (rate_tmp == LL_RCC_PERIPH_FREQUENCY_NO) { |
| 53 | LOG_ERR("Can't read core clock"); |
| 54 | return -EIO; |
| 55 | } |
| 56 | |
| 57 | *rate = rate_tmp; |
| 58 | |
| 59 | LOG_DBG("rate=%d", *rate); |
| 60 | |
| 61 | return 0; |
| 62 | } |
| 63 | |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 64 | static int can_stm32h7_clock_enable(const struct device *dev) |
| 65 | { |
Henrik Brix Andersen | 5b3712a | 2022-04-19 13:46:30 +0200 | [diff] [blame] | 66 | const struct can_mcan_config *mcan_cfg = dev->config; |
| 67 | const struct can_stm32h7_config *stm32h7_cfg = mcan_cfg->custom; |
Gerard Marull-Paretas | a202341 | 2022-08-22 10:36:10 +0200 | [diff] [blame] | 68 | const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); |
Henrik Brix Andersen | 5b3712a | 2022-04-19 13:46:30 +0200 | [diff] [blame] | 69 | int ret; |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 70 | |
| 71 | LL_RCC_SetFDCANClockSource(LL_RCC_FDCAN_CLKSOURCE_PLL1Q); |
| 72 | |
Henrik Brix Andersen | 035c7d2 | 2022-08-08 13:31:51 +0200 | [diff] [blame] | 73 | if (!device_is_ready(clk)) { |
| 74 | LOG_ERR("clock control device not ready"); |
| 75 | return -ENODEV; |
| 76 | } |
| 77 | |
Pieter De Gendt | 6b532ff | 2023-03-28 08:24:07 +0200 | [diff] [blame] | 78 | ret = clock_control_on(clk, (clock_control_subsys_t)&stm32h7_cfg->pclken); |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 79 | if (ret != 0) { |
| 80 | LOG_ERR("failure enabling clock"); |
| 81 | return ret; |
| 82 | } |
| 83 | |
| 84 | if (!LL_RCC_PLL1Q_IsEnabled()) { |
| 85 | LOG_ERR("PLL1Q clock must be enabled!"); |
| 86 | return -EIO; |
| 87 | } |
| 88 | |
| 89 | return 0; |
| 90 | } |
| 91 | |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 92 | static int can_stm32h7_init(const struct device *dev) |
| 93 | { |
Henrik Brix Andersen | 5b3712a | 2022-04-19 13:46:30 +0200 | [diff] [blame] | 94 | const struct can_mcan_config *mcan_cfg = dev->config; |
| 95 | const struct can_stm32h7_config *stm32h7_cfg = mcan_cfg->custom; |
Henrik Brix Andersen | a781ccd | 2023-05-07 19:00:15 +0200 | [diff] [blame] | 96 | struct can_mcan_data *mcan_data = dev->data; |
| 97 | const uintptr_t mrba = POINTER_TO_UINT(mcan_data->msg_ram); |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 98 | int ret; |
| 99 | |
| 100 | /* Configure dt provided device signals when available */ |
Henrik Brix Andersen | 5b3712a | 2022-04-19 13:46:30 +0200 | [diff] [blame] | 101 | ret = pinctrl_apply_state(stm32h7_cfg->pcfg, PINCTRL_STATE_DEFAULT); |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 102 | if (ret != 0) { |
| 103 | LOG_ERR("CAN pinctrl setup failed (%d)", ret); |
| 104 | return ret; |
| 105 | } |
| 106 | |
| 107 | ret = can_stm32h7_clock_enable(dev); |
| 108 | if (ret != 0) { |
| 109 | return ret; |
| 110 | } |
| 111 | |
Henrik Brix Andersen | a781ccd | 2023-05-07 19:00:15 +0200 | [diff] [blame] | 112 | ret = can_mcan_configure_message_ram(dev, mrba); |
| 113 | if (ret != 0) { |
| 114 | return ret; |
| 115 | } |
| 116 | |
Henrik Brix Andersen | 5b3712a | 2022-04-19 13:46:30 +0200 | [diff] [blame] | 117 | ret = can_mcan_init(dev); |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 118 | if (ret != 0) { |
| 119 | return ret; |
| 120 | } |
| 121 | |
Henrik Brix Andersen | 5b3712a | 2022-04-19 13:46:30 +0200 | [diff] [blame] | 122 | stm32h7_cfg->config_irq(); |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 123 | |
| 124 | return 0; |
| 125 | } |
| 126 | |
Henrik Brix Andersen | 5b3712a | 2022-04-19 13:46:30 +0200 | [diff] [blame] | 127 | static const struct can_driver_api can_stm32h7_driver_api = { |
Henrik Brix Andersen | bb08e42 | 2022-07-12 16:36:20 +0200 | [diff] [blame] | 128 | .get_capabilities = can_mcan_get_capabilities, |
Henrik Brix Andersen | 180cdc1 | 2022-08-31 14:28:42 +0200 | [diff] [blame] | 129 | .start = can_mcan_start, |
| 130 | .stop = can_mcan_stop, |
Henrik Brix Andersen | 5b3712a | 2022-04-19 13:46:30 +0200 | [diff] [blame] | 131 | .set_mode = can_mcan_set_mode, |
| 132 | .set_timing = can_mcan_set_timing, |
| 133 | .send = can_mcan_send, |
| 134 | .add_rx_filter = can_mcan_add_rx_filter, |
| 135 | .remove_rx_filter = can_mcan_remove_rx_filter, |
| 136 | .get_state = can_mcan_get_state, |
Henrik Brix Andersen | e0aaaea | 2022-03-31 21:31:15 +0200 | [diff] [blame] | 137 | #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY |
Henrik Brix Andersen | 5b3712a | 2022-04-19 13:46:30 +0200 | [diff] [blame] | 138 | .recover = can_mcan_recover, |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 139 | #endif |
| 140 | .get_core_clock = can_stm32h7_get_core_clock, |
Henrik Brix Andersen | 5b3712a | 2022-04-19 13:46:30 +0200 | [diff] [blame] | 141 | .get_max_bitrate = can_mcan_get_max_bitrate, |
Henrik Brix Andersen | 5fd079b | 2022-03-18 10:37:37 +0100 | [diff] [blame] | 142 | .get_max_filters = can_mcan_get_max_filters, |
Henrik Brix Andersen | 5b3712a | 2022-04-19 13:46:30 +0200 | [diff] [blame] | 143 | .set_state_change_callback = can_mcan_set_state_change_callback, |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 144 | /* Timing limits are per the STM32H7 Reference Manual (RM0433 Rev 7), |
| 145 | * section 56.5.7, FDCAN nominal bit timing and prescaler register |
| 146 | * (FDCAN_NBTP). |
| 147 | */ |
| 148 | .timing_min = { |
Tomislav Milkovic | fc7598f | 2022-05-17 12:23:52 +0200 | [diff] [blame] | 149 | .sjw = 0x01, |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 150 | .prop_seg = 0x00, |
Tomislav Milkovic | fc7598f | 2022-05-17 12:23:52 +0200 | [diff] [blame] | 151 | .phase_seg1 = 0x01, |
| 152 | .phase_seg2 = 0x01, |
| 153 | .prescaler = 0x01 |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 154 | }, |
| 155 | .timing_max = { |
Tomislav Milkovic | fc7598f | 2022-05-17 12:23:52 +0200 | [diff] [blame] | 156 | .sjw = 0x80, |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 157 | .prop_seg = 0x00, |
| 158 | .phase_seg1 = 0x100, |
| 159 | .phase_seg2 = 0x80, |
| 160 | .prescaler = 0x200 |
| 161 | }, |
| 162 | #ifdef CONFIG_CAN_FD_MODE |
Henrik Brix Andersen | 1889082 | 2022-05-03 22:05:53 +0200 | [diff] [blame] | 163 | .set_timing_data = can_mcan_set_timing_data, |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 164 | /* Data timing limits are per the STM32H7 Reference Manual |
| 165 | * (RM0433 Rev 7), section 56.5.3, FDCAN data bit timing and prescaler |
| 166 | * register (FDCAN_DBTP). |
| 167 | */ |
Henrik Brix Andersen | 2f7c01b | 2022-05-03 22:13:13 +0200 | [diff] [blame] | 168 | .timing_data_min = { |
Tomislav Milkovic | fc7598f | 2022-05-17 12:23:52 +0200 | [diff] [blame] | 169 | .sjw = 0x01, |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 170 | .prop_seg = 0x00, |
Tomislav Milkovic | fc7598f | 2022-05-17 12:23:52 +0200 | [diff] [blame] | 171 | .phase_seg1 = 0x01, |
| 172 | .phase_seg2 = 0x01, |
| 173 | .prescaler = 0x01 |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 174 | }, |
Henrik Brix Andersen | 2f7c01b | 2022-05-03 22:13:13 +0200 | [diff] [blame] | 175 | .timing_data_max = { |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 176 | .sjw = 0x10, |
| 177 | .prop_seg = 0x00, |
| 178 | .phase_seg1 = 0x20, |
| 179 | .phase_seg2 = 0x10, |
| 180 | .prescaler = 0x20 |
| 181 | } |
| 182 | #endif |
| 183 | }; |
| 184 | |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 185 | #define CAN_STM32H7_MCAN_INIT(n) \ |
| 186 | static void stm32h7_mcan_irq_config_##n(void); \ |
| 187 | \ |
| 188 | PINCTRL_DT_INST_DEFINE(n); \ |
| 189 | \ |
| 190 | static const struct can_stm32h7_config can_stm32h7_cfg_##n = { \ |
Henrik Brix Andersen | bbfc1f9 | 2023-05-04 11:14:31 +0200 | [diff] [blame] | 191 | .base = (mm_reg_t)DT_INST_REG_ADDR_BY_NAME(n, m_can), \ |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 192 | .config_irq = stm32h7_mcan_irq_config_##n, \ |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 193 | .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ |
| 194 | .pclken = { \ |
| 195 | .enr = DT_INST_CLOCKS_CELL(n, bits), \ |
| 196 | .bus = DT_INST_CLOCKS_CELL(n, bus), \ |
| 197 | }, \ |
| 198 | }; \ |
| 199 | \ |
Henrik Brix Andersen | 5b3712a | 2022-04-19 13:46:30 +0200 | [diff] [blame] | 200 | static const struct can_mcan_config can_mcan_cfg_##n = \ |
Henrik Brix Andersen | bbfc1f9 | 2023-05-04 11:14:31 +0200 | [diff] [blame] | 201 | CAN_MCAN_DT_CONFIG_INST_GET(n, &can_stm32h7_cfg_##n, \ |
| 202 | can_stm32h7_read_reg, \ |
| 203 | can_stm32h7_write_reg); \ |
Henrik Brix Andersen | 5b3712a | 2022-04-19 13:46:30 +0200 | [diff] [blame] | 204 | \ |
Henrik Brix Andersen | 41a77be | 2022-04-19 16:23:31 +0200 | [diff] [blame] | 205 | static struct can_mcan_data can_mcan_data_##n = \ |
| 206 | CAN_MCAN_DATA_INITIALIZER((struct can_mcan_msg_sram *) \ |
| 207 | DT_INST_REG_ADDR_BY_NAME(n, message_ram), NULL); \ |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 208 | \ |
| 209 | DEVICE_DT_INST_DEFINE(n, &can_stm32h7_init, NULL, \ |
Henrik Brix Andersen | 5b3712a | 2022-04-19 13:46:30 +0200 | [diff] [blame] | 210 | &can_mcan_data_##n, \ |
| 211 | &can_mcan_cfg_##n, \ |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 212 | POST_KERNEL, CONFIG_CAN_INIT_PRIORITY, \ |
Henrik Brix Andersen | 5b3712a | 2022-04-19 13:46:30 +0200 | [diff] [blame] | 213 | &can_stm32h7_driver_api); \ |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 214 | \ |
| 215 | static void stm32h7_mcan_irq_config_##n(void) \ |
| 216 | { \ |
| 217 | LOG_DBG("Enable CAN inst" #n " IRQ"); \ |
| 218 | IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, line_0, irq), \ |
| 219 | DT_INST_IRQ_BY_NAME(n, line_0, priority), \ |
Henrik Brix Andersen | 5b3712a | 2022-04-19 13:46:30 +0200 | [diff] [blame] | 220 | can_mcan_line_0_isr, DEVICE_DT_INST_GET(n), 0); \ |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 221 | irq_enable(DT_INST_IRQ_BY_NAME(n, line_0, irq)); \ |
| 222 | IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, line_1, irq), \ |
| 223 | DT_INST_IRQ_BY_NAME(n, line_1, priority), \ |
Henrik Brix Andersen | 5b3712a | 2022-04-19 13:46:30 +0200 | [diff] [blame] | 224 | can_mcan_line_1_isr, DEVICE_DT_INST_GET(n), 0); \ |
Jeremy Wood | 1caa7f6 | 2021-12-28 17:45:28 -0800 | [diff] [blame] | 225 | irq_enable(DT_INST_IRQ_BY_NAME(n, line_1, irq)); \ |
| 226 | } |
| 227 | |
| 228 | DT_INST_FOREACH_STATUS_OKAY(CAN_STM32H7_MCAN_INIT) |