/* * Copyright (c) 2019 Vestas Wind Systems A/S * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include #define LOG_LEVEL CONFIG_CAN_LOG_LEVEL #include LOG_MODULE_REGISTER(can_mcux_flexcan); /* * RX message buffers (filters) will take up the first N message * buffers. The rest are available for TX use. */ #define MCUX_FLEXCAN_MAX_RX CONFIG_CAN_MAX_FILTER #define MCUX_FLEXCAN_MAX_TX \ (FSL_FEATURE_FLEXCAN_HAS_MESSAGE_BUFFER_MAX_NUMBERn(0) \ - MCUX_FLEXCAN_MAX_RX) #define MCUX_N_TX_ALLOC_ELEM (1 + (MCUX_FLEXCAN_MAX_TX - 1) / ATOMIC_BITS) /* * Convert from RX message buffer index to allocated filter ID and * vice versa. */ #define RX_MBIDX_TO_ALLOC_IDX(x) (x) #define ALLOC_IDX_TO_RXMB_IDX(x) (x) /* * Convert from TX message buffer index to allocated TX ID and vice * versa. */ #define TX_MBIDX_TO_ALLOC_IDX(x) (x - MCUX_FLEXCAN_MAX_RX) #define ALLOC_IDX_TO_TXMB_IDX(x) (x + MCUX_FLEXCAN_MAX_RX) /* Convert from back from FLEXCAN IDs to Zephyr CAN IDs. */ #define FLEXCAN_ID_TO_ZCAN_ID_STD(id) \ ((u32_t)((((u32_t)(id)) & CAN_ID_STD_MASK) >> CAN_ID_STD_SHIFT)) #define FLEXCAN_ID_TO_ZCAN_ID_EXT(id) \ ((u32_t)((((u32_t)(id)) & (CAN_ID_STD_MASK | CAN_ID_EXT_MASK)) \ >> CAN_ID_EXT_SHIFT)) struct mcux_flexcan_config { CAN_Type *base; char *clock_name; clock_control_subsys_t clock_subsys; int clk_source; u32_t bitrate; u32_t sjw; u32_t prop_seg; u32_t phase_seg1; u32_t phase_seg2; void (*irq_config_func)(struct device *dev); }; struct mcux_flexcan_rx_callback { flexcan_rx_mb_config_t mb_config; flexcan_frame_t frame; can_rx_callback_t function; void *arg; }; struct mcux_flexcan_tx_callback { struct k_sem done; int status; flexcan_frame_t frame; can_tx_callback_t function; void *arg; }; struct mcux_flexcan_data { flexcan_handle_t handle; ATOMIC_DEFINE(rx_allocs, MCUX_FLEXCAN_MAX_RX); struct k_mutex rx_mutex; struct mcux_flexcan_rx_callback rx_cbs[MCUX_FLEXCAN_MAX_RX]; ATOMIC_DEFINE(tx_allocs, MCUX_FLEXCAN_MAX_TX); struct k_sem tx_allocs_sem; struct mcux_flexcan_tx_callback tx_cbs[MCUX_FLEXCAN_MAX_TX]; enum can_state state; can_state_change_isr_t state_change_isr; }; #if (!defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_9595) || \ !FSL_FEATURE_FLEXCAN_HAS_ERRATA_9595) static void mcux_flexcan_freeze(struct device *dev) { const struct mcux_flexcan_config *config = dev->config->config_info; /* * Simple freeze implementation without support for * FSL_FEATURE_FLEXCAN_HAS_ERRATA_9595. * * This can be removed once the MCUX FlexCAN driver supports * setting the MCR->LOM and CTRL1->SRXDIS bits or exposes its * internal freeze/unfreeze functions through the API. */ config->base->MCR |= CAN_MCR_FRZ_MASK; config->base->MCR |= CAN_MCR_HALT_MASK; while ((config->base->MCR & CAN_MCR_FRZACK_MASK) == 0U) { } } static void mcux_flexcan_thaw(struct device *dev) { const struct mcux_flexcan_config *config = dev->config->config_info; config->base->MCR &= ~CAN_MCR_HALT_MASK; config->base->MCR &= ~CAN_MCR_FRZ_MASK; while ((config->base->MCR & CAN_MCR_FRZACK_MASK) != 0U) { } } #endif static int mcux_flexcan_configure(struct device *dev, enum can_mode mode, u32_t bitrate) { const struct mcux_flexcan_config *config = dev->config->config_info; flexcan_config_t flexcan_config; struct device *clock_dev; u32_t clock_freq; #if (defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_9595) && \ FSL_FEATURE_FLEXCAN_HAS_ERRATA_9595) if (mode == CAN_SILENT_MODE || mode == CAN_SILENT_LOOPBACK_MODE) { return -ENOTSUP; } #endif clock_dev = device_get_binding(config->clock_name); if (clock_dev == NULL) { return -EINVAL; } if (clock_control_get_rate(clock_dev, config->clock_subsys, &clock_freq)) { return -EINVAL; } FLEXCAN_GetDefaultConfig(&flexcan_config); flexcan_config.clkSrc = config->clk_source; flexcan_config.baudRate = bitrate ? bitrate : config->bitrate; flexcan_config.enableLoopBack = (mode == CAN_LOOPBACK_MODE); flexcan_config.enableIndividMask = true; flexcan_config.timingConfig.rJumpwidth = config->sjw; flexcan_config.timingConfig.propSeg = config->prop_seg; flexcan_config.timingConfig.phaseSeg1 = config->phase_seg1; flexcan_config.timingConfig.phaseSeg2 = config->phase_seg2; FLEXCAN_Init(config->base, &flexcan_config, clock_freq); #if (!defined(FSL_FEATURE_FLEXCAN_HAS_ERRATA_9595) || \ !FSL_FEATURE_FLEXCAN_HAS_ERRATA_9595) mcux_flexcan_freeze(dev); if (mode == CAN_SILENT_MODE || mode == CAN_SILENT_LOOPBACK_MODE) { config->base->CTRL1 |= CAN_CTRL1_LOM(1); } if (mode != CAN_LOOPBACK_MODE && mode != CAN_SILENT_LOOPBACK_MODE) { /* Disable self-reception unless loopback is requested */ config->base->MCR |= CAN_MCR_SRXDIS(1); } mcux_flexcan_thaw(dev); #endif return 0; } static void mcux_flexcan_copy_zframe_to_frame(const struct zcan_frame *src, flexcan_frame_t *dest) { if (src->id_type == CAN_STANDARD_IDENTIFIER) { dest->format = kFLEXCAN_FrameFormatStandard; dest->id = FLEXCAN_ID_STD(src->std_id); } else { dest->format = kFLEXCAN_FrameFormatExtend; dest->id = FLEXCAN_ID_EXT(src->ext_id); } if (src->rtr == CAN_DATAFRAME) { dest->type = kFLEXCAN_FrameTypeData; } else { dest->type = kFLEXCAN_FrameTypeRemote; } dest->length = src->dlc; dest->dataWord0 = sys_cpu_to_be32(src->data_32[0]); dest->dataWord1 = sys_cpu_to_be32(src->data_32[1]); } static void mcux_flexcan_copy_frame_to_zframe(const flexcan_frame_t *src, struct zcan_frame *dest) { if (src->format == kFLEXCAN_FrameFormatStandard) { dest->id_type = CAN_STANDARD_IDENTIFIER; dest->std_id = FLEXCAN_ID_TO_ZCAN_ID_STD(src->id); } else { dest->id_type = CAN_EXTENDED_IDENTIFIER; dest->ext_id = FLEXCAN_ID_TO_ZCAN_ID_EXT(src->id); } if (src->type == kFLEXCAN_FrameTypeData) { dest->rtr = CAN_DATAFRAME; } else { dest->rtr = CAN_REMOTEREQUEST; } dest->dlc = src->length; dest->data_32[0] = sys_be32_to_cpu(src->dataWord0); dest->data_32[1] = sys_be32_to_cpu(src->dataWord1); #ifdef CONFIG_CAN_RX_TIMESTAMP dest->timestamp = src->timestamp; #endif /* CAN_RX_TIMESTAMP */ } static void mcux_flexcan_copy_zfilter_to_mbconfig(const struct zcan_filter *src, flexcan_rx_mb_config_t *dest, u32_t *mask) { if (src->id_type == CAN_STANDARD_IDENTIFIER) { dest->format = kFLEXCAN_FrameFormatStandard; dest->id = FLEXCAN_ID_STD(src->std_id); *mask = FLEXCAN_RX_MB_STD_MASK(src->std_id_mask, src->rtr & src->rtr_mask, 1); } else { dest->format = kFLEXCAN_FrameFormatExtend; dest->id = FLEXCAN_ID_EXT(src->ext_id); *mask = FLEXCAN_RX_MB_EXT_MASK(src->ext_id_mask, src->rtr & src->rtr_mask, 1); } if ((src->rtr & src->rtr_mask) == CAN_DATAFRAME) { dest->type = kFLEXCAN_FrameTypeData; } else { dest->type = kFLEXCAN_FrameTypeRemote; } } /* mcux_get_tx_alloc is a linear on array, and binary on atomic_val_t search * for the highest bit set in data->tx_allocs. 0 is returned in case of an empty * tx_alloc, the next free bit otherwise. * The reason to always use a higher buffer number than the current in use is * that a FIFO manner is kept. The Controller would otherwise send the frame * that is in the lowest buffer number first. */ static int mcux_get_tx_alloc(struct mcux_flexcan_data *data) { atomic_val_t *allocs = data->tx_allocs; atomic_val_t pivot = ATOMIC_BITS / 2; atomic_val_t alloc, mask; int i; for (i = MCUX_N_TX_ALLOC_ELEM - 1; i >= 0; i--) { alloc = allocs[i]; if (alloc) { for (atomic_val_t bits = ATOMIC_BITS / 2U; bits; bits >>= 1) { mask = GENMASK(pivot + bits - 1, pivot); if (alloc & mask) { pivot += bits / 2U; } else { pivot -= bits / 2U; } } if (!(alloc & mask)) { pivot--; } break; } } alloc = alloc ? (pivot + 1 + i * ATOMIC_BITS) : 0; return alloc >= MCUX_FLEXCAN_MAX_TX ? -1 : alloc; } static int mcux_flexcan_send(struct device *dev, const struct zcan_frame *msg, s32_t timeout, can_tx_callback_t callback_isr, void *callback_arg) { const struct mcux_flexcan_config *config = dev->config->config_info; struct mcux_flexcan_data *data = dev->driver_data; flexcan_mb_transfer_t xfer; status_t status; int alloc; if (msg->dlc > CAN_MAX_DLC) { LOG_ERR("DLC of %d exceeds maximum (%d)", msg->dlc, CAN_MAX_DLC); return CAN_TX_EINVAL; } while (true) { alloc = mcux_get_tx_alloc(data); if (alloc >= 0) { if (atomic_test_and_set_bit(data->tx_allocs, alloc)) { continue; } break; } if (k_sem_take(&data->tx_allocs_sem, timeout) != 0) { return CAN_TIMEOUT; } } mcux_flexcan_copy_zframe_to_frame(msg, &data->tx_cbs[alloc].frame); data->tx_cbs[alloc].function = callback_isr; data->tx_cbs[alloc].arg = callback_arg; xfer.frame = &data->tx_cbs[alloc].frame; xfer.mbIdx = ALLOC_IDX_TO_TXMB_IDX(alloc); FLEXCAN_SetTxMbConfig(config->base, xfer.mbIdx, true); status = FLEXCAN_TransferSendNonBlocking(config->base, &data->handle, &xfer); if (status != kStatus_Success) { return CAN_TX_ERR; } if (callback_isr == NULL) { k_sem_take(&data->tx_cbs[alloc].done, K_FOREVER); return data->tx_cbs[alloc].status; } return CAN_TX_OK; } static int mcux_flexcan_attach_isr(struct device *dev, can_rx_callback_t isr, void *callback_arg, const struct zcan_filter *filter) { const struct mcux_flexcan_config *config = dev->config->config_info; struct mcux_flexcan_data *data = dev->driver_data; flexcan_mb_transfer_t xfer; status_t status; u32_t mask; int alloc = CAN_NO_FREE_FILTER; int i; __ASSERT_NO_MSG(isr); k_mutex_lock(&data->rx_mutex, K_FOREVER); /* Find and allocate RX message buffer */ for (i = 0; i < MCUX_FLEXCAN_MAX_RX; i++) { if (!atomic_test_and_set_bit(data->rx_allocs, i)) { alloc = i; break; } } if (alloc == CAN_NO_FREE_FILTER) { return alloc; } mcux_flexcan_copy_zfilter_to_mbconfig(filter, &data->rx_cbs[alloc].mb_config, &mask); data->rx_cbs[alloc].arg = callback_arg; data->rx_cbs[alloc].function = isr; FLEXCAN_SetRxIndividualMask(config->base, ALLOC_IDX_TO_RXMB_IDX(alloc), mask); FLEXCAN_SetRxMbConfig(config->base, ALLOC_IDX_TO_RXMB_IDX(alloc), &data->rx_cbs[alloc].mb_config, true); xfer.frame = &data->rx_cbs[alloc].frame; xfer.mbIdx = ALLOC_IDX_TO_RXMB_IDX(alloc); status = FLEXCAN_TransferReceiveNonBlocking(config->base, &data->handle, &xfer); if (status != kStatus_Success) { LOG_ERR("Failed to start rx for filter id %d (err = %d)", alloc, status); alloc = CAN_NO_FREE_FILTER; } k_mutex_unlock(&data->rx_mutex); return alloc; } static void mcux_flexcan_register_state_change_isr(struct device *dev, can_state_change_isr_t isr) { struct mcux_flexcan_data *data = dev->driver_data; data->state_change_isr = isr; } static enum can_state mcux_flexcan_get_state(struct device *dev, struct can_bus_err_cnt *err_cnt) { const struct mcux_flexcan_config *config = dev->config->config_info; u32_t status_flags; if (err_cnt) { FLEXCAN_GetBusErrCount(config->base, &err_cnt->tx_err_cnt, &err_cnt->rx_err_cnt); } status_flags = (FLEXCAN_GetStatusFlags(config->base) & CAN_ESR1_FLTCONF_MASK) << CAN_ESR1_FLTCONF_SHIFT; if (status_flags & 0x02) { return CAN_BUS_OFF; } if (status_flags & 0x01) { return CAN_ERROR_PASSIVE; } return CAN_ERROR_ACTIVE; } #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY int mcux_flexcan_recover(struct device *dev, s32_t timeout) { const struct mcux_flexcan_config *config = dev->config->config_info; int ret = 0; u64_t start_time; if (mcux_flexcan_get_state(dev, NULL) != CAN_BUS_OFF) { return 0; } start_time = k_uptime_get(); config->base->CTRL1 &= ~CAN_CTRL1_BOFFREC_MASK; if (timeout != K_NO_WAIT) { while (mcux_flexcan_get_state(dev, NULL) == CAN_BUS_OFF) { if (timeout != K_FOREVER && k_uptime_get() - start_time >= timeout) { ret = CAN_TIMEOUT; } } } config->base->CTRL1 |= CAN_CTRL1_BOFFREC_MASK; return ret; } #endif /* CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ static void mcux_flexcan_detach(struct device *dev, int filter_id) { const struct mcux_flexcan_config *config = dev->config->config_info; struct mcux_flexcan_data *data = dev->driver_data; if (filter_id >= MCUX_FLEXCAN_MAX_RX) { LOG_ERR("Detach: Filter id >= MAX_RX (%d >= %d)", filter_id, MCUX_FLEXCAN_MAX_RX); return; } k_mutex_lock(&data->rx_mutex, K_FOREVER); if (atomic_test_and_clear_bit(data->rx_allocs, filter_id)) { FLEXCAN_TransferAbortReceive(config->base, &data->handle, ALLOC_IDX_TO_RXMB_IDX(filter_id)); FLEXCAN_SetRxMbConfig(config->base, ALLOC_IDX_TO_RXMB_IDX(filter_id), NULL, false); data->rx_cbs[filter_id].function = NULL; data->rx_cbs[filter_id].arg = NULL; } else { LOG_WRN("Filter ID %d already detached", filter_id); } k_mutex_unlock(&data->rx_mutex); } static inline void mcux_flexcan_transfer_error_status(struct device *dev, u32_t error) { const struct mcux_flexcan_config *config = dev->config->config_info; struct mcux_flexcan_data *data = dev->driver_data; can_tx_callback_t function; int status = CAN_TX_OK; void *arg; int alloc; enum can_state state; struct can_bus_err_cnt err_cnt; if (error & CAN_ESR1_FLTCONF(2)) { LOG_DBG("Tx bus off (error 0x%08x)", error); status = CAN_TX_BUS_OFF; } else if ((error & kFLEXCAN_Bit0Error) || (error & kFLEXCAN_Bit1Error)) { LOG_DBG("TX arbitration lost (error 0x%08x)", error); status = CAN_TX_ARB_LOST; } else if (error & kFLEXCAN_AckError) { LOG_DBG("TX no ACK received (error 0x%08x)", error); status = CAN_TX_ERR; } else if (error & kFLEXCAN_StuffingError) { LOG_DBG("RX stuffing error (error 0x%08x)", error); } else if (error & kFLEXCAN_FormError) { LOG_DBG("RX form error (error 0x%08x)", error); } else if (error & kFLEXCAN_CrcError) { LOG_DBG("RX CRC error (error 0x%08x)", error); } else { LOG_DBG("Unhandled error (error 0x%08x)", error); } state = mcux_flexcan_get_state(dev, &err_cnt); if (data->state != state) { data->state = state; if (data->state_change_isr) { data->state_change_isr(state, err_cnt); } } if (status == CAN_TX_OK) { /* * Error/status is not TX related. No further action * required. */ return; } /* * Since the FlexCAN module ESR1 register accumulates errors * and warnings across multiple transmitted frames (until the * CPU reads the register) it is not possible to find out * which transfer caused the error/warning. * * We therefore propagate the error/warning to all currently * active transmitters. */ for (alloc = 0; alloc < MCUX_FLEXCAN_MAX_TX; alloc++) { /* Copy callback function and argument before clearing bit */ function = data->tx_cbs[alloc].function; arg = data->tx_cbs[alloc].arg; if (atomic_test_and_clear_bit(data->tx_allocs, alloc)) { FLEXCAN_TransferAbortSend(config->base, &data->handle, ALLOC_IDX_TO_TXMB_IDX(alloc)); if (function != NULL) { function(status, arg); } else { data->tx_cbs[alloc].status = status; k_sem_give(&data->tx_cbs[alloc].done); } k_sem_give(&data->tx_allocs_sem); } } } static inline void mcux_flexcan_transfer_tx_idle(struct device *dev, u32_t mb) { struct mcux_flexcan_data *data = dev->driver_data; can_tx_callback_t function; void *arg; int alloc; alloc = TX_MBIDX_TO_ALLOC_IDX(mb); /* Copy callback function and argument before clearing bit */ function = data->tx_cbs[alloc].function; arg = data->tx_cbs[alloc].arg; if (atomic_test_and_clear_bit(data->tx_allocs, alloc)) { if (function != NULL) { function(CAN_TX_OK, arg); } else { data->tx_cbs[alloc].status = CAN_TX_OK; k_sem_give(&data->tx_cbs[alloc].done); } k_sem_give(&data->tx_allocs_sem); } } static inline void mcux_flexcan_transfer_rx_idle(struct device *dev, u32_t mb) { const struct mcux_flexcan_config *config = dev->config->config_info; struct mcux_flexcan_data *data = dev->driver_data; can_rx_callback_t function; flexcan_mb_transfer_t xfer; struct zcan_frame frame; status_t status; void *arg; int alloc; alloc = RX_MBIDX_TO_ALLOC_IDX(mb); function = data->rx_cbs[alloc].function; arg = data->rx_cbs[alloc].arg; if (atomic_test_bit(data->rx_allocs, alloc)) { mcux_flexcan_copy_frame_to_zframe(&data->rx_cbs[alloc].frame, &frame); function(&frame, arg); /* Setup RX message buffer to receive next message */ FLEXCAN_SetRxMbConfig(config->base, mb, &data->rx_cbs[alloc].mb_config, true); xfer.frame = &data->rx_cbs[alloc].frame; xfer.mbIdx = mb; status = FLEXCAN_TransferReceiveNonBlocking(config->base, &data->handle, &xfer); if (status != kStatus_Success) { LOG_ERR("Failed to restart rx for filter id %d " "(err = %d)", alloc, status); } } } static void mcux_flexcan_transfer_callback(CAN_Type *base, flexcan_handle_t *handle, status_t status, u32_t result, void *userData) { struct device *dev = (struct device *)userData; switch (status) { case kStatus_FLEXCAN_ErrorStatus: mcux_flexcan_transfer_error_status(dev, result); break; case kStatus_FLEXCAN_TxSwitchToRx: /* fallthrough */ case kStatus_FLEXCAN_TxIdle: mcux_flexcan_transfer_tx_idle(dev, result); break; case kStatus_FLEXCAN_RxIdle: mcux_flexcan_transfer_rx_idle(dev, result); break; default: LOG_WRN("Unhandled error/status (status 0x%08x, " "result = 0x%08x", status, result); } } static void mcux_flexcan_isr(void *arg) { struct device *dev = (struct device *)arg; const struct mcux_flexcan_config *config = dev->config->config_info; struct mcux_flexcan_data *data = dev->driver_data; FLEXCAN_TransferHandleIRQ(config->base, &data->handle); } static int mcux_flexcan_init(struct device *dev) { const struct mcux_flexcan_config *config = dev->config->config_info; struct mcux_flexcan_data *data = dev->driver_data; int err; int i; k_mutex_init(&data->rx_mutex); k_sem_init(&data->tx_allocs_sem, 0, 1); for (i = 0; i < ARRAY_SIZE(data->tx_cbs); i++) { k_sem_init(&data->tx_cbs[i].done, 0, 1); } err = mcux_flexcan_configure(dev, CAN_NORMAL_MODE, 0); if (err) { return err; } FLEXCAN_TransferCreateHandle(config->base, &data->handle, mcux_flexcan_transfer_callback, dev); config->irq_config_func(dev); #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY config->base->CTRL1 |= CAN_CTRL1_BOFFREC_MASK; #endif /* CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */ data->state = mcux_flexcan_get_state(dev, NULL); return 0; } static const struct can_driver_api mcux_flexcan_driver_api = { .configure = mcux_flexcan_configure, .send = mcux_flexcan_send, .attach_isr = mcux_flexcan_attach_isr, .detach = mcux_flexcan_detach, .get_state = mcux_flexcan_get_state, #ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY .recover = mcux_flexcan_recover, #endif .register_state_change_isr = mcux_flexcan_register_state_change_isr }; #ifdef CONFIG_CAN_0 static void mcux_flexcan_config_func_0(struct device *dev); static const struct mcux_flexcan_config mcux_flexcan_config_0 = { .base = (CAN_Type *) DT_INST_0_NXP_KINETIS_FLEXCAN_BASE_ADDRESS, .clock_name = DT_INST_0_NXP_KINETIS_FLEXCAN_CLOCK_CONTROLLER, .clock_subsys = (clock_control_subsys_t) DT_INST_0_NXP_KINETIS_FLEXCAN_CLOCK_NAME, .clk_source = DT_INST_0_NXP_KINETIS_FLEXCAN_CLK_SOURCE, .bitrate = DT_INST_0_NXP_KINETIS_FLEXCAN_BUS_SPEED, .sjw = DT_INST_0_NXP_KINETIS_FLEXCAN_SJW, .prop_seg = DT_INST_0_NXP_KINETIS_FLEXCAN_PROP_SEG, .phase_seg1 = DT_INST_0_NXP_KINETIS_FLEXCAN_PHASE_SEG1, .phase_seg2 = DT_INST_0_NXP_KINETIS_FLEXCAN_PHASE_SEG2, .irq_config_func = mcux_flexcan_config_func_0, }; static struct mcux_flexcan_data mcux_flexcan_data_0 = { }; DEVICE_AND_API_INIT(can_mcux_flexcan_0, DT_INST_0_NXP_KINETIS_FLEXCAN_LABEL, &mcux_flexcan_init, &mcux_flexcan_data_0, &mcux_flexcan_config_0, POST_KERNEL, CONFIG_CAN_INIT_PRIORITY, &mcux_flexcan_driver_api); static void mcux_flexcan_config_func_0(struct device *dev) { #ifdef DT_INST_0_NXP_KINETIS_FLEXCAN_IRQ_RX_WARNING IRQ_CONNECT(DT_INST_0_NXP_KINETIS_FLEXCAN_IRQ_RX_WARNING, DT_INST_0_NXP_KINETIS_FLEXCAN_IRQ_RX_WARNING_PRIORITY, mcux_flexcan_isr, DEVICE_GET(can_mcux_flexcan_0), 0); irq_enable(DT_INST_0_NXP_KINETIS_FLEXCAN_IRQ_RX_WARNING); #endif #ifdef DT_INST_0_NXP_KINETIS_FLEXCAN_IRQ_TX_WARNING IRQ_CONNECT(DT_INST_0_NXP_KINETIS_FLEXCAN_IRQ_TX_WARNING, DT_INST_0_NXP_KINETIS_FLEXCAN_IRQ_TX_WARNING_PRIORITY, mcux_flexcan_isr, DEVICE_GET(can_mcux_flexcan_0), 0); irq_enable(DT_INST_0_NXP_KINETIS_FLEXCAN_IRQ_TX_WARNING); #endif #ifdef DT_INST_0_NXP_KINETIS_FLEXCAN_IRQ_BUS_OFF IRQ_CONNECT(DT_INST_0_NXP_KINETIS_FLEXCAN_IRQ_BUS_OFF, DT_INST_0_NXP_KINETIS_FLEXCAN_IRQ_BUS_OFF_PRIORITY, mcux_flexcan_isr, DEVICE_GET(can_mcux_flexcan_0), 0); irq_enable(DT_INST_0_NXP_KINETIS_FLEXCAN_IRQ_BUS_OFF); #endif #ifdef DT_INST_0_NXP_KINETIS_FLEXCAN_IRQ_WARNING IRQ_CONNECT(DT_INST_0_NXP_KINETIS_FLEXCAN_IRQ_WARNING, DT_INST_0_NXP_KINETIS_FLEXCAN_IRQ_WARNING_PRIORITY, mcux_flexcan_isr, DEVICE_GET(can_mcux_flexcan_0), 0); irq_enable(DT_INST_0_NXP_KINETIS_FLEXCAN_IRQ_WARNING); #endif IRQ_CONNECT(DT_INST_0_NXP_KINETIS_FLEXCAN_IRQ_ERROR, DT_INST_0_NXP_KINETIS_FLEXCAN_IRQ_ERROR_PRIORITY, mcux_flexcan_isr, DEVICE_GET(can_mcux_flexcan_0), 0); irq_enable(DT_INST_0_NXP_KINETIS_FLEXCAN_IRQ_ERROR); IRQ_CONNECT(DT_INST_0_NXP_KINETIS_FLEXCAN_IRQ_WAKE_UP, DT_INST_0_NXP_KINETIS_FLEXCAN_IRQ_WAKE_UP_PRIORITY, mcux_flexcan_isr, DEVICE_GET(can_mcux_flexcan_0), 0); irq_enable(DT_INST_0_NXP_KINETIS_FLEXCAN_IRQ_WAKE_UP); IRQ_CONNECT(DT_INST_0_NXP_KINETIS_FLEXCAN_IRQ_MB_0_15, DT_INST_0_NXP_KINETIS_FLEXCAN_IRQ_MB_0_15_PRIORITY, mcux_flexcan_isr, DEVICE_GET(can_mcux_flexcan_0), 0); irq_enable(DT_INST_0_NXP_KINETIS_FLEXCAN_IRQ_MB_0_15); } #endif /* CONFIG_CAN_0 */ #ifdef CONFIG_CAN_1 static void mcux_flexcan_config_func_1(struct device *dev); static const struct mcux_flexcan_config mcux_flexcan_config_1 = { .base = (CAN_Type *) DT_INST_1_NXP_KINETIS_FLEXCAN_BASE_ADDRESS, .clock_name = DT_INST_1_NXP_KINETIS_FLEXCAN_CLOCK_CONTROLLER, .clock_subsys = (clock_control_subsys_t) DT_INST_1_NXP_KINETIS_FLEXCAN_CLOCK_NAME, .clk_source = DT_INST_1_NXP_KINETIS_FLEXCAN_CLK_SOURCE, .bitrate = DT_INST_1_NXP_KINETIS_FLEXCAN_BUS_SPEED, .sjw = DT_INST_1_NXP_KINETIS_FLEXCAN_SJW, .prop_seg = DT_INST_1_NXP_KINETIS_FLEXCAN_PROP_SEG, .phase_seg1 = DT_INST_1_NXP_KINETIS_FLEXCAN_PHASE_SEG1, .phase_seg2 = DT_INST_1_NXP_KINETIS_FLEXCAN_PHASE_SEG2, .irq_config_func = mcux_flexcan_config_func_1, }; static struct mcux_flexcan_data mcux_flexcan_data_1 = { }; DEVICE_AND_API_INIT(can_mcux_flexcan_1, DT_INST_1_NXP_KINETIS_FLEXCAN_LABEL, &mcux_flexcan_init, &mcux_flexcan_data_1, &mcux_flexcan_config_1, POST_KERNEL, CONFIG_CAN_INIT_PRIORITY, &mcux_flexcan_driver_api); static void mcux_flexcan_config_func_1(struct device *dev) { IRQ_CONNECT(DT_INST_1_NXP_KINETIS_FLEXCAN_IRQ_WARNING, DT_INST_1_NXP_KINETIS_FLEXCAN_IRQ_WARNING_PRIORITY, mcux_flexcan_isr, DEVICE_GET(can_mcux_flexcan_1), 0); irq_enable(DT_INST_1_NXP_KINETIS_FLEXCAN_IRQ_WARNING); IRQ_CONNECT(DT_INST_1_NXP_KINETIS_FLEXCAN_IRQ_ERROR, DT_INST_1_NXP_KINETIS_FLEXCAN_IRQ_ERROR_PRIORITY, mcux_flexcan_isr, DEVICE_GET(can_mcux_flexcan_1), 0); irq_enable(DT_INST_1_NXP_KINETIS_FLEXCAN_IRQ_ERROR); IRQ_CONNECT(DT_INST_1_NXP_KINETIS_FLEXCAN_IRQ_WAKE_UP, DT_INST_1_NXP_KINETIS_FLEXCAN_IRQ_WAKE_UP_PRIORITY, mcux_flexcan_isr, DEVICE_GET(can_mcux_flexcan_1), 0); irq_enable(DT_INST_1_NXP_KINETIS_FLEXCAN_IRQ_WAKE_UP); IRQ_CONNECT(DT_INST_1_NXP_KINETIS_FLEXCAN_IRQ_MB_0_15, DT_INST_1_NXP_KINETIS_FLEXCAN_IRQ_MB_0_15_PRIORITY, mcux_flexcan_isr, DEVICE_GET(can_mcux_flexcan_1), 0); irq_enable(DT_INST_1_NXP_KINETIS_FLEXCAN_IRQ_MB_0_15); } #endif /* CONFIG_CAN_1 */