2018-05-03 10:59:12 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2018 Alexander Wachter
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
2022-03-01 14:15:19 +01:00
|
|
|
#include <drivers/can/transceiver.h>
|
2020-01-25 05:34:53 -06:00
|
|
|
#include <drivers/clock_control/stm32_clock_control.h>
|
2019-06-25 15:53:47 -04:00
|
|
|
#include <drivers/clock_control.h>
|
2021-11-05 15:21:13 +01:00
|
|
|
#include <drivers/pinctrl.h>
|
2019-06-26 10:33:55 -04:00
|
|
|
#include <sys/util.h>
|
2018-05-03 10:59:12 +02:00
|
|
|
#include <string.h>
|
|
|
|
#include <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>
|
2019-06-25 15:53:46 -04:00
|
|
|
#include <drivers/can.h>
|
2022-02-22 12:06:54 +01:00
|
|
|
#include <logging/log.h>
|
|
|
|
|
2019-04-19 18:23:17 +02:00
|
|
|
#include "can_stm32.h"
|
2018-05-03 10:59:12 +02:00
|
|
|
|
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
|
|
|
|
2020-05-07 12:22:26 -05:00
|
|
|
#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(can1), st_stm32_can, okay) && \
|
|
|
|
DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(can2), st_stm32_can, okay)
|
2020-01-25 07:19:26 -08:00
|
|
|
#error Simultaneous use of CAN_1 and CAN_2 not supported yet
|
|
|
|
#endif
|
|
|
|
|
2020-11-20 13:39:48 +01:00
|
|
|
#define DT_DRV_COMPAT st_stm32_can
|
|
|
|
|
|
|
|
#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
|
|
|
|
|
2019-02-06 22:34:59 +01:00
|
|
|
/*
|
|
|
|
* Translation tables
|
|
|
|
* filter_in_bank[enum can_filter_type] = number of filters in bank for this type
|
|
|
|
* reg_demand[enum can_filter_type] = how many registers are used for this type
|
|
|
|
*/
|
2020-05-27 11:26:57 -05:00
|
|
|
static const uint8_t filter_in_bank[] = {2, 4, 1, 2};
|
|
|
|
static const uint8_t reg_demand[] = {2, 1, 4, 2};
|
2019-02-06 22:34:59 +01:00
|
|
|
|
2022-03-17 22:06:51 +01:00
|
|
|
static void can_stm32_signal_tx_complete(const struct device *dev, struct can_mailbox *mb)
|
2018-05-03 10:59:12 +02:00
|
|
|
{
|
|
|
|
if (mb->tx_callback) {
|
2022-03-17 22:06:51 +01:00
|
|
|
mb->tx_callback(dev, mb->error, mb->callback_arg);
|
2018-05-03 10:59:12 +02:00
|
|
|
} else {
|
|
|
|
k_sem_give(&mb->tx_int_sem);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-06 22:34:59 +01:00
|
|
|
static void can_stm32_get_msg_fifo(CAN_FIFOMailBox_TypeDef *mbox,
|
2021-12-04 15:21:32 +01:00
|
|
|
struct zcan_frame *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;
|
|
|
|
frame->id_type = CAN_EXTENDED_IDENTIFIER;
|
2018-05-03 10:59:12 +02:00
|
|
|
} else {
|
2021-12-04 15:21:32 +01:00
|
|
|
frame->id = mbox->RIR >> CAN_RI0R_STID_Pos;
|
|
|
|
frame->id_type = CAN_STANDARD_IDENTIFIER;
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
2021-12-04 15:21:32 +01:00
|
|
|
frame->rtr = mbox->RIR & CAN_RI0R_RTR ? CAN_REMOTEREQUEST : CAN_DATAFRAME;
|
|
|
|
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;
|
|
|
|
int filter_match_index;
|
2021-12-04 15:21:32 +01:00
|
|
|
struct zcan_frame frame;
|
2019-03-17 22:51:13 +01:00
|
|
|
can_rx_callback_t callback;
|
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];
|
|
|
|
filter_match_index = ((mbox->RDTR & CAN_RDT0R_FMI)
|
|
|
|
>> CAN_RDT0R_FMI_Pos);
|
|
|
|
|
|
|
|
if (filter_match_index >= CONFIG_CAN_MAX_FILTER) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-09-17 12:13:20 -05:00
|
|
|
LOG_DBG("Message on filter index %d", filter_match_index);
|
2021-12-04 15:21:32 +01:00
|
|
|
can_stm32_get_msg_fifo(mbox, &frame);
|
2018-05-23 10:54:56 +02:00
|
|
|
|
2019-03-17 22:51:13 +01:00
|
|
|
callback = data->rx_cb[filter_match_index];
|
2018-05-23 10:54:56 +02:00
|
|
|
|
2019-03-17 22:51:13 +01:00
|
|
|
if (callback) {
|
2022-03-17 22:06:51 +01:00
|
|
|
callback(dev, &frame, data->cb_arg[filter_match_index]);
|
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");
|
|
|
|
}
|
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-02-25 13:49:01 +01:00
|
|
|
CAN_TypeDef *can = cfg->can;
|
|
|
|
|
|
|
|
if (state != NULL) {
|
|
|
|
if (can->ESR & CAN_ESR_BOFF) {
|
|
|
|
*state = CAN_BUS_OFF;
|
|
|
|
} else if (can->ESR & CAN_ESR_EPVF) {
|
|
|
|
*state = CAN_ERROR_PASSIVE;
|
|
|
|
} else if (can->ESR & CAN_ESR_EWGF) {
|
|
|
|
*state = CAN_ERROR_WARNING;
|
|
|
|
} else {
|
|
|
|
*state = CAN_ERROR_ACTIVE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2018-05-03 10:59:12 +02:00
|
|
|
|
|
|
|
bus_off = can->ESR & CAN_ESR_BOFF;
|
|
|
|
|
|
|
|
if ((can->TSR & CAN_TSR_RQCP0) | bus_off) {
|
2021-12-28 22:28:54 +01:00
|
|
|
data->mb0.error =
|
2021-12-08 00:01:57 +01:00
|
|
|
can->TSR & CAN_TSR_TXOK0 ? 0 :
|
|
|
|
can->TSR & CAN_TSR_TERR0 ? -EIO :
|
|
|
|
can->TSR & CAN_TSR_ALST0 ? -EBUSY :
|
|
|
|
bus_off ? -ENETDOWN :
|
|
|
|
-EIO;
|
2018-05-03 10:59:12 +02:00
|
|
|
/* clear the request. */
|
|
|
|
can->TSR |= CAN_TSR_RQCP0;
|
2022-03-17 22:06:51 +01:00
|
|
|
can_stm32_signal_tx_complete(dev, &data->mb0);
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((can->TSR & CAN_TSR_RQCP1) | bus_off) {
|
2021-12-28 22:28:54 +01:00
|
|
|
data->mb1.error =
|
2021-12-08 00:01:57 +01:00
|
|
|
can->TSR & CAN_TSR_TXOK1 ? 0 :
|
|
|
|
can->TSR & CAN_TSR_TERR1 ? -EIO :
|
|
|
|
can->TSR & CAN_TSR_ALST1 ? -EBUSY :
|
|
|
|
bus_off ? -ENETDOWN :
|
|
|
|
-EIO;
|
2018-05-03 10:59:12 +02:00
|
|
|
/* clear the request. */
|
|
|
|
can->TSR |= CAN_TSR_RQCP1;
|
2022-03-17 22:06:51 +01:00
|
|
|
can_stm32_signal_tx_complete(dev, &data->mb1);
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((can->TSR & CAN_TSR_RQCP2) | bus_off) {
|
2021-12-28 22:28:54 +01:00
|
|
|
data->mb2.error =
|
2021-12-08 00:01:57 +01:00
|
|
|
can->TSR & CAN_TSR_TXOK2 ? 0 :
|
|
|
|
can->TSR & CAN_TSR_TERR2 ? -EIO :
|
|
|
|
can->TSR & CAN_TSR_ALST2 ? -EBUSY :
|
|
|
|
bus_off ? -ENETDOWN :
|
|
|
|
-EIO;
|
2018-05-03 10:59:12 +02:00
|
|
|
/* clear the request. */
|
|
|
|
can->TSR |= CAN_TSR_RQCP2;
|
2022-03-17 22:06:51 +01:00
|
|
|
can_stm32_signal_tx_complete(dev, &data->mb2);
|
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
|
|
|
|
|
2019-07-01 16:44:33 +02:00
|
|
|
static int can_enter_init_mode(CAN_TypeDef *can)
|
|
|
|
{
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int can_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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int can_leave_sleep_mode(CAN_TypeDef *can)
|
|
|
|
{
|
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-03-30 15:09:31 +02:00
|
|
|
static int can_stm32_set_mode(const struct device *dev, enum can_mode mode)
|
2018-05-03 10:59:12 +02:00
|
|
|
{
|
2022-01-18 12:50:32 +01:00
|
|
|
const struct can_stm32_config *cfg = dev->config;
|
2018-05-03 10:59:12 +02:00
|
|
|
CAN_TypeDef *can = cfg->can;
|
2022-01-18 12:50:32 +01:00
|
|
|
struct can_stm32_data *data = dev->data;
|
2019-03-04 01:19:40 +03:00
|
|
|
int ret;
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2020-04-27 18:58:05 +02:00
|
|
|
LOG_DBG("Set mode %d", mode);
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2020-04-27 18:58:05 +02:00
|
|
|
k_mutex_lock(&data->inst_mutex, K_FOREVER);
|
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);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-27 18:58:05 +02:00
|
|
|
ret = can_enter_init_mode(can);
|
|
|
|
if (ret) {
|
|
|
|
LOG_ERR("Failed to enter init mode");
|
|
|
|
goto done;
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
2020-04-27 18:58:05 +02:00
|
|
|
switch (mode) {
|
|
|
|
case CAN_NORMAL_MODE:
|
|
|
|
can->BTR &= ~(CAN_BTR_LBKM | CAN_BTR_SILM);
|
|
|
|
break;
|
|
|
|
case CAN_LOOPBACK_MODE:
|
|
|
|
can->BTR &= ~(CAN_BTR_SILM);
|
|
|
|
can->BTR |= CAN_BTR_LBKM;
|
|
|
|
break;
|
|
|
|
case CAN_SILENT_MODE:
|
|
|
|
can->BTR &= ~(CAN_BTR_LBKM);
|
|
|
|
can->BTR |= CAN_BTR_SILM;
|
|
|
|
break;
|
|
|
|
case CAN_SILENT_LOOPBACK_MODE:
|
|
|
|
can->BTR |= CAN_BTR_LBKM | CAN_BTR_SILM;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
2020-04-27 18:58:05 +02:00
|
|
|
done:
|
|
|
|
ret = can_leave_init_mode(can);
|
|
|
|
if (ret) {
|
|
|
|
LOG_ERR("Failed to leave init mode");
|
2022-03-01 14:15:19 +01:00
|
|
|
|
|
|
|
if (cfg->phy != NULL) {
|
|
|
|
/* Attempt to disable the CAN transceiver in case of error */
|
|
|
|
(void)can_transceiver_disable(cfg->phy);
|
|
|
|
}
|
2018-05-29 16:10:31 +02:00
|
|
|
}
|
2022-03-01 14:15:19 +01:00
|
|
|
|
2020-04-27 18:58:05 +02:00
|
|
|
k_mutex_unlock(&data->inst_mutex);
|
2022-03-01 14:15:19 +01:00
|
|
|
|
2020-04-27 18:58:05 +02:00
|
|
|
return ret;
|
|
|
|
}
|
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,
|
|
|
|
const struct can_timing *timing,
|
|
|
|
const struct can_timing *timing_data)
|
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;
|
2020-04-27 18:58:05 +02:00
|
|
|
int ret = -EIO;
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2020-04-27 18:58:05 +02:00
|
|
|
ARG_UNUSED(timing_data);
|
2019-07-01 16:44:33 +02:00
|
|
|
|
2018-06-19 18:26:31 +02:00
|
|
|
k_mutex_lock(&data->inst_mutex, K_FOREVER);
|
2019-07-01 16:44:33 +02:00
|
|
|
ret = can_enter_init_mode(can);
|
|
|
|
if (ret) {
|
|
|
|
LOG_ERR("Failed to enter init mode");
|
2018-06-19 18:26:31 +02:00
|
|
|
goto done;
|
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);
|
|
|
|
}
|
|
|
|
|
2019-07-01 16:44:33 +02:00
|
|
|
ret = can_leave_init_mode(can);
|
|
|
|
if (ret) {
|
|
|
|
LOG_ERR("Failed to leave init mode");
|
2020-04-27 18:58:05 +02:00
|
|
|
} else {
|
|
|
|
ret = 0;
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
2018-06-19 18:26:31 +02:00
|
|
|
done:
|
|
|
|
k_mutex_unlock(&data->inst_mutex);
|
|
|
|
return ret;
|
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,
|
|
|
|
(clock_control_subsys_t *) &cfg->pclken,
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
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-05-11 11:56:08 -07:00
|
|
|
#if DT_NODE_HAS_STATUS(DT_NODELABEL(can2), okay)
|
2020-01-25 07:19:26 -08:00
|
|
|
CAN_TypeDef *master_can = cfg->master_can;
|
|
|
|
#endif
|
2020-04-30 20:33:38 +02:00
|
|
|
const struct device *clock;
|
2018-05-03 10:59:12 +02:00
|
|
|
int ret;
|
|
|
|
|
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);
|
|
|
|
k_sem_init(&data->mb0.tx_int_sem, 0, 1);
|
|
|
|
k_sem_init(&data->mb1.tx_int_sem, 0, 1);
|
|
|
|
k_sem_init(&data->mb2.tx_int_sem, 0, 1);
|
|
|
|
data->mb0.tx_callback = NULL;
|
|
|
|
data->mb1.tx_callback = NULL;
|
|
|
|
data->mb2.tx_callback = NULL;
|
2021-12-28 20:00:34 +01:00
|
|
|
data->state_change_cb = NULL;
|
2022-01-10 12:32:19 +01:00
|
|
|
data->state_change_cb_data = NULL;
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2019-01-19 14:30:54 +01:00
|
|
|
data->filter_usage = (1ULL << CAN_MAX_NUMBER_OF_FILTERS) - 1ULL;
|
2019-02-13 10:26:17 +01:00
|
|
|
(void)memset(data->rx_cb, 0, sizeof(data->rx_cb));
|
|
|
|
(void)memset(data->cb_arg, 0, sizeof(data->cb_arg));
|
2018-05-03 10:59:12 +02:00
|
|
|
|
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);
|
2018-05-03 10:59:12 +02:00
|
|
|
|
|
|
|
ret = clock_control_on(clock, (clock_control_subsys_t *) &cfg->pclken);
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2019-07-01 16:44:33 +02:00
|
|
|
ret = can_leave_sleep_mode(can);
|
|
|
|
if (ret) {
|
|
|
|
LOG_ERR("Failed to exit sleep mode");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = can_enter_init_mode(can);
|
|
|
|
if (ret) {
|
|
|
|
LOG_ERR("Failed to enter init mode");
|
|
|
|
return ret;
|
|
|
|
}
|
2019-07-02 12:39:19 +02:00
|
|
|
|
2020-05-11 11:56:08 -07:00
|
|
|
#if DT_NODE_HAS_STATUS(DT_NODELABEL(can2), okay)
|
2020-01-25 07:19:26 -08:00
|
|
|
master_can->FMR &= ~CAN_FMR_CAN2SB; /* Assign all filters to CAN2 */
|
|
|
|
#endif
|
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
|
2022-01-14 15:17:32 +01:00
|
|
|
if (cfg->one_shot) {
|
|
|
|
can->MCR |= CAN_MCR_NART;
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = can_stm32_set_timing(dev, &timing, NULL);
|
|
|
|
if (ret) {
|
|
|
|
return ret;
|
|
|
|
}
|
2019-07-01 16:44:33 +02:00
|
|
|
|
2020-04-27 18:58:05 +02:00
|
|
|
ret = can_stm32_set_mode(dev, CAN_NORMAL_MODE);
|
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;
|
2020-03-09 12:49:07 +01:00
|
|
|
LOG_INF("Init of %s done", dev->name);
|
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
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
ret = can_enter_init_mode(can);
|
|
|
|
if (ret) {
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
can_leave_init_mode(can);
|
|
|
|
|
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-03-30 15:09:31 +02:00
|
|
|
static int can_stm32_send(const struct device *dev, const struct zcan_frame *frame,
|
|
|
|
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;
|
|
|
|
struct can_mailbox *mb = NULL;
|
|
|
|
|
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
|
|
|
|
, frame->id_type == CAN_STANDARD_IDENTIFIER ?
|
2018-05-03 10:59:12 +02:00
|
|
|
"standard" : "extended"
|
2021-12-04 15:21:32 +01:00
|
|
|
, frame->rtr == CAN_DATAFRAME ? "no" : "yes");
|
2018-05-03 10:59:12 +02:00
|
|
|
|
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
|
|
|
|
|
|
|
if (can->ESR & CAN_ESR_BOFF) {
|
2021-12-08 00:01:57 +01:00
|
|
|
return -ENETDOWN;
|
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) {
|
2018-09-17 12:13:20 -05:00
|
|
|
LOG_DBG("Using 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) {
|
2018-09-17 12:13:20 -05:00
|
|
|
LOG_DBG("Using 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) {
|
2018-09-17 12:13:20 -05:00
|
|
|
LOG_DBG("Using 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-06-08 09:23:47 +02:00
|
|
|
k_sem_reset(&mb->tx_int_sem);
|
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;
|
|
|
|
|
2021-12-04 15:21:32 +01:00
|
|
|
if (frame->id_type == CAN_STANDARD_IDENTIFIER) {
|
|
|
|
mailbox->TIR |= (frame->id << CAN_TI0R_STID_Pos);
|
2018-05-03 10:59:12 +02:00
|
|
|
} else {
|
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;
|
|
|
|
}
|
|
|
|
|
2021-12-04 15:21:32 +01:00
|
|
|
if (frame->rtr == CAN_REMOTEREQUEST) {
|
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
|
|
|
|
|
|
|
if (callback == NULL) {
|
|
|
|
k_sem_take(&mb->tx_int_sem, K_FOREVER);
|
2021-12-28 22:28:54 +01:00
|
|
|
return mb->error;
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-02-06 22:34:59 +01:00
|
|
|
static inline int can_stm32_check_free(void **arr, int start, int end)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = start; i <= end; i++) {
|
|
|
|
if (arr[i] != NULL) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-05-03 10:59:12 +02:00
|
|
|
static int can_stm32_shift_arr(void **arr, int start, int count)
|
|
|
|
{
|
|
|
|
void **start_ptr = arr + start;
|
|
|
|
size_t cnt;
|
|
|
|
|
|
|
|
if (start > CONFIG_CAN_MAX_FILTER) {
|
2021-12-08 00:01:57 +01:00
|
|
|
return -ENOSPC;
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (count > 0) {
|
|
|
|
void *move_dest;
|
|
|
|
|
2019-02-06 22:34:59 +01:00
|
|
|
/* Check if nothing used will be overwritten */
|
|
|
|
if (!can_stm32_check_free(arr, CONFIG_CAN_MAX_FILTER - count,
|
|
|
|
CONFIG_CAN_MAX_FILTER - 1)) {
|
2021-12-08 00:01:57 +01:00
|
|
|
return -ENOSPC;
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
2019-02-06 22:34:59 +01:00
|
|
|
/* No need to shift. Destination is already outside the arr*/
|
|
|
|
if ((start + count) >= CONFIG_CAN_MAX_FILTER) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-05-03 10:59:12 +02:00
|
|
|
cnt = (CONFIG_CAN_MAX_FILTER - start - count) * sizeof(void *);
|
|
|
|
move_dest = start_ptr + count;
|
|
|
|
memmove(move_dest, start_ptr, cnt);
|
2018-09-11 19:09:03 -07:00
|
|
|
(void)memset(start_ptr, 0, count * sizeof(void *));
|
2018-05-03 10:59:12 +02:00
|
|
|
} else if (count < 0) {
|
|
|
|
count = -count;
|
|
|
|
|
|
|
|
if (start - count < 0) {
|
2021-12-08 00:01:57 +01:00
|
|
|
return -ENOSPC;
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
cnt = (CONFIG_CAN_MAX_FILTER - start) * sizeof(void *);
|
|
|
|
memmove(start_ptr - count, start_ptr, cnt);
|
2018-09-11 19:09:03 -07:00
|
|
|
(void)memset(arr + CONFIG_CAN_MAX_FILTER - count, 0,
|
|
|
|
count * sizeof(void *));
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-03-30 15:09:31 +02:00
|
|
|
static enum can_filter_type can_stm32_get_filter_type(int bank_nr, uint32_t mode_reg,
|
|
|
|
uint32_t scale_reg)
|
2019-02-06 22:34:59 +01:00
|
|
|
{
|
2020-05-27 11:26:57 -05:00
|
|
|
uint32_t mode_masked = (mode_reg >> bank_nr) & 0x01;
|
|
|
|
uint32_t scale_masked = (scale_reg >> bank_nr) & 0x01;
|
2019-02-06 22:34:59 +01:00
|
|
|
enum can_filter_type type = (scale_masked << 1) | mode_masked;
|
|
|
|
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
2021-12-28 20:00:34 +01:00
|
|
|
static int can_calc_filter_index(int filter_id, uint32_t mode_reg, uint32_t scale_reg)
|
2018-05-03 10:59:12 +02:00
|
|
|
{
|
2021-12-28 20:00:34 +01:00
|
|
|
int filter_bank = filter_id / 4;
|
2018-05-03 10:59:12 +02:00
|
|
|
int cnt = 0;
|
2020-05-27 11:26:57 -05:00
|
|
|
uint32_t mode_masked, scale_masked;
|
2019-02-06 22:34:59 +01:00
|
|
|
enum can_filter_type filter_type;
|
2018-05-03 10:59:12 +02:00
|
|
|
/*count filters in the banks before */
|
|
|
|
for (int i = 0; i < filter_bank; i++) {
|
2019-02-06 22:34:59 +01:00
|
|
|
filter_type = can_stm32_get_filter_type(i, mode_reg, scale_reg);
|
|
|
|
cnt += filter_in_bank[filter_type];
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* plus the filters in the same bank */
|
|
|
|
mode_masked = mode_reg & (1U << filter_bank);
|
|
|
|
scale_masked = scale_reg & (1U << filter_bank);
|
2021-12-28 20:00:34 +01:00
|
|
|
cnt += (!scale_masked && mode_masked) ? filter_id & 0x03 :
|
|
|
|
(filter_id & 0x03) >> 1;
|
2018-05-03 10:59:12 +02:00
|
|
|
return cnt;
|
|
|
|
}
|
|
|
|
|
2021-12-28 20:00:34 +01:00
|
|
|
static void can_stm32_set_filter_bank(int filter_id,
|
2018-05-03 10:59:12 +02:00
|
|
|
CAN_FilterRegister_TypeDef *filter_reg,
|
|
|
|
enum can_filter_type filter_type,
|
2020-05-27 11:26:57 -05:00
|
|
|
uint32_t id, uint32_t mask)
|
2018-05-03 10:59:12 +02:00
|
|
|
{
|
|
|
|
switch (filter_type) {
|
|
|
|
case CAN_FILTER_STANDARD:
|
2021-12-28 20:00:34 +01:00
|
|
|
switch (filter_id & 0x03) {
|
2018-05-03 10:59:12 +02:00
|
|
|
case 0:
|
|
|
|
filter_reg->FR1 = (filter_reg->FR1 & 0xFFFF0000) | id;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
filter_reg->FR1 = (filter_reg->FR1 & 0x0000FFFF)
|
|
|
|
| (id << 16);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
filter_reg->FR2 = (filter_reg->FR2 & 0xFFFF0000) | id;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
filter_reg->FR2 = (filter_reg->FR2 & 0x0000FFFF)
|
|
|
|
| (id << 16);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case CAN_FILTER_STANDARD_MASKED:
|
2021-12-28 20:00:34 +01:00
|
|
|
switch (filter_id & 0x02) {
|
2018-05-03 10:59:12 +02:00
|
|
|
case 0:
|
|
|
|
filter_reg->FR1 = id | (mask << 16);
|
2019-02-06 22:34:59 +01:00
|
|
|
break;
|
2018-05-03 10:59:12 +02:00
|
|
|
case 2:
|
|
|
|
filter_reg->FR2 = id | (mask << 16);
|
2019-02-06 22:34:59 +01:00
|
|
|
break;
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case CAN_FILTER_EXTENDED:
|
2021-12-28 20:00:34 +01:00
|
|
|
switch (filter_id & 0x02) {
|
2018-05-03 10:59:12 +02:00
|
|
|
case 0:
|
|
|
|
filter_reg->FR1 = id;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
filter_reg->FR2 = id;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case CAN_FILTER_EXTENDED_MASKED:
|
|
|
|
filter_reg->FR1 = id;
|
|
|
|
filter_reg->FR2 = mask;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-06 22:34:59 +01:00
|
|
|
static inline void can_stm32_set_mode_scale(enum can_filter_type filter_type,
|
2020-05-27 11:26:57 -05:00
|
|
|
uint32_t *mode_reg, uint32_t *scale_reg,
|
2019-04-29 13:10:28 +02:00
|
|
|
int bank_nr)
|
2018-05-03 10:59:12 +02:00
|
|
|
{
|
2020-05-27 11:26:57 -05:00
|
|
|
uint32_t mode_reg_bit = (filter_type & 0x01) << bank_nr;
|
|
|
|
uint32_t scale_reg_bit = (filter_type >> 1) << bank_nr;
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2019-04-29 13:10:28 +02:00
|
|
|
*mode_reg &= ~(1 << bank_nr);
|
2019-02-06 22:34:59 +01:00
|
|
|
*mode_reg |= mode_reg_bit;
|
|
|
|
|
2019-04-29 13:10:28 +02:00
|
|
|
*scale_reg &= ~(1 << bank_nr);
|
2019-02-06 22:34:59 +01:00
|
|
|
*scale_reg |= scale_reg_bit;
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
2020-05-27 11:26:57 -05:00
|
|
|
static inline uint32_t can_generate_std_mask(const struct zcan_filter *filter)
|
2018-05-03 10:59:12 +02:00
|
|
|
{
|
2020-11-19 20:46:56 +01:00
|
|
|
return (filter->id_mask << CAN_FIRX_STD_ID_POS) |
|
|
|
|
(filter->rtr_mask << CAN_FIRX_STD_RTR_POS) |
|
|
|
|
(1U << CAN_FIRX_STD_IDE_POS);
|
2019-02-06 22:34:59 +01:00
|
|
|
}
|
|
|
|
|
2020-05-27 11:26:57 -05:00
|
|
|
static inline uint32_t can_generate_ext_mask(const struct zcan_filter *filter)
|
2019-02-06 22:34:59 +01:00
|
|
|
{
|
2020-11-19 20:46:56 +01:00
|
|
|
return (filter->id_mask << CAN_FIRX_EXT_EXT_ID_POS) |
|
|
|
|
(filter->rtr_mask << CAN_FIRX_EXT_RTR_POS) |
|
|
|
|
(1U << CAN_FIRX_EXT_IDE_POS);
|
2019-02-06 22:34:59 +01:00
|
|
|
}
|
|
|
|
|
2020-05-27 11:26:57 -05:00
|
|
|
static inline uint32_t can_generate_std_id(const struct zcan_filter *filter)
|
2019-02-06 22:34:59 +01:00
|
|
|
{
|
|
|
|
|
2020-11-19 20:46:56 +01:00
|
|
|
return (filter->id << CAN_FIRX_STD_ID_POS) |
|
2019-02-06 22:34:59 +01:00
|
|
|
(filter->rtr << CAN_FIRX_STD_RTR_POS);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-05-27 11:26:57 -05:00
|
|
|
static inline uint32_t can_generate_ext_id(const struct zcan_filter *filter)
|
2019-02-06 22:34:59 +01:00
|
|
|
{
|
2020-11-19 20:46:56 +01:00
|
|
|
return (filter->id << CAN_FIRX_EXT_EXT_ID_POS) |
|
|
|
|
(filter->rtr << CAN_FIRX_EXT_RTR_POS) |
|
|
|
|
(1U << CAN_FIRX_EXT_IDE_POS);
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
2019-02-21 13:23:44 +02:00
|
|
|
static inline int can_stm32_set_filter(const struct zcan_filter *filter,
|
2018-05-03 10:59:12 +02:00
|
|
|
struct can_stm32_data *device_data,
|
|
|
|
CAN_TypeDef *can,
|
|
|
|
int *filter_index)
|
|
|
|
{
|
2020-05-27 11:26:57 -05:00
|
|
|
uint32_t mask = 0U;
|
|
|
|
uint32_t id = 0U;
|
2021-12-28 20:00:34 +01:00
|
|
|
int filter_id = 0;
|
2021-12-08 00:01:57 +01:00
|
|
|
int filter_index_new = -ENOSPC;
|
2018-05-03 10:59:12 +02:00
|
|
|
int bank_nr;
|
2020-05-27 11:26:57 -05:00
|
|
|
uint32_t bank_bit;
|
2018-05-03 10:59:12 +02:00
|
|
|
int register_demand;
|
|
|
|
enum can_filter_type filter_type;
|
|
|
|
enum can_filter_type bank_mode;
|
|
|
|
|
|
|
|
if (filter->id_type == CAN_STANDARD_IDENTIFIER) {
|
2019-02-06 22:34:59 +01:00
|
|
|
id = can_generate_std_id(filter);
|
|
|
|
filter_type = CAN_FILTER_STANDARD;
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2020-11-19 20:46:56 +01:00
|
|
|
if (filter->id_mask != CAN_STD_ID_MASK) {
|
2019-02-06 22:34:59 +01:00
|
|
|
mask = can_generate_std_mask(filter);
|
2018-05-03 10:59:12 +02:00
|
|
|
filter_type = CAN_FILTER_STANDARD_MASKED;
|
|
|
|
}
|
|
|
|
} else {
|
2019-02-06 22:34:59 +01:00
|
|
|
id = can_generate_ext_id(filter);
|
|
|
|
filter_type = CAN_FILTER_EXTENDED;
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2020-11-19 20:46:56 +01:00
|
|
|
if (filter->id_mask != CAN_EXT_ID_MASK) {
|
2019-02-06 22:34:59 +01:00
|
|
|
mask = can_generate_ext_mask(filter);
|
2018-05-03 10:59:12 +02:00
|
|
|
filter_type = CAN_FILTER_EXTENDED_MASKED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-06 22:34:59 +01:00
|
|
|
register_demand = reg_demand[filter_type];
|
|
|
|
|
2020-11-19 20:46:56 +01:00
|
|
|
LOG_DBG("Setting filter ID: 0x%x, mask: 0x%x", filter->id,
|
|
|
|
filter->id_mask);
|
2018-09-17 12:13:20 -05:00
|
|
|
LOG_DBG("Filter type: %s ID %s mask (%d)",
|
2018-05-03 10:59:12 +02:00
|
|
|
(filter_type == CAN_FILTER_STANDARD ||
|
|
|
|
filter_type == CAN_FILTER_STANDARD_MASKED) ?
|
|
|
|
"standard" : "extended",
|
|
|
|
(filter_type == CAN_FILTER_STANDARD_MASKED ||
|
|
|
|
filter_type == CAN_FILTER_EXTENDED_MASKED) ?
|
|
|
|
"with" : "without",
|
|
|
|
filter_type);
|
|
|
|
|
|
|
|
do {
|
2021-12-28 20:00:34 +01:00
|
|
|
uint64_t usage_shifted = (device_data->filter_usage >> filter_id);
|
2020-05-27 11:26:57 -05:00
|
|
|
uint64_t usage_demand_mask = (1ULL << register_demand) - 1;
|
2018-05-03 10:59:12 +02:00
|
|
|
bool bank_is_empty;
|
|
|
|
|
2021-12-28 20:00:34 +01:00
|
|
|
bank_nr = filter_id / 4;
|
2018-05-03 10:59:12 +02:00
|
|
|
bank_bit = (1U << bank_nr);
|
2019-02-06 22:34:59 +01:00
|
|
|
bank_mode = can_stm32_get_filter_type(bank_nr, can->FM1R,
|
2018-05-03 10:59:12 +02:00
|
|
|
can->FS1R);
|
2019-02-06 22:34:59 +01:00
|
|
|
|
2018-05-03 10:59:12 +02:00
|
|
|
bank_is_empty = CAN_BANK_IS_EMPTY(device_data->filter_usage,
|
|
|
|
bank_nr);
|
|
|
|
|
2019-02-06 22:34:59 +01:00
|
|
|
if (!bank_is_empty && bank_mode != filter_type) {
|
2021-12-28 20:00:34 +01:00
|
|
|
filter_id = (bank_nr + 1) * 4;
|
2019-02-06 22:34:59 +01:00
|
|
|
} else if (usage_shifted & usage_demand_mask) {
|
|
|
|
device_data->filter_usage &=
|
2021-12-28 20:00:34 +01:00
|
|
|
~(usage_demand_mask << filter_id);
|
2019-02-06 22:34:59 +01:00
|
|
|
break;
|
2018-05-03 10:59:12 +02:00
|
|
|
} else {
|
2021-12-28 20:00:34 +01:00
|
|
|
filter_id += register_demand;
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!usage_shifted) {
|
2018-09-17 12:13:20 -05:00
|
|
|
LOG_INF("No free filter bank found");
|
2021-12-08 00:01:57 +01:00
|
|
|
return -ENOSPC;
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
2021-12-28 20:00:34 +01:00
|
|
|
} while (filter_id < CAN_MAX_NUMBER_OF_FILTERS);
|
2018-05-03 10:59:12 +02:00
|
|
|
|
|
|
|
/* set the filter init mode */
|
|
|
|
can->FMR |= CAN_FMR_FINIT;
|
|
|
|
can->FA1R &= ~bank_bit;
|
|
|
|
|
|
|
|
/* TODO fifo balancing */
|
|
|
|
if (filter_type != bank_mode) {
|
2019-02-06 22:34:59 +01:00
|
|
|
int shift_width, start_index;
|
2018-05-03 10:59:12 +02:00
|
|
|
int res;
|
2020-05-27 11:26:57 -05:00
|
|
|
uint32_t mode_reg = can->FM1R;
|
|
|
|
uint32_t scale_reg = can->FS1R;
|
2018-05-03 10:59:12 +02:00
|
|
|
|
|
|
|
can_stm32_set_mode_scale(filter_type, &mode_reg, &scale_reg,
|
2019-04-29 13:10:28 +02:00
|
|
|
bank_nr);
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2019-02-06 22:34:59 +01:00
|
|
|
shift_width = filter_in_bank[filter_type] - filter_in_bank[bank_mode];
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2021-12-28 20:00:34 +01:00
|
|
|
filter_index_new = can_calc_filter_index(filter_id, mode_reg,
|
2018-05-03 10:59:12 +02:00
|
|
|
scale_reg);
|
|
|
|
|
2019-02-06 22:34:59 +01:00
|
|
|
start_index = filter_index_new + filter_in_bank[bank_mode];
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2019-02-13 11:18:27 +01:00
|
|
|
if (shift_width && start_index <= CAN_MAX_NUMBER_OF_FILTERS) {
|
2019-03-17 22:51:13 +01:00
|
|
|
res = can_stm32_shift_arr((void **)device_data->rx_cb,
|
2019-02-13 11:18:27 +01:00
|
|
|
start_index,
|
|
|
|
shift_width);
|
|
|
|
|
2019-02-11 14:40:28 +01:00
|
|
|
res |= can_stm32_shift_arr(device_data->cb_arg,
|
|
|
|
start_index,
|
|
|
|
shift_width);
|
|
|
|
|
2019-02-13 11:18:27 +01:00
|
|
|
if (filter_index_new >= CONFIG_CAN_MAX_FILTER || res) {
|
|
|
|
LOG_INF("No space for a new filter!");
|
2021-12-28 20:00:34 +01:00
|
|
|
filter_id = -ENOSPC;
|
2019-02-13 11:18:27 +01:00
|
|
|
goto done;
|
|
|
|
}
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
can->FM1R = mode_reg;
|
|
|
|
can->FS1R = scale_reg;
|
|
|
|
} else {
|
2021-12-28 20:00:34 +01:00
|
|
|
filter_index_new = can_calc_filter_index(filter_id, can->FM1R,
|
2018-05-03 10:59:12 +02:00
|
|
|
can->FS1R);
|
2019-02-06 22:34:59 +01:00
|
|
|
if (filter_index_new >= CAN_MAX_NUMBER_OF_FILTERS) {
|
2021-12-28 20:00:34 +01:00
|
|
|
filter_id = -ENOSPC;
|
2018-05-03 10:59:12 +02:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-28 20:00:34 +01:00
|
|
|
can_stm32_set_filter_bank(filter_id, &can->sFilterRegister[bank_nr],
|
2018-05-03 10:59:12 +02:00
|
|
|
filter_type, id, mask);
|
|
|
|
done:
|
|
|
|
can->FA1R |= bank_bit;
|
|
|
|
can->FMR &= ~(CAN_FMR_FINIT);
|
2018-09-17 12:13:20 -05:00
|
|
|
LOG_DBG("Filter set! Filter number: %d (index %d)",
|
2021-12-28 20:00:34 +01:00
|
|
|
filter_id, filter_index_new);
|
2019-02-06 22:34:59 +01:00
|
|
|
*filter_index = filter_index_new;
|
2021-12-28 20:00:34 +01:00
|
|
|
return filter_id;
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
2021-12-28 20:00:34 +01:00
|
|
|
static inline int can_stm32_add_rx_filter_unlocked(const struct device *dev,
|
|
|
|
can_rx_callback_t cb,
|
|
|
|
void *cb_arg,
|
|
|
|
const struct zcan_filter *filter)
|
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;
|
2019-03-17 22:51:13 +01:00
|
|
|
int filter_index = 0;
|
2021-12-28 20:00:34 +01:00
|
|
|
int filter_id;
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2021-12-28 20:00:34 +01:00
|
|
|
filter_id = can_stm32_set_filter(filter, data, can, &filter_index);
|
|
|
|
if (filter_id != -ENOSPC) {
|
2019-03-17 22:51:13 +01:00
|
|
|
data->rx_cb[filter_index] = cb;
|
|
|
|
data->cb_arg[filter_index] = cb_arg;
|
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-03-30 15:09:31 +02:00
|
|
|
static int can_stm32_add_rx_filter(const struct device *dev, can_rx_callback_t cb,
|
|
|
|
void *cb_arg,
|
2021-12-28 20:00:34 +01:00
|
|
|
const struct zcan_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
|
|
|
|
2018-06-19 18:26:31 +02:00
|
|
|
k_mutex_lock(&data->inst_mutex, K_FOREVER);
|
2021-12-28 20:00:34 +01:00
|
|
|
filter_id = can_stm32_add_rx_filter_unlocked(dev, cb, cb_arg, filter);
|
2018-06-19 18:26:31 +02:00
|
|
|
k_mutex_unlock(&data->inst_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;
|
2018-05-03 10:59:12 +02:00
|
|
|
int bank_nr;
|
|
|
|
int filter_index;
|
2020-05-27 11:26:57 -05:00
|
|
|
uint32_t bank_bit;
|
|
|
|
uint32_t mode_reg;
|
|
|
|
uint32_t scale_reg;
|
2018-05-03 10:59:12 +02:00
|
|
|
enum can_filter_type type;
|
2020-05-27 11:26:57 -05:00
|
|
|
uint32_t reset_mask;
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2021-12-28 20:00:34 +01:00
|
|
|
__ASSERT_NO_MSG(filter_id >= 0 && filter_id < CAN_MAX_NUMBER_OF_FILTERS);
|
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
|
|
|
|
2021-12-28 20:00:34 +01:00
|
|
|
bank_nr = filter_id / 4;
|
2018-05-03 10:59:12 +02:00
|
|
|
bank_bit = (1U << bank_nr);
|
|
|
|
mode_reg = can->FM1R;
|
|
|
|
scale_reg = can->FS1R;
|
|
|
|
|
2021-12-28 20:00:34 +01:00
|
|
|
filter_index = can_calc_filter_index(filter_id, mode_reg, scale_reg);
|
2019-02-06 22:34:59 +01:00
|
|
|
type = can_stm32_get_filter_type(bank_nr, mode_reg, scale_reg);
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2022-03-16 21:07:43 +00:00
|
|
|
LOG_DBG("Detach filter number %d (index %d), type %d", filter_id,
|
2018-05-03 10:59:12 +02:00
|
|
|
filter_index,
|
|
|
|
type);
|
|
|
|
|
2021-12-28 20:00:34 +01:00
|
|
|
reset_mask = ((1 << (reg_demand[type])) - 1) << filter_id;
|
2018-05-03 10:59:12 +02:00
|
|
|
data->filter_usage |= reset_mask;
|
|
|
|
can->FMR |= CAN_FMR_FINIT;
|
|
|
|
can->FA1R &= ~bank_bit;
|
|
|
|
|
2021-12-28 20:00:34 +01:00
|
|
|
can_stm32_set_filter_bank(filter_id, &can->sFilterRegister[bank_nr],
|
2018-05-03 10:59:12 +02:00
|
|
|
type, 0, 0xFFFFFFFF);
|
|
|
|
|
|
|
|
if (!CAN_BANK_IS_EMPTY(data->filter_usage, bank_nr)) {
|
|
|
|
can->FA1R |= bank_bit;
|
|
|
|
} else {
|
2022-02-24 12:00:55 +00:00
|
|
|
LOG_DBG("Bank number %d is empty -> deactivate", bank_nr);
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
can->FMR &= ~(CAN_FMR_FINIT);
|
2019-03-17 22:51:13 +01:00
|
|
|
data->rx_cb[filter_index] = NULL;
|
2019-02-11 14:40:28 +01:00
|
|
|
data->cb_arg[filter_index] = NULL;
|
2018-05-03 10:59:12 +02:00
|
|
|
|
2018-06-19 18:26:31 +02:00
|
|
|
k_mutex_unlock(&data->inst_mutex);
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct can_driver_api can_api_funcs = {
|
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,
|
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 = {
|
|
|
|
.sjw = 0x07,
|
|
|
|
.prop_seg = 0x00,
|
|
|
|
.phase_seg1 = 0x0F,
|
|
|
|
.phase_seg2 = 0x07,
|
|
|
|
.prescaler = 0x400
|
|
|
|
}
|
2018-05-03 10:59:12 +02:00
|
|
|
};
|
|
|
|
|
2020-05-07 12:22:26 -05:00
|
|
|
#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(can1), st_stm32_can, okay)
|
2018-05-03 10:59:12 +02:00
|
|
|
|
|
|
|
static void config_can_1_irq(CAN_TypeDef *can);
|
|
|
|
|
2021-12-23 12:33:03 +01:00
|
|
|
PINCTRL_DT_DEFINE(DT_NODELABEL(can1));
|
2020-10-09 10:54:44 +02:00
|
|
|
|
2018-05-03 10:59:12 +02:00
|
|
|
static const struct can_stm32_config can_stm32_cfg_1 = {
|
2020-04-17 09:03:03 +02:00
|
|
|
.can = (CAN_TypeDef *)DT_REG_ADDR(DT_NODELABEL(can1)),
|
|
|
|
.master_can = (CAN_TypeDef *)DT_REG_ADDR(DT_NODELABEL(can1)),
|
|
|
|
.bus_speed = DT_PROP(DT_NODELABEL(can1), bus_speed),
|
2020-11-20 13:39:48 +01:00
|
|
|
.sample_point = DT_PROP_OR(DT_NODELABEL(can1), sample_point, 0),
|
|
|
|
.sjw = DT_PROP_OR(DT_NODELABEL(can1), sjw, 1),
|
|
|
|
.prop_ts1 = DT_PROP_OR(DT_NODELABEL(can1), prop_seg, 0) +
|
|
|
|
DT_PROP_OR(DT_NODELABEL(can1), phase_seg1, 0),
|
|
|
|
.ts2 = DT_PROP_OR(DT_NODELABEL(can1), phase_seg2, 0),
|
2022-01-14 15:17:32 +01:00
|
|
|
.one_shot = DT_PROP(DT_NODELABEL(can1), one_shot),
|
2018-05-03 10:59:12 +02:00
|
|
|
.pclken = {
|
2020-04-17 09:03:03 +02:00
|
|
|
.enr = DT_CLOCKS_CELL(DT_NODELABEL(can1), bits),
|
|
|
|
.bus = DT_CLOCKS_CELL(DT_NODELABEL(can1), bus),
|
2018-05-03 10:59:12 +02:00
|
|
|
},
|
2020-10-09 10:54:44 +02:00
|
|
|
.config_irq = config_can_1_irq,
|
2022-03-01 14:15:19 +01:00
|
|
|
.pcfg = PINCTRL_DT_DEV_CONFIG_GET(DT_NODELABEL(can1)),
|
|
|
|
.phy = DEVICE_DT_GET_OR_NULL(DT_PHANDLE(DT_NODELABEL(can1), phys)),
|
|
|
|
.max_bitrate = DT_CAN_TRANSCEIVER_MAX_BITRATE(DT_NODELABEL(can1), 1000000),
|
2018-05-03 10:59:12 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct can_stm32_data can_stm32_dev_data_1;
|
|
|
|
|
2022-02-25 11:10:38 +01:00
|
|
|
CAN_DEVICE_DT_DEFINE(DT_NODELABEL(can1), can_stm32_init, NULL,
|
|
|
|
&can_stm32_dev_data_1, &can_stm32_cfg_1,
|
|
|
|
POST_KERNEL, CONFIG_CAN_INIT_PRIORITY,
|
|
|
|
&can_api_funcs);
|
2018-05-03 10:59:12 +02:00
|
|
|
|
|
|
|
static void config_can_1_irq(CAN_TypeDef *can)
|
|
|
|
{
|
2018-09-17 12:13:20 -05:00
|
|
|
LOG_DBG("Enable CAN1 IRQ");
|
2018-05-23 10:54:56 +02:00
|
|
|
#ifdef CONFIG_SOC_SERIES_STM32F0X
|
2020-04-17 09:03:03 +02:00
|
|
|
IRQ_CONNECT(DT_IRQN(DT_NODELABEL(can1)),
|
|
|
|
DT_IRQ(DT_NODELABEL(can1), priority),
|
2020-12-17 11:35:11 -06:00
|
|
|
can_stm32_isr, DEVICE_DT_GET(DT_NODELABEL(can1)), 0);
|
2020-04-17 09:03:03 +02:00
|
|
|
irq_enable(DT_IRQN(DT_NODELABEL(can1)));
|
2018-05-23 10:54:56 +02:00
|
|
|
#else
|
2020-04-17 09:03:03 +02:00
|
|
|
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_NODELABEL(can1), rx0, irq),
|
|
|
|
DT_IRQ_BY_NAME(DT_NODELABEL(can1), rx0, priority),
|
2020-12-17 11:35:11 -06:00
|
|
|
can_stm32_rx_isr, DEVICE_DT_GET(DT_NODELABEL(can1)), 0);
|
2020-04-17 09:03:03 +02:00
|
|
|
irq_enable(DT_IRQ_BY_NAME(DT_NODELABEL(can1), rx0, irq));
|
2018-05-23 10:54:56 +02:00
|
|
|
|
2020-04-17 09:03:03 +02:00
|
|
|
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_NODELABEL(can1), tx, irq),
|
|
|
|
DT_IRQ_BY_NAME(DT_NODELABEL(can1), tx, priority),
|
2020-12-17 11:35:11 -06:00
|
|
|
can_stm32_tx_isr, DEVICE_DT_GET(DT_NODELABEL(can1)), 0);
|
2020-04-17 09:03:03 +02:00
|
|
|
irq_enable(DT_IRQ_BY_NAME(DT_NODELABEL(can1), tx, irq));
|
2018-05-23 10:54:56 +02:00
|
|
|
|
2020-04-17 09:03:03 +02:00
|
|
|
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_NODELABEL(can1), sce, irq),
|
|
|
|
DT_IRQ_BY_NAME(DT_NODELABEL(can1), sce, priority),
|
2020-12-17 11:35:11 -06:00
|
|
|
can_stm32_state_change_isr,
|
|
|
|
DEVICE_DT_GET(DT_NODELABEL(can1)), 0);
|
2020-04-17 09:03:03 +02:00
|
|
|
irq_enable(DT_IRQ_BY_NAME(DT_NODELABEL(can1), sce, irq));
|
2018-05-23 10:54:56 +02:00
|
|
|
#endif
|
2019-07-01 16:44:33 +02:00
|
|
|
can->IER |= CAN_IER_TMEIE | CAN_IER_ERRIE | CAN_IER_FMPIE0 |
|
|
|
|
CAN_IER_FMPIE1 | CAN_IER_BOFIE;
|
2022-02-25 11:10:38 +01:00
|
|
|
#ifdef CONFIG_CAN_STATS
|
|
|
|
can->IER |= CAN_IER_LECIE;
|
|
|
|
#endif /* CONFIG_CAN_STATS */
|
2018-05-03 10:59:12 +02:00
|
|
|
}
|
|
|
|
|
2020-05-11 11:56:08 -07:00
|
|
|
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(can1), okay) */
|
2020-01-25 07:19:26 -08:00
|
|
|
|
2020-05-07 12:22:26 -05:00
|
|
|
#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(can2), st_stm32_can, okay)
|
2020-01-25 07:19:26 -08:00
|
|
|
|
|
|
|
static void config_can_2_irq(CAN_TypeDef *can);
|
|
|
|
|
2021-12-23 12:33:03 +01:00
|
|
|
PINCTRL_DT_DEFINE(DT_NODELABEL(can2));
|
2020-10-09 10:54:44 +02:00
|
|
|
|
2020-01-25 07:19:26 -08:00
|
|
|
static const struct can_stm32_config can_stm32_cfg_2 = {
|
2020-04-17 09:03:03 +02:00
|
|
|
.can = (CAN_TypeDef *)DT_REG_ADDR(DT_NODELABEL(can2)),
|
|
|
|
.master_can = (CAN_TypeDef *)DT_PROP(DT_NODELABEL(can2),
|
|
|
|
master_can_reg),
|
|
|
|
.bus_speed = DT_PROP(DT_NODELABEL(can2), bus_speed),
|
2020-11-20 13:39:48 +01:00
|
|
|
.sample_point = DT_PROP_OR(DT_NODELABEL(can2), sample_point, 0),
|
|
|
|
.sjw = DT_PROP_OR(DT_NODELABEL(can2), sjw, 1),
|
|
|
|
.prop_ts1 = DT_PROP_OR(DT_NODELABEL(can2), prop_seg, 0) +
|
|
|
|
DT_PROP_OR(DT_NODELABEL(can2), phase_seg1, 0),
|
|
|
|
.ts2 = DT_PROP_OR(DT_NODELABEL(can2), phase_seg2, 0),
|
2022-01-14 15:17:32 +01:00
|
|
|
.one_shot = DT_PROP(DT_NODELABEL(can2), one_shot),
|
2020-01-25 07:19:26 -08:00
|
|
|
.pclken = {
|
2020-04-17 09:03:03 +02:00
|
|
|
.enr = DT_CLOCKS_CELL(DT_NODELABEL(can2), bits),
|
|
|
|
.bus = DT_CLOCKS_CELL(DT_NODELABEL(can2), bus),
|
2020-01-25 07:19:26 -08:00
|
|
|
},
|
2020-10-09 10:54:44 +02:00
|
|
|
.config_irq = config_can_2_irq,
|
2022-03-01 14:15:19 +01:00
|
|
|
.pcfg = PINCTRL_DT_DEV_CONFIG_GET(DT_NODELABEL(can2)),
|
|
|
|
.phy = DEVICE_DT_GET_OR_NULL(DT_PHANDLE(DT_NODELABEL(can2), phys)),
|
|
|
|
.max_bitrate = DT_CAN_TRANSCEIVER_MAX_BITRATE(DT_NODELABEL(can2), 1000000),
|
2020-01-25 07:19:26 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct can_stm32_data can_stm32_dev_data_2;
|
|
|
|
|
2022-02-25 11:10:38 +01:00
|
|
|
CAN_DEVICE_DT_DEFINE(DT_NODELABEL(can2), can_stm32_init, NULL,
|
|
|
|
&can_stm32_dev_data_2, &can_stm32_cfg_2,
|
|
|
|
POST_KERNEL, CONFIG_CAN_INIT_PRIORITY,
|
|
|
|
&can_api_funcs);
|
2020-01-25 07:19:26 -08:00
|
|
|
|
|
|
|
static void config_can_2_irq(CAN_TypeDef *can)
|
|
|
|
{
|
|
|
|
LOG_DBG("Enable CAN2 IRQ");
|
2020-04-17 09:03:03 +02:00
|
|
|
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_NODELABEL(can2), rx0, irq),
|
|
|
|
DT_IRQ_BY_NAME(DT_NODELABEL(can2), rx0, priority),
|
2020-12-17 11:35:11 -06:00
|
|
|
can_stm32_rx_isr, DEVICE_DT_GET(DT_NODELABEL(can2)), 0);
|
2020-04-17 09:03:03 +02:00
|
|
|
irq_enable(DT_IRQ_BY_NAME(DT_NODELABEL(can2), rx0, irq));
|
2020-01-25 07:19:26 -08:00
|
|
|
|
2020-04-17 09:03:03 +02:00
|
|
|
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_NODELABEL(can2), tx, irq),
|
|
|
|
DT_IRQ_BY_NAME(DT_NODELABEL(can2), tx, priority),
|
2020-12-17 11:35:11 -06:00
|
|
|
can_stm32_tx_isr, DEVICE_DT_GET(DT_NODELABEL(can2)), 0);
|
2020-04-17 09:03:03 +02:00
|
|
|
irq_enable(DT_IRQ_BY_NAME(DT_NODELABEL(can2), tx, irq));
|
2020-01-25 07:19:26 -08:00
|
|
|
|
2020-04-17 09:03:03 +02:00
|
|
|
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_NODELABEL(can2), sce, irq),
|
|
|
|
DT_IRQ_BY_NAME(DT_NODELABEL(can2), sce, priority),
|
2020-12-17 11:35:11 -06:00
|
|
|
can_stm32_state_change_isr,
|
|
|
|
DEVICE_DT_GET(DT_NODELABEL(can2)), 0);
|
2020-04-17 09:03:03 +02:00
|
|
|
irq_enable(DT_IRQ_BY_NAME(DT_NODELABEL(can2), sce, irq));
|
2020-01-25 07:19:26 -08:00
|
|
|
can->IER |= CAN_IER_TMEIE | CAN_IER_ERRIE | CAN_IER_FMPIE0 |
|
|
|
|
CAN_IER_FMPIE1 | CAN_IER_BOFIE;
|
2022-02-25 11:10:38 +01:00
|
|
|
#ifdef CONFIG_CAN_STATS
|
|
|
|
can->IER |= CAN_IER_LECIE;
|
|
|
|
#endif /* CONFIG_CAN_STATS */
|
2020-01-25 07:19:26 -08:00
|
|
|
}
|
|
|
|
|
2020-05-11 11:56:08 -07:00
|
|
|
#endif /* DT_NODE_HAS_STATUS(DT_NODELABEL(can2), okay) */
|