2018-05-03 10:59:12 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2018 Alexander Wachter
|
2022-07-23 08:01:10 +02:00
|
|
|
* Copyright (c) 2022 Martin Jäger <martin@libre.solar>
|
2018-05-03 10:59:12 +02:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
2022-05-06 10:25:46 +02:00
|
|
|
#include <zephyr/drivers/can/transceiver.h>
|
|
|
|
#include <zephyr/drivers/clock_control/stm32_clock_control.h>
|
|
|
|
#include <zephyr/drivers/clock_control.h>
|
|
|
|
#include <zephyr/drivers/pinctrl.h>
|
|
|
|
#include <zephyr/sys/util.h>
|
2018-05-03 10:59:12 +02:00
|
|
|
#include <string.h>
|
2022-05-06 10:25:46 +02:00
|
|
|
#include <zephyr/kernel.h>
|
2018-10-31 12:44:45 -05:00
|
|
|
#include <soc.h>
|
2018-05-03 10:59:12 +02:00
|
|
|
#include <errno.h>
|
|
|
|
#include <stdbool.h>
|
2022-05-06 10:25:46 +02:00
|
|
|
#include <zephyr/drivers/can.h>
|
|
|
|
#include <zephyr/logging/log.h>
|
2022-10-17 10:24:11 +02:00
|
|
|
#include <zephyr/irq.h>
|
2022-02-22 12:06:54 +01:00
|
|
|
|
|
|
|
LOG_MODULE_REGISTER(can_stm32, CONFIG_CAN_LOG_LEVEL);
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2018-06-19 18:26:31 +02:00
|
|
|
#define CAN_INIT_TIMEOUT (10 * sys_clock_hw_cycles_per_sec() / MSEC_PER_SEC)
|
2019-07-01 16:44:33 +02:00
|
|
|
|
2023-08-15 10:37:32 +02:00
|
|
|
#define DT_DRV_COMPAT st_stm32_bxcan
|
2020-11-20 13:39:48 +01:00
|
|
|
|
|
|
|
#define SP_IS_SET(inst) DT_INST_NODE_HAS_PROP(inst, sample_point) ||
|
|
|
|
|
|
|
|
/* Macro to exclude the sample point algorithm from compilation if not used
|
|
|
|
* Without the macro, the algorithm would always waste ROM
|
|
|
|
*/
|
|
|
|
#define USE_SP_ALGO (DT_INST_FOREACH_STATUS_OKAY(SP_IS_SET) 0)
|
|
|
|
|
|
|
|
#define SP_AND_TIMING_NOT_SET(inst) \
|
|
|
|
(!DT_INST_NODE_HAS_PROP(inst, sample_point) && \
|
|
|
|
!(DT_INST_NODE_HAS_PROP(inst, prop_seg) && \
|
|
|
|
DT_INST_NODE_HAS_PROP(inst, phase_seg1) && \
|
|
|
|
DT_INST_NODE_HAS_PROP(inst, phase_seg2))) ||
|
|
|
|
|
|
|
|
#if DT_INST_FOREACH_STATUS_OKAY(SP_AND_TIMING_NOT_SET) 0
|
|
|
|
#error You must either set a sampling-point or timings (phase-seg* and prop-seg)
|
|
|
|
#endif
|
|
|
|
|
2023-08-15 10:24:49 +02:00
|
|
|
#define CAN_STM32_NUM_FILTER_BANKS (14)
|
|
|
|
#define CAN_STM32_MAX_FILTER_ID \
|
|
|
|
(CONFIG_CAN_MAX_EXT_ID_FILTER + CONFIG_CAN_MAX_STD_ID_FILTER * 2)
|
|
|
|
|
|
|
|
#define CAN_STM32_FIRX_STD_IDE_POS (3U)
|
|
|
|
#define CAN_STM32_FIRX_STD_RTR_POS (4U)
|
|
|
|
#define CAN_STM32_FIRX_STD_ID_POS (5U)
|
|
|
|
|
|
|
|
#define CAN_STM32_FIRX_EXT_IDE_POS (2U)
|
|
|
|
#define CAN_STM32_FIRX_EXT_RTR_POS (1U)
|
|
|
|
#define CAN_STM32_FIRX_EXT_STD_ID_POS (21U)
|
|
|
|
#define CAN_STM32_FIRX_EXT_EXT_ID_POS (3U)
|
|
|
|
|
2022-07-23 08:01:10 +02:00
|
|
|
#if (CONFIG_CAN_MAX_STD_ID_FILTER + CONFIG_CAN_MAX_EXT_ID_FILTER * 2) > \
|
|
|
|
(CAN_STM32_NUM_FILTER_BANKS * 2)
|
|
|
|
#error Number of configured filters exceeds available filter bank slots.
|
|
|
|
#endif
|
2019-02-06 22:34:59 +01:00
|
|
|
|
2023-08-15 10:24:49 +02:00
|
|
|
struct can_stm32_mailbox {
|
|
|
|
can_tx_callback_t tx_callback;
|
|
|
|
void *callback_arg;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct can_stm32_data {
|
|
|
|
struct k_mutex inst_mutex;
|
|
|
|
struct k_sem tx_int_sem;
|
|
|
|
struct can_stm32_mailbox mb0;
|
|
|
|
struct can_stm32_mailbox mb1;
|
|
|
|
struct can_stm32_mailbox mb2;
|
|
|
|
can_rx_callback_t rx_cb_std[CONFIG_CAN_MAX_STD_ID_FILTER];
|
|
|
|
can_rx_callback_t rx_cb_ext[CONFIG_CAN_MAX_EXT_ID_FILTER];
|
|
|
|
void *cb_arg_std[CONFIG_CAN_MAX_STD_ID_FILTER];
|
|
|
|
void *cb_arg_ext[CONFIG_CAN_MAX_EXT_ID_FILTER];
|
|
|
|
can_state_change_callback_t state_change_cb;
|
|
|
|
void *state_change_cb_data;
|
|
|
|
enum can_state state;
|
|
|
|
bool started;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct can_stm32_config {
|
|
|
|
CAN_TypeDef *can; /*!< CAN Registers*/
|
|
|
|
CAN_TypeDef *master_can; /*!< CAN Registers for shared filter */
|
|
|
|
uint32_t bus_speed;
|
|
|
|
uint16_t sample_point;
|
|
|
|
uint8_t sjw;
|
|
|
|
uint8_t prop_ts1;
|
|
|
|
uint8_t ts2;
|
|
|
|
struct stm32_pclken pclken;
|
|
|
|
void (*config_irq)(CAN_TypeDef *can);
|
|
|
|
const struct pinctrl_dev_config *pcfg;
|
|
|
|
const struct device *phy;
|
|
|
|
uint32_t max_bitrate;
|
|
|
|
};
|
|
|
|
|
2022-06-17 13:35:39 +02:00
|
|
|
/*
|
|
|
|
* Mutex to prevent simultaneous access to filter registers shared between CAN1
|
|
|
|
* and CAN2.
|
|
|
|
*/
|
|
|
|
static struct k_mutex filter_mutex;
|
|
|
|
|
2022-09-21 16:46:38 +02:00
|
|
|
static void can_stm32_signal_tx_complete(const struct device *dev, struct can_stm32_mailbox *mb,
|
|
|
|
int status)
|
2018-05-03 10:59:12 +02:00
|
|
|
{
|
2022-09-21 16:46:38 +02:00
|
|
|
can_tx_callback_t callback = mb->tx_callback;
|
|
|
|
|
|
|
|
if (callback != NULL) {
|
|
|
|
callback(dev, status, mb->callback_arg);
|
|
|
|
mb->tx_callback = NULL;
|
|
|
|
}
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
2022-08-11 15:31:59 +02:00
|
|
|
static void can_stm32_rx_fifo_pop(CAN_FIFOMailBox_TypeDef *mbox, struct can_frame *frame)
|
2018-05-03 10:59:12 +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
|
|
|
memset(frame, 0, sizeof(*frame));
|
|
|
|
|
2018-05-03 10:59:12 +02:00
|
|
|
if (mbox->RIR & CAN_RI0R_IDE) {
|
2021-12-04 15:21:32 +01:00
|
|
|
frame->id = mbox->RIR >> CAN_RI0R_EXID_Pos;
|
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->flags |= CAN_FRAME_IDE;
|
2018-05-03 10:59:12 +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 = mbox->RIR >> CAN_RI0R_STID_Pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((mbox->RIR & CAN_RI0R_RTR) != 0) {
|
|
|
|
frame->flags |= CAN_FRAME_RTR;
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
2021-12-04 15:21:32 +01:00
|
|
|
frame->dlc = mbox->RDTR & (CAN_RDT0R_DLC >> CAN_RDT0R_DLC_Pos);
|
|
|
|
frame->data_32[0] = mbox->RDLR;
|
|
|
|
frame->data_32[1] = mbox->RDHR;
|
2019-07-24 15:38:11 +02:00
|
|
|
#ifdef CONFIG_CAN_RX_TIMESTAMP
|
2021-12-04 15:21:32 +01:00
|
|
|
frame->timestamp = ((mbox->RDTR & CAN_RDT0R_TIME) >> CAN_RDT0R_TIME_Pos);
|
2019-07-24 15:38:11 +02:00
|
|
|
#endif
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
2022-03-30 15:09:31 +02:00
|
|
|
static inline void can_stm32_rx_isr_handler(const struct device *dev)
|
2018-05-03 10:59:12 +02:00
|
|
|
{
|
2022-03-17 22:06:51 +01:00
|
|
|
struct can_stm32_data *data = dev->data;
|
|
|
|
const struct can_stm32_config *cfg = dev->config;
|
|
|
|
CAN_TypeDef *can = cfg->can;
|
2018-05-23 10:54:56 +02:00
|
|
|
CAN_FIFOMailBox_TypeDef *mbox;
|
2022-07-23 08:01:10 +02:00
|
|
|
int filter_id, index;
|
2022-08-11 15:31:59 +02:00
|
|
|
struct can_frame frame;
|
2022-07-23 08:01:10 +02:00
|
|
|
can_rx_callback_t callback = NULL;
|
|
|
|
void *cb_arg;
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2018-05-23 10:54:56 +02:00
|
|
|
while (can->RF0R & CAN_RF0R_FMP0) {
|
|
|
|
mbox = &can->sFIFOMailBox[0];
|
2022-07-23 08:01:10 +02:00
|
|
|
filter_id = ((mbox->RDTR & CAN_RDT0R_FMI) >> CAN_RDT0R_FMI_Pos);
|
2018-05-23 10:54:56 +02:00
|
|
|
|
2022-07-23 08:01:10 +02:00
|
|
|
LOG_DBG("Message on filter_id %d", filter_id);
|
2018-05-23 10:54:56 +02:00
|
|
|
|
2022-07-15 11:07:18 +02:00
|
|
|
can_stm32_rx_fifo_pop(mbox, &frame);
|
2018-05-23 10:54:56 +02:00
|
|
|
|
2022-07-23 08:01:10 +02:00
|
|
|
if (filter_id < CONFIG_CAN_MAX_EXT_ID_FILTER) {
|
|
|
|
callback = data->rx_cb_ext[filter_id];
|
|
|
|
cb_arg = data->cb_arg_ext[filter_id];
|
|
|
|
} else if (filter_id < CAN_STM32_MAX_FILTER_ID) {
|
|
|
|
index = filter_id - CONFIG_CAN_MAX_EXT_ID_FILTER;
|
|
|
|
callback = data->rx_cb_std[index];
|
|
|
|
cb_arg = data->cb_arg_std[index];
|
|
|
|
}
|
2018-05-23 10:54:56 +02:00
|
|
|
|
2019-03-17 22:51:13 +01:00
|
|
|
if (callback) {
|
2022-07-23 08:01:10 +02:00
|
|
|
callback(dev, &frame, cb_arg);
|
2018-05-23 10:54:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Release message */
|
|
|
|
can->RF0R |= CAN_RF0R_RFOM0;
|
|
|
|
}
|
2019-07-02 12:42:38 +02:00
|
|
|
|
|
|
|
if (can->RF0R & CAN_RF0R_FOVR0) {
|
|
|
|
LOG_ERR("RX FIFO Overflow");
|
2023-01-03 13:22:22 +01:00
|
|
|
CAN_STATS_RX_OVERRUN_INC(dev);
|
2019-07-02 12:42:38 +02:00
|
|
|
}
|
2018-05-23 10:54:56 +02:00
|
|
|
}
|
|
|
|
|
2022-02-25 13:49:01 +01:00
|
|
|
static int can_stm32_get_state(const struct device *dev, enum can_state *state,
|
|
|
|
struct can_bus_err_cnt *err_cnt)
|
2018-06-19 18:26:31 +02:00
|
|
|
{
|
2022-02-25 11:10:38 +01:00
|
|
|
const struct can_stm32_config *cfg = dev->config;
|
2022-08-31 14:28:42 +02:00
|
|
|
struct can_stm32_data *data = dev->data;
|
2022-02-25 13:49:01 +01:00
|
|
|
CAN_TypeDef *can = cfg->can;
|
|
|
|
|
|
|
|
if (state != NULL) {
|
2022-08-31 14:28:42 +02:00
|
|
|
if (!data->started) {
|
|
|
|
*state = CAN_STATE_STOPPED;
|
|
|
|
} else if (can->ESR & CAN_ESR_BOFF) {
|
2022-08-18 16:14:48 +02:00
|
|
|
*state = CAN_STATE_BUS_OFF;
|
2022-02-25 13:49:01 +01:00
|
|
|
} else if (can->ESR & CAN_ESR_EPVF) {
|
2022-08-18 16:14:48 +02:00
|
|
|
*state = CAN_STATE_ERROR_PASSIVE;
|
2022-02-25 13:49:01 +01:00
|
|
|
} else if (can->ESR & CAN_ESR_EWGF) {
|
2022-08-18 16:14:48 +02:00
|
|
|
*state = CAN_STATE_ERROR_WARNING;
|
2022-02-25 13:49:01 +01:00
|
|
|
} else {
|
2022-08-18 16:14:48 +02:00
|
|
|
*state = CAN_STATE_ERROR_ACTIVE;
|
2022-02-25 13:49:01 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err_cnt != NULL) {
|
|
|
|
err_cnt->tx_err_cnt =
|
|
|
|
((can->ESR & CAN_ESR_TEC) >> CAN_ESR_TEC_Pos);
|
|
|
|
err_cnt->rx_err_cnt =
|
|
|
|
((can->ESR & CAN_ESR_REC) >> CAN_ESR_REC_Pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void can_stm32_bus_state_change_isr(const struct device *dev)
|
|
|
|
{
|
2022-02-25 11:10:38 +01:00
|
|
|
struct can_stm32_data *data = dev->data;
|
2018-06-19 18:26:31 +02:00
|
|
|
struct can_bus_err_cnt err_cnt;
|
|
|
|
enum can_state state;
|
2021-12-28 20:00:34 +01:00
|
|
|
const can_state_change_callback_t cb = data->state_change_cb;
|
2022-01-10 12:32:19 +01:00
|
|
|
void *state_change_cb_data = data->state_change_cb_data;
|
2022-02-25 11:10:38 +01:00
|
|
|
|
|
|
|
#ifdef CONFIG_CAN_STATS
|
2022-02-25 13:49:01 +01:00
|
|
|
const struct can_stm32_config *cfg = dev->config;
|
|
|
|
CAN_TypeDef *can = cfg->can;
|
|
|
|
|
2022-02-25 11:10:38 +01:00
|
|
|
switch (can->ESR & CAN_ESR_LEC) {
|
|
|
|
case (CAN_ESR_LEC_0):
|
|
|
|
CAN_STATS_STUFF_ERROR_INC(dev);
|
|
|
|
break;
|
|
|
|
case (CAN_ESR_LEC_1):
|
|
|
|
CAN_STATS_FORM_ERROR_INC(dev);
|
|
|
|
break;
|
|
|
|
case (CAN_ESR_LEC_1 | CAN_ESR_LEC_0):
|
|
|
|
CAN_STATS_ACK_ERROR_INC(dev);
|
|
|
|
break;
|
|
|
|
case (CAN_ESR_LEC_2):
|
|
|
|
CAN_STATS_BIT1_ERROR_INC(dev);
|
|
|
|
break;
|
|
|
|
case (CAN_ESR_LEC_2 | CAN_ESR_LEC_0):
|
|
|
|
CAN_STATS_BIT0_ERROR_INC(dev);
|
|
|
|
break;
|
|
|
|
case (CAN_ESR_LEC_2 | CAN_ESR_LEC_1):
|
|
|
|
CAN_STATS_CRC_ERROR_INC(dev);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Clear last error code flag */
|
|
|
|
can->ESR |= CAN_ESR_LEC;
|
|
|
|
#endif /* CONFIG_CAN_STATS */
|
2018-06-19 18:26:31 +02:00
|
|
|
|
2022-02-25 13:49:01 +01:00
|
|
|
(void)can_stm32_get_state(dev, &state, &err_cnt);
|
2018-06-19 18:26:31 +02:00
|
|
|
|
2022-02-25 13:49:01 +01:00
|
|
|
if (state != data->state) {
|
|
|
|
data->state = state;
|
2018-06-19 18:26:31 +02:00
|
|
|
|
2022-02-25 13:49:01 +01:00
|
|
|
if (cb != NULL) {
|
2022-03-17 22:06:51 +01:00
|
|
|
cb(dev, state, err_cnt, state_change_cb_data);
|
2022-02-25 13:49:01 +01:00
|
|
|
}
|
2018-06-19 18:26:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-30 15:09:31 +02:00
|
|
|
static inline void can_stm32_tx_isr_handler(const struct device *dev)
|
2018-05-23 10:54:56 +02:00
|
|
|
{
|
2022-03-17 22:06:51 +01:00
|
|
|
struct can_stm32_data *data = dev->data;
|
|
|
|
const struct can_stm32_config *cfg = dev->config;
|
|
|
|
CAN_TypeDef *can = cfg->can;
|
2020-05-27 11:26:57 -05:00
|
|
|
uint32_t bus_off;
|
2022-09-21 16:46:38 +02:00
|
|
|
int status;
|
2018-05-03 10:59:12 +02:00
|
|
|
|
|
|
|
bus_off = can->ESR & CAN_ESR_BOFF;
|
|
|
|
|
|
|
|
if ((can->TSR & CAN_TSR_RQCP0) | bus_off) {
|
2022-09-21 16:46:38 +02:00
|
|
|
status = can->TSR & CAN_TSR_TXOK0 ? 0 :
|
|
|
|
can->TSR & CAN_TSR_TERR0 ? -EIO :
|
|
|
|
can->TSR & CAN_TSR_ALST0 ? -EBUSY :
|
|
|
|
bus_off ? -ENETUNREACH :
|
|
|
|
-EIO;
|
2018-05-03 10:59:12 +02:00
|
|
|
/* clear the request. */
|
|
|
|
can->TSR |= CAN_TSR_RQCP0;
|
2022-09-21 16:46:38 +02:00
|
|
|
can_stm32_signal_tx_complete(dev, &data->mb0, status);
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((can->TSR & CAN_TSR_RQCP1) | bus_off) {
|
2022-09-21 16:46:38 +02:00
|
|
|
status = can->TSR & CAN_TSR_TXOK1 ? 0 :
|
|
|
|
can->TSR & CAN_TSR_TERR1 ? -EIO :
|
|
|
|
can->TSR & CAN_TSR_ALST1 ? -EBUSY :
|
|
|
|
bus_off ? -ENETUNREACH :
|
|
|
|
-EIO;
|
2018-05-03 10:59:12 +02:00
|
|
|
/* clear the request. */
|
|
|
|
can->TSR |= CAN_TSR_RQCP1;
|
2022-09-21 16:46:38 +02:00
|
|
|
can_stm32_signal_tx_complete(dev, &data->mb1, status);
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((can->TSR & CAN_TSR_RQCP2) | bus_off) {
|
2022-09-21 16:46:38 +02:00
|
|
|
status = can->TSR & CAN_TSR_TXOK2 ? 0 :
|
|
|
|
can->TSR & CAN_TSR_TERR2 ? -EIO :
|
|
|
|
can->TSR & CAN_TSR_ALST2 ? -EBUSY :
|
|
|
|
bus_off ? -ENETUNREACH :
|
|
|
|
-EIO;
|
2018-05-03 10:59:12 +02:00
|
|
|
/* clear the request. */
|
|
|
|
can->TSR |= CAN_TSR_RQCP2;
|
2022-09-21 16:46:38 +02:00
|
|
|
can_stm32_signal_tx_complete(dev, &data->mb2, status);
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
2018-05-29 16:10:31 +02:00
|
|
|
if (can->TSR & CAN_TSR_TME) {
|
2018-05-03 10:59:12 +02:00
|
|
|
k_sem_give(&data->tx_int_sem);
|
|
|
|
}
|
2018-05-23 10:54:56 +02:00
|
|
|
}
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2018-05-23 10:54:56 +02:00
|
|
|
#ifdef CONFIG_SOC_SERIES_STM32F0X
|
2018-05-03 10:59:12 +02:00
|
|
|
|
isr: Normalize usage of device instance through ISR
The goal of this patch is to replace the 'void *' parameter by 'struct
device *' if they use such variable or just 'const void *' on all
relevant ISRs
This will avoid not-so-nice const qualifier tweaks when device instances
will be constant.
Note that only the ISR passed to IRQ_CONNECT are of interest here.
In order to do so, the script fix_isr.py below is necessary:
from pathlib import Path
import subprocess
import pickle
import mmap
import sys
import re
import os
cocci_template = """
@r_fix_isr_0
@
type ret_type;
identifier P;
identifier D;
@@
-ret_type <!fn!>(void *P)
+ret_type <!fn!>(const struct device *P)
{
...
(
const struct device *D = (const struct device *)P;
|
const struct device *D = P;
)
...
}
@r_fix_isr_1
@
type ret_type;
identifier P;
identifier D;
@@
-ret_type <!fn!>(void *P)
+ret_type <!fn!>(const struct device *P)
{
...
const struct device *D;
...
(
D = (const struct device *)P;
|
D = P;
)
...
}
@r_fix_isr_2
@
type ret_type;
identifier A;
@@
-ret_type <!fn!>(void *A)
+ret_type <!fn!>(const void *A)
{
...
}
@r_fix_isr_3
@
const struct device *D;
@@
-<!fn!>((void *)D);
+<!fn!>(D);
@r_fix_isr_4
@
type ret_type;
identifier D;
identifier P;
@@
-ret_type <!fn!>(const struct device *P)
+ret_type <!fn!>(const struct device *D)
{
...
(
-const struct device *D = (const struct device *)P;
|
-const struct device *D = P;
)
...
}
@r_fix_isr_5
@
type ret_type;
identifier D;
identifier P;
@@
-ret_type <!fn!>(const struct device *P)
+ret_type <!fn!>(const struct device *D)
{
...
-const struct device *D;
...
(
-D = (const struct device *)P;
|
-D = P;
)
...
}
"""
def find_isr(fn):
db = []
data = None
start = 0
try:
with open(fn, 'r+') as f:
data = str(mmap.mmap(f.fileno(), 0).read())
except Exception as e:
return db
while True:
isr = ""
irq = data.find('IRQ_CONNECT', start)
while irq > -1:
p = 1
arg = 1
p_o = data.find('(', irq)
if p_o < 0:
irq = -1
break;
pos = p_o + 1
while p > 0:
if data[pos] == ')':
p -= 1
elif data[pos] == '(':
p += 1
elif data[pos] == ',' and p == 1:
arg += 1
if arg == 3:
isr += data[pos]
pos += 1
isr = isr.strip(',\\n\\t ')
if isr not in db and len(isr) > 0:
db.append(isr)
start = pos
break
if irq < 0:
break
return db
def patch_isr(fn, isr_list):
if len(isr_list) <= 0:
return
for isr in isr_list:
tmplt = cocci_template.replace('<!fn!>', isr)
with open('/tmp/isr_fix.cocci', 'w') as f:
f.write(tmplt)
cmd = ['spatch', '--sp-file', '/tmp/isr_fix.cocci', '--in-place', fn]
subprocess.run(cmd)
def process_files(path):
if path.is_file() and path.suffix in ['.h', '.c']:
p = str(path.parent) + '/' + path.name
isr_list = find_isr(p)
patch_isr(p, isr_list)
elif path.is_dir():
for p in path.iterdir():
process_files(p)
if len(sys.argv) < 2:
print("You need to provide a dir/file path")
sys.exit(1)
process_files(Path(sys.argv[1]))
And is run: ./fix_isr.py <zephyr root directory>
Finally, some files needed manual fixes such.
Fixes #27399
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2020-06-17 14:58:56 +02:00
|
|
|
static void can_stm32_isr(const struct device *dev)
|
2018-05-23 10:54:56 +02:00
|
|
|
{
|
2022-03-17 22:06:51 +01:00
|
|
|
const struct can_stm32_config *cfg = dev->config;
|
|
|
|
CAN_TypeDef *can = cfg->can;
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2022-03-17 22:06:51 +01:00
|
|
|
can_stm32_tx_isr_handler(dev);
|
|
|
|
can_stm32_rx_isr_handler(dev);
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2018-06-19 18:26:31 +02:00
|
|
|
if (can->MSR & CAN_MSR_ERRI) {
|
2022-02-25 11:10:38 +01:00
|
|
|
can_stm32_bus_state_change_isr(dev);
|
2018-06-19 18:26:31 +02:00
|
|
|
can->MSR |= CAN_MSR_ERRI;
|
|
|
|
}
|
2018-05-23 10:54:56 +02:00
|
|
|
}
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2018-05-23 10:54:56 +02:00
|
|
|
#else
|
2018-05-03 10:59:12 +02:00
|
|
|
|
isr: Normalize usage of device instance through ISR
The goal of this patch is to replace the 'void *' parameter by 'struct
device *' if they use such variable or just 'const void *' on all
relevant ISRs
This will avoid not-so-nice const qualifier tweaks when device instances
will be constant.
Note that only the ISR passed to IRQ_CONNECT are of interest here.
In order to do so, the script fix_isr.py below is necessary:
from pathlib import Path
import subprocess
import pickle
import mmap
import sys
import re
import os
cocci_template = """
@r_fix_isr_0
@
type ret_type;
identifier P;
identifier D;
@@
-ret_type <!fn!>(void *P)
+ret_type <!fn!>(const struct device *P)
{
...
(
const struct device *D = (const struct device *)P;
|
const struct device *D = P;
)
...
}
@r_fix_isr_1
@
type ret_type;
identifier P;
identifier D;
@@
-ret_type <!fn!>(void *P)
+ret_type <!fn!>(const struct device *P)
{
...
const struct device *D;
...
(
D = (const struct device *)P;
|
D = P;
)
...
}
@r_fix_isr_2
@
type ret_type;
identifier A;
@@
-ret_type <!fn!>(void *A)
+ret_type <!fn!>(const void *A)
{
...
}
@r_fix_isr_3
@
const struct device *D;
@@
-<!fn!>((void *)D);
+<!fn!>(D);
@r_fix_isr_4
@
type ret_type;
identifier D;
identifier P;
@@
-ret_type <!fn!>(const struct device *P)
+ret_type <!fn!>(const struct device *D)
{
...
(
-const struct device *D = (const struct device *)P;
|
-const struct device *D = P;
)
...
}
@r_fix_isr_5
@
type ret_type;
identifier D;
identifier P;
@@
-ret_type <!fn!>(const struct device *P)
+ret_type <!fn!>(const struct device *D)
{
...
-const struct device *D;
...
(
-D = (const struct device *)P;
|
-D = P;
)
...
}
"""
def find_isr(fn):
db = []
data = None
start = 0
try:
with open(fn, 'r+') as f:
data = str(mmap.mmap(f.fileno(), 0).read())
except Exception as e:
return db
while True:
isr = ""
irq = data.find('IRQ_CONNECT', start)
while irq > -1:
p = 1
arg = 1
p_o = data.find('(', irq)
if p_o < 0:
irq = -1
break;
pos = p_o + 1
while p > 0:
if data[pos] == ')':
p -= 1
elif data[pos] == '(':
p += 1
elif data[pos] == ',' and p == 1:
arg += 1
if arg == 3:
isr += data[pos]
pos += 1
isr = isr.strip(',\\n\\t ')
if isr not in db and len(isr) > 0:
db.append(isr)
start = pos
break
if irq < 0:
break
return db
def patch_isr(fn, isr_list):
if len(isr_list) <= 0:
return
for isr in isr_list:
tmplt = cocci_template.replace('<!fn!>', isr)
with open('/tmp/isr_fix.cocci', 'w') as f:
f.write(tmplt)
cmd = ['spatch', '--sp-file', '/tmp/isr_fix.cocci', '--in-place', fn]
subprocess.run(cmd)
def process_files(path):
if path.is_file() and path.suffix in ['.h', '.c']:
p = str(path.parent) + '/' + path.name
isr_list = find_isr(p)
patch_isr(p, isr_list)
elif path.is_dir():
for p in path.iterdir():
process_files(p)
if len(sys.argv) < 2:
print("You need to provide a dir/file path")
sys.exit(1)
process_files(Path(sys.argv[1]))
And is run: ./fix_isr.py <zephyr root directory>
Finally, some files needed manual fixes such.
Fixes #27399
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2020-06-17 14:58:56 +02:00
|
|
|
static void can_stm32_rx_isr(const struct device *dev)
|
2018-05-23 10:54:56 +02:00
|
|
|
{
|
2022-03-17 22:06:51 +01:00
|
|
|
can_stm32_rx_isr_handler(dev);
|
2018-05-23 10:54:56 +02:00
|
|
|
}
|
|
|
|
|
isr: Normalize usage of device instance through ISR
The goal of this patch is to replace the 'void *' parameter by 'struct
device *' if they use such variable or just 'const void *' on all
relevant ISRs
This will avoid not-so-nice const qualifier tweaks when device instances
will be constant.
Note that only the ISR passed to IRQ_CONNECT are of interest here.
In order to do so, the script fix_isr.py below is necessary:
from pathlib import Path
import subprocess
import pickle
import mmap
import sys
import re
import os
cocci_template = """
@r_fix_isr_0
@
type ret_type;
identifier P;
identifier D;
@@
-ret_type <!fn!>(void *P)
+ret_type <!fn!>(const struct device *P)
{
...
(
const struct device *D = (const struct device *)P;
|
const struct device *D = P;
)
...
}
@r_fix_isr_1
@
type ret_type;
identifier P;
identifier D;
@@
-ret_type <!fn!>(void *P)
+ret_type <!fn!>(const struct device *P)
{
...
const struct device *D;
...
(
D = (const struct device *)P;
|
D = P;
)
...
}
@r_fix_isr_2
@
type ret_type;
identifier A;
@@
-ret_type <!fn!>(void *A)
+ret_type <!fn!>(const void *A)
{
...
}
@r_fix_isr_3
@
const struct device *D;
@@
-<!fn!>((void *)D);
+<!fn!>(D);
@r_fix_isr_4
@
type ret_type;
identifier D;
identifier P;
@@
-ret_type <!fn!>(const struct device *P)
+ret_type <!fn!>(const struct device *D)
{
...
(
-const struct device *D = (const struct device *)P;
|
-const struct device *D = P;
)
...
}
@r_fix_isr_5
@
type ret_type;
identifier D;
identifier P;
@@
-ret_type <!fn!>(const struct device *P)
+ret_type <!fn!>(const struct device *D)
{
...
-const struct device *D;
...
(
-D = (const struct device *)P;
|
-D = P;
)
...
}
"""
def find_isr(fn):
db = []
data = None
start = 0
try:
with open(fn, 'r+') as f:
data = str(mmap.mmap(f.fileno(), 0).read())
except Exception as e:
return db
while True:
isr = ""
irq = data.find('IRQ_CONNECT', start)
while irq > -1:
p = 1
arg = 1
p_o = data.find('(', irq)
if p_o < 0:
irq = -1
break;
pos = p_o + 1
while p > 0:
if data[pos] == ')':
p -= 1
elif data[pos] == '(':
p += 1
elif data[pos] == ',' and p == 1:
arg += 1
if arg == 3:
isr += data[pos]
pos += 1
isr = isr.strip(',\\n\\t ')
if isr not in db and len(isr) > 0:
db.append(isr)
start = pos
break
if irq < 0:
break
return db
def patch_isr(fn, isr_list):
if len(isr_list) <= 0:
return
for isr in isr_list:
tmplt = cocci_template.replace('<!fn!>', isr)
with open('/tmp/isr_fix.cocci', 'w') as f:
f.write(tmplt)
cmd = ['spatch', '--sp-file', '/tmp/isr_fix.cocci', '--in-place', fn]
subprocess.run(cmd)
def process_files(path):
if path.is_file() and path.suffix in ['.h', '.c']:
p = str(path.parent) + '/' + path.name
isr_list = find_isr(p)
patch_isr(p, isr_list)
elif path.is_dir():
for p in path.iterdir():
process_files(p)
if len(sys.argv) < 2:
print("You need to provide a dir/file path")
sys.exit(1)
process_files(Path(sys.argv[1]))
And is run: ./fix_isr.py <zephyr root directory>
Finally, some files needed manual fixes such.
Fixes #27399
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2020-06-17 14:58:56 +02:00
|
|
|
static void can_stm32_tx_isr(const struct device *dev)
|
2018-05-23 10:54:56 +02:00
|
|
|
{
|
2022-03-17 22:06:51 +01:00
|
|
|
can_stm32_tx_isr_handler(dev);
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
isr: Normalize usage of device instance through ISR
The goal of this patch is to replace the 'void *' parameter by 'struct
device *' if they use such variable or just 'const void *' on all
relevant ISRs
This will avoid not-so-nice const qualifier tweaks when device instances
will be constant.
Note that only the ISR passed to IRQ_CONNECT are of interest here.
In order to do so, the script fix_isr.py below is necessary:
from pathlib import Path
import subprocess
import pickle
import mmap
import sys
import re
import os
cocci_template = """
@r_fix_isr_0
@
type ret_type;
identifier P;
identifier D;
@@
-ret_type <!fn!>(void *P)
+ret_type <!fn!>(const struct device *P)
{
...
(
const struct device *D = (const struct device *)P;
|
const struct device *D = P;
)
...
}
@r_fix_isr_1
@
type ret_type;
identifier P;
identifier D;
@@
-ret_type <!fn!>(void *P)
+ret_type <!fn!>(const struct device *P)
{
...
const struct device *D;
...
(
D = (const struct device *)P;
|
D = P;
)
...
}
@r_fix_isr_2
@
type ret_type;
identifier A;
@@
-ret_type <!fn!>(void *A)
+ret_type <!fn!>(const void *A)
{
...
}
@r_fix_isr_3
@
const struct device *D;
@@
-<!fn!>((void *)D);
+<!fn!>(D);
@r_fix_isr_4
@
type ret_type;
identifier D;
identifier P;
@@
-ret_type <!fn!>(const struct device *P)
+ret_type <!fn!>(const struct device *D)
{
...
(
-const struct device *D = (const struct device *)P;
|
-const struct device *D = P;
)
...
}
@r_fix_isr_5
@
type ret_type;
identifier D;
identifier P;
@@
-ret_type <!fn!>(const struct device *P)
+ret_type <!fn!>(const struct device *D)
{
...
-const struct device *D;
...
(
-D = (const struct device *)P;
|
-D = P;
)
...
}
"""
def find_isr(fn):
db = []
data = None
start = 0
try:
with open(fn, 'r+') as f:
data = str(mmap.mmap(f.fileno(), 0).read())
except Exception as e:
return db
while True:
isr = ""
irq = data.find('IRQ_CONNECT', start)
while irq > -1:
p = 1
arg = 1
p_o = data.find('(', irq)
if p_o < 0:
irq = -1
break;
pos = p_o + 1
while p > 0:
if data[pos] == ')':
p -= 1
elif data[pos] == '(':
p += 1
elif data[pos] == ',' and p == 1:
arg += 1
if arg == 3:
isr += data[pos]
pos += 1
isr = isr.strip(',\\n\\t ')
if isr not in db and len(isr) > 0:
db.append(isr)
start = pos
break
if irq < 0:
break
return db
def patch_isr(fn, isr_list):
if len(isr_list) <= 0:
return
for isr in isr_list:
tmplt = cocci_template.replace('<!fn!>', isr)
with open('/tmp/isr_fix.cocci', 'w') as f:
f.write(tmplt)
cmd = ['spatch', '--sp-file', '/tmp/isr_fix.cocci', '--in-place', fn]
subprocess.run(cmd)
def process_files(path):
if path.is_file() and path.suffix in ['.h', '.c']:
p = str(path.parent) + '/' + path.name
isr_list = find_isr(p)
patch_isr(p, isr_list)
elif path.is_dir():
for p in path.iterdir():
process_files(p)
if len(sys.argv) < 2:
print("You need to provide a dir/file path")
sys.exit(1)
process_files(Path(sys.argv[1]))
And is run: ./fix_isr.py <zephyr root directory>
Finally, some files needed manual fixes such.
Fixes #27399
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
2020-06-17 14:58:56 +02:00
|
|
|
static void can_stm32_state_change_isr(const struct device *dev)
|
2018-06-19 18:26:31 +02:00
|
|
|
{
|
2022-03-17 22:06:51 +01:00
|
|
|
const struct can_stm32_config *cfg = dev->config;
|
|
|
|
CAN_TypeDef *can = cfg->can;
|
2018-06-19 18:26:31 +02:00
|
|
|
|
2022-03-17 22:06:51 +01:00
|
|
|
/* Signal bus-off to waiting tx */
|
2018-06-19 18:26:31 +02:00
|
|
|
if (can->MSR & CAN_MSR_ERRI) {
|
2022-03-17 22:06:51 +01:00
|
|
|
can_stm32_tx_isr_handler(dev);
|
2022-02-25 11:10:38 +01:00
|
|
|
can_stm32_bus_state_change_isr(dev);
|
2018-06-19 18:26:31 +02:00
|
|
|
can->MSR |= CAN_MSR_ERRI;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-23 10:54:56 +02:00
|
|
|
#endif
|
|
|
|
|
2022-07-15 11:07:18 +02:00
|
|
|
static int can_stm32_enter_init_mode(CAN_TypeDef *can)
|
2019-07-01 16:44:33 +02:00
|
|
|
{
|
2020-05-27 11:26:57 -05:00
|
|
|
uint32_t start_time;
|
2019-07-01 16:44:33 +02:00
|
|
|
|
|
|
|
can->MCR |= CAN_MCR_INRQ;
|
|
|
|
start_time = k_cycle_get_32();
|
|
|
|
|
|
|
|
while ((can->MSR & CAN_MSR_INAK) == 0U) {
|
2018-06-19 18:26:31 +02:00
|
|
|
if (k_cycle_get_32() - start_time > CAN_INIT_TIMEOUT) {
|
|
|
|
can->MCR &= ~CAN_MCR_INRQ;
|
2021-12-08 00:01:57 +01:00
|
|
|
return -EAGAIN;
|
2019-07-01 16:44:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-07-15 11:07:18 +02:00
|
|
|
static int can_stm32_leave_init_mode(CAN_TypeDef *can)
|
2018-05-03 10:59:12 +02:00
|
|
|
{
|
2020-05-27 11:26:57 -05:00
|
|
|
uint32_t start_time;
|
2019-07-01 16:44:33 +02:00
|
|
|
|
|
|
|
can->MCR &= ~CAN_MCR_INRQ;
|
|
|
|
start_time = k_cycle_get_32();
|
|
|
|
|
|
|
|
while ((can->MSR & CAN_MSR_INAK) != 0U) {
|
2018-06-19 18:26:31 +02:00
|
|
|
if (k_cycle_get_32() - start_time > CAN_INIT_TIMEOUT) {
|
2021-12-08 00:01:57 +01:00
|
|
|
return -EAGAIN;
|
2019-07-01 16:44:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-07-15 11:07:18 +02:00
|
|
|
static int can_stm32_leave_sleep_mode(CAN_TypeDef *can)
|
2019-07-01 16:44:33 +02:00
|
|
|
{
|
2020-05-27 11:26:57 -05:00
|
|
|
uint32_t start_time;
|
2019-07-01 16:44:33 +02:00
|
|
|
|
|
|
|
can->MCR &= ~CAN_MCR_SLEEP;
|
|
|
|
start_time = k_cycle_get_32();
|
|
|
|
|
|
|
|
while ((can->MSR & CAN_MSR_SLAK) != 0) {
|
2018-06-19 18:26:31 +02:00
|
|
|
if (k_cycle_get_32() - start_time > CAN_INIT_TIMEOUT) {
|
2021-12-08 00:01:57 +01:00
|
|
|
return -EAGAIN;
|
2019-07-01 16:44:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
2022-07-12 16:36:20 +02:00
|
|
|
static int can_stm32_get_capabilities(const struct device *dev, can_mode_t *cap)
|
|
|
|
{
|
|
|
|
ARG_UNUSED(dev);
|
|
|
|
|
2022-07-13 10:41:20 +02:00
|
|
|
*cap = CAN_MODE_NORMAL | CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY | CAN_MODE_ONE_SHOT;
|
2022-07-12 16:36:20 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-08-31 14:28:42 +02:00
|
|
|
static int can_stm32_start(const struct device *dev)
|
2018-05-03 10:59:12 +02:00
|
|
|
{
|
2022-01-18 12:50:32 +01:00
|
|
|
const struct can_stm32_config *cfg = dev->config;
|
|
|
|
struct can_stm32_data *data = dev->data;
|
2022-08-31 14:28:42 +02:00
|
|
|
CAN_TypeDef *can = cfg->can;
|
|
|
|
int ret = 0;
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2022-08-31 14:28:42 +02:00
|
|
|
k_mutex_lock(&data->inst_mutex, K_FOREVER);
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2022-08-31 14:28:42 +02:00
|
|
|
if (data->started) {
|
|
|
|
ret = -EALREADY;
|
|
|
|
goto unlock;
|
2022-05-05 11:28:30 +02:00
|
|
|
}
|
|
|
|
|
2022-03-01 14:15:19 +01:00
|
|
|
if (cfg->phy != NULL) {
|
|
|
|
ret = can_transceiver_enable(cfg->phy);
|
|
|
|
if (ret != 0) {
|
|
|
|
LOG_ERR("failed to enable CAN transceiver (err %d)", ret);
|
2022-08-31 14:28:42 +02:00
|
|
|
goto unlock;
|
2022-03-01 14:15:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-14 13:28:36 +01:00
|
|
|
CAN_STATS_RESET(dev);
|
|
|
|
|
2022-08-31 14:28:42 +02:00
|
|
|
ret = can_stm32_leave_init_mode(can);
|
|
|
|
if (ret < 0) {
|
|
|
|
LOG_ERR("Failed to leave init mode");
|
|
|
|
|
|
|
|
if (cfg->phy != NULL) {
|
|
|
|
/* Attempt to disable the CAN transceiver in case of error */
|
|
|
|
(void)can_transceiver_disable(cfg->phy);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = -EIO;
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
data->started = true;
|
|
|
|
|
|
|
|
unlock:
|
|
|
|
k_mutex_unlock(&data->inst_mutex);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int can_stm32_stop(const struct device *dev)
|
|
|
|
{
|
|
|
|
const struct can_stm32_config *cfg = dev->config;
|
|
|
|
struct can_stm32_data *data = dev->data;
|
|
|
|
CAN_TypeDef *can = cfg->can;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
k_mutex_lock(&data->inst_mutex, K_FOREVER);
|
|
|
|
|
|
|
|
if (!data->started) {
|
|
|
|
ret = -EALREADY;
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
2022-07-15 11:07:18 +02:00
|
|
|
ret = can_stm32_enter_init_mode(can);
|
2022-08-31 14:28:42 +02:00
|
|
|
if (ret < 0) {
|
2020-04-27 18:58:05 +02:00
|
|
|
LOG_ERR("Failed to enter init mode");
|
2022-08-31 14:28:42 +02:00
|
|
|
ret = -EIO;
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
|
2022-09-21 16:46:38 +02:00
|
|
|
/* Abort any pending transmissions */
|
|
|
|
can_stm32_signal_tx_complete(dev, &data->mb0, -ENETDOWN);
|
|
|
|
can_stm32_signal_tx_complete(dev, &data->mb1, -ENETDOWN);
|
|
|
|
can_stm32_signal_tx_complete(dev, &data->mb2, -ENETDOWN);
|
|
|
|
can->TSR |= CAN_TSR_ABRQ2 | CAN_TSR_ABRQ1 | CAN_TSR_ABRQ0;
|
|
|
|
|
2022-08-31 14:28:42 +02:00
|
|
|
if (cfg->phy != NULL) {
|
|
|
|
ret = can_transceiver_disable(cfg->phy);
|
|
|
|
if (ret != 0) {
|
|
|
|
LOG_ERR("failed to enable CAN transceiver (err %d)", ret);
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
data->started = false;
|
|
|
|
|
|
|
|
unlock:
|
|
|
|
k_mutex_unlock(&data->inst_mutex);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int can_stm32_set_mode(const struct device *dev, can_mode_t mode)
|
|
|
|
{
|
|
|
|
const struct can_stm32_config *cfg = dev->config;
|
|
|
|
CAN_TypeDef *can = cfg->can;
|
|
|
|
struct can_stm32_data *data = dev->data;
|
|
|
|
|
|
|
|
LOG_DBG("Set mode %d", mode);
|
|
|
|
|
|
|
|
if ((mode & ~(CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY | CAN_MODE_ONE_SHOT)) != 0) {
|
|
|
|
LOG_ERR("unsupported mode: 0x%08x", mode);
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (data->started) {
|
|
|
|
return -EBUSY;
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
2022-08-31 14:28:42 +02:00
|
|
|
k_mutex_lock(&data->inst_mutex, K_FOREVER);
|
|
|
|
|
2022-05-05 11:28:30 +02:00
|
|
|
if ((mode & CAN_MODE_LOOPBACK) != 0) {
|
|
|
|
/* Loopback mode */
|
2020-04-27 18:58:05 +02:00
|
|
|
can->BTR |= CAN_BTR_LBKM;
|
2022-05-05 11:28:30 +02:00
|
|
|
} else {
|
|
|
|
can->BTR &= ~CAN_BTR_LBKM;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((mode & CAN_MODE_LISTENONLY) != 0) {
|
|
|
|
/* Silent mode */
|
2020-04-27 18:58:05 +02:00
|
|
|
can->BTR |= CAN_BTR_SILM;
|
2022-05-05 11:28:30 +02:00
|
|
|
} else {
|
|
|
|
can->BTR &= ~CAN_BTR_SILM;
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
2022-07-12 22:16:48 +02:00
|
|
|
if ((mode & CAN_MODE_ONE_SHOT) != 0) {
|
|
|
|
/* No automatic retransmission */
|
|
|
|
can->MCR |= CAN_MCR_NART;
|
|
|
|
} else {
|
|
|
|
can->MCR &= ~CAN_MCR_NART;
|
|
|
|
}
|
|
|
|
|
2020-04-27 18:58:05 +02:00
|
|
|
k_mutex_unlock(&data->inst_mutex);
|
2022-03-01 14:15:19 +01:00
|
|
|
|
2022-08-31 14:28:42 +02:00
|
|
|
return 0;
|
2020-04-27 18:58:05 +02:00
|
|
|
}
|
2018-05-29 16:10:31 +02:00
|
|
|
|
2022-03-30 15:09:31 +02:00
|
|
|
static int can_stm32_set_timing(const struct device *dev,
|
2022-05-03 22:05:53 +02:00
|
|
|
const struct can_timing *timing)
|
2020-04-27 18:58:05 +02:00
|
|
|
{
|
2022-01-18 12:50:32 +01:00
|
|
|
const struct can_stm32_config *cfg = dev->config;
|
2020-04-27 18:58:05 +02:00
|
|
|
CAN_TypeDef *can = cfg->can;
|
2022-01-18 12:50:32 +01:00
|
|
|
struct can_stm32_data *data = dev->data;
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2018-06-19 18:26:31 +02:00
|
|
|
k_mutex_lock(&data->inst_mutex, K_FOREVER);
|
2022-08-31 14:28:42 +02:00
|
|
|
|
|
|
|
if (data->started) {
|
|
|
|
k_mutex_unlock(&data->inst_mutex);
|
|
|
|
return -EBUSY;
|
2019-07-01 16:44:33 +02:00
|
|
|
}
|
|
|
|
|
2021-04-25 17:15:56 +02:00
|
|
|
can->BTR = (can->BTR & ~(CAN_BTR_BRP_Msk | CAN_BTR_TS1_Msk | CAN_BTR_TS2_Msk)) |
|
2021-01-07 18:39:22 +01:00
|
|
|
(((timing->phase_seg1 - 1) << CAN_BTR_TS1_Pos) & CAN_BTR_TS1_Msk) |
|
|
|
|
(((timing->phase_seg2 - 1) << CAN_BTR_TS2_Pos) & CAN_BTR_TS2_Msk) |
|
|
|
|
(((timing->prescaler - 1) << CAN_BTR_BRP_Pos) & CAN_BTR_BRP_Msk);
|
2019-07-01 16:44:33 +02:00
|
|
|
|
2021-04-25 17:15:56 +02:00
|
|
|
if (timing->sjw != CAN_SJW_NO_CHANGE) {
|
|
|
|
can->BTR = (can->BTR & ~CAN_BTR_SJW_Msk) |
|
|
|
|
(((timing->sjw - 1) << CAN_BTR_SJW_Pos) & CAN_BTR_SJW_Msk);
|
|
|
|
}
|
|
|
|
|
2018-06-19 18:26:31 +02:00
|
|
|
k_mutex_unlock(&data->inst_mutex);
|
2022-08-31 14:28:42 +02:00
|
|
|
|
|
|
|
return 0;
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
2022-03-30 15:09:31 +02:00
|
|
|
static int can_stm32_get_core_clock(const struct device *dev, uint32_t *rate)
|
2020-04-27 18:58:05 +02:00
|
|
|
{
|
2022-01-18 12:50:32 +01:00
|
|
|
const struct can_stm32_config *cfg = dev->config;
|
2020-04-27 18:58:05 +02:00
|
|
|
const struct device *clock;
|
|
|
|
int ret;
|
|
|
|
|
2021-02-11 11:49:24 -06:00
|
|
|
clock = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
|
2020-04-27 18:58:05 +02:00
|
|
|
|
|
|
|
ret = clock_control_get_rate(clock,
|
2023-03-28 08:24:07 +02:00
|
|
|
(clock_control_subsys_t) &cfg->pclken,
|
2020-04-27 18:58:05 +02:00
|
|
|
rate);
|
|
|
|
if (ret != 0) {
|
|
|
|
LOG_ERR("Failed call clock_control_get_rate: return [%d]", ret);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-03-30 15:09:31 +02:00
|
|
|
static int can_stm32_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate)
|
2022-03-01 14:15:19 +01:00
|
|
|
{
|
|
|
|
const struct can_stm32_config *config = dev->config;
|
|
|
|
|
|
|
|
*max_bitrate = config->max_bitrate;
|
|
|
|
|
|
|
|
return 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
|
|
|
static int can_stm32_get_max_filters(const struct device *dev, bool ide)
|
2022-07-23 08:01:10 +02:00
|
|
|
{
|
|
|
|
ARG_UNUSED(dev);
|
|
|
|
|
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) {
|
2022-07-23 08:01:10 +02:00
|
|
|
return CONFIG_CAN_MAX_EXT_ID_FILTER;
|
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 {
|
|
|
|
return CONFIG_CAN_MAX_STD_ID_FILTER;
|
2022-07-23 08:01:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-30 20:33:38 +02:00
|
|
|
static int can_stm32_init(const struct device *dev)
|
2018-05-03 10:59:12 +02:00
|
|
|
{
|
2022-01-18 12:50:32 +01:00
|
|
|
const struct can_stm32_config *cfg = dev->config;
|
|
|
|
struct can_stm32_data *data = dev->data;
|
2018-05-03 10:59:12 +02:00
|
|
|
CAN_TypeDef *can = cfg->can;
|
2020-04-27 18:58:05 +02:00
|
|
|
struct can_timing timing;
|
2020-04-30 20:33:38 +02:00
|
|
|
const struct device *clock;
|
2022-07-23 08:01:10 +02:00
|
|
|
uint32_t bank_offset;
|
2018-05-03 10:59:12 +02:00
|
|
|
int ret;
|
|
|
|
|
2022-06-17 13:35:39 +02:00
|
|
|
k_mutex_init(&filter_mutex);
|
2018-06-19 18:26:31 +02:00
|
|
|
k_mutex_init(&data->inst_mutex);
|
2018-05-03 10:59:12 +02:00
|
|
|
k_sem_init(&data->tx_int_sem, 0, 1);
|
|
|
|
|
2022-03-01 14:15:19 +01:00
|
|
|
if (cfg->phy != NULL) {
|
|
|
|
if (!device_is_ready(cfg->phy)) {
|
|
|
|
LOG_ERR("CAN transceiver not ready");
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-11 11:49:24 -06:00
|
|
|
clock = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
|
2022-08-08 13:31:51 +02:00
|
|
|
if (!device_is_ready(clock)) {
|
|
|
|
LOG_ERR("clock control device not ready");
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2023-03-28 08:24:07 +02:00
|
|
|
ret = clock_control_on(clock, (clock_control_subsys_t) &cfg->pclken);
|
2018-05-03 10:59:12 +02:00
|
|
|
if (ret != 0) {
|
2018-09-17 12:13:20 -05:00
|
|
|
LOG_ERR("HAL_CAN_Init clock control on failed: %d", ret);
|
2018-05-03 10:59:12 +02:00
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
2020-10-16 17:20:00 +02:00
|
|
|
/* Configure dt provided device signals when available */
|
2021-11-05 15:21:13 +01:00
|
|
|
ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
|
2020-10-16 17:20:00 +02:00
|
|
|
if (ret < 0) {
|
|
|
|
LOG_ERR("CAN pinctrl setup failed (%d)", ret);
|
|
|
|
return ret;
|
2020-10-09 10:54:44 +02:00
|
|
|
}
|
|
|
|
|
2022-07-15 11:07:18 +02:00
|
|
|
ret = can_stm32_leave_sleep_mode(can);
|
2019-07-01 16:44:33 +02:00
|
|
|
if (ret) {
|
|
|
|
LOG_ERR("Failed to exit sleep mode");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-07-15 11:07:18 +02:00
|
|
|
ret = can_stm32_enter_init_mode(can);
|
2019-07-01 16:44:33 +02:00
|
|
|
if (ret) {
|
|
|
|
LOG_ERR("Failed to enter init mode");
|
|
|
|
return ret;
|
|
|
|
}
|
2019-07-02 12:39:19 +02:00
|
|
|
|
2022-07-23 08:01:10 +02:00
|
|
|
/* configure scale of filter banks < CONFIG_CAN_MAX_EXT_ID_FILTER for ext ids */
|
|
|
|
bank_offset = (cfg->can == cfg->master_can) ? 0 : CAN_STM32_NUM_FILTER_BANKS;
|
|
|
|
cfg->master_can->FMR |= CAN_FMR_FINIT;
|
|
|
|
cfg->master_can->FS1R |= ((1U << CONFIG_CAN_MAX_EXT_ID_FILTER) - 1) << bank_offset;
|
|
|
|
cfg->master_can->FMR &= ~CAN_FMR_FINIT;
|
|
|
|
|
2021-07-16 19:03:55 +02:00
|
|
|
can->MCR &= ~CAN_MCR_TTCM & ~CAN_MCR_ABOM & ~CAN_MCR_AWUM &
|
2022-01-21 18:19:22 +01:00
|
|
|
~CAN_MCR_NART & ~CAN_MCR_RFLM & ~CAN_MCR_TXFP;
|
2019-07-24 15:38:11 +02:00
|
|
|
#ifdef CONFIG_CAN_RX_TIMESTAMP
|
|
|
|
can->MCR |= CAN_MCR_TTCM;
|
|
|
|
#endif
|
2018-06-19 18:26:31 +02:00
|
|
|
#ifdef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY
|
|
|
|
can->MCR |= CAN_MCR_ABOM;
|
|
|
|
#endif
|
2020-04-27 18:58:05 +02:00
|
|
|
timing.sjw = cfg->sjw;
|
2020-11-20 13:39:48 +01:00
|
|
|
if (cfg->sample_point && USE_SP_ALGO) {
|
2020-04-27 18:58:05 +02:00
|
|
|
ret = can_calc_timing(dev, &timing, cfg->bus_speed,
|
|
|
|
cfg->sample_point);
|
|
|
|
if (ret == -EINVAL) {
|
|
|
|
LOG_ERR("Can't find timing for given param");
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
LOG_DBG("Presc: %d, TS1: %d, TS2: %d",
|
|
|
|
timing.prescaler, timing.phase_seg1, timing.phase_seg2);
|
|
|
|
LOG_DBG("Sample-point err : %d", ret);
|
2020-11-20 13:39:48 +01:00
|
|
|
} else {
|
2020-04-27 18:58:05 +02:00
|
|
|
timing.prop_seg = 0;
|
|
|
|
timing.phase_seg1 = cfg->prop_ts1;
|
|
|
|
timing.phase_seg2 = cfg->ts2;
|
|
|
|
ret = can_calc_prescaler(dev, &timing, cfg->bus_speed);
|
|
|
|
if (ret) {
|
|
|
|
LOG_WRN("Bitrate error: %d", ret);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-03 22:05:53 +02:00
|
|
|
ret = can_stm32_set_timing(dev, &timing);
|
2020-04-27 18:58:05 +02:00
|
|
|
if (ret) {
|
|
|
|
return ret;
|
|
|
|
}
|
2019-07-01 16:44:33 +02:00
|
|
|
|
2022-05-05 11:28:30 +02:00
|
|
|
ret = can_stm32_set_mode(dev, CAN_MODE_NORMAL);
|
2018-05-03 10:59:12 +02:00
|
|
|
if (ret) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-02-25 13:49:01 +01:00
|
|
|
(void)can_stm32_get_state(dev, &data->state, NULL);
|
|
|
|
|
2018-05-03 10:59:12 +02:00
|
|
|
cfg->config_irq(can);
|
2019-07-01 16:44:33 +02:00
|
|
|
can->IER |= CAN_IER_TMEIE;
|
2022-07-23 08:01:10 +02:00
|
|
|
|
2018-05-03 10:59:12 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-12-28 20:00:34 +01:00
|
|
|
static void can_stm32_set_state_change_callback(const struct device *dev,
|
2022-01-10 12:32:19 +01:00
|
|
|
can_state_change_callback_t cb,
|
|
|
|
void *user_data)
|
2018-06-19 18:26:31 +02:00
|
|
|
{
|
2022-01-18 12:50:32 +01:00
|
|
|
struct can_stm32_data *data = dev->data;
|
|
|
|
const struct can_stm32_config *cfg = dev->config;
|
2018-06-19 18:26:31 +02:00
|
|
|
CAN_TypeDef *can = cfg->can;
|
|
|
|
|
2021-12-28 20:00:34 +01:00
|
|
|
data->state_change_cb = cb;
|
2022-01-10 12:32:19 +01:00
|
|
|
data->state_change_cb_data = user_data;
|
2018-06-19 18:26:31 +02:00
|
|
|
|
2021-12-28 20:00:34 +01:00
|
|
|
if (cb == NULL) {
|
2022-01-18 16:29:14 +01:00
|
|
|
can->IER &= ~(CAN_IER_BOFIE | CAN_IER_EPVIE | CAN_IER_EWGIE);
|
2018-06-19 18:26:31 +02:00
|
|
|
} else {
|
2022-01-18 16:29:14 +01:00
|
|
|
can->IER |= CAN_IER_BOFIE | CAN_IER_EPVIE | CAN_IER_EWGIE;
|
2018-06-19 18:26:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY
|
2022-03-30 15:09:31 +02:00
|
|
|
static int can_stm32_recover(const struct device *dev, k_timeout_t timeout)
|
2018-06-19 18:26:31 +02:00
|
|
|
{
|
2022-01-18 12:50:32 +01:00
|
|
|
const struct can_stm32_config *cfg = dev->config;
|
|
|
|
struct can_stm32_data *data = dev->data;
|
2018-06-19 18:26:31 +02:00
|
|
|
CAN_TypeDef *can = cfg->can;
|
2021-12-08 00:01:57 +01:00
|
|
|
int ret = -EAGAIN;
|
2020-05-27 11:26:57 -05:00
|
|
|
int64_t start_time;
|
2018-06-19 18:26:31 +02:00
|
|
|
|
2022-08-31 14:28:42 +02:00
|
|
|
if (!data->started) {
|
|
|
|
return -ENETDOWN;
|
|
|
|
}
|
|
|
|
|
2018-06-19 18:26:31 +02:00
|
|
|
if (!(can->ESR & CAN_ESR_BOFF)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (k_mutex_lock(&data->inst_mutex, K_FOREVER)) {
|
2021-12-08 00:01:57 +01:00
|
|
|
return -EAGAIN;
|
2018-06-19 18:26:31 +02:00
|
|
|
}
|
|
|
|
|
2022-07-15 11:07:18 +02:00
|
|
|
ret = can_stm32_enter_init_mode(can);
|
2018-06-19 18:26:31 +02:00
|
|
|
if (ret) {
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2022-07-15 11:07:18 +02:00
|
|
|
can_stm32_leave_init_mode(can);
|
2018-06-19 18:26:31 +02:00
|
|
|
|
2020-05-04 15:11:41 +02:00
|
|
|
start_time = k_uptime_ticks();
|
2018-06-19 18:26:31 +02:00
|
|
|
|
|
|
|
while (can->ESR & CAN_ESR_BOFF) {
|
2021-11-15 19:06:46 +01:00
|
|
|
if (!K_TIMEOUT_EQ(timeout, K_FOREVER) &&
|
2020-05-04 15:11:41 +02:00
|
|
|
k_uptime_ticks() - start_time >= timeout.ticks) {
|
2018-06-19 18:26:31 +02:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
done:
|
|
|
|
k_mutex_unlock(&data->inst_mutex);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */
|
|
|
|
|
|
|
|
|
2022-08-11 15:31:59 +02:00
|
|
|
static int can_stm32_send(const struct device *dev, const struct can_frame *frame,
|
2022-03-30 15:09:31 +02:00
|
|
|
k_timeout_t timeout, can_tx_callback_t callback,
|
|
|
|
void *user_data)
|
2018-05-03 10:59:12 +02:00
|
|
|
{
|
2022-01-18 12:50:32 +01:00
|
|
|
const struct can_stm32_config *cfg = dev->config;
|
|
|
|
struct can_stm32_data *data = dev->data;
|
2018-05-03 10:59:12 +02:00
|
|
|
CAN_TypeDef *can = cfg->can;
|
2020-05-27 11:26:57 -05:00
|
|
|
uint32_t transmit_status_register = can->TSR;
|
2018-05-03 10:59:12 +02:00
|
|
|
CAN_TxMailBox_TypeDef *mailbox = NULL;
|
2022-07-15 11:07:18 +02:00
|
|
|
struct can_stm32_mailbox *mb = NULL;
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2018-09-17 12:13:20 -05:00
|
|
|
LOG_DBG("Sending %d bytes on %s. "
|
2018-05-03 10:59:12 +02:00
|
|
|
"Id: 0x%x, "
|
|
|
|
"ID type: %s, "
|
|
|
|
"Remote Frame: %s"
|
2021-12-04 15:21:32 +01:00
|
|
|
, frame->dlc, dev->name
|
|
|
|
, 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
|
|
|
, (frame->flags & CAN_FRAME_IDE) != 0 ? "extended" : "standard"
|
|
|
|
, (frame->flags & CAN_FRAME_RTR) != 0 ? "yes" : "no");
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2022-09-20 17:17:06 +02:00
|
|
|
__ASSERT_NO_MSG(callback != NULL);
|
2021-12-04 15:21:32 +01:00
|
|
|
__ASSERT(frame->dlc == 0U || frame->data != NULL, "Dataptr is null");
|
2019-11-06 10:03:20 +01:00
|
|
|
|
2021-12-04 15:21:32 +01:00
|
|
|
if (frame->dlc > CAN_MAX_DLC) {
|
|
|
|
LOG_ERR("DLC of %d exceeds maximum (%d)", frame->dlc, CAN_MAX_DLC);
|
2021-12-08 00:01:57 +01:00
|
|
|
return -EINVAL;
|
2019-11-06 10:03:20 +01:00
|
|
|
}
|
2018-05-03 10:59:12 +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
|
|
|
if ((frame->flags & ~(CAN_FRAME_IDE | CAN_FRAME_RTR)) != 0) {
|
|
|
|
LOG_ERR("unsupported CAN frame flags 0x%02x", frame->flags);
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
2022-08-31 14:28:42 +02:00
|
|
|
if (!data->started) {
|
|
|
|
return -ENETDOWN;
|
|
|
|
}
|
|
|
|
|
2018-05-03 10:59:12 +02:00
|
|
|
if (can->ESR & CAN_ESR_BOFF) {
|
2022-08-19 10:43:34 +02:00
|
|
|
return -ENETUNREACH;
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
2018-06-19 18:26:31 +02:00
|
|
|
k_mutex_lock(&data->inst_mutex, K_FOREVER);
|
2018-05-29 16:10:31 +02:00
|
|
|
while (!(transmit_status_register & CAN_TSR_TME)) {
|
2018-06-19 18:26:31 +02:00
|
|
|
k_mutex_unlock(&data->inst_mutex);
|
2020-05-04 15:11:41 +02:00
|
|
|
LOG_DBG("Transmit buffer full");
|
2018-06-08 09:23:47 +02:00
|
|
|
if (k_sem_take(&data->tx_int_sem, timeout)) {
|
2021-12-08 00:01:57 +01:00
|
|
|
return -EAGAIN;
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
2018-06-19 18:26:31 +02:00
|
|
|
k_mutex_lock(&data->inst_mutex, K_FOREVER);
|
2018-05-03 10:59:12 +02:00
|
|
|
transmit_status_register = can->TSR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (transmit_status_register & CAN_TSR_TME0) {
|
2022-07-23 08:01:10 +02:00
|
|
|
LOG_DBG("Using TX mailbox 0");
|
2019-07-01 16:44:33 +02:00
|
|
|
mailbox = &can->sTxMailBox[0];
|
2018-05-03 10:59:12 +02:00
|
|
|
mb = &(data->mb0);
|
|
|
|
} else if (transmit_status_register & CAN_TSR_TME1) {
|
2022-07-23 08:01:10 +02:00
|
|
|
LOG_DBG("Using TX mailbox 1");
|
2019-07-01 16:44:33 +02:00
|
|
|
mailbox = &can->sTxMailBox[1];
|
2018-05-03 10:59:12 +02:00
|
|
|
mb = &data->mb1;
|
|
|
|
} else if (transmit_status_register & CAN_TSR_TME2) {
|
2022-07-23 08:01:10 +02:00
|
|
|
LOG_DBG("Using TX mailbox 2");
|
2019-07-01 16:44:33 +02:00
|
|
|
mailbox = &can->sTxMailBox[2];
|
2018-05-03 10:59:12 +02:00
|
|
|
mb = &data->mb2;
|
|
|
|
}
|
|
|
|
|
|
|
|
mb->tx_callback = callback;
|
2021-12-04 15:21:32 +01:00
|
|
|
mb->callback_arg = user_data;
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2021-07-16 19:05:34 +02:00
|
|
|
/* mailbox identifier register setup */
|
2018-05-03 10:59:12 +02:00
|
|
|
mailbox->TIR &= CAN_TI0R_TXRQ;
|
|
|
|
|
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-12-04 15:21:32 +01:00
|
|
|
mailbox->TIR |= (frame->id << CAN_TI0R_EXID_Pos)
|
2018-05-03 10:59:12 +02:00
|
|
|
| CAN_TI0R_IDE;
|
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 {
|
|
|
|
mailbox->TIR |= (frame->id << CAN_TI0R_STID_Pos);
|
2018-05-03 10:59:12 +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
|
|
|
if ((frame->flags & CAN_FRAME_RTR) != 0) {
|
2018-05-03 10:59:12 +02:00
|
|
|
mailbox->TIR |= CAN_TI1R_RTR;
|
|
|
|
}
|
|
|
|
|
2018-05-29 16:10:31 +02:00
|
|
|
mailbox->TDTR = (mailbox->TDTR & ~CAN_TDT1R_DLC) |
|
2021-12-04 15:21:32 +01:00
|
|
|
((frame->dlc & 0xF) << CAN_TDT1R_DLC_Pos);
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2021-12-04 15:21:32 +01:00
|
|
|
mailbox->TDLR = frame->data_32[0];
|
|
|
|
mailbox->TDHR = frame->data_32[1];
|
2018-05-03 10:59:12 +02:00
|
|
|
|
|
|
|
mailbox->TIR |= CAN_TI0R_TXRQ;
|
2018-06-19 18:26:31 +02:00
|
|
|
k_mutex_unlock(&data->inst_mutex);
|
2018-05-03 10:59:12 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-07-23 08:01:10 +02:00
|
|
|
static void can_stm32_set_filter_bank(int filter_id, CAN_FilterRegister_TypeDef *filter_reg,
|
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
|
|
|
bool ide, uint32_t id, uint32_t mask)
|
2018-05-03 10:59:12 +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
|
|
|
if (ide) {
|
|
|
|
filter_reg->FR1 = id;
|
|
|
|
filter_reg->FR2 = mask;
|
|
|
|
} else {
|
2022-07-23 08:01:10 +02:00
|
|
|
if ((filter_id - CONFIG_CAN_MAX_EXT_ID_FILTER) % 2 == 0) {
|
|
|
|
/* even std filter id: first 1/2 bank */
|
2018-05-03 10:59:12 +02:00
|
|
|
filter_reg->FR1 = id | (mask << 16);
|
2022-07-23 08:01:10 +02:00
|
|
|
} else {
|
|
|
|
/* uneven std filter id: first 1/2 bank */
|
2018-05-03 10:59:12 +02:00
|
|
|
filter_reg->FR2 = id | (mask << 16);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-11 15:31:59 +02:00
|
|
|
static inline uint32_t can_stm32_filter_to_std_mask(const struct can_filter *filter)
|
2018-05-03 10:59:12 +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
|
|
|
uint32_t rtr_mask = (filter->flags & (CAN_FILTER_DATA | CAN_FILTER_RTR)) !=
|
|
|
|
(CAN_FILTER_DATA | CAN_FILTER_RTR) ? 1U : 0U;
|
|
|
|
|
|
|
|
return (filter->mask << CAN_STM32_FIRX_STD_ID_POS) |
|
|
|
|
(rtr_mask << CAN_STM32_FIRX_STD_RTR_POS) |
|
|
|
|
(1U << CAN_STM32_FIRX_STD_IDE_POS);
|
2019-02-06 22:34:59 +01:00
|
|
|
}
|
|
|
|
|
2022-08-11 15:31:59 +02:00
|
|
|
static inline uint32_t can_stm32_filter_to_ext_mask(const struct can_filter *filter)
|
2019-02-06 22:34:59 +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
|
|
|
uint32_t rtr_mask = (filter->flags & (CAN_FILTER_DATA | CAN_FILTER_RTR)) !=
|
|
|
|
(CAN_FILTER_DATA | CAN_FILTER_RTR) ? 1U : 0U;
|
|
|
|
|
|
|
|
return (filter->mask << CAN_STM32_FIRX_EXT_EXT_ID_POS) |
|
|
|
|
(rtr_mask << CAN_STM32_FIRX_EXT_RTR_POS) |
|
|
|
|
(1U << CAN_STM32_FIRX_EXT_IDE_POS);
|
2019-02-06 22:34:59 +01:00
|
|
|
}
|
|
|
|
|
2022-08-11 15:31:59 +02:00
|
|
|
static inline uint32_t can_stm32_filter_to_std_id(const struct can_filter *filter)
|
2019-02-06 22:34:59 +01:00
|
|
|
{
|
2022-07-15 11:07:18 +02:00
|
|
|
return (filter->id << CAN_STM32_FIRX_STD_ID_POS) |
|
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
|
|
|
(((filter->flags & CAN_FILTER_RTR) != 0) ? (1U << CAN_STM32_FIRX_STD_RTR_POS) : 0U);
|
2019-02-06 22:34:59 +01:00
|
|
|
}
|
|
|
|
|
2022-08-11 15:31:59 +02:00
|
|
|
static inline uint32_t can_stm32_filter_to_ext_id(const struct can_filter *filter)
|
2019-02-06 22:34:59 +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
|
|
|
return (filter->id << CAN_STM32_FIRX_EXT_EXT_ID_POS) |
|
|
|
|
(((filter->flags & CAN_FILTER_RTR) != 0) ?
|
|
|
|
(1U << CAN_STM32_FIRX_EXT_RTR_POS) : 0U) |
|
|
|
|
(1U << CAN_STM32_FIRX_EXT_IDE_POS);
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
2022-08-11 15:31:59 +02:00
|
|
|
static inline int can_stm32_set_filter(const struct device *dev, const struct can_filter *filter)
|
2018-05-03 10:59:12 +02:00
|
|
|
{
|
2022-06-17 13:35:39 +02:00
|
|
|
const struct can_stm32_config *cfg = dev->config;
|
2022-07-23 08:01:10 +02:00
|
|
|
struct can_stm32_data *data = dev->data;
|
2022-06-17 13:35:39 +02:00
|
|
|
CAN_TypeDef *can = cfg->master_can;
|
2020-05-27 11:26:57 -05:00
|
|
|
uint32_t mask = 0U;
|
|
|
|
uint32_t id = 0U;
|
2022-07-23 08:01:10 +02:00
|
|
|
int filter_id = -ENOSPC;
|
2022-06-17 13:35:39 +02:00
|
|
|
int bank_offset = 0;
|
2022-07-23 08:01:10 +02:00
|
|
|
int bank_num;
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2022-06-17 13:35:39 +02:00
|
|
|
if (cfg->can != cfg->master_can) {
|
|
|
|
/* CAN slave instance: start with offset */
|
2022-07-15 11:07:18 +02:00
|
|
|
bank_offset = CAN_STM32_NUM_FILTER_BANKS;
|
2022-06-17 13:35:39 +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
|
|
|
if ((filter->flags & CAN_FILTER_IDE) != 0) {
|
2022-07-23 08:01:10 +02:00
|
|
|
for (int i = 0; i < CONFIG_CAN_MAX_EXT_ID_FILTER; i++) {
|
|
|
|
if (data->rx_cb_ext[i] == NULL) {
|
|
|
|
id = can_stm32_filter_to_ext_id(filter);
|
|
|
|
mask = can_stm32_filter_to_ext_mask(filter);
|
|
|
|
filter_id = i;
|
|
|
|
bank_num = bank_offset + i;
|
|
|
|
break;
|
|
|
|
}
|
2018-05-03 10:59:12 +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 {
|
|
|
|
for (int i = 0; i < CONFIG_CAN_MAX_STD_ID_FILTER; i++) {
|
|
|
|
if (data->rx_cb_std[i] == NULL) {
|
|
|
|
id = can_stm32_filter_to_std_id(filter);
|
|
|
|
mask = can_stm32_filter_to_std_mask(filter);
|
|
|
|
filter_id = CONFIG_CAN_MAX_EXT_ID_FILTER + i;
|
|
|
|
bank_num = bank_offset + CONFIG_CAN_MAX_EXT_ID_FILTER + i / 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
2022-07-23 08:01:10 +02:00
|
|
|
if (filter_id != -ENOSPC) {
|
|
|
|
LOG_DBG("Adding filter_id %d, CAN ID: 0x%x, mask: 0x%x",
|
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
|
|
|
filter_id, filter->id, filter->mask);
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2022-07-23 08:01:10 +02:00
|
|
|
/* set the filter init mode */
|
|
|
|
can->FMR |= CAN_FMR_FINIT;
|
2019-02-13 11:18:27 +01:00
|
|
|
|
2022-07-23 08:01:10 +02:00
|
|
|
can_stm32_set_filter_bank(filter_id, &can->sFilterRegister[bank_num],
|
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
|
|
|
(filter->flags & CAN_FILTER_IDE) != 0,
|
|
|
|
id, mask);
|
2019-02-11 14:40:28 +01:00
|
|
|
|
2022-07-23 08:01:10 +02:00
|
|
|
can->FA1R |= 1U << bank_num;
|
|
|
|
can->FMR &= ~(CAN_FMR_FINIT);
|
2018-05-03 10:59:12 +02:00
|
|
|
} else {
|
2022-07-23 08:01:10 +02:00
|
|
|
LOG_WRN("No free filter left");
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
2021-12-28 20:00:34 +01:00
|
|
|
return filter_id;
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
2022-07-23 08:01:10 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* This driver uses masked mode for all filters (CAN_FM1R left at reset value
|
|
|
|
* 0x00) in order to simplify mapping between filter match index from the FIFOs
|
|
|
|
* and array index for the callbacks. All ext ID filters are stored in the
|
|
|
|
* banks below CONFIG_CAN_MAX_EXT_ID_FILTER, followed by the std ID filters,
|
|
|
|
* which consume only 1/2 bank per filter.
|
|
|
|
*
|
|
|
|
* The more complicated list mode must be implemented if someone requires more
|
|
|
|
* than 28 std ID or 14 ext ID filters.
|
|
|
|
*
|
|
|
|
* Currently, all filter banks are assigned to FIFO 0 and FIFO 1 is not used.
|
|
|
|
*/
|
2022-06-17 08:14:51 +02:00
|
|
|
static int can_stm32_add_rx_filter(const struct device *dev, can_rx_callback_t cb,
|
2022-08-11 15:31:59 +02:00
|
|
|
void *cb_arg, const struct can_filter *filter)
|
2018-05-03 10:59:12 +02:00
|
|
|
{
|
2022-01-18 12:50:32 +01:00
|
|
|
struct can_stm32_data *data = dev->data;
|
2021-12-28 20:00:34 +01:00
|
|
|
int filter_id;
|
2018-05-03 10:59:12 +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
|
|
|
if ((filter->flags & ~(CAN_FILTER_IDE | CAN_FILTER_DATA | CAN_FILTER_RTR)) != 0) {
|
|
|
|
LOG_ERR("unsupported CAN filter flags 0x%02x", filter->flags);
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
2022-06-17 13:35:39 +02:00
|
|
|
k_mutex_lock(&filter_mutex, K_FOREVER);
|
2022-06-17 08:14:51 +02:00
|
|
|
k_mutex_lock(&data->inst_mutex, K_FOREVER);
|
2022-06-17 13:35:39 +02:00
|
|
|
|
2022-07-23 08:01:10 +02:00
|
|
|
filter_id = can_stm32_set_filter(dev, filter);
|
|
|
|
if (filter_id >= 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
|
|
|
if ((filter->flags & CAN_FILTER_IDE) != 0) {
|
2022-07-23 08:01:10 +02:00
|
|
|
data->rx_cb_ext[filter_id] = cb;
|
|
|
|
data->cb_arg_ext[filter_id] = cb_arg;
|
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 {
|
|
|
|
data->rx_cb_std[filter_id - CONFIG_CAN_MAX_EXT_ID_FILTER] = cb;
|
|
|
|
data->cb_arg_std[filter_id - CONFIG_CAN_MAX_EXT_ID_FILTER] = cb_arg;
|
2022-07-23 08:01:10 +02:00
|
|
|
}
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
2022-06-17 13:35:39 +02:00
|
|
|
|
2018-06-19 18:26:31 +02:00
|
|
|
k_mutex_unlock(&data->inst_mutex);
|
2022-06-17 13:35:39 +02:00
|
|
|
k_mutex_unlock(&filter_mutex);
|
2021-12-28 20:00:34 +01:00
|
|
|
|
|
|
|
return filter_id;
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
2022-03-30 15:09:31 +02:00
|
|
|
static void can_stm32_remove_rx_filter(const struct device *dev, int filter_id)
|
2018-05-03 10:59:12 +02:00
|
|
|
{
|
2022-01-18 12:50:32 +01:00
|
|
|
const struct can_stm32_config *cfg = dev->config;
|
|
|
|
struct can_stm32_data *data = dev->data;
|
2020-01-25 07:19:26 -08:00
|
|
|
CAN_TypeDef *can = cfg->master_can;
|
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
|
|
|
bool ide;
|
2022-06-17 13:35:39 +02:00
|
|
|
int bank_offset = 0;
|
2022-07-15 11:07:18 +02:00
|
|
|
int bank_num;
|
2022-07-23 08:01:10 +02:00
|
|
|
bool bank_unused;
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2022-07-23 08:01:10 +02:00
|
|
|
__ASSERT_NO_MSG(filter_id >= 0 && filter_id < CAN_STM32_MAX_FILTER_ID);
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2022-06-17 13:35:39 +02:00
|
|
|
k_mutex_lock(&filter_mutex, K_FOREVER);
|
2018-06-19 18:26:31 +02:00
|
|
|
k_mutex_lock(&data->inst_mutex, K_FOREVER);
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2022-06-17 13:35:39 +02:00
|
|
|
if (cfg->can != cfg->master_can) {
|
2022-07-15 11:07:18 +02:00
|
|
|
bank_offset = CAN_STM32_NUM_FILTER_BANKS;
|
2022-06-17 13:35:39 +02:00
|
|
|
}
|
|
|
|
|
2022-07-23 08:01:10 +02:00
|
|
|
if (filter_id < CONFIG_CAN_MAX_EXT_ID_FILTER) {
|
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
|
|
|
ide = true;
|
2022-07-23 08:01:10 +02:00
|
|
|
bank_num = bank_offset + filter_id;
|
|
|
|
|
|
|
|
data->rx_cb_ext[filter_id] = NULL;
|
|
|
|
data->cb_arg_ext[filter_id] = NULL;
|
|
|
|
|
|
|
|
bank_unused = true;
|
|
|
|
} else {
|
|
|
|
int filter_index = filter_id - CONFIG_CAN_MAX_EXT_ID_FILTER;
|
|
|
|
|
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
|
|
|
ide = false;
|
2022-07-23 08:01:10 +02:00
|
|
|
bank_num = bank_offset + CONFIG_CAN_MAX_EXT_ID_FILTER +
|
|
|
|
(filter_id - CONFIG_CAN_MAX_EXT_ID_FILTER) / 2;
|
|
|
|
|
|
|
|
data->rx_cb_std[filter_index] = NULL;
|
|
|
|
data->cb_arg_std[filter_index] = NULL;
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2022-07-23 08:01:10 +02:00
|
|
|
if (filter_index % 2 == 1) {
|
|
|
|
bank_unused = data->rx_cb_std[filter_index - 1] == NULL;
|
|
|
|
} else if (filter_index + 1 < CONFIG_CAN_MAX_STD_ID_FILTER) {
|
|
|
|
bank_unused = data->rx_cb_std[filter_index + 1] == NULL;
|
|
|
|
} else {
|
|
|
|
bank_unused = true;
|
|
|
|
}
|
|
|
|
}
|
2018-05-03 10:59:12 +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
|
|
|
LOG_DBG("Removing filter_id %d, ide %d", filter_id, ide);
|
2018-05-03 10:59:12 +02:00
|
|
|
|
|
|
|
can->FMR |= CAN_FMR_FINIT;
|
|
|
|
|
2022-07-15 11:07:18 +02:00
|
|
|
can_stm32_set_filter_bank(filter_id, &can->sFilterRegister[bank_num],
|
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
|
|
|
ide, 0, 0xFFFFFFFF);
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2022-07-23 08:01:10 +02:00
|
|
|
if (bank_unused) {
|
|
|
|
can->FA1R &= ~(1U << bank_num);
|
|
|
|
LOG_DBG("Filter bank %d is unused -> deactivate", bank_num);
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
can->FMR &= ~(CAN_FMR_FINIT);
|
|
|
|
|
2018-06-19 18:26:31 +02:00
|
|
|
k_mutex_unlock(&data->inst_mutex);
|
2022-06-17 13:35:39 +02:00
|
|
|
k_mutex_unlock(&filter_mutex);
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct can_driver_api can_api_funcs = {
|
2022-07-12 16:36:20 +02:00
|
|
|
.get_capabilities = can_stm32_get_capabilities,
|
2022-08-31 14:28:42 +02:00
|
|
|
.start = can_stm32_start,
|
|
|
|
.stop = can_stm32_stop,
|
2020-04-27 18:58:05 +02:00
|
|
|
.set_mode = can_stm32_set_mode,
|
|
|
|
.set_timing = can_stm32_set_timing,
|
2018-05-03 10:59:12 +02:00
|
|
|
.send = can_stm32_send,
|
2021-12-28 20:00:34 +01:00
|
|
|
.add_rx_filter = can_stm32_add_rx_filter,
|
|
|
|
.remove_rx_filter = can_stm32_remove_rx_filter,
|
2018-06-19 18:26:31 +02:00
|
|
|
.get_state = can_stm32_get_state,
|
|
|
|
#ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY
|
|
|
|
.recover = can_stm32_recover,
|
|
|
|
#endif
|
2021-12-28 20:00:34 +01:00
|
|
|
.set_state_change_callback = can_stm32_set_state_change_callback,
|
2020-04-27 18:58:05 +02:00
|
|
|
.get_core_clock = can_stm32_get_core_clock,
|
2022-03-01 14:15:19 +01:00
|
|
|
.get_max_bitrate = can_stm32_get_max_bitrate,
|
2022-07-23 08:01:10 +02:00
|
|
|
.get_max_filters = can_stm32_get_max_filters,
|
2020-04-27 18:58:05 +02:00
|
|
|
.timing_min = {
|
|
|
|
.sjw = 0x1,
|
|
|
|
.prop_seg = 0x00,
|
|
|
|
.phase_seg1 = 0x01,
|
|
|
|
.phase_seg2 = 0x01,
|
|
|
|
.prescaler = 0x01
|
|
|
|
},
|
|
|
|
.timing_max = {
|
drivers: can: stm32: correct timing_max parameters
The timing_max parameters defined in the stm32 bxcan driver don't match the
register description in the reference manuals.
- sjw does have only 2 bits representing 1 to 4 tq.
- phase_seg1 and phase_seg2 max is one tq higher.
I have checked the following reference manuals and all match:
- RM0090: STM32F405, F415, F407, F417, F427, F437 AND F429
- RM0008: STM32F101, F102, F103, F105, F107 advanced arm-based mcus
- RM0351, RM0394: all STM32L4
- RM0091: all STM32F0 with CAN support
Signed-off-by: Thomas Stranger <thomas.stranger@outlook.com>
2023-08-13 13:09:26 +02:00
|
|
|
.sjw = 0x04,
|
2020-04-27 18:58:05 +02:00
|
|
|
.prop_seg = 0x00,
|
drivers: can: stm32: correct timing_max parameters
The timing_max parameters defined in the stm32 bxcan driver don't match the
register description in the reference manuals.
- sjw does have only 2 bits representing 1 to 4 tq.
- phase_seg1 and phase_seg2 max is one tq higher.
I have checked the following reference manuals and all match:
- RM0090: STM32F405, F415, F407, F417, F427, F437 AND F429
- RM0008: STM32F101, F102, F103, F105, F107 advanced arm-based mcus
- RM0351, RM0394: all STM32L4
- RM0091: all STM32F0 with CAN support
Signed-off-by: Thomas Stranger <thomas.stranger@outlook.com>
2023-08-13 13:09:26 +02:00
|
|
|
.phase_seg1 = 0x10,
|
|
|
|
.phase_seg2 = 0x08,
|
2020-04-27 18:58:05 +02:00
|
|
|
.prescaler = 0x400
|
|
|
|
}
|
2018-05-03 10:59:12 +02:00
|
|
|
};
|
|
|
|
|
2018-05-23 10:54:56 +02:00
|
|
|
#ifdef CONFIG_SOC_SERIES_STM32F0X
|
2022-06-16 14:16:08 +02:00
|
|
|
#define CAN_STM32_IRQ_INST(inst) \
|
|
|
|
static void config_can_##inst##_irq(CAN_TypeDef *can) \
|
|
|
|
{ \
|
|
|
|
IRQ_CONNECT(DT_INST_IRQN(inst), \
|
|
|
|
DT_INST_IRQ(inst, priority), \
|
|
|
|
can_stm32_isr, DEVICE_DT_INST_GET(inst), 0); \
|
|
|
|
irq_enable(DT_INST_IRQN(inst)); \
|
|
|
|
can->IER |= CAN_IER_TMEIE | CAN_IER_ERRIE | CAN_IER_FMPIE0 | \
|
|
|
|
CAN_IER_FMPIE1 | CAN_IER_BOFIE; \
|
|
|
|
if (IS_ENABLED(CONFIG_CAN_STATS)) { \
|
|
|
|
can->IER |= CAN_IER_LECIE; \
|
|
|
|
} \
|
|
|
|
}
|
2018-05-23 10:54:56 +02:00
|
|
|
#else
|
2022-06-16 14:16:08 +02:00
|
|
|
#define CAN_STM32_IRQ_INST(inst) \
|
|
|
|
static void config_can_##inst##_irq(CAN_TypeDef *can) \
|
|
|
|
{ \
|
|
|
|
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, rx0, irq), \
|
|
|
|
DT_INST_IRQ_BY_NAME(inst, rx0, priority), \
|
|
|
|
can_stm32_rx_isr, DEVICE_DT_INST_GET(inst), 0); \
|
|
|
|
irq_enable(DT_INST_IRQ_BY_NAME(inst, rx0, irq)); \
|
|
|
|
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, tx, irq), \
|
|
|
|
DT_INST_IRQ_BY_NAME(inst, tx, priority), \
|
|
|
|
can_stm32_tx_isr, DEVICE_DT_INST_GET(inst), 0); \
|
|
|
|
irq_enable(DT_INST_IRQ_BY_NAME(inst, tx, irq)); \
|
|
|
|
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, sce, irq), \
|
|
|
|
DT_INST_IRQ_BY_NAME(inst, sce, priority), \
|
|
|
|
can_stm32_state_change_isr, \
|
|
|
|
DEVICE_DT_INST_GET(inst), 0); \
|
|
|
|
irq_enable(DT_INST_IRQ_BY_NAME(inst, sce, irq)); \
|
|
|
|
can->IER |= CAN_IER_TMEIE | CAN_IER_ERRIE | CAN_IER_FMPIE0 | \
|
|
|
|
CAN_IER_FMPIE1 | CAN_IER_BOFIE; \
|
|
|
|
if (IS_ENABLED(CONFIG_CAN_STATS)) { \
|
|
|
|
can->IER |= CAN_IER_LECIE; \
|
|
|
|
} \
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
2022-06-16 14:16:08 +02:00
|
|
|
#endif /* CONFIG_SOC_SERIES_STM32F0X */
|
|
|
|
|
|
|
|
#define CAN_STM32_CONFIG_INST(inst) \
|
|
|
|
PINCTRL_DT_INST_DEFINE(inst); \
|
|
|
|
static const struct can_stm32_config can_stm32_cfg_##inst = { \
|
|
|
|
.can = (CAN_TypeDef *)DT_INST_REG_ADDR(inst), \
|
|
|
|
.master_can = (CAN_TypeDef *)DT_INST_PROP_OR(inst, \
|
|
|
|
master_can_reg, DT_INST_REG_ADDR(inst)), \
|
|
|
|
.bus_speed = DT_INST_PROP(inst, bus_speed), \
|
|
|
|
.sample_point = DT_INST_PROP_OR(inst, sample_point, 0), \
|
|
|
|
.sjw = DT_INST_PROP_OR(inst, sjw, 1), \
|
|
|
|
.prop_ts1 = DT_INST_PROP_OR(inst, prop_seg, 0) + \
|
|
|
|
DT_INST_PROP_OR(inst, phase_seg1, 0), \
|
|
|
|
.ts2 = DT_INST_PROP_OR(inst, phase_seg2, 0), \
|
|
|
|
.pclken = { \
|
|
|
|
.enr = DT_INST_CLOCKS_CELL(inst, bits), \
|
|
|
|
.bus = DT_INST_CLOCKS_CELL(inst, bus), \
|
|
|
|
}, \
|
|
|
|
.config_irq = config_can_##inst##_irq, \
|
|
|
|
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \
|
2023-08-31 13:59:13 +02:00
|
|
|
.phy = DEVICE_DT_GET_OR_NULL(DT_INST_PHANDLE(inst, phys)), \
|
|
|
|
.max_bitrate = DT_INST_CAN_TRANSCEIVER_MAX_BITRATE(inst, 1000000), \
|
2020-01-25 07:19:26 -08:00
|
|
|
};
|
|
|
|
|
2022-06-16 14:16:08 +02:00
|
|
|
#define CAN_STM32_DATA_INST(inst) \
|
|
|
|
static struct can_stm32_data can_stm32_dev_data_##inst;
|
2020-01-25 07:19:26 -08:00
|
|
|
|
2022-06-16 14:16:08 +02:00
|
|
|
#define CAN_STM32_DEFINE_INST(inst) \
|
2023-09-20 17:40:07 +02:00
|
|
|
CAN_DEVICE_DT_INST_DEFINE(inst, can_stm32_init, NULL, \
|
|
|
|
&can_stm32_dev_data_##inst, &can_stm32_cfg_##inst, \
|
|
|
|
POST_KERNEL, CONFIG_CAN_INIT_PRIORITY, \
|
|
|
|
&can_api_funcs);
|
2020-01-25 07:19:26 -08:00
|
|
|
|
2022-06-16 14:16:08 +02:00
|
|
|
#define CAN_STM32_INST(inst) \
|
|
|
|
CAN_STM32_IRQ_INST(inst) \
|
|
|
|
CAN_STM32_CONFIG_INST(inst) \
|
|
|
|
CAN_STM32_DATA_INST(inst) \
|
|
|
|
CAN_STM32_DEFINE_INST(inst)
|
2020-01-25 07:19:26 -08:00
|
|
|
|
2022-06-16 14:16:08 +02:00
|
|
|
DT_INST_FOREACH_STATUS_OKAY(CAN_STM32_INST)
|