-
Notifications
You must be signed in to change notification settings - Fork 8.2k
sam: atsamc21: driver for CAN for SAMC21 #50408
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,3 +17,4 @@ supported: | |
| - i2c | ||
| - pwm | ||
| - spi | ||
| - can | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| # SAM CAN configuration options | ||
| # Copyright (c) 2022 Kamil Serwus | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| config CAN_SAM0 | ||
| bool "Atmel SAM0 CAN driver" | ||
| default y | ||
| depends on DT_HAS_ATMEL_SAM0_CAN_ENABLED | ||
| select CAN_MCAN |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,227 @@ | ||
| /* | ||
| * Copyright (c) 2022 Vestas Wind Systems A/S | ||
| * Copyright (c) 2021 Alexander Wachter | ||
| * Copyright (c) 2022 Kamil Serwus | ||
| * | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| #include <zephyr/drivers/can.h> | ||
| #include <zephyr/drivers/pinctrl.h> | ||
| #include <zephyr/irq.h> | ||
| #include <zephyr/kernel.h> | ||
| #include <zephyr/logging/log.h> | ||
benys marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| #include <soc.h> | ||
|
|
||
| #include "can_mcan.h" | ||
|
|
||
| LOG_MODULE_REGISTER(can_sam0, CONFIG_CAN_LOG_LEVEL); | ||
|
|
||
| #define DT_DRV_COMPAT atmel_sam0_can | ||
|
|
||
| struct can_sam0_config { | ||
| mm_reg_t base; | ||
| void (*config_irq)(void); | ||
| const struct pinctrl_dev_config *pcfg; | ||
| volatile uint32_t *mclk; | ||
| uint32_t mclk_mask; | ||
| uint16_t gclk_core_id; | ||
| int divider; | ||
| }; | ||
|
|
||
| struct can_sam0_data { | ||
| struct can_mcan_msg_sram msg_ram; | ||
| }; | ||
|
|
||
| static int can_sam0_read_reg(const struct device *dev, uint16_t reg, uint32_t *val) | ||
| { | ||
| const struct can_mcan_config *mcan_config = dev->config; | ||
| const struct can_sam0_config *sam_config = mcan_config->custom; | ||
|
|
||
| return can_mcan_sys_read_reg(sam_config->base, reg, val); | ||
| } | ||
|
|
||
| static int can_sam0_write_reg(const struct device *dev, uint16_t reg, uint32_t val) | ||
| { | ||
| const struct can_mcan_config *mcan_config = dev->config; | ||
| const struct can_sam0_config *sam_config = mcan_config->custom; | ||
| uint32_t bits = 0U; | ||
|
|
||
| switch (reg) { | ||
| case CAN_MCAN_ILS: | ||
| /* All interrupts are assigned to MCAN_INT0 */ | ||
| val = 0; | ||
| break; | ||
| case CAN_MCAN_ILE: | ||
| /* SAM0 has only one line to handle interrupts */ | ||
| val = CAN_MCAN_ILE_EINT0; | ||
| break; | ||
| default: | ||
| /* No field remap needed */ | ||
| bits = val; | ||
| break; | ||
| }; | ||
|
|
||
| return can_mcan_sys_write_reg(sam_config->base, reg, val); | ||
| } | ||
|
|
||
| void can_sam0_line_x_isr(const struct device *dev) | ||
| { | ||
| can_mcan_line_0_isr(dev); | ||
| can_mcan_line_1_isr(dev); | ||
| } | ||
|
|
||
| static int can_sam0_get_core_clock(const struct device *dev, uint32_t *rate) | ||
| { | ||
| const struct can_mcan_config *mcan_cfg = dev->config; | ||
| const struct can_sam0_config *sam_cfg = mcan_cfg->custom; | ||
|
|
||
| *rate = SOC_ATMEL_SAM0_OSC48M_FREQ_HZ / (sam_cfg->divider); | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| static void can_sam0_clock_enable(const struct can_sam0_config *cfg) | ||
| { | ||
| /* Enable the GLCK7 with DIV*/ | ||
| GCLK->GENCTRL[7].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_OSC48M) | ||
| | GCLK_GENCTRL_DIV(cfg->divider) | ||
| | GCLK_GENCTRL_GENEN; | ||
|
|
||
| /* Route channel */ | ||
| GCLK->PCHCTRL[cfg->gclk_core_id].reg = GCLK_PCHCTRL_GEN_GCLK7 | ||
| | GCLK_PCHCTRL_CHEN; | ||
|
|
||
| /* Enable CAN clock in MCLK */ | ||
| *cfg->mclk |= cfg->mclk_mask; | ||
| } | ||
|
|
||
| static int can_sam0_init(const struct device *dev) | ||
| { | ||
| const struct can_mcan_config *mcan_cfg = dev->config; | ||
| const struct can_sam0_config *sam_cfg = mcan_cfg->custom; | ||
| int ret; | ||
|
|
||
| can_sam0_clock_enable(sam_cfg); | ||
|
|
||
| ret = pinctrl_apply_state(sam_cfg->pcfg, PINCTRL_STATE_DEFAULT); | ||
| if (ret < 0) { | ||
| LOG_ERR("failed to apply pinctrl"); | ||
| return ret; | ||
benys marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| ret = can_mcan_configure_message_ram(dev, 0U); | ||
| if (ret != 0) { | ||
| LOG_ERR("failed to configure message ram"); | ||
| return ret; | ||
| } | ||
|
|
||
| ret = can_mcan_init(dev); | ||
| if (ret != 0) { | ||
| LOG_ERR("failed to mcan init"); | ||
| return ret; | ||
| } | ||
|
|
||
| sam_cfg->config_irq(); | ||
|
|
||
| return ret; | ||
| } | ||
|
|
||
| static const struct can_driver_api can_sam0_driver_api = { | ||
| .get_capabilities = can_mcan_get_capabilities, | ||
| .start = can_mcan_start, | ||
| .stop = can_mcan_stop, | ||
| .set_mode = can_mcan_set_mode, | ||
| .set_timing = can_mcan_set_timing, | ||
| .send = can_mcan_send, | ||
| .add_rx_filter = can_mcan_add_rx_filter, | ||
| .remove_rx_filter = can_mcan_remove_rx_filter, | ||
| .get_state = can_mcan_get_state, | ||
| #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY | ||
| .recover = can_mcan_recover, | ||
| #endif /* CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ | ||
| .get_core_clock = can_sam0_get_core_clock, | ||
| .get_max_filters = can_mcan_get_max_filters, | ||
| .get_max_bitrate = can_mcan_get_max_bitrate, | ||
| .set_state_change_callback = can_mcan_set_state_change_callback, | ||
| .timing_min = { | ||
| .sjw = 0x1, | ||
| .prop_seg = 0x00, | ||
| .phase_seg1 = 0x01, | ||
| .phase_seg2 = 0x01, | ||
| .prescaler = 0x01 | ||
| }, | ||
| .timing_max = { | ||
| .sjw = 0x7f, | ||
| .prop_seg = 0x00, | ||
| .phase_seg1 = 0x100, | ||
| .phase_seg2 = 0x80, | ||
| .prescaler = 0x200 | ||
| }, | ||
| #ifdef CONFIG_CAN_FD_MODE | ||
| .set_timing_data = can_mcan_set_timing_data, | ||
| .timing_data_min = { | ||
| .sjw = 0x01, | ||
| .prop_seg = 0x00, | ||
| .phase_seg1 = 0x01, | ||
| .phase_seg2 = 0x01, | ||
| .prescaler = 0x01 | ||
| }, | ||
| .timing_data_max = { | ||
| .sjw = 0x10, | ||
| .prop_seg = 0x00, | ||
| .phase_seg1 = 0x20, | ||
| .phase_seg2 = 0x10, | ||
| .prescaler = 0x20 | ||
| } | ||
| #endif /* CONFIG_CAN_FD_MODE */ | ||
| }; | ||
|
|
||
| #define CAN_SAM0_IRQ_CFG_FUNCTION(inst) \ | ||
| static void config_can_##inst##_irq(void) \ | ||
| { \ | ||
| LOG_DBG("Enable CAN##inst## IRQ"); \ | ||
| IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, line_0, irq), \ | ||
| DT_INST_IRQ_BY_NAME(inst, line_0, priority), can_sam0_line_x_isr, \ | ||
| DEVICE_DT_INST_GET(inst), 0); \ | ||
| irq_enable(DT_INST_IRQ_BY_NAME(inst, line_0, irq)); \ | ||
| } | ||
|
|
||
| #define CAN_SAM0_CFG_INST(inst) \ | ||
| static const struct can_sam0_config can_sam0_cfg_##inst = { \ | ||
| .base = (mm_reg_t)DT_INST_REG_ADDR(inst), \ | ||
| .mclk = (volatile uint32_t *)MCLK_MASK_DT_INT_REG_ADDR(inst), \ | ||
benys marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| .mclk_mask = BIT(DT_INST_CLOCKS_CELL_BY_NAME(inst, mclk, bit)), \ | ||
| .gclk_core_id = DT_INST_CLOCKS_CELL_BY_NAME(inst, gclk, periph_ch), \ | ||
| .divider = DT_INST_PROP(inst, divider), \ | ||
| .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ | ||
| .config_irq = config_can_##inst##_irq, \ | ||
| }; \ | ||
| \ | ||
| static const struct can_mcan_config can_mcan_cfg_##inst = \ | ||
| CAN_MCAN_DT_CONFIG_INST_GET(inst, &can_sam0_cfg_##inst, \ | ||
| can_sam0_read_reg, \ | ||
| can_sam0_write_reg); | ||
|
|
||
| #define CAN_SAM0_DATA_INST(inst) \ | ||
| static struct can_sam0_data can_sam0_data_##inst; \ | ||
| \ | ||
| static struct can_mcan_data can_mcan_data_##inst = \ | ||
| CAN_MCAN_DATA_INITIALIZER(&can_sam0_data_##inst.msg_ram, \ | ||
| &can_sam0_data_##inst); \ | ||
|
|
||
| #define CAN_SAM0_DEVICE_INST(inst) \ | ||
| DEVICE_DT_INST_DEFINE(inst, &can_sam0_init, NULL, \ | ||
| &can_mcan_data_##inst, \ | ||
| &can_mcan_cfg_##inst, \ | ||
| POST_KERNEL, CONFIG_CAN_INIT_PRIORITY, \ | ||
| &can_sam0_driver_api); | ||
|
|
||
| #define CAN_SAM0_INST(inst) \ | ||
| PINCTRL_DT_INST_DEFINE(inst); \ | ||
| CAN_SAM0_IRQ_CFG_FUNCTION(inst) \ | ||
| CAN_SAM0_CFG_INST(inst) \ | ||
| CAN_SAM0_DATA_INST(inst) \ | ||
| CAN_SAM0_DEVICE_INST(inst) | ||
|
|
||
| DT_INST_FOREACH_STATUS_OKAY(CAN_SAM0_INST) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.