2021-02-11 20:07:04 +01:00
|
|
|
/*
|
2023-05-02 13:24:18 +02:00
|
|
|
* Copyright (c) 2022-2023 Vestas Wind Systems A/S
|
2021-02-11 20:07:04 +01:00
|
|
|
* Copyright (c) 2020 Alexander Wachter
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
2022-05-06 10:25:46 +02:00
|
|
|
#include <zephyr/drivers/can.h>
|
2023-06-01 15:30:53 +02:00
|
|
|
#include <zephyr/drivers/can/can_mcan.h>
|
2022-05-06 10:25:46 +02:00
|
|
|
#include <zephyr/drivers/can/transceiver.h>
|
2023-04-24 22:27:48 +02:00
|
|
|
#include <zephyr/kernel.h>
|
2022-05-06 10:25:46 +02:00
|
|
|
#include <zephyr/logging/log.h>
|
2023-05-02 13:24:18 +02:00
|
|
|
#include <zephyr/sys/sys_io.h>
|
2023-04-24 22:27:48 +02:00
|
|
|
#include <zephyr/sys/util.h>
|
2022-02-22 12:06:54 +01:00
|
|
|
|
|
|
|
LOG_MODULE_REGISTER(can_mcan, CONFIG_CAN_LOG_LEVEL);
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
#define CAN_INIT_TIMEOUT_MS 100
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2023-05-04 12:41:32 +02:00
|
|
|
int can_mcan_read_reg(const struct device *dev, uint16_t reg, uint32_t *val)
|
2023-05-02 13:24:18 +02:00
|
|
|
{
|
|
|
|
const struct can_mcan_config *config = dev->config;
|
2023-05-04 11:14:31 +02:00
|
|
|
int err;
|
2023-05-02 13:24:18 +02:00
|
|
|
|
2023-05-10 22:07:42 +02:00
|
|
|
err = config->ops->read_reg(dev, reg, val);
|
2023-05-04 11:14:31 +02:00
|
|
|
if (err != 0) {
|
|
|
|
LOG_ERR("failed to read reg 0x%03x (err %d)", reg, err);
|
|
|
|
}
|
2023-05-02 13:24:18 +02:00
|
|
|
|
2023-05-04 11:14:31 +02:00
|
|
|
return err;
|
2023-05-02 13:24:18 +02:00
|
|
|
}
|
|
|
|
|
2023-05-04 12:41:32 +02:00
|
|
|
int can_mcan_write_reg(const struct device *dev, uint16_t reg, uint32_t val)
|
2021-02-11 20:07:04 +01:00
|
|
|
{
|
2023-04-24 14:43:51 +02:00
|
|
|
const struct can_mcan_config *config = dev->config;
|
2023-05-04 11:14:31 +02:00
|
|
|
int err;
|
2023-05-02 13:24:18 +02:00
|
|
|
|
2023-05-10 22:07:42 +02:00
|
|
|
err = config->ops->write_reg(dev, reg, val);
|
2023-05-04 11:14:31 +02:00
|
|
|
if (err != 0) {
|
|
|
|
LOG_ERR("failed to write reg 0x%03x (err %d)", reg, err);
|
|
|
|
}
|
2023-05-02 13:24:18 +02:00
|
|
|
|
2023-05-04 11:14:31 +02:00
|
|
|
return err;
|
2023-05-02 13:24:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int can_mcan_exit_sleep_mode(const struct device *dev)
|
|
|
|
{
|
|
|
|
struct can_mcan_data *data = dev->data;
|
2021-02-11 20:07:04 +01:00
|
|
|
uint32_t start_time;
|
2023-05-02 13:24:18 +02:00
|
|
|
uint32_t cccr;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
k_mutex_lock(&data->lock, K_FOREVER);
|
|
|
|
|
|
|
|
err = can_mcan_read_reg(dev, CAN_MCAN_CCCR, &cccr);
|
|
|
|
if (err != 0) {
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
cccr &= ~CAN_MCAN_CCCR_CSR;
|
|
|
|
|
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_CCCR, cccr);
|
|
|
|
if (err != 0) {
|
|
|
|
goto unlock;
|
|
|
|
}
|
2021-02-11 20:07:04 +01:00
|
|
|
|
|
|
|
start_time = k_cycle_get_32();
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_read_reg(dev, CAN_MCAN_CCCR, &cccr);
|
|
|
|
if (err != 0) {
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((cccr & CAN_MCAN_CCCR_CSA) == CAN_MCAN_CCCR_CSA) {
|
|
|
|
if (k_cycle_get_32() - start_time > k_ms_to_cyc_ceil32(CAN_INIT_TIMEOUT_MS)) {
|
|
|
|
cccr |= CAN_MCAN_CCCR_CSR;
|
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_CCCR, cccr);
|
|
|
|
if (err != 0) {
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = -EAGAIN;
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = can_mcan_read_reg(dev, CAN_MCAN_CCCR, &cccr);
|
|
|
|
if (err != 0) {
|
|
|
|
goto unlock;
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
|
|
|
|
unlock:
|
|
|
|
k_mutex_unlock(&data->lock);
|
|
|
|
|
|
|
|
return err;
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2023-04-24 14:17:19 +02:00
|
|
|
static int can_mcan_enter_init_mode(const struct device *dev, k_timeout_t timeout)
|
2021-02-11 20:07:04 +01:00
|
|
|
{
|
2023-05-02 13:24:18 +02:00
|
|
|
struct can_mcan_data *data = dev->data;
|
2021-02-11 20:07:04 +01:00
|
|
|
int64_t start_time;
|
2023-05-02 13:24:18 +02:00
|
|
|
uint32_t cccr;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
k_mutex_lock(&data->lock, K_FOREVER);
|
|
|
|
|
|
|
|
err = can_mcan_read_reg(dev, CAN_MCAN_CCCR, &cccr);
|
|
|
|
if (err != 0) {
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
cccr |= CAN_MCAN_CCCR_INIT;
|
|
|
|
|
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_CCCR, cccr);
|
|
|
|
if (err != 0) {
|
|
|
|
goto unlock;
|
|
|
|
}
|
2021-02-11 20:07:04 +01:00
|
|
|
|
|
|
|
start_time = k_uptime_ticks();
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_read_reg(dev, CAN_MCAN_CCCR, &cccr);
|
|
|
|
if (err != 0) {
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((cccr & CAN_MCAN_CCCR_INIT) == 0U) {
|
2021-02-11 20:07:04 +01:00
|
|
|
if (k_uptime_ticks() - start_time > timeout.ticks) {
|
2023-05-02 13:24:18 +02:00
|
|
|
cccr &= ~CAN_MCAN_CCCR_INIT;
|
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_CCCR, cccr);
|
|
|
|
if (err != 0) {
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = -EAGAIN;
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = can_mcan_read_reg(dev, CAN_MCAN_CCCR, &cccr);
|
|
|
|
if (err != 0) {
|
|
|
|
goto unlock;
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
unlock:
|
|
|
|
k_mutex_unlock(&data->lock);
|
|
|
|
|
|
|
|
return err;
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2023-04-24 14:17:19 +02:00
|
|
|
static int can_mcan_leave_init_mode(const struct device *dev, k_timeout_t timeout)
|
2021-02-11 20:07:04 +01:00
|
|
|
{
|
2023-05-02 13:24:18 +02:00
|
|
|
struct can_mcan_data *data = dev->data;
|
2021-02-11 20:07:04 +01:00
|
|
|
int64_t start_time;
|
2023-05-02 13:24:18 +02:00
|
|
|
uint32_t cccr;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
k_mutex_lock(&data->lock, K_FOREVER);
|
|
|
|
|
|
|
|
err = can_mcan_read_reg(dev, CAN_MCAN_CCCR, &cccr);
|
|
|
|
if (err != 0) {
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
cccr &= ~CAN_MCAN_CCCR_INIT;
|
|
|
|
|
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_CCCR, cccr);
|
|
|
|
if (err != 0) {
|
|
|
|
goto unlock;
|
|
|
|
}
|
2021-02-11 20:07:04 +01:00
|
|
|
|
|
|
|
start_time = k_uptime_ticks();
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_read_reg(dev, CAN_MCAN_CCCR, &cccr);
|
|
|
|
if (err != 0) {
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((cccr & CAN_MCAN_CCCR_INIT) != 0U) {
|
2021-02-11 20:07:04 +01:00
|
|
|
if (k_uptime_ticks() - start_time > timeout.ticks) {
|
2023-05-02 13:24:18 +02:00
|
|
|
err = -EAGAIN;
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = can_mcan_read_reg(dev, CAN_MCAN_CCCR, &cccr);
|
|
|
|
if (err != 0) {
|
|
|
|
goto unlock;
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
unlock:
|
|
|
|
k_mutex_unlock(&data->lock);
|
|
|
|
|
|
|
|
return err;
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2023-04-24 14:40:02 +02:00
|
|
|
int can_mcan_set_timing(const struct device *dev, const struct can_timing *timing)
|
2021-02-11 20:07:04 +01:00
|
|
|
{
|
2023-04-24 14:40:02 +02:00
|
|
|
struct can_mcan_data *data = dev->data;
|
2023-05-02 13:24:18 +02:00
|
|
|
uint32_t nbtp = 0U;
|
|
|
|
int err;
|
2023-04-24 14:13:47 +02:00
|
|
|
|
2024-01-17 19:52:24 +01:00
|
|
|
if (data->common.started) {
|
2023-04-24 14:40:02 +02:00
|
|
|
return -EBUSY;
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
k_mutex_lock(&data->lock, K_FOREVER);
|
2022-05-03 22:05:53 +02:00
|
|
|
|
2023-09-22 12:07:16 +02:00
|
|
|
nbtp |= FIELD_PREP(CAN_MCAN_NBTP_NSJW, timing->sjw - 1UL) |
|
|
|
|
FIELD_PREP(CAN_MCAN_NBTP_NTSEG1, timing->phase_seg1 - 1UL) |
|
2023-05-02 13:24:18 +02:00
|
|
|
FIELD_PREP(CAN_MCAN_NBTP_NTSEG2, timing->phase_seg2 - 1UL) |
|
|
|
|
FIELD_PREP(CAN_MCAN_NBTP_NBRP, timing->prescaler - 1UL);
|
|
|
|
|
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_NBTP, nbtp);
|
|
|
|
if (err != 0) {
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
unlock:
|
|
|
|
k_mutex_unlock(&data->lock);
|
|
|
|
|
|
|
|
return err;
|
2022-05-03 22:05:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_CAN_FD_MODE
|
2023-04-24 14:22:14 +02:00
|
|
|
int can_mcan_set_timing_data(const struct device *dev, const struct can_timing *timing_data)
|
2021-02-11 20:07:04 +01:00
|
|
|
{
|
2024-03-10 18:28:18 +01:00
|
|
|
const uint8_t tdco_max = FIELD_GET(CAN_MCAN_TDCR_TDCO, CAN_MCAN_TDCR_TDCO);
|
2022-08-31 14:28:42 +02:00
|
|
|
struct can_mcan_data *data = dev->data;
|
2023-05-02 13:24:18 +02:00
|
|
|
uint32_t dbtp = 0U;
|
2024-03-10 18:28:18 +01:00
|
|
|
uint8_t tdco;
|
2023-05-02 13:24:18 +02:00
|
|
|
int err;
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2024-01-17 19:52:24 +01:00
|
|
|
if (data->common.started) {
|
2022-08-31 14:28:42 +02:00
|
|
|
return -EBUSY;
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
k_mutex_lock(&data->lock, K_FOREVER);
|
2023-04-24 14:40:02 +02:00
|
|
|
|
2023-09-22 12:07:16 +02:00
|
|
|
dbtp |= FIELD_PREP(CAN_MCAN_DBTP_DSJW, timing_data->sjw - 1UL) |
|
|
|
|
FIELD_PREP(CAN_MCAN_DBTP_DTSEG1, timing_data->phase_seg1 - 1UL) |
|
2023-05-02 13:24:18 +02:00
|
|
|
FIELD_PREP(CAN_MCAN_DBTP_DTSEG2, timing_data->phase_seg2 - 1UL) |
|
|
|
|
FIELD_PREP(CAN_MCAN_DBTP_DBRP, timing_data->prescaler - 1UL);
|
|
|
|
|
2024-03-10 18:28:18 +01:00
|
|
|
if (timing_data->prescaler == 1U || timing_data->prescaler == 2U) {
|
|
|
|
/* TDC can only be enabled if DBRP = { 0, 1 } */
|
|
|
|
dbtp |= CAN_MCAN_DBTP_TDC;
|
|
|
|
|
|
|
|
/* Set TDC offset for correct location of the Secondary Sample Point (SSP) */
|
|
|
|
tdco = CAN_CALC_TDCO(timing_data, 0U, tdco_max);
|
|
|
|
LOG_DBG("TDC enabled, using TDCO %u", tdco);
|
|
|
|
|
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_TDCR, FIELD_PREP(CAN_MCAN_TDCR_TDCO, tdco));
|
|
|
|
if (err != 0) {
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
LOG_DBG("TDC cannot be enabled, prescaler value %u too high",
|
|
|
|
timing_data->prescaler);
|
|
|
|
}
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_DBTP, dbtp);
|
|
|
|
if (err != 0) {
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
unlock:
|
|
|
|
k_mutex_unlock(&data->lock);
|
|
|
|
|
|
|
|
return err;
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
2022-05-03 22:05:53 +02:00
|
|
|
#endif /* CONFIG_CAN_FD_MODE */
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2022-07-12 16:36:20 +02:00
|
|
|
int can_mcan_get_capabilities(const struct device *dev, can_mode_t *cap)
|
|
|
|
{
|
|
|
|
ARG_UNUSED(dev);
|
|
|
|
|
|
|
|
*cap = CAN_MODE_NORMAL | CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY;
|
|
|
|
|
2024-02-14 22:38:34 +01:00
|
|
|
if (IS_ENABLED(CONFIG_CAN_MANUAL_RECOVERY_MODE)) {
|
|
|
|
*cap |= CAN_MODE_MANUAL_RECOVERY;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_CAN_FD_MODE)) {
|
|
|
|
*cap |= CAN_MODE_FD;
|
|
|
|
}
|
2022-07-12 16:36:20 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-08-31 14:28:42 +02:00
|
|
|
int can_mcan_start(const struct device *dev)
|
2021-02-11 20:07:04 +01:00
|
|
|
{
|
2023-04-24 14:43:51 +02:00
|
|
|
const struct can_mcan_config *config = dev->config;
|
2022-08-31 14:28:42 +02:00
|
|
|
struct can_mcan_data *data = dev->data;
|
2023-05-02 13:24:18 +02:00
|
|
|
int err;
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2024-01-17 19:52:24 +01:00
|
|
|
if (data->common.started) {
|
2022-08-31 14:28:42 +02:00
|
|
|
return -EALREADY;
|
2022-05-05 11:28:30 +02:00
|
|
|
}
|
|
|
|
|
2024-01-17 19:52:24 +01:00
|
|
|
if (config->common.phy != NULL) {
|
2024-01-24 14:09:31 +01:00
|
|
|
err = can_transceiver_enable(config->common.phy, data->common.mode);
|
2023-05-02 13:24:18 +02:00
|
|
|
if (err != 0) {
|
|
|
|
LOG_ERR("failed to enable CAN transceiver (err %d)", err);
|
|
|
|
return err;
|
2022-03-01 16:02:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-18 03:42:16 +02:00
|
|
|
/* Reset statistics */
|
|
|
|
CAN_STATS_RESET(dev);
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_leave_init_mode(dev, K_MSEC(CAN_INIT_TIMEOUT_MS));
|
|
|
|
if (err != 0) {
|
2022-08-31 14:28:42 +02:00
|
|
|
LOG_ERR("failed to leave init mode");
|
2022-03-01 16:02:08 +01:00
|
|
|
|
2024-01-17 19:52:24 +01:00
|
|
|
if (config->common.phy != NULL) {
|
2022-03-01 16:02:08 +01:00
|
|
|
/* Attempt to disable the CAN transceiver in case of error */
|
2024-01-17 19:52:24 +01:00
|
|
|
(void)can_transceiver_disable(config->common.phy);
|
2022-03-01 16:02:08 +01:00
|
|
|
}
|
|
|
|
|
2021-02-11 20:07:04 +01:00
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
2024-01-17 19:52:24 +01:00
|
|
|
data->common.started = true;
|
2022-08-31 14:28:42 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int can_mcan_stop(const struct device *dev)
|
|
|
|
{
|
2023-04-24 14:43:51 +02:00
|
|
|
const struct can_mcan_config *config = dev->config;
|
2023-05-22 16:31:09 +02:00
|
|
|
const struct can_mcan_callbacks *cbs = config->callbacks;
|
2022-08-31 14:28:42 +02:00
|
|
|
struct can_mcan_data *data = dev->data;
|
2022-09-21 16:07:26 +02:00
|
|
|
can_tx_callback_t tx_cb;
|
|
|
|
uint32_t tx_idx;
|
2023-05-02 13:24:18 +02:00
|
|
|
int err;
|
2022-08-31 14:28:42 +02:00
|
|
|
|
2024-01-17 19:52:24 +01:00
|
|
|
if (!data->common.started) {
|
2022-08-31 14:28:42 +02:00
|
|
|
return -EALREADY;
|
|
|
|
}
|
|
|
|
|
2022-09-21 16:07:26 +02:00
|
|
|
/* CAN transmissions are automatically stopped when entering init mode */
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_enter_init_mode(dev, K_MSEC(CAN_INIT_TIMEOUT_MS));
|
|
|
|
if (err != 0) {
|
2022-08-31 14:28:42 +02:00
|
|
|
LOG_ERR("Failed to enter init mode");
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
2024-01-17 19:52:24 +01:00
|
|
|
if (config->common.phy != NULL) {
|
|
|
|
err = can_transceiver_disable(config->common.phy);
|
2023-05-02 13:24:18 +02:00
|
|
|
if (err != 0) {
|
|
|
|
LOG_ERR("failed to disable CAN transceiver (err %d)", err);
|
|
|
|
return err;
|
2022-08-31 14:28:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
can_mcan_enable_configuration_change(dev);
|
|
|
|
|
2024-01-17 19:52:24 +01:00
|
|
|
data->common.started = false;
|
2022-08-31 14:28:42 +02:00
|
|
|
|
2023-05-22 16:31:09 +02:00
|
|
|
for (tx_idx = 0U; tx_idx < cbs->num_tx; tx_idx++) {
|
|
|
|
tx_cb = cbs->tx[tx_idx].function;
|
2022-09-21 16:07:26 +02:00
|
|
|
|
|
|
|
if (tx_cb != NULL) {
|
2023-05-22 16:31:09 +02:00
|
|
|
cbs->tx[tx_idx].function = NULL;
|
|
|
|
tx_cb(dev, -ENETDOWN, cbs->tx[tx_idx].user_data);
|
2022-09-21 16:07:26 +02:00
|
|
|
k_sem_give(&data->tx_sem);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-31 14:28:42 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int can_mcan_set_mode(const struct device *dev, can_mode_t mode)
|
|
|
|
{
|
2024-02-14 22:38:34 +01:00
|
|
|
can_mode_t supported = CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY;
|
2022-08-31 14:28:42 +02:00
|
|
|
struct can_mcan_data *data = dev->data;
|
2023-05-02 13:24:18 +02:00
|
|
|
uint32_t cccr;
|
|
|
|
uint32_t test;
|
|
|
|
int err;
|
2022-08-31 14:28:42 +02:00
|
|
|
|
2024-02-14 22:38:34 +01:00
|
|
|
if (IS_ENABLED(CONFIG_CAN_MANUAL_RECOVERY_MODE)) {
|
|
|
|
supported |= CAN_MODE_MANUAL_RECOVERY;
|
2022-08-31 14:28:42 +02:00
|
|
|
}
|
2024-02-14 22:38:34 +01:00
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_CAN_FD_MODE)) {
|
|
|
|
supported |= CAN_MODE_FD;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((mode & ~(supported)) != 0U) {
|
2022-08-31 14:28:42 +02:00
|
|
|
LOG_ERR("unsupported mode: 0x%08x", mode);
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
2024-01-17 19:52:24 +01:00
|
|
|
if (data->common.started) {
|
2022-08-31 14:28:42 +02:00
|
|
|
return -EBUSY;
|
|
|
|
}
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
k_mutex_lock(&data->lock, K_FOREVER);
|
|
|
|
|
|
|
|
err = can_mcan_read_reg(dev, CAN_MCAN_CCCR, &cccr);
|
|
|
|
if (err != 0) {
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = can_mcan_read_reg(dev, CAN_MCAN_TEST, &test);
|
|
|
|
if (err != 0) {
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
2022-05-05 11:28:30 +02:00
|
|
|
if ((mode & CAN_MODE_LOOPBACK) != 0) {
|
|
|
|
/* Loopback mode */
|
2023-05-02 13:24:18 +02:00
|
|
|
cccr |= CAN_MCAN_CCCR_TEST;
|
|
|
|
test |= CAN_MCAN_TEST_LBCK;
|
2022-05-05 11:28:30 +02:00
|
|
|
} else {
|
2023-05-02 13:24:18 +02:00
|
|
|
cccr &= ~CAN_MCAN_CCCR_TEST;
|
2022-05-05 11:28:30 +02:00
|
|
|
}
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2022-05-05 11:28:30 +02:00
|
|
|
if ((mode & CAN_MODE_LISTENONLY) != 0) {
|
|
|
|
/* Bus monitoring mode */
|
2023-05-02 13:24:18 +02:00
|
|
|
cccr |= CAN_MCAN_CCCR_MON;
|
2022-05-05 11:28:30 +02:00
|
|
|
} else {
|
2023-05-02 13:24:18 +02:00
|
|
|
cccr &= ~CAN_MCAN_CCCR_MON;
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2022-05-05 13:46:43 +02:00
|
|
|
#ifdef CONFIG_CAN_FD_MODE
|
|
|
|
if ((mode & CAN_MODE_FD) != 0) {
|
2023-05-02 13:24:18 +02:00
|
|
|
cccr |= CAN_MCAN_CCCR_FDOE | CAN_MCAN_CCCR_BRSE;
|
2022-05-05 13:46:43 +02:00
|
|
|
} else {
|
2023-05-02 13:24:18 +02:00
|
|
|
cccr &= ~(CAN_MCAN_CCCR_FDOE | CAN_MCAN_CCCR_BRSE);
|
2022-05-05 13:46:43 +02:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_CAN_FD_MODE */
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_CCCR, cccr);
|
|
|
|
if (err != 0) {
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_TEST, test);
|
|
|
|
if (err != 0) {
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
2024-01-17 19:52:24 +01:00
|
|
|
data->common.mode = mode;
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
unlock:
|
|
|
|
k_mutex_unlock(&data->lock);
|
|
|
|
|
|
|
|
return err;
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2022-04-19 13:46:30 +02:00
|
|
|
static void can_mcan_state_change_handler(const struct device *dev)
|
2021-02-11 20:07:04 +01:00
|
|
|
{
|
2024-02-13 20:21:17 +01:00
|
|
|
const struct can_mcan_config *config = dev->config;
|
2022-04-19 13:46:30 +02:00
|
|
|
struct can_mcan_data *data = dev->data;
|
2024-02-13 20:21:17 +01:00
|
|
|
const can_state_change_callback_t state_cb = data->common.state_change_cb;
|
|
|
|
void *state_cb_data = data->common.state_change_cb_user_data;
|
|
|
|
const struct can_mcan_callbacks *cbs = config->callbacks;
|
|
|
|
can_tx_callback_t tx_cb;
|
|
|
|
uint32_t tx_idx;
|
2022-04-19 13:46:30 +02:00
|
|
|
struct can_bus_err_cnt err_cnt;
|
|
|
|
enum can_state state;
|
2024-02-13 20:21:17 +01:00
|
|
|
uint32_t cccr;
|
|
|
|
int err;
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2024-04-21 03:06:54 +02:00
|
|
|
err = can_mcan_get_state(dev, &state, &err_cnt);
|
|
|
|
if (err != 0) {
|
|
|
|
return;
|
|
|
|
}
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2024-02-13 20:21:17 +01:00
|
|
|
if (state_cb != NULL) {
|
|
|
|
state_cb(dev, state, err_cnt, state_cb_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state == CAN_STATE_BUS_OFF) {
|
|
|
|
/* Request all TX buffers to be cancelled */
|
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_TXBCR, CAN_MCAN_TXBCR_CR);
|
|
|
|
if (err != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Call all TX queue callbacks with -ENETUNREACH */
|
|
|
|
for (tx_idx = 0U; tx_idx < cbs->num_tx; tx_idx++) {
|
|
|
|
tx_cb = cbs->tx[tx_idx].function;
|
|
|
|
|
|
|
|
if (tx_cb != NULL) {
|
|
|
|
cbs->tx[tx_idx].function = NULL;
|
|
|
|
tx_cb(dev, -ENETUNREACH, cbs->tx[tx_idx].user_data);
|
|
|
|
k_sem_give(&data->tx_sem);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-14 22:38:34 +01:00
|
|
|
if (!IS_ENABLED(CONFIG_CAN_MANUAL_RECOVERY_MODE) ||
|
|
|
|
(data->common.mode & CAN_MODE_MANUAL_RECOVERY) == 0U) {
|
2024-02-13 20:21:17 +01:00
|
|
|
/*
|
|
|
|
* Request leaving init mode, but do not take the lock (as we are in ISR
|
|
|
|
* context), nor wait for the result.
|
|
|
|
*/
|
|
|
|
err = can_mcan_read_reg(dev, CAN_MCAN_CCCR, &cccr);
|
|
|
|
if (err != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cccr &= ~CAN_MCAN_CCCR_INIT;
|
|
|
|
|
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_CCCR, cccr);
|
|
|
|
if (err != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-01 15:23:39 +02:00
|
|
|
static void can_mcan_tx_event_handler(const struct device *dev)
|
2021-02-11 20:07:04 +01:00
|
|
|
{
|
2023-05-22 16:31:09 +02:00
|
|
|
const struct can_mcan_config *config = dev->config;
|
|
|
|
const struct can_mcan_callbacks *cbs = config->callbacks;
|
2022-04-19 13:46:30 +02:00
|
|
|
struct can_mcan_data *data = dev->data;
|
2023-05-10 22:07:42 +02:00
|
|
|
struct can_mcan_tx_event_fifo tx_event;
|
2021-02-11 20:07:04 +01:00
|
|
|
can_tx_callback_t tx_cb;
|
2023-08-03 04:20:53 +02:00
|
|
|
void *user_data;
|
2023-05-02 13:24:18 +02:00
|
|
|
uint32_t event_idx;
|
|
|
|
uint32_t tx_idx;
|
|
|
|
uint32_t txefs;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = can_mcan_read_reg(dev, CAN_MCAN_TXEFS, &txefs);
|
|
|
|
if (err != 0) {
|
|
|
|
return;
|
|
|
|
}
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
while ((txefs & CAN_MCAN_TXEFS_EFFL) != 0U) {
|
|
|
|
event_idx = FIELD_GET(CAN_MCAN_TXEFS_EFGI, txefs);
|
2023-05-22 16:31:09 +02:00
|
|
|
err = can_mcan_read_mram(dev,
|
|
|
|
config->mram_offsets[CAN_MCAN_MRAM_CFG_TX_EVENT_FIFO] +
|
2023-05-10 22:07:42 +02:00
|
|
|
event_idx * sizeof(struct can_mcan_tx_event_fifo),
|
|
|
|
&tx_event,
|
|
|
|
sizeof(struct can_mcan_tx_event_fifo));
|
|
|
|
if (err != 0) {
|
|
|
|
LOG_ERR("failed to read tx event fifo (err %d)", err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-05-22 16:26:58 +02:00
|
|
|
tx_idx = tx_event.mm;
|
2023-05-10 22:07:42 +02:00
|
|
|
|
2021-02-11 20:07:04 +01:00
|
|
|
/* Acknowledge TX event */
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_TXEFA, event_idx);
|
|
|
|
if (err != 0) {
|
|
|
|
return;
|
|
|
|
}
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2023-09-25 23:05:33 +02:00
|
|
|
__ASSERT_NO_MSG(tx_idx < cbs->num_tx);
|
2023-05-22 16:31:09 +02:00
|
|
|
tx_cb = cbs->tx[tx_idx].function;
|
2023-08-03 04:20:53 +02:00
|
|
|
user_data = cbs->tx[tx_idx].user_data;
|
2023-05-22 16:31:09 +02:00
|
|
|
cbs->tx[tx_idx].function = NULL;
|
2023-08-03 04:20:53 +02:00
|
|
|
|
|
|
|
k_sem_give(&data->tx_sem);
|
|
|
|
|
|
|
|
tx_cb(dev, 0, user_data);
|
2023-05-02 13:24:18 +02:00
|
|
|
|
|
|
|
err = can_mcan_read_reg(dev, CAN_MCAN_TXEFS, &txefs);
|
|
|
|
if (err != 0) {
|
|
|
|
return;
|
|
|
|
}
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-18 03:42:16 +02:00
|
|
|
#ifdef CONFIG_CAN_STATS
|
|
|
|
static void can_mcan_lec_update_stats(const struct device *dev, enum can_mcan_psr_lec lec)
|
|
|
|
{
|
|
|
|
switch (lec) {
|
|
|
|
case CAN_MCAN_PSR_LEC_STUFF_ERROR:
|
|
|
|
CAN_STATS_STUFF_ERROR_INC(dev);
|
|
|
|
break;
|
|
|
|
case CAN_MCAN_PSR_LEC_FORM_ERROR:
|
|
|
|
CAN_STATS_FORM_ERROR_INC(dev);
|
|
|
|
break;
|
|
|
|
case CAN_MCAN_PSR_LEC_ACK_ERROR:
|
|
|
|
CAN_STATS_ACK_ERROR_INC(dev);
|
|
|
|
break;
|
|
|
|
case CAN_MCAN_PSR_LEC_BIT1_ERROR:
|
|
|
|
CAN_STATS_BIT1_ERROR_INC(dev);
|
|
|
|
break;
|
|
|
|
case CAN_MCAN_PSR_LEC_BIT0_ERROR:
|
|
|
|
CAN_STATS_BIT0_ERROR_INC(dev);
|
|
|
|
break;
|
|
|
|
case CAN_MCAN_PSR_LEC_CRC_ERROR:
|
|
|
|
CAN_STATS_CRC_ERROR_INC(dev);
|
|
|
|
break;
|
|
|
|
case CAN_MCAN_PSR_LEC_NO_ERROR:
|
|
|
|
case CAN_MCAN_PSR_LEC_NO_CHANGE:
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_CAN_STATS */
|
|
|
|
|
|
|
|
static int can_mcan_read_psr(const struct device *dev, uint32_t *val)
|
|
|
|
{
|
|
|
|
/* Reading the lower byte of the PSR register clears the protocol last
|
|
|
|
* error codes (LEC). To avoid missing errors, this function should be
|
|
|
|
* used whenever the PSR register is read.
|
|
|
|
*/
|
|
|
|
int err = can_mcan_read_reg(dev, CAN_MCAN_PSR, val);
|
|
|
|
|
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_CAN_STATS
|
|
|
|
enum can_mcan_psr_lec lec;
|
|
|
|
|
|
|
|
lec = FIELD_GET(CAN_MCAN_PSR_LEC, *val);
|
|
|
|
can_mcan_lec_update_stats(dev, lec);
|
|
|
|
#ifdef CONFIG_CAN_FD_MODE
|
|
|
|
lec = FIELD_GET(CAN_MCAN_PSR_DLEC, *val);
|
|
|
|
can_mcan_lec_update_stats(dev, lec);
|
|
|
|
#endif
|
|
|
|
#endif /* CONFIG_CAN_STATS */
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-04-19 13:46:30 +02:00
|
|
|
void can_mcan_line_0_isr(const struct device *dev)
|
2021-02-11 20:07:04 +01:00
|
|
|
{
|
2023-05-02 13:24:18 +02:00
|
|
|
const uint32_t events = CAN_MCAN_IR_BO | CAN_MCAN_IR_EP | CAN_MCAN_IR_EW |
|
|
|
|
CAN_MCAN_IR_TEFN | CAN_MCAN_IR_TEFL | CAN_MCAN_IR_ARA |
|
2023-09-18 03:42:16 +02:00
|
|
|
CAN_MCAN_IR_MRAF | CAN_MCAN_IR_PEA | CAN_MCAN_IR_PED;
|
2022-04-19 13:46:30 +02:00
|
|
|
struct can_mcan_data *data = dev->data;
|
2023-05-02 13:24:18 +02:00
|
|
|
uint32_t ir;
|
|
|
|
int err;
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_read_reg(dev, CAN_MCAN_IR, &ir);
|
|
|
|
if (err != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((ir & events) != 0U) {
|
2023-06-01 11:15:08 +02:00
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_IR, ir & events);
|
|
|
|
if (err != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
if ((ir & (CAN_MCAN_IR_BO | CAN_MCAN_IR_EP | CAN_MCAN_IR_EW)) != 0U) {
|
2022-04-19 13:46:30 +02:00
|
|
|
can_mcan_state_change_handler(dev);
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
2023-05-02 13:24:18 +02:00
|
|
|
|
2021-02-11 20:07:04 +01:00
|
|
|
/* TX event FIFO new entry */
|
2023-05-02 13:24:18 +02:00
|
|
|
if ((ir & CAN_MCAN_IR_TEFN) != 0U) {
|
2023-06-01 15:23:39 +02:00
|
|
|
can_mcan_tx_event_handler(dev);
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
if ((ir & CAN_MCAN_IR_TEFL) != 0U) {
|
2021-02-11 20:07:04 +01:00
|
|
|
LOG_ERR("TX FIFO element lost");
|
|
|
|
k_sem_give(&data->tx_sem);
|
|
|
|
}
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
if ((ir & CAN_MCAN_IR_ARA) != 0U) {
|
2021-02-11 20:07:04 +01:00
|
|
|
LOG_ERR("Access to reserved address");
|
|
|
|
}
|
|
|
|
|
2023-09-18 03:42:16 +02:00
|
|
|
if ((ir & CAN_MCAN_IR_MRAF) != 0U) {
|
2021-02-11 20:07:04 +01:00
|
|
|
LOG_ERR("Message RAM access failure");
|
|
|
|
}
|
|
|
|
|
2023-09-18 03:42:16 +02:00
|
|
|
#ifdef CONFIG_CAN_STATS
|
|
|
|
if ((ir & (CAN_MCAN_IR_PEA | CAN_MCAN_IR_PED)) != 0U) {
|
|
|
|
uint32_t reg;
|
|
|
|
/* This function automatically updates protocol error stats */
|
|
|
|
can_mcan_read_psr(dev, ®);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_read_reg(dev, CAN_MCAN_IR, &ir);
|
|
|
|
if (err != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2023-05-10 22:07:42 +02:00
|
|
|
static void can_mcan_get_message(const struct device *dev, uint16_t fifo_offset,
|
2023-05-02 13:24:18 +02:00
|
|
|
uint16_t fifo_status_reg, uint16_t fifo_ack_reg)
|
2021-02-11 20:07:04 +01:00
|
|
|
{
|
2023-05-22 16:31:09 +02:00
|
|
|
const struct can_mcan_config *config = dev->config;
|
|
|
|
const struct can_mcan_callbacks *cbs = config->callbacks;
|
|
|
|
struct can_mcan_rx_fifo_hdr hdr;
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
struct can_frame frame = {0};
|
2021-02-11 20:07:04 +01:00
|
|
|
can_rx_callback_t cb;
|
2023-05-22 16:31:09 +02:00
|
|
|
void *user_data;
|
|
|
|
uint32_t get_idx;
|
|
|
|
uint32_t filt_idx;
|
2021-02-11 20:07:04 +01:00
|
|
|
int data_length;
|
2023-05-02 13:24:18 +02:00
|
|
|
uint32_t fifo_status;
|
|
|
|
int err;
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_read_reg(dev, fifo_status_reg, &fifo_status);
|
|
|
|
if (err != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-05-10 22:07:42 +02:00
|
|
|
while (FIELD_GET(CAN_MCAN_RXF0S_F0FL, fifo_status) != 0U) {
|
2023-05-02 13:24:18 +02:00
|
|
|
get_idx = FIELD_GET(CAN_MCAN_RXF0S_F0GI, fifo_status);
|
2021-12-19 17:56:54 +01:00
|
|
|
|
2023-05-10 22:07:42 +02:00
|
|
|
err = can_mcan_read_mram(dev, fifo_offset + get_idx *
|
|
|
|
sizeof(struct can_mcan_rx_fifo) +
|
|
|
|
offsetof(struct can_mcan_rx_fifo, hdr),
|
|
|
|
&hdr, sizeof(struct can_mcan_rx_fifo_hdr));
|
|
|
|
if (err != 0) {
|
|
|
|
LOG_ERR("failed to read Rx FIFO header (err %d)", err);
|
|
|
|
return;
|
|
|
|
}
|
2021-02-11 20:07:04 +01:00
|
|
|
|
|
|
|
frame.dlc = hdr.dlc;
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
|
|
|
|
if (hdr.rtr != 0) {
|
|
|
|
frame.flags |= CAN_FRAME_RTR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hdr.fdf != 0) {
|
|
|
|
frame.flags |= CAN_FRAME_FDF;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hdr.brs != 0) {
|
|
|
|
frame.flags |= CAN_FRAME_BRS;
|
|
|
|
}
|
|
|
|
|
2023-03-10 19:39:21 +01:00
|
|
|
if (hdr.esi != 0) {
|
|
|
|
frame.flags |= CAN_FRAME_ESI;
|
|
|
|
}
|
|
|
|
|
2023-04-24 14:54:52 +02:00
|
|
|
#ifdef CONFIG_CAN_RX_TIMESTAMP
|
2021-02-11 20:07:04 +01:00
|
|
|
frame.timestamp = hdr.rxts;
|
2023-04-24 14:54:52 +02:00
|
|
|
#endif /* CONFIG_CAN_RX_TIMESTAMP */
|
2021-02-11 20:07:04 +01:00
|
|
|
|
|
|
|
filt_idx = hdr.fidx;
|
|
|
|
|
2022-07-16 21:43:21 +02:00
|
|
|
if (hdr.xtd != 0) {
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
frame.id = hdr.ext_id;
|
|
|
|
frame.flags |= CAN_FRAME_IDE;
|
2022-07-16 21:43:21 +02:00
|
|
|
} else {
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
frame.id = hdr.std_id;
|
2023-05-22 16:31:09 +02:00
|
|
|
}
|
|
|
|
|
2021-02-11 20:07:04 +01:00
|
|
|
data_length = can_dlc_to_bytes(frame.dlc);
|
|
|
|
if (data_length <= sizeof(frame.data)) {
|
2023-10-11 13:27:47 +02:00
|
|
|
if ((frame.flags & CAN_FRAME_RTR) == 0U) {
|
|
|
|
err = can_mcan_read_mram(dev, fifo_offset + get_idx *
|
|
|
|
sizeof(struct can_mcan_rx_fifo) +
|
|
|
|
offsetof(struct can_mcan_rx_fifo, data_32),
|
|
|
|
&frame.data_32,
|
|
|
|
ROUND_UP(data_length, sizeof(uint32_t)));
|
|
|
|
if (err != 0) {
|
|
|
|
LOG_ERR("failed to read Rx FIFO data (err %d)", err);
|
|
|
|
return;
|
|
|
|
}
|
2023-05-10 22:07:42 +02:00
|
|
|
}
|
2021-02-11 20:07:04 +01:00
|
|
|
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
if ((frame.flags & CAN_FRAME_IDE) != 0) {
|
2021-02-11 20:07:04 +01:00
|
|
|
LOG_DBG("Frame on filter %d, ID: 0x%x",
|
2023-05-22 16:31:09 +02:00
|
|
|
filt_idx + cbs->num_std, frame.id);
|
2023-09-25 23:05:33 +02:00
|
|
|
__ASSERT_NO_MSG(filt_idx < cbs->num_ext);
|
2023-05-22 16:31:09 +02:00
|
|
|
cb = cbs->ext[filt_idx].function;
|
|
|
|
user_data = cbs->ext[filt_idx].user_data;
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
} else {
|
2023-04-24 14:22:14 +02:00
|
|
|
LOG_DBG("Frame on filter %d, ID: 0x%x", filt_idx, frame.id);
|
2023-09-25 23:05:33 +02:00
|
|
|
__ASSERT_NO_MSG(filt_idx < cbs->num_std);
|
2023-05-22 16:31:09 +02:00
|
|
|
cb = cbs->std[filt_idx].function;
|
|
|
|
user_data = cbs->std[filt_idx].user_data;
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (cb) {
|
2023-05-22 16:31:09 +02:00
|
|
|
cb(dev, &frame, user_data);
|
2021-02-11 20:07:04 +01:00
|
|
|
} else {
|
|
|
|
LOG_DBG("cb missing");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
LOG_ERR("Frame is too big");
|
|
|
|
}
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_write_reg(dev, fifo_ack_reg, get_idx);
|
|
|
|
if (err != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = can_mcan_read_reg(dev, fifo_status_reg, &fifo_status);
|
|
|
|
if (err != 0) {
|
|
|
|
return;
|
|
|
|
}
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-19 13:46:30 +02:00
|
|
|
void can_mcan_line_1_isr(const struct device *dev)
|
2021-02-11 20:07:04 +01:00
|
|
|
{
|
2023-05-22 16:31:09 +02:00
|
|
|
const struct can_mcan_config *config = dev->config;
|
2023-05-02 13:24:18 +02:00
|
|
|
const uint32_t events =
|
|
|
|
CAN_MCAN_IR_RF0N | CAN_MCAN_IR_RF1N | CAN_MCAN_IR_RF0L | CAN_MCAN_IR_RF1L;
|
|
|
|
uint32_t ir;
|
|
|
|
int err;
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_read_reg(dev, CAN_MCAN_IR, &ir);
|
|
|
|
if (err != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((ir & events) != 0U) {
|
2023-06-01 11:15:08 +02:00
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_IR, events & ir);
|
|
|
|
if (err != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
if ((ir & CAN_MCAN_IR_RF0N) != 0U) {
|
2021-02-11 20:07:04 +01:00
|
|
|
LOG_DBG("RX FIFO0 INT");
|
2023-05-22 16:31:09 +02:00
|
|
|
can_mcan_get_message(dev, config->mram_offsets[CAN_MCAN_MRAM_CFG_RX_FIFO0],
|
|
|
|
CAN_MCAN_RXF0S, CAN_MCAN_RXF0A);
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
if ((ir & CAN_MCAN_IR_RF1N) != 0U) {
|
2021-02-11 20:07:04 +01:00
|
|
|
LOG_DBG("RX FIFO1 INT");
|
2023-05-22 16:31:09 +02:00
|
|
|
can_mcan_get_message(dev, config->mram_offsets[CAN_MCAN_MRAM_CFG_RX_FIFO1],
|
|
|
|
CAN_MCAN_RXF1S, CAN_MCAN_RXF1A);
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
if ((ir & CAN_MCAN_IR_RF0L) != 0U) {
|
2021-02-11 20:07:04 +01:00
|
|
|
LOG_ERR("Message lost on FIFO0");
|
2023-09-18 03:42:16 +02:00
|
|
|
CAN_STATS_RX_OVERRUN_INC(dev);
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
if ((ir & CAN_MCAN_IR_RF1L) != 0U) {
|
2021-02-11 20:07:04 +01:00
|
|
|
LOG_ERR("Message lost on FIFO1");
|
2023-09-18 03:42:16 +02:00
|
|
|
CAN_STATS_RX_OVERRUN_INC(dev);
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_read_reg(dev, CAN_MCAN_IR, &ir);
|
|
|
|
if (err != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2022-04-19 13:46:30 +02:00
|
|
|
int can_mcan_get_state(const struct device *dev, enum can_state *state,
|
2022-01-19 10:21:01 +01:00
|
|
|
struct can_bus_err_cnt *err_cnt)
|
2021-02-11 20:07:04 +01:00
|
|
|
{
|
2022-08-31 14:28:42 +02:00
|
|
|
struct can_mcan_data *data = dev->data;
|
2023-05-02 13:24:18 +02:00
|
|
|
uint32_t reg;
|
|
|
|
int err;
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2022-01-19 10:21:01 +01:00
|
|
|
if (state != NULL) {
|
2023-09-18 03:42:16 +02:00
|
|
|
err = can_mcan_read_psr(dev, ®);
|
2023-05-02 13:24:18 +02:00
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2024-01-17 19:52:24 +01:00
|
|
|
if (!data->common.started) {
|
2022-08-31 14:28:42 +02:00
|
|
|
*state = CAN_STATE_STOPPED;
|
2023-05-02 13:24:18 +02:00
|
|
|
} else if ((reg & CAN_MCAN_PSR_BO) != 0U) {
|
2022-08-18 16:14:48 +02:00
|
|
|
*state = CAN_STATE_BUS_OFF;
|
2023-05-02 13:24:18 +02:00
|
|
|
} else if ((reg & CAN_MCAN_PSR_EP) != 0U) {
|
2022-08-18 16:14:48 +02:00
|
|
|
*state = CAN_STATE_ERROR_PASSIVE;
|
2023-05-02 13:24:18 +02:00
|
|
|
} else if ((reg & CAN_MCAN_PSR_EW) != 0U) {
|
2022-08-18 16:14:48 +02:00
|
|
|
*state = CAN_STATE_ERROR_WARNING;
|
2022-01-19 10:21:01 +01:00
|
|
|
} else {
|
2022-08-18 16:14:48 +02:00
|
|
|
*state = CAN_STATE_ERROR_ACTIVE;
|
2022-01-19 10:21:01 +01:00
|
|
|
}
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2022-01-19 10:21:01 +01:00
|
|
|
if (err_cnt != NULL) {
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_read_reg(dev, CAN_MCAN_ECR, ®);
|
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
err_cnt->tx_err_cnt = FIELD_GET(CAN_MCAN_ECR_TEC, reg);
|
|
|
|
err_cnt->rx_err_cnt = FIELD_GET(CAN_MCAN_ECR_REC, reg);
|
2022-01-18 16:40:09 +01:00
|
|
|
}
|
|
|
|
|
2022-01-19 10:21:01 +01:00
|
|
|
return 0;
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2024-02-14 22:38:34 +01:00
|
|
|
#ifdef CONFIG_CAN_MANUAL_RECOVERY_MODE
|
2022-04-19 13:46:30 +02:00
|
|
|
int can_mcan_recover(const struct device *dev, k_timeout_t timeout)
|
2021-02-11 20:07:04 +01:00
|
|
|
{
|
2022-08-31 14:28:42 +02:00
|
|
|
struct can_mcan_data *data = dev->data;
|
2022-03-30 11:36:00 +02:00
|
|
|
|
2024-01-17 19:52:24 +01:00
|
|
|
if (!data->common.started) {
|
2022-08-31 14:28:42 +02:00
|
|
|
return -ENETDOWN;
|
|
|
|
}
|
|
|
|
|
2024-02-14 22:38:34 +01:00
|
|
|
if ((data->common.mode & CAN_MODE_MANUAL_RECOVERY) == 0U) {
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
2023-04-24 14:17:19 +02:00
|
|
|
return can_mcan_leave_init_mode(dev, timeout);
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
2024-02-14 22:38:34 +01:00
|
|
|
#endif /* CONFIG_CAN_MANUAL_RECOVERY_MODE */
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2023-04-24 14:22:14 +02:00
|
|
|
int can_mcan_send(const struct device *dev, const struct can_frame *frame, k_timeout_t timeout,
|
2021-12-04 15:21:32 +01:00
|
|
|
can_tx_callback_t callback, void *user_data)
|
2021-02-11 20:07:04 +01:00
|
|
|
{
|
2023-05-22 16:31:09 +02:00
|
|
|
const struct can_mcan_config *config = dev->config;
|
|
|
|
const struct can_mcan_callbacks *cbs = config->callbacks;
|
2022-04-19 13:46:30 +02:00
|
|
|
struct can_mcan_data *data = dev->data;
|
2021-02-11 20:07:04 +01:00
|
|
|
size_t data_length = can_dlc_to_bytes(frame->dlc);
|
2021-02-07 15:47:52 +01:00
|
|
|
struct can_mcan_tx_buffer_hdr tx_hdr = {
|
2023-05-02 13:24:18 +02:00
|
|
|
.rtr = (frame->flags & CAN_FRAME_RTR) != 0U ? 1U : 0U,
|
|
|
|
.xtd = (frame->flags & CAN_FRAME_IDE) != 0U ? 1U : 0U,
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
.esi = 0U,
|
2021-02-11 20:07:04 +01:00
|
|
|
.dlc = frame->dlc,
|
|
|
|
#ifdef CONFIG_CAN_FD_MODE
|
2023-05-02 13:24:18 +02:00
|
|
|
.fdf = (frame->flags & CAN_FRAME_FDF) != 0U ? 1U : 0U,
|
|
|
|
.brs = (frame->flags & CAN_FRAME_BRS) != 0U ? 1U : 0U,
|
2023-04-24 14:22:14 +02:00
|
|
|
#else /* CONFIG_CAN_FD_MODE */
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
.fdf = 0U,
|
|
|
|
.brs = 0U,
|
|
|
|
#endif /* !CONFIG_CAN_FD_MODE */
|
|
|
|
.efc = 1U,
|
2021-02-11 20:07:04 +01:00
|
|
|
};
|
2023-08-03 04:08:00 +02:00
|
|
|
uint32_t put_idx = -1;
|
2023-05-02 13:24:18 +02:00
|
|
|
uint32_t reg;
|
|
|
|
int err;
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2023-08-03 04:33:55 +02:00
|
|
|
LOG_DBG("Sending %zu bytes. Id: 0x%x, ID type: %s %s %s %s", data_length, frame->id,
|
2023-05-02 13:24:18 +02:00
|
|
|
(frame->flags & CAN_FRAME_IDE) != 0U ? "extended" : "standard",
|
|
|
|
(frame->flags & CAN_FRAME_RTR) != 0U ? "RTR" : "",
|
|
|
|
(frame->flags & CAN_FRAME_FDF) != 0U ? "FD frame" : "",
|
|
|
|
(frame->flags & CAN_FRAME_BRS) != 0U ? "BRS" : "");
|
2021-02-11 20:07:04 +01:00
|
|
|
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
#ifdef CONFIG_CAN_FD_MODE
|
2023-04-24 14:22:14 +02:00
|
|
|
if ((frame->flags & ~(CAN_FRAME_IDE | CAN_FRAME_RTR | CAN_FRAME_FDF | CAN_FRAME_BRS)) !=
|
|
|
|
0) {
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
LOG_ERR("unsupported CAN frame flags 0x%02x", frame->flags);
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
2024-01-17 19:52:24 +01:00
|
|
|
if ((data->common.mode & CAN_MODE_FD) == 0U &&
|
|
|
|
((frame->flags & (CAN_FRAME_FDF | CAN_FRAME_BRS)) != 0U)) {
|
2023-10-31 10:09:38 +01:00
|
|
|
LOG_ERR("CAN FD format not supported in non-FD mode");
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
2023-04-24 14:22:14 +02:00
|
|
|
#else /* CONFIG_CAN_FD_MODE */
|
2023-05-02 13:24:18 +02:00
|
|
|
if ((frame->flags & ~(CAN_FRAME_IDE | CAN_FRAME_RTR)) != 0U) {
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
LOG_ERR("unsupported CAN frame flags 0x%02x", frame->flags);
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
#endif /* !CONFIG_CAN_FD_MODE */
|
|
|
|
|
2021-02-11 20:07:04 +01:00
|
|
|
if (data_length > sizeof(frame->data)) {
|
2023-04-24 14:22:14 +02:00
|
|
|
LOG_ERR("data length (%zu) > max frame data length (%zu)", data_length,
|
|
|
|
sizeof(frame->data));
|
2021-12-08 00:01:57 +01:00
|
|
|
return -EINVAL;
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
if ((frame->flags & CAN_FRAME_FDF) != 0U) {
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
if (frame->dlc > CANFD_MAX_DLC) {
|
2023-10-31 10:09:38 +01:00
|
|
|
LOG_ERR("DLC of %d for CAN FD format frame", frame->dlc);
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (frame->dlc > CAN_MAX_DLC) {
|
|
|
|
LOG_ERR("DLC of %d for non-FD format frame", frame->dlc);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2024-01-17 19:52:24 +01:00
|
|
|
if (!data->common.started) {
|
2022-08-31 14:28:42 +02:00
|
|
|
return -ENETDOWN;
|
|
|
|
}
|
|
|
|
|
2023-09-18 03:42:16 +02:00
|
|
|
err = can_mcan_read_psr(dev, ®);
|
2023-05-02 13:24:18 +02:00
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((reg & CAN_MCAN_PSR_BO) != 0U) {
|
2022-08-19 10:43:34 +02:00
|
|
|
return -ENETUNREACH;
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
err = k_sem_take(&data->tx_sem, timeout);
|
|
|
|
if (err != 0) {
|
2021-12-08 00:01:57 +01:00
|
|
|
return -EAGAIN;
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
k_mutex_lock(&data->tx_mtx, K_FOREVER);
|
|
|
|
|
2023-08-03 04:08:00 +02:00
|
|
|
/* Acquire a free TX buffer */
|
|
|
|
for (int i = 0; i < cbs->num_tx; i++) {
|
|
|
|
if (cbs->tx[i].function == NULL) {
|
|
|
|
put_idx = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-22 16:26:58 +02:00
|
|
|
tx_hdr.mm = put_idx;
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
if ((frame->flags & CAN_FRAME_IDE) != 0U) {
|
2021-02-11 20:07:04 +01:00
|
|
|
tx_hdr.ext_id = frame->id;
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
} else {
|
|
|
|
tx_hdr.std_id = frame->id & CAN_STD_ID_MASK;
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2023-05-22 16:31:09 +02:00
|
|
|
err = can_mcan_write_mram(dev, config->mram_offsets[CAN_MCAN_MRAM_CFG_TX_BUFFER] + put_idx *
|
2023-05-10 22:07:42 +02:00
|
|
|
sizeof(struct can_mcan_tx_buffer) +
|
|
|
|
offsetof(struct can_mcan_tx_buffer, hdr),
|
|
|
|
&tx_hdr, sizeof(struct can_mcan_tx_buffer_hdr));
|
|
|
|
if (err != 0) {
|
|
|
|
LOG_ERR("failed to write Tx Buffer header (err %d)", err);
|
2023-08-03 03:40:13 +02:00
|
|
|
goto err_unlock;
|
2023-05-10 22:07:42 +02:00
|
|
|
}
|
|
|
|
|
2023-10-11 13:27:47 +02:00
|
|
|
if ((frame->flags & CAN_FRAME_RTR) == 0U) {
|
|
|
|
err = can_mcan_write_mram(dev, config->mram_offsets[CAN_MCAN_MRAM_CFG_TX_BUFFER] +
|
|
|
|
put_idx * sizeof(struct can_mcan_tx_buffer) +
|
|
|
|
offsetof(struct can_mcan_tx_buffer, data_32),
|
|
|
|
&frame->data_32, ROUND_UP(data_length, sizeof(uint32_t)));
|
|
|
|
if (err != 0) {
|
|
|
|
LOG_ERR("failed to write Tx Buffer data (err %d)", err);
|
|
|
|
goto err_unlock;
|
|
|
|
}
|
2023-05-10 22:07:42 +02:00
|
|
|
}
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2023-08-03 03:56:13 +02:00
|
|
|
__ASSERT_NO_MSG(put_idx < cbs->num_tx);
|
2023-05-22 16:31:09 +02:00
|
|
|
cbs->tx[put_idx].function = callback;
|
|
|
|
cbs->tx[put_idx].user_data = user_data;
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_TXBAR, BIT(put_idx));
|
|
|
|
if (err != 0) {
|
2023-08-03 04:08:00 +02:00
|
|
|
cbs->tx[put_idx].function = NULL;
|
|
|
|
goto err_unlock;
|
2023-05-02 13:24:18 +02:00
|
|
|
}
|
2021-02-11 20:07:04 +01:00
|
|
|
|
|
|
|
k_mutex_unlock(&data->tx_mtx);
|
2023-08-03 03:40:13 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_unlock:
|
|
|
|
k_mutex_unlock(&data->tx_mtx);
|
|
|
|
k_sem_give(&data->tx_sem);
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
return err;
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
int can_mcan_get_max_filters(const struct device *dev, bool ide)
|
2022-03-18 10:37:37 +01:00
|
|
|
{
|
2023-05-22 16:31:09 +02:00
|
|
|
const struct can_mcan_config *config = dev->config;
|
|
|
|
const struct can_mcan_callbacks *cbs = config->callbacks;
|
2022-03-18 10:37:37 +01:00
|
|
|
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
if (ide) {
|
2023-05-22 16:31:09 +02:00
|
|
|
return cbs->num_ext;
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
} else {
|
2023-05-22 16:31:09 +02:00
|
|
|
return cbs->num_std;
|
2022-03-18 10:37:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-11 20:07:04 +01:00
|
|
|
/* Use masked configuration only for simplicity. If someone needs more than
|
|
|
|
* 28 standard filters, dual mode needs to be implemented.
|
|
|
|
* Dual mode gets tricky, because we can only activate both filters.
|
|
|
|
* If one of the IDs is not used anymore, we would need to mark it as unused.
|
|
|
|
*/
|
2023-04-24 14:22:14 +02:00
|
|
|
int can_mcan_add_rx_filter_std(const struct device *dev, can_rx_callback_t callback,
|
|
|
|
void *user_data, const struct can_filter *filter)
|
2021-02-11 20:07:04 +01:00
|
|
|
{
|
2023-05-22 16:31:09 +02:00
|
|
|
const struct can_mcan_config *config = dev->config;
|
|
|
|
const struct can_mcan_callbacks *cbs = config->callbacks;
|
2022-04-19 13:46:30 +02:00
|
|
|
struct can_mcan_data *data = dev->data;
|
2021-02-11 20:07:04 +01:00
|
|
|
struct can_mcan_std_filter filter_element = {
|
2023-06-01 15:23:39 +02:00
|
|
|
.sfid1 = filter->id,
|
|
|
|
.sfid2 = filter->mask,
|
|
|
|
.sft = CAN_MCAN_SFT_CLASSIC
|
2023-05-10 22:07:42 +02:00
|
|
|
};
|
2023-05-26 14:54:42 +02:00
|
|
|
int filter_id = -ENOSPC;
|
2023-05-10 22:07:42 +02:00
|
|
|
int err;
|
2023-05-26 14:54:42 +02:00
|
|
|
int i;
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
k_mutex_lock(&data->lock, K_FOREVER);
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2023-05-26 14:54:42 +02:00
|
|
|
for (i = 0; i < cbs->num_std; i++) {
|
|
|
|
if (cbs->std[i].function == NULL) {
|
|
|
|
filter_id = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (filter_id == -ENOSPC) {
|
2022-04-08 14:57:53 +02:00
|
|
|
LOG_WRN("No free standard id filter left");
|
2023-05-02 13:24:18 +02:00
|
|
|
k_mutex_unlock(&data->lock);
|
2021-12-08 00:01:57 +01:00
|
|
|
return -ENOSPC;
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2022-03-16 22:07:43 +01:00
|
|
|
/* TODO proper fifo balancing */
|
2023-06-01 15:23:39 +02:00
|
|
|
filter_element.sfec = filter_id & 0x01 ? CAN_MCAN_XFEC_FIFO1 : CAN_MCAN_XFEC_FIFO0;
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2023-05-22 16:31:09 +02:00
|
|
|
err = can_mcan_write_mram(dev, config->mram_offsets[CAN_MCAN_MRAM_CFG_STD_FILTER] +
|
2023-05-10 22:07:42 +02:00
|
|
|
filter_id * sizeof(struct can_mcan_std_filter),
|
|
|
|
&filter_element, sizeof(filter_element));
|
|
|
|
if (err != 0) {
|
|
|
|
LOG_ERR("failed to write std filter element (err %d)", err);
|
|
|
|
return err;
|
|
|
|
}
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
k_mutex_unlock(&data->lock);
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2021-12-28 20:00:34 +01:00
|
|
|
LOG_DBG("Attached std filter at %d", filter_id);
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2023-09-25 23:05:33 +02:00
|
|
|
__ASSERT_NO_MSG(filter_id < cbs->num_std);
|
2023-05-22 16:31:09 +02:00
|
|
|
cbs->std[filter_id].function = callback;
|
|
|
|
cbs->std[filter_id].user_data = user_data;
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2021-12-28 20:00:34 +01:00
|
|
|
return filter_id;
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2023-04-24 14:22:14 +02:00
|
|
|
static int can_mcan_add_rx_filter_ext(const struct device *dev, can_rx_callback_t callback,
|
|
|
|
void *user_data, const struct can_filter *filter)
|
2021-02-11 20:07:04 +01:00
|
|
|
{
|
2023-05-22 16:31:09 +02:00
|
|
|
const struct can_mcan_config *config = dev->config;
|
|
|
|
const struct can_mcan_callbacks *cbs = config->callbacks;
|
2022-04-19 13:46:30 +02:00
|
|
|
struct can_mcan_data *data = dev->data;
|
2021-02-11 20:07:04 +01:00
|
|
|
struct can_mcan_ext_filter filter_element = {
|
2023-06-01 15:23:39 +02:00
|
|
|
.efid2 = filter->mask,
|
|
|
|
.efid1 = filter->id,
|
|
|
|
.eft = CAN_MCAN_EFT_CLASSIC
|
2023-05-10 22:07:42 +02:00
|
|
|
};
|
2023-05-26 14:54:42 +02:00
|
|
|
int filter_id = -ENOSPC;
|
2023-05-10 22:07:42 +02:00
|
|
|
int err;
|
2023-05-26 14:54:42 +02:00
|
|
|
int i;
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
k_mutex_lock(&data->lock, K_FOREVER);
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2023-05-26 14:54:42 +02:00
|
|
|
for (i = 0; i < cbs->num_ext; i++) {
|
|
|
|
if (cbs->ext[i].function == NULL) {
|
|
|
|
filter_id = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (filter_id == -ENOSPC) {
|
2022-04-08 14:57:53 +02:00
|
|
|
LOG_WRN("No free extended id filter left");
|
2023-05-02 13:24:18 +02:00
|
|
|
k_mutex_unlock(&data->lock);
|
2021-12-08 00:01:57 +01:00
|
|
|
return -ENOSPC;
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2022-03-16 22:07:43 +01:00
|
|
|
/* TODO proper fifo balancing */
|
2023-06-01 15:23:39 +02:00
|
|
|
filter_element.efec = filter_id & 0x01 ? CAN_MCAN_XFEC_FIFO1 : CAN_MCAN_XFEC_FIFO0;
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2023-05-22 16:31:09 +02:00
|
|
|
err = can_mcan_write_mram(dev, config->mram_offsets[CAN_MCAN_MRAM_CFG_EXT_FILTER] +
|
2023-05-10 22:07:42 +02:00
|
|
|
filter_id * sizeof(struct can_mcan_ext_filter),
|
|
|
|
&filter_element, sizeof(filter_element));
|
|
|
|
if (err != 0) {
|
|
|
|
LOG_ERR("failed to write std filter element (err %d)", err);
|
|
|
|
return err;
|
|
|
|
}
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
k_mutex_unlock(&data->lock);
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2021-12-28 20:00:34 +01:00
|
|
|
LOG_DBG("Attached ext filter at %d", filter_id);
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2023-09-25 23:05:33 +02:00
|
|
|
__ASSERT_NO_MSG(filter_id < cbs->num_ext);
|
2023-05-22 16:31:09 +02:00
|
|
|
cbs->ext[filter_id].function = callback;
|
|
|
|
cbs->ext[filter_id].user_data = user_data;
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2021-12-28 20:00:34 +01:00
|
|
|
return filter_id;
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2023-04-24 14:22:14 +02:00
|
|
|
int can_mcan_add_rx_filter(const struct device *dev, can_rx_callback_t callback, void *user_data,
|
2022-08-11 15:31:59 +02:00
|
|
|
const struct can_filter *filter)
|
2021-02-11 20:07:04 +01:00
|
|
|
{
|
2023-05-22 16:31:09 +02:00
|
|
|
const struct can_mcan_config *config = dev->config;
|
|
|
|
const struct can_mcan_callbacks *cbs = config->callbacks;
|
2021-12-28 20:00:34 +01:00
|
|
|
int filter_id;
|
2021-02-11 20:07:04 +01:00
|
|
|
|
2023-12-15 13:36:18 +01:00
|
|
|
if ((filter->flags & ~(CAN_FILTER_IDE)) != 0U) {
|
2022-11-09 05:23:54 +01:00
|
|
|
LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags);
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
if ((filter->flags & CAN_FILTER_IDE) != 0U) {
|
2022-04-19 13:46:30 +02:00
|
|
|
filter_id = can_mcan_add_rx_filter_ext(dev, callback, user_data, filter);
|
2022-04-08 14:57:53 +02:00
|
|
|
if (filter_id >= 0) {
|
2023-05-22 16:31:09 +02:00
|
|
|
filter_id += cbs->num_std;
|
2022-04-08 14:57:53 +02:00
|
|
|
}
|
drivers: can: use flags fields for can_frame and can_filter structs
The can_frame and can_filter structs support a number of different flags
(standard/extended CAN ID type, Remote Transmission Request, CAN-FD format,
Bit Rate Switch, ...). Each of these flags is represented as a discrete bit
in the given structure.
This design pattern requires every user of these structs to initialize all
of these flags to either 0 or 1, which does not scale well for future flag
additions.
Some of these flags have associated enumerations to be used for assignment,
some do not. CAN drivers and protocols tend to rely on the logical value of
the flag instead of using the enumeration, leading to a very fragile
API. The enumerations are used inconsistently between the can_frame and
can_filter structures, which further complicates the API.
Instead, convert these flags to bitfields with separate flag definitions
for the can_frame and can_filter structures. This API allows for future
extensions without having to revisit existing users of the two
structures. Furthermore, this allows driver to easily check for unsupported
flags in the respective API calls.
As this change leads to the "id_mask" field of the can_filter to be the
only mask present in that structure, rename it to "mask" for simplicity.
Fixes: #50776
Signed-off-by: Henrik Brix Andersen <hebad@vestas.com>
2022-09-30 14:44:16 +02:00
|
|
|
} else {
|
|
|
|
filter_id = can_mcan_add_rx_filter_std(dev, callback, user_data, filter);
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2021-12-28 20:00:34 +01:00
|
|
|
return filter_id;
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2022-04-19 13:46:30 +02:00
|
|
|
void can_mcan_remove_rx_filter(const struct device *dev, int filter_id)
|
2021-02-11 20:07:04 +01:00
|
|
|
{
|
2023-05-22 16:31:09 +02:00
|
|
|
const struct can_mcan_config *config = dev->config;
|
|
|
|
const struct can_mcan_callbacks *cbs = config->callbacks;
|
2022-04-19 13:46:30 +02:00
|
|
|
struct can_mcan_data *data = dev->data;
|
2023-05-10 22:07:42 +02:00
|
|
|
int err;
|
2022-04-19 13:46:30 +02:00
|
|
|
|
2023-10-24 22:16:11 +02:00
|
|
|
if (filter_id < 0) {
|
|
|
|
LOG_ERR("filter ID %d out of bounds", filter_id);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
k_mutex_lock(&data->lock, K_FOREVER);
|
|
|
|
|
2023-05-22 16:31:09 +02:00
|
|
|
if (filter_id >= cbs->num_std) {
|
|
|
|
filter_id -= cbs->num_std;
|
|
|
|
if (filter_id >= cbs->num_ext) {
|
2023-10-24 22:16:11 +02:00
|
|
|
LOG_ERR("filter ID %d out of bounds", filter_id);
|
2023-05-02 13:24:18 +02:00
|
|
|
k_mutex_unlock(&data->lock);
|
2021-02-11 20:07:04 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-05-26 14:54:42 +02:00
|
|
|
cbs->ext[filter_id].function = NULL;
|
|
|
|
cbs->ext[filter_id].user_data = NULL;
|
|
|
|
|
2023-05-22 16:31:09 +02:00
|
|
|
err = can_mcan_clear_mram(dev, config->mram_offsets[CAN_MCAN_MRAM_CFG_EXT_FILTER] +
|
2023-05-10 22:07:42 +02:00
|
|
|
filter_id * sizeof(struct can_mcan_ext_filter),
|
|
|
|
sizeof(struct can_mcan_ext_filter));
|
|
|
|
if (err != 0) {
|
|
|
|
LOG_ERR("failed to clear ext filter element (err %d)", err);
|
|
|
|
}
|
2021-02-11 20:07:04 +01:00
|
|
|
} else {
|
2023-05-26 14:54:42 +02:00
|
|
|
cbs->std[filter_id].function = NULL;
|
|
|
|
cbs->std[filter_id].user_data = NULL;
|
|
|
|
|
2023-05-22 16:31:09 +02:00
|
|
|
err = can_mcan_clear_mram(dev, config->mram_offsets[CAN_MCAN_MRAM_CFG_STD_FILTER] +
|
2023-05-10 22:07:42 +02:00
|
|
|
filter_id * sizeof(struct can_mcan_std_filter),
|
|
|
|
sizeof(struct can_mcan_std_filter));
|
|
|
|
if (err != 0) {
|
|
|
|
LOG_ERR("failed to clear std filter element (err %d)", err);
|
|
|
|
}
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
k_mutex_unlock(&data->lock);
|
2021-02-11 20:07:04 +01:00
|
|
|
}
|
2022-04-19 13:46:30 +02:00
|
|
|
|
|
|
|
void can_mcan_set_state_change_callback(const struct device *dev,
|
2023-04-24 14:22:14 +02:00
|
|
|
can_state_change_callback_t callback, void *user_data)
|
2022-04-19 13:46:30 +02:00
|
|
|
{
|
|
|
|
struct can_mcan_data *data = dev->data;
|
|
|
|
|
2024-01-17 19:52:24 +01:00
|
|
|
data->common.state_change_cb = callback;
|
|
|
|
data->common.state_change_cb_user_data = user_data;
|
2022-04-19 13:46:30 +02:00
|
|
|
}
|
|
|
|
|
2022-08-12 23:42:16 +02:00
|
|
|
/* helper function allowing mcan drivers without access to private mcan
|
|
|
|
* definitions to set CCCR_CCE, which might be needed to disable write
|
|
|
|
* protection for some registers.
|
|
|
|
*/
|
|
|
|
void can_mcan_enable_configuration_change(const struct device *dev)
|
|
|
|
{
|
2023-05-02 13:24:18 +02:00
|
|
|
struct can_mcan_data *data = dev->data;
|
|
|
|
uint32_t cccr;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
k_mutex_lock(&data->lock, K_FOREVER);
|
|
|
|
|
|
|
|
err = can_mcan_read_reg(dev, CAN_MCAN_CCCR, &cccr);
|
|
|
|
if (err != 0) {
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
cccr |= CAN_MCAN_CCCR_CCE;
|
2022-08-12 23:42:16 +02:00
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_CCCR, cccr);
|
|
|
|
if (err != 0) {
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
unlock:
|
|
|
|
k_mutex_unlock(&data->lock);
|
2022-08-12 23:42:16 +02:00
|
|
|
}
|
2023-04-24 14:31:44 +02:00
|
|
|
|
2023-05-10 22:07:42 +02:00
|
|
|
int can_mcan_configure_mram(const struct device *dev, uintptr_t mrba, uintptr_t mram)
|
2023-04-24 14:31:44 +02:00
|
|
|
{
|
2023-05-22 16:31:09 +02:00
|
|
|
const struct can_mcan_config *config = dev->config;
|
|
|
|
uint32_t addr;
|
2023-05-02 13:24:18 +02:00
|
|
|
uint32_t reg;
|
|
|
|
int err;
|
2023-04-24 14:31:44 +02:00
|
|
|
|
2023-05-18 12:22:37 +02:00
|
|
|
err = can_mcan_exit_sleep_mode(dev);
|
|
|
|
if (err != 0) {
|
|
|
|
LOG_ERR("Failed to exit sleep mode");
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = can_mcan_enter_init_mode(dev, K_MSEC(CAN_INIT_TIMEOUT_MS));
|
|
|
|
if (err != 0) {
|
|
|
|
LOG_ERR("Failed to enter init mode");
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
2023-04-24 14:31:44 +02:00
|
|
|
can_mcan_enable_configuration_change(dev);
|
|
|
|
|
2023-05-22 16:31:09 +02:00
|
|
|
addr = mram - mrba + config->mram_offsets[CAN_MCAN_MRAM_CFG_STD_FILTER];
|
|
|
|
reg = (addr & CAN_MCAN_SIDFC_FLSSA) | FIELD_PREP(CAN_MCAN_SIDFC_LSS,
|
|
|
|
config->mram_elements[CAN_MCAN_MRAM_CFG_STD_FILTER]);
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_SIDFC, reg);
|
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2023-05-22 16:31:09 +02:00
|
|
|
addr = mram - mrba + config->mram_offsets[CAN_MCAN_MRAM_CFG_EXT_FILTER];
|
|
|
|
reg = (addr & CAN_MCAN_XIDFC_FLESA) | FIELD_PREP(CAN_MCAN_XIDFC_LSS,
|
|
|
|
config->mram_elements[CAN_MCAN_MRAM_CFG_EXT_FILTER]);
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_XIDFC, reg);
|
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2023-05-22 16:31:09 +02:00
|
|
|
addr = mram - mrba + config->mram_offsets[CAN_MCAN_MRAM_CFG_RX_FIFO0];
|
|
|
|
reg = (addr & CAN_MCAN_RXF0C_F0SA) | FIELD_PREP(CAN_MCAN_RXF0C_F0S,
|
|
|
|
config->mram_elements[CAN_MCAN_MRAM_CFG_RX_FIFO0]);
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_RXF0C, reg);
|
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2023-05-22 16:31:09 +02:00
|
|
|
addr = mram - mrba + config->mram_offsets[CAN_MCAN_MRAM_CFG_RX_FIFO1];
|
|
|
|
reg = (addr & CAN_MCAN_RXF1C_F1SA) | FIELD_PREP(CAN_MCAN_RXF1C_F1S,
|
|
|
|
config->mram_elements[CAN_MCAN_MRAM_CFG_RX_FIFO1]);
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_RXF1C, reg);
|
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2023-05-22 16:31:09 +02:00
|
|
|
addr = mram - mrba + config->mram_offsets[CAN_MCAN_MRAM_CFG_RX_BUFFER];
|
|
|
|
reg = (addr & CAN_MCAN_RXBC_RBSA);
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_RXBC, reg);
|
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2023-05-22 16:31:09 +02:00
|
|
|
addr = mram - mrba + config->mram_offsets[CAN_MCAN_MRAM_CFG_TX_EVENT_FIFO];
|
|
|
|
reg = (addr & CAN_MCAN_TXEFC_EFSA) | FIELD_PREP(CAN_MCAN_TXEFC_EFS,
|
|
|
|
config->mram_elements[CAN_MCAN_MRAM_CFG_TX_EVENT_FIFO]);
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_TXEFC, reg);
|
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2023-05-22 16:31:09 +02:00
|
|
|
addr = mram - mrba + config->mram_offsets[CAN_MCAN_MRAM_CFG_TX_BUFFER];
|
|
|
|
reg = (addr & CAN_MCAN_TXBC_TBSA) | FIELD_PREP(CAN_MCAN_TXBC_TFQS,
|
|
|
|
config->mram_elements[CAN_MCAN_MRAM_CFG_TX_BUFFER]) | CAN_MCAN_TXBC_TFQM;
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_TXBC, reg);
|
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
|
|
|
}
|
2023-04-24 14:31:44 +02:00
|
|
|
|
2023-05-10 22:07:42 +02:00
|
|
|
/* 64 byte Tx Buffer data fields size */
|
|
|
|
reg = CAN_MCAN_TXESC_TBDS;
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_TXESC, reg);
|
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
2023-04-24 14:31:44 +02:00
|
|
|
}
|
|
|
|
|
2023-05-10 22:07:42 +02:00
|
|
|
/* 64 byte Rx Buffer/FIFO1/FIFO0 data fields size */
|
|
|
|
reg = CAN_MCAN_RXESC_RBDS | CAN_MCAN_RXESC_F1DS | CAN_MCAN_RXESC_F0DS;
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_RXESC, reg);
|
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2023-05-07 19:00:15 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int can_mcan_init(const struct device *dev)
|
|
|
|
{
|
|
|
|
const struct can_mcan_config *config = dev->config;
|
2023-05-22 16:31:09 +02:00
|
|
|
const struct can_mcan_callbacks *cbs = config->callbacks;
|
2023-05-07 19:00:15 +02:00
|
|
|
struct can_mcan_data *data = dev->data;
|
2023-09-22 12:07:16 +02:00
|
|
|
struct can_timing timing = { 0 };
|
2023-05-07 19:00:15 +02:00
|
|
|
#ifdef CONFIG_CAN_FD_MODE
|
2023-09-22 12:07:16 +02:00
|
|
|
struct can_timing timing_data = { 0 };
|
2023-05-07 19:00:15 +02:00
|
|
|
#endif /* CONFIG_CAN_FD_MODE */
|
|
|
|
uint32_t reg;
|
|
|
|
int err;
|
|
|
|
|
2023-05-10 22:07:42 +02:00
|
|
|
__ASSERT_NO_MSG(config->ops->read_reg != NULL);
|
|
|
|
__ASSERT_NO_MSG(config->ops->write_reg != NULL);
|
|
|
|
__ASSERT_NO_MSG(config->ops->read_mram != NULL);
|
|
|
|
__ASSERT_NO_MSG(config->ops->write_mram != NULL);
|
|
|
|
__ASSERT_NO_MSG(config->ops->clear_mram != NULL);
|
2023-05-22 16:31:09 +02:00
|
|
|
__ASSERT_NO_MSG(config->callbacks != NULL);
|
|
|
|
|
|
|
|
__ASSERT_NO_MSG(cbs->num_tx <= config->mram_elements[CAN_MCAN_MRAM_CFG_TX_BUFFER]);
|
|
|
|
__ASSERT_NO_MSG(cbs->num_std <= config->mram_elements[CAN_MCAN_MRAM_CFG_STD_FILTER]);
|
|
|
|
__ASSERT_NO_MSG(cbs->num_ext <= config->mram_elements[CAN_MCAN_MRAM_CFG_EXT_FILTER]);
|
2023-05-10 22:07:42 +02:00
|
|
|
|
2023-05-07 19:00:15 +02:00
|
|
|
k_mutex_init(&data->lock);
|
|
|
|
k_mutex_init(&data->tx_mtx);
|
2023-05-22 16:31:09 +02:00
|
|
|
k_sem_init(&data->tx_sem, cbs->num_tx, cbs->num_tx);
|
2023-05-07 19:00:15 +02:00
|
|
|
|
2024-01-17 19:52:24 +01:00
|
|
|
if (config->common.phy != NULL) {
|
|
|
|
if (!device_is_ready(config->common.phy)) {
|
2023-05-07 19:00:15 +02:00
|
|
|
LOG_ERR("CAN transceiver not ready");
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
err = can_mcan_exit_sleep_mode(dev);
|
|
|
|
if (err != 0) {
|
|
|
|
LOG_ERR("Failed to exit sleep mode");
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = can_mcan_enter_init_mode(dev, K_MSEC(CAN_INIT_TIMEOUT_MS));
|
|
|
|
if (err != 0) {
|
|
|
|
LOG_ERR("Failed to enter init mode");
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
can_mcan_enable_configuration_change(dev);
|
|
|
|
|
|
|
|
#if CONFIG_CAN_LOG_LEVEL >= LOG_LEVEL_DBG
|
|
|
|
err = can_mcan_read_reg(dev, CAN_MCAN_CREL, ®);
|
|
|
|
if (err != 0) {
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
LOG_DBG("IP rel: %lu.%lu.%lu %02lu.%lu.%lu", FIELD_GET(CAN_MCAN_CREL_REL, reg),
|
|
|
|
FIELD_GET(CAN_MCAN_CREL_STEP, reg), FIELD_GET(CAN_MCAN_CREL_SUBSTEP, reg),
|
|
|
|
FIELD_GET(CAN_MCAN_CREL_YEAR, reg), FIELD_GET(CAN_MCAN_CREL_MON, reg),
|
|
|
|
FIELD_GET(CAN_MCAN_CREL_DAY, reg));
|
|
|
|
#endif /* CONFIG_CAN_LOG_LEVEL >= LOG_LEVEL_DBG */
|
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_read_reg(dev, CAN_MCAN_CCCR, ®);
|
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
reg &= ~(CAN_MCAN_CCCR_FDOE | CAN_MCAN_CCCR_BRSE | CAN_MCAN_CCCR_TEST | CAN_MCAN_CCCR_MON |
|
|
|
|
CAN_MCAN_CCCR_ASM);
|
|
|
|
|
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_CCCR, reg);
|
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = can_mcan_read_reg(dev, CAN_MCAN_TEST, ®);
|
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
reg &= ~(CAN_MCAN_TEST_LBCK);
|
|
|
|
|
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_TEST, reg);
|
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
|
|
|
}
|
2023-04-24 14:31:44 +02:00
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_read_reg(dev, CAN_MCAN_GFC, ®);
|
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
reg |= FIELD_PREP(CAN_MCAN_GFC_ANFE, 0x2) | FIELD_PREP(CAN_MCAN_GFC_ANFS, 0x2);
|
2023-12-15 13:36:18 +01:00
|
|
|
if (!IS_ENABLED(CONFIG_CAN_ACCEPT_RTR)) {
|
|
|
|
reg |= CAN_MCAN_GFC_RRFS | CAN_MCAN_GFC_RRFE;
|
|
|
|
}
|
2023-05-02 13:24:18 +02:00
|
|
|
|
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_GFC, reg);
|
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
|
|
|
}
|
2023-04-24 14:31:44 +02:00
|
|
|
|
2024-02-07 17:35:21 +01:00
|
|
|
err = can_calc_timing(dev, &timing, config->common.bus_speed,
|
|
|
|
config->common.sample_point);
|
|
|
|
if (err == -EINVAL) {
|
|
|
|
LOG_ERR("Can't find timing for given param");
|
|
|
|
return -EIO;
|
2023-04-24 14:31:44 +02:00
|
|
|
}
|
|
|
|
|
2024-02-07 17:35:21 +01:00
|
|
|
LOG_DBG("Presc: %d, TS1: %d, TS2: %d", timing.prescaler, timing.phase_seg1,
|
|
|
|
timing.phase_seg2);
|
|
|
|
LOG_DBG("Sample-point err : %d", err);
|
|
|
|
#ifdef CONFIG_CAN_FD_MODE
|
|
|
|
err = can_calc_timing_data(dev, &timing_data, config->common.bus_speed_data,
|
|
|
|
config->common.sample_point_data);
|
|
|
|
if (err == -EINVAL) {
|
|
|
|
LOG_ERR("Can't find timing for given dataphase param");
|
|
|
|
return -EIO;
|
2023-04-24 14:31:44 +02:00
|
|
|
}
|
2024-02-07 17:35:21 +01:00
|
|
|
|
|
|
|
LOG_DBG("Sample-point err data phase: %d", err);
|
2023-04-24 14:54:52 +02:00
|
|
|
#endif /* CONFIG_CAN_FD_MODE */
|
2023-04-24 14:31:44 +02:00
|
|
|
|
2023-09-22 12:07:16 +02:00
|
|
|
err = can_set_timing(dev, &timing);
|
|
|
|
if (err != 0) {
|
|
|
|
LOG_ERR("failed to set timing (err %d)", err);
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
2023-04-24 14:40:02 +02:00
|
|
|
|
2023-04-24 14:31:44 +02:00
|
|
|
#ifdef CONFIG_CAN_FD_MODE
|
2023-09-22 12:07:16 +02:00
|
|
|
err = can_set_timing_data(dev, &timing_data);
|
|
|
|
if (err != 0) {
|
|
|
|
LOG_ERR("failed to set data phase timing (err %d)", err);
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
2023-04-24 14:54:52 +02:00
|
|
|
#endif /* CONFIG_CAN_FD_MODE */
|
2023-04-24 14:31:44 +02:00
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
reg = CAN_MCAN_IE_BOE | CAN_MCAN_IE_EWE | CAN_MCAN_IE_EPE | CAN_MCAN_IE_MRAFE |
|
|
|
|
CAN_MCAN_IE_TEFLE | CAN_MCAN_IE_TEFNE | CAN_MCAN_IE_RF0NE | CAN_MCAN_IE_RF1NE |
|
|
|
|
CAN_MCAN_IE_RF0LE | CAN_MCAN_IE_RF1LE;
|
2023-09-18 03:42:16 +02:00
|
|
|
#ifdef CONFIG_CAN_STATS
|
|
|
|
/* These ISRs are only enabled/used for statistics, they are otherwise
|
|
|
|
* disabled as they may produce a significant amount of frequent ISRs.
|
|
|
|
*/
|
|
|
|
reg |= CAN_MCAN_IE_PEAE | CAN_MCAN_IE_PEDE;
|
|
|
|
#endif
|
2023-04-24 14:31:44 +02:00
|
|
|
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_IE, reg);
|
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
|
|
|
}
|
2023-05-07 19:48:21 +02:00
|
|
|
|
2023-10-04 00:45:13 +02:00
|
|
|
reg = CAN_MCAN_ILS_RF0NL | CAN_MCAN_ILS_RF1NL | CAN_MCAN_ILS_RF0LL | CAN_MCAN_ILS_RF1LL;
|
2023-05-02 13:24:18 +02:00
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_ILS, reg);
|
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
reg = CAN_MCAN_ILE_EINT0 | CAN_MCAN_ILE_EINT1;
|
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_ILE, reg);
|
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2024-02-13 20:21:17 +01:00
|
|
|
/* Interrupt on every TX buffer transmission event */
|
2023-05-02 13:24:18 +02:00
|
|
|
reg = CAN_MCAN_TXBTIE_TIE;
|
|
|
|
err = can_mcan_write_reg(dev, CAN_MCAN_TXBTIE, reg);
|
|
|
|
if (err != 0) {
|
|
|
|
return err;
|
|
|
|
}
|
2023-04-24 14:31:44 +02:00
|
|
|
|
2023-05-22 16:31:09 +02:00
|
|
|
return can_mcan_clear_mram(dev, 0, config->mram_size);
|
2023-04-24 14:31:44 +02:00
|
|
|
}
|