drivers: can: add NXP SJA1000 common driver backend
Add a common driver backend for NXP SJA1000 compatible CAN controllers. Signed-off-by: Henrik Brix Andersen <henrik@brixandersen.dk>
This commit is contained in:
parent
f6445858e3
commit
491e831436
6 changed files with 1011 additions and 0 deletions
|
@ -14,6 +14,8 @@ zephyr_library_sources_ifdef(CONFIG_CAN_STM32FD can_stm32fd.c)
|
|||
zephyr_library_sources_ifdef(CONFIG_CAN_STM32H7 can_stm32h7.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_CAN_RCAR can_rcar.c)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_CAN_SJA1000 can_sja1000.c)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_USERSPACE can_handlers.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_CAN_SHELL can_shell.c)
|
||||
|
||||
|
|
|
@ -93,6 +93,8 @@ source "drivers/can/Kconfig.mcan"
|
|||
source "drivers/can/Kconfig.rcar"
|
||||
source "drivers/can/Kconfig.loopback"
|
||||
|
||||
source "drivers/can/Kconfig.sja1000"
|
||||
|
||||
source "drivers/can/transceiver/Kconfig"
|
||||
|
||||
endif # CAN
|
||||
|
|
18
drivers/can/Kconfig.sja1000
Normal file
18
drivers/can/Kconfig.sja1000
Normal file
|
@ -0,0 +1,18 @@
|
|||
# NXP SJA1000 configuration options
|
||||
|
||||
# Copyright (c) 2022 Henrik Brix Andersen <henrik@brixandersen.dk>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config CAN_SJA1000
|
||||
bool
|
||||
help
|
||||
This enables support for the shared NXP SJA1000 CAN driver.
|
||||
|
||||
config CAN_MAX_FILTER
|
||||
int "Maximum number of concurrent active RX filters"
|
||||
depends on CAN_SJA1000
|
||||
default 5
|
||||
range 1 32
|
||||
help
|
||||
As the NXP SJA1000 only supports one full-width RX filter, filtering of received CAN
|
||||
frames are done in software.
|
709
drivers/can/can_sja1000.c
Normal file
709
drivers/can/can_sja1000.c
Normal file
|
@ -0,0 +1,709 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Henrik Brix Andersen <henrik@brixandersen.dk>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "can_sja1000.h"
|
||||
#include "can_sja1000_priv.h"
|
||||
#include "can_utils.h"
|
||||
|
||||
#include <zephyr/drivers/can.h>
|
||||
#include <zephyr/drivers/can/transceiver.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_REGISTER(can_sja1000, CONFIG_CAN_LOG_LEVEL);
|
||||
|
||||
/* Timeout for entering/leaving reset mode */
|
||||
#define CAN_SJA1000_RESET_MODE_TIMEOUT_USEC 1000
|
||||
#define CAN_SJA1000_RESET_MODE_RETRIES 100
|
||||
#define CAN_SJA1000_RESET_MODE_DELAY \
|
||||
K_USEC(CAN_SJA1000_RESET_MODE_TIMEOUT_USEC / CAN_SJA1000_RESET_MODE_RETRIES)
|
||||
|
||||
static inline void can_sja1000_write_reg(const struct device *dev, uint8_t reg, uint8_t val)
|
||||
{
|
||||
const struct can_sja1000_config *config = dev->config;
|
||||
|
||||
LOG_DBG("write reg %d = 0x%02x", reg, val);
|
||||
return config->write_reg(dev, reg, val);
|
||||
}
|
||||
|
||||
static inline uint8_t can_sja1000_read_reg(const struct device *dev, uint8_t reg)
|
||||
{
|
||||
const struct can_sja1000_config *config = dev->config;
|
||||
uint8_t val;
|
||||
|
||||
val = config->read_reg(dev, reg);
|
||||
LOG_DBG("read reg %d = 0x%02x", reg, val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline int can_sja1000_enter_reset_mode(const struct device *dev)
|
||||
{
|
||||
int retries = CAN_SJA1000_RESET_MODE_RETRIES;
|
||||
uint8_t mod;
|
||||
|
||||
mod = can_sja1000_read_reg(dev, CAN_SJA1000_MOD);
|
||||
|
||||
while ((mod & CAN_SJA1000_MOD_RM) == 0) {
|
||||
if (--retries < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_MOD, mod | CAN_SJA1000_MOD_RM);
|
||||
k_sleep(CAN_SJA1000_RESET_MODE_DELAY);
|
||||
mod = can_sja1000_read_reg(dev, CAN_SJA1000_MOD);
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int can_sja1000_leave_reset_mode(const struct device *dev)
|
||||
{
|
||||
int retries = CAN_SJA1000_RESET_MODE_RETRIES;
|
||||
uint8_t mod;
|
||||
|
||||
mod = can_sja1000_read_reg(dev, CAN_SJA1000_MOD);
|
||||
|
||||
while ((mod & CAN_SJA1000_MOD_RM) == 1) {
|
||||
if (--retries < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_MOD, mod & ~(CAN_SJA1000_MOD_RM));
|
||||
k_sleep(CAN_SJA1000_RESET_MODE_DELAY);
|
||||
mod = can_sja1000_read_reg(dev, CAN_SJA1000_MOD);
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int can_sja1000_set_timing(const struct device *dev, const struct can_timing *timing)
|
||||
{
|
||||
struct can_sja1000_data *data = dev->data;
|
||||
uint8_t btr0;
|
||||
uint8_t btr1;
|
||||
uint8_t sjw;
|
||||
int err;
|
||||
|
||||
__ASSERT_NO_MSG(timing->sjw == CAN_SJW_NO_CHANGE || (timing->sjw >= 1 && timing->sjw <= 4));
|
||||
__ASSERT_NO_MSG(timing->prop_seg == 0);
|
||||
__ASSERT_NO_MSG(timing->phase_seg1 >= 1 && timing->phase_seg1 <= 16);
|
||||
__ASSERT_NO_MSG(timing->phase_seg2 >= 1 && timing->phase_seg2 <= 8);
|
||||
__ASSERT_NO_MSG(timing->prescaler >= 1 && timing->prescaler <= 64);
|
||||
|
||||
k_mutex_lock(&data->mod_lock, K_FOREVER);
|
||||
|
||||
err = can_sja1000_enter_reset_mode(dev);
|
||||
if (err != 0) {
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (timing->sjw == CAN_SJW_NO_CHANGE) {
|
||||
sjw = data->sjw;
|
||||
} else {
|
||||
sjw = timing->sjw;
|
||||
data->sjw = timing->sjw;
|
||||
}
|
||||
|
||||
btr0 = CAN_SJA1000_BTR0_BRP_PREP(timing->prescaler - 1) |
|
||||
CAN_SJA1000_BTR0_SJW_PREP(sjw - 1);
|
||||
btr1 = CAN_SJA1000_BTR1_TSEG1_PREP(timing->phase_seg1 - 1) |
|
||||
CAN_SJA1000_BTR1_TSEG2_PREP(timing->phase_seg2 - 1);
|
||||
|
||||
if ((data->mode & CAN_MODE_3_SAMPLES) != 0) {
|
||||
btr1 |= CAN_SJA1000_BTR1_SAM;
|
||||
}
|
||||
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_BTR0, btr0);
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_BTR1, btr1);
|
||||
|
||||
err = can_sja1000_leave_reset_mode(dev);
|
||||
if (err != 0) {
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
unlock:
|
||||
k_mutex_unlock(&data->mod_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int can_sja1000_get_capabilities(const struct device *dev, can_mode_t *cap)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
*cap = CAN_MODE_NORMAL | CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY |
|
||||
CAN_MODE_ONE_SHOT | CAN_MODE_3_SAMPLES;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int can_sja1000_set_mode(const struct device *dev, can_mode_t mode)
|
||||
{
|
||||
const struct can_sja1000_config *config = dev->config;
|
||||
struct can_sja1000_data *data = dev->data;
|
||||
uint8_t btr1;
|
||||
uint8_t mod;
|
||||
int err;
|
||||
|
||||
if ((mode & ~(CAN_MODE_LOOPBACK | CAN_MODE_LISTENONLY | CAN_MODE_ONE_SHOT |
|
||||
CAN_MODE_3_SAMPLES)) != 0) {
|
||||
LOG_ERR("unsupported mode: 0x%08x", mode);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (config->phy != NULL) {
|
||||
err = can_transceiver_enable(config->phy);
|
||||
if (err != 0) {
|
||||
LOG_ERR("failed to enable CAN transceiver (err %d)", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
k_mutex_lock(&data->mod_lock, K_FOREVER);
|
||||
|
||||
err = can_sja1000_enter_reset_mode(dev);
|
||||
if (err != 0) {
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
mod = can_sja1000_read_reg(dev, CAN_SJA1000_MOD);
|
||||
mod |= CAN_SJA1000_MOD_AFM;
|
||||
|
||||
if ((mode & CAN_MODE_LOOPBACK) != 0) {
|
||||
/* (Local) self test mode */
|
||||
mod |= CAN_SJA1000_MOD_STM;
|
||||
} else {
|
||||
mod &= ~(CAN_SJA1000_MOD_STM);
|
||||
}
|
||||
|
||||
if ((mode & CAN_MODE_LISTENONLY) != 0) {
|
||||
mod |= CAN_SJA1000_MOD_LOM;
|
||||
} else {
|
||||
mod &= ~(CAN_SJA1000_MOD_LOM);
|
||||
}
|
||||
|
||||
btr1 = can_sja1000_read_reg(dev, CAN_SJA1000_BTR1);
|
||||
if ((mode & CAN_MODE_3_SAMPLES) != 0) {
|
||||
btr1 |= CAN_SJA1000_BTR1_SAM;
|
||||
} else {
|
||||
btr1 &= ~(CAN_SJA1000_BTR1_SAM);
|
||||
}
|
||||
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_MOD, mod);
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_BTR1, btr1);
|
||||
|
||||
err = can_sja1000_leave_reset_mode(dev);
|
||||
if (err != 0) {
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
data->mode = mode;
|
||||
unlock:
|
||||
k_mutex_unlock(&data->mod_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void can_sja1000_read_frame(const struct device *dev, struct zcan_frame *frame)
|
||||
{
|
||||
uint8_t info;
|
||||
int i;
|
||||
|
||||
memset(frame, 0, sizeof(*frame));
|
||||
|
||||
info = can_sja1000_read_reg(dev, CAN_SJA1000_FRAME_INFO);
|
||||
|
||||
if ((info & CAN_SJA1000_FRAME_INFO_RTR) != 0) {
|
||||
frame->rtr = CAN_REMOTEREQUEST;
|
||||
} else {
|
||||
frame->rtr = CAN_DATAFRAME;
|
||||
}
|
||||
|
||||
frame->dlc = CAN_SJA1000_FRAME_INFO_DLC_GET(info);
|
||||
if (frame->dlc > CAN_MAX_DLC) {
|
||||
LOG_ERR("RX frame DLC %u exceeds maximum (%d)", frame->dlc, CAN_MAX_DLC);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((info & CAN_SJA1000_FRAME_INFO_FF) != 0) {
|
||||
frame->id_type = CAN_EXTENDED_IDENTIFIER;
|
||||
|
||||
frame->id = FIELD_PREP(GENMASK(28, 21),
|
||||
can_sja1000_read_reg(dev, CAN_SJA1000_XFF_ID1));
|
||||
frame->id |= FIELD_PREP(GENMASK(20, 13),
|
||||
can_sja1000_read_reg(dev, CAN_SJA1000_XFF_ID2));
|
||||
frame->id |= FIELD_PREP(GENMASK(12, 5),
|
||||
can_sja1000_read_reg(dev, CAN_SJA1000_EFF_ID3));
|
||||
frame->id |= FIELD_PREP(GENMASK(4, 0),
|
||||
can_sja1000_read_reg(dev, CAN_SJA1000_EFF_ID4) >> 3);
|
||||
|
||||
for (i = 0; i < frame->dlc; i++) {
|
||||
frame->data[i] = can_sja1000_read_reg(dev, CAN_SJA1000_EFF_DATA + i);
|
||||
}
|
||||
} else {
|
||||
frame->id_type = CAN_STANDARD_IDENTIFIER;
|
||||
|
||||
frame->id = FIELD_PREP(GENMASK(10, 3),
|
||||
can_sja1000_read_reg(dev, CAN_SJA1000_XFF_ID1));
|
||||
frame->id |= FIELD_PREP(GENMASK(2, 0),
|
||||
can_sja1000_read_reg(dev, CAN_SJA1000_XFF_ID2) >> 5);
|
||||
|
||||
for (i = 0; i < frame->dlc; i++) {
|
||||
frame->data[i] = can_sja1000_read_reg(dev, CAN_SJA1000_SFF_DATA + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void can_sja1000_write_frame(const struct device *dev, const struct zcan_frame *frame)
|
||||
{
|
||||
uint8_t info;
|
||||
int i;
|
||||
|
||||
info = CAN_SJA1000_FRAME_INFO_DLC_PREP(frame->dlc);
|
||||
|
||||
if (frame->rtr == CAN_REMOTEREQUEST) {
|
||||
info |= CAN_SJA1000_FRAME_INFO_RTR;
|
||||
}
|
||||
|
||||
if (frame->id_type == CAN_EXTENDED_IDENTIFIER) {
|
||||
info |= CAN_SJA1000_FRAME_INFO_FF;
|
||||
}
|
||||
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_FRAME_INFO, info);
|
||||
|
||||
if (frame->id_type == CAN_EXTENDED_IDENTIFIER) {
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_XFF_ID1,
|
||||
FIELD_GET(GENMASK(28, 21), frame->id));
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_XFF_ID2,
|
||||
FIELD_GET(GENMASK(20, 13), frame->id));
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_EFF_ID3,
|
||||
FIELD_GET(GENMASK(12, 5), frame->id));
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_EFF_ID4,
|
||||
FIELD_GET(GENMASK(4, 0), frame->id) << 3);
|
||||
|
||||
for (i = 0; i < frame->dlc; i++) {
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_EFF_DATA + i, frame->data[i]);
|
||||
}
|
||||
} else {
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_XFF_ID1,
|
||||
FIELD_GET(GENMASK(10, 3), frame->id));
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_XFF_ID2,
|
||||
FIELD_GET(GENMASK(2, 0), frame->id) << 5);
|
||||
|
||||
for (i = 0; i < frame->dlc; i++) {
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_SFF_DATA + i, frame->data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int can_sja1000_send(const struct device *dev, const struct zcan_frame *frame, k_timeout_t timeout,
|
||||
can_tx_callback_t callback, void *user_data)
|
||||
{
|
||||
struct can_sja1000_data *data = dev->data;
|
||||
uint8_t cmr;
|
||||
uint8_t sr;
|
||||
|
||||
if (frame->dlc > CAN_MAX_DLC) {
|
||||
LOG_ERR("TX frame DLC %u exceeds maximum (%d)", frame->dlc, CAN_MAX_DLC);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (data->state == CAN_BUS_OFF) {
|
||||
LOG_DBG("transmit failed, bus-off");
|
||||
return -ENETDOWN;
|
||||
}
|
||||
|
||||
if (k_sem_take(&data->tx_idle, timeout) != 0) {
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
sr = can_sja1000_read_reg(dev, CAN_SJA1000_SR);
|
||||
if ((sr & CAN_SJA1000_SR_TBS) == 0) {
|
||||
LOG_ERR("transmit buffer locked, sr = 0x%02x", sr);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
data->tx_callback = callback;
|
||||
data->tx_user_data = user_data;
|
||||
|
||||
can_sja1000_write_frame(dev, frame);
|
||||
|
||||
if ((data->mode & CAN_MODE_LOOPBACK) != 0) {
|
||||
cmr = CAN_SJA1000_CMR_SRR;
|
||||
} else {
|
||||
cmr = CAN_SJA1000_CMR_TR;
|
||||
}
|
||||
|
||||
if ((data->mode & CAN_MODE_ONE_SHOT) != 0) {
|
||||
cmr |= CAN_SJA1000_CMR_AT;
|
||||
}
|
||||
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_CMR, cmr);
|
||||
|
||||
if (callback == NULL) {
|
||||
k_sem_take(&data->tx_done, K_FOREVER);
|
||||
return data->tx_status;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int can_sja1000_add_rx_filter(const struct device *dev, can_rx_callback_t callback, void *user_data,
|
||||
const struct zcan_filter *filter)
|
||||
{
|
||||
struct can_sja1000_data *data = dev->data;
|
||||
int filter_id = -ENOSPC;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(data->filters); i++) {
|
||||
if (!atomic_test_and_set_bit(data->rx_allocs, i)) {
|
||||
filter_id = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (filter_id >= 0) {
|
||||
data->filters[filter_id].filter = *filter;
|
||||
data->filters[filter_id].user_data = user_data;
|
||||
data->filters[filter_id].callback = callback;
|
||||
}
|
||||
|
||||
return filter_id;
|
||||
}
|
||||
|
||||
void can_sja1000_remove_rx_filter(const struct device *dev, int filter_id)
|
||||
{
|
||||
struct can_sja1000_data *data = dev->data;
|
||||
|
||||
if (filter_id < 0 || filter_id >= ARRAY_SIZE(data->filters)) {
|
||||
LOG_ERR("filter ID %d out of bounds", filter_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (atomic_test_and_clear_bit(data->rx_allocs, filter_id)) {
|
||||
data->filters[filter_id].callback = NULL;
|
||||
data->filters[filter_id].user_data = NULL;
|
||||
data->filters[filter_id].filter = (struct zcan_filter){0};
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY
|
||||
int can_sja1000_recover(const struct device *dev, k_timeout_t timeout)
|
||||
{
|
||||
struct can_sja1000_data *data = dev->data;
|
||||
int64_t start_ticks;
|
||||
uint8_t sr;
|
||||
int err;
|
||||
|
||||
sr = can_sja1000_read_reg(dev, CAN_SJA1000_SR);
|
||||
if ((sr & CAN_SJA1000_SR_BS) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
start_ticks = k_uptime_ticks();
|
||||
|
||||
err = k_mutex_lock(&data->mod_lock, timeout);
|
||||
if (err != 0) {
|
||||
LOG_WRN("failed to acquire MOD lock");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = can_sja1000_leave_reset_mode(dev);
|
||||
if (err != 0) {
|
||||
LOG_ERR("failed to initiate bus recovery");
|
||||
k_mutex_unlock(&data->mod_lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
k_mutex_unlock(&data->mod_lock);
|
||||
|
||||
while ((sr & CAN_SJA1000_SR_BS) != 0) {
|
||||
if (k_uptime_ticks() - start_ticks > timeout.ticks) {
|
||||
LOG_WRN("bus recovery timed out");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
sr = can_sja1000_read_reg(dev, CAN_SJA1000_SR);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* !CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */
|
||||
|
||||
int can_sja1000_get_state(const struct device *dev, enum can_state *state,
|
||||
struct can_bus_err_cnt *err_cnt)
|
||||
{
|
||||
struct can_sja1000_data *data = dev->data;
|
||||
|
||||
if (state != NULL) {
|
||||
*state = data->state;
|
||||
}
|
||||
|
||||
if (err_cnt != NULL) {
|
||||
err_cnt->rx_err_cnt = can_sja1000_read_reg(dev, CAN_SJA1000_RXERR);
|
||||
err_cnt->tx_err_cnt = can_sja1000_read_reg(dev, CAN_SJA1000_TXERR);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void can_sja1000_set_state_change_callback(const struct device *dev,
|
||||
can_state_change_callback_t callback, void *user_data)
|
||||
{
|
||||
struct can_sja1000_data *data = dev->data;
|
||||
|
||||
data->state_change_cb = callback;
|
||||
data->state_change_cb_data = user_data;
|
||||
}
|
||||
|
||||
int can_sja1000_get_max_filters(const struct device *dev, enum can_ide id_type)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
ARG_UNUSED(id_type);
|
||||
|
||||
return CONFIG_CAN_MAX_FILTER;
|
||||
}
|
||||
|
||||
int can_sja1000_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate)
|
||||
{
|
||||
const struct can_sja1000_config *config = dev->config;
|
||||
|
||||
*max_bitrate = config->max_bitrate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void can_sja1000_handle_receive_irq(const struct device *dev)
|
||||
{
|
||||
struct can_sja1000_data *data = dev->data;
|
||||
struct zcan_frame frame;
|
||||
can_rx_callback_t callback;
|
||||
uint8_t sr;
|
||||
int i;
|
||||
|
||||
do {
|
||||
can_sja1000_read_frame(dev, &frame);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(data->filters); i++) {
|
||||
if (!atomic_test_bit(data->rx_allocs, i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (can_utils_filter_match(&frame, &data->filters[i].filter)) {
|
||||
callback = data->filters[i].callback;
|
||||
if (callback != NULL) {
|
||||
callback(dev, &frame, data->filters[i].user_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_CMR, CAN_SJA1000_CMR_RRB);
|
||||
sr = can_sja1000_read_reg(dev, CAN_SJA1000_SR);
|
||||
} while ((sr & CAN_SJA1000_SR_RBS) != 0);
|
||||
}
|
||||
|
||||
static void can_sja1000_tx_done(const struct device *dev, int status)
|
||||
{
|
||||
struct can_sja1000_data *data = dev->data;
|
||||
can_tx_callback_t callback = data->tx_callback;
|
||||
void *user_data = data->tx_user_data;
|
||||
|
||||
if (callback != NULL) {
|
||||
data->tx_callback = NULL;
|
||||
callback(dev, status, user_data);
|
||||
} else {
|
||||
data->tx_status = status;
|
||||
k_sem_give(&data->tx_done);
|
||||
}
|
||||
|
||||
k_sem_give(&data->tx_idle);
|
||||
}
|
||||
|
||||
static void can_sja1000_handle_transmit_irq(const struct device *dev)
|
||||
{
|
||||
int status = 0;
|
||||
uint8_t sr;
|
||||
|
||||
sr = can_sja1000_read_reg(dev, CAN_SJA1000_SR);
|
||||
if ((sr & CAN_SJA1000_SR_TCS) == 0) {
|
||||
status = -EIO;
|
||||
}
|
||||
|
||||
can_sja1000_tx_done(dev, status);
|
||||
}
|
||||
|
||||
static void can_sja1000_handle_error_warning_irq(const struct device *dev)
|
||||
{
|
||||
struct can_sja1000_data *data = dev->data;
|
||||
uint8_t sr;
|
||||
int err;
|
||||
|
||||
sr = can_sja1000_read_reg(dev, CAN_SJA1000_SR);
|
||||
if ((sr & CAN_SJA1000_SR_BS) != 0) {
|
||||
data->state = CAN_BUS_OFF;
|
||||
can_sja1000_tx_done(dev, -ENETDOWN);
|
||||
#ifdef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY
|
||||
/* Recover bus now unless interrupted in the middle of a MOD register change. */
|
||||
err = k_mutex_lock(&data->mod_lock, K_NO_WAIT);
|
||||
if (err == 0) {
|
||||
(void)can_sja1000_leave_reset_mode(dev);
|
||||
k_mutex_unlock(&data->mod_lock);
|
||||
}
|
||||
#endif /* CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */
|
||||
} else if ((sr & CAN_SJA1000_SR_ES) != 0) {
|
||||
data->state = CAN_ERROR_WARNING;
|
||||
} else {
|
||||
data->state = CAN_ERROR_ACTIVE;
|
||||
}
|
||||
}
|
||||
|
||||
static void can_sja1000_handle_error_passive_irq(const struct device *dev)
|
||||
{
|
||||
struct can_sja1000_data *data = dev->data;
|
||||
|
||||
if (data->state == CAN_ERROR_PASSIVE) {
|
||||
data->state = CAN_ERROR_WARNING;
|
||||
} else {
|
||||
data->state = CAN_ERROR_PASSIVE;
|
||||
}
|
||||
}
|
||||
|
||||
void can_sja1000_isr(const struct device *dev)
|
||||
{
|
||||
struct can_sja1000_data *data = dev->data;
|
||||
const can_state_change_callback_t cb = data->state_change_cb;
|
||||
void *cb_data = data->state_change_cb_data;
|
||||
enum can_state prev_state = data->state;
|
||||
struct can_bus_err_cnt err_cnt;
|
||||
uint8_t ir;
|
||||
|
||||
ir = can_sja1000_read_reg(dev, CAN_SJA1000_IR);
|
||||
|
||||
if ((ir & CAN_SJA1000_IR_TI) != 0) {
|
||||
can_sja1000_handle_transmit_irq(dev);
|
||||
}
|
||||
|
||||
if ((ir & CAN_SJA1000_IR_RI) != 0) {
|
||||
can_sja1000_handle_receive_irq(dev);
|
||||
}
|
||||
|
||||
if ((ir & CAN_SJA1000_IR_EI) != 0) {
|
||||
can_sja1000_handle_error_warning_irq(dev);
|
||||
}
|
||||
|
||||
if ((ir & CAN_SJA1000_IR_EPI) != 0) {
|
||||
can_sja1000_handle_error_passive_irq(dev);
|
||||
}
|
||||
|
||||
if (prev_state != data->state && cb != NULL) {
|
||||
err_cnt.rx_err_cnt = can_sja1000_read_reg(dev, CAN_SJA1000_RXERR);
|
||||
err_cnt.tx_err_cnt = can_sja1000_read_reg(dev, CAN_SJA1000_TXERR);
|
||||
cb(dev, data->state, err_cnt, cb_data);
|
||||
}
|
||||
}
|
||||
|
||||
int can_sja1000_init(const struct device *dev)
|
||||
{
|
||||
const struct can_sja1000_config *config = dev->config;
|
||||
struct can_sja1000_data *data = dev->data;
|
||||
struct can_timing timing;
|
||||
int err;
|
||||
|
||||
__ASSERT_NO_MSG(config->read_reg != NULL);
|
||||
__ASSERT_NO_MSG(config->write_reg != NULL);
|
||||
|
||||
if (config->phy != NULL) {
|
||||
if (!device_is_ready(config->phy)) {
|
||||
LOG_ERR("CAN transceiver not ready");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
k_mutex_init(&data->mod_lock);
|
||||
k_sem_init(&data->tx_idle, 1, 1);
|
||||
k_sem_init(&data->tx_done, 0, 1);
|
||||
|
||||
data->state = CAN_ERROR_ACTIVE;
|
||||
|
||||
/* See NXP SJA1000 Application Note AN97076 (figure 12) for initialization sequence */
|
||||
|
||||
/* Enter reset mode */
|
||||
err = can_sja1000_enter_reset_mode(dev);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Set PeliCAN mode */
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_CDR, config->cdr | CAN_SJA1000_CDR_CAN_MODE);
|
||||
|
||||
/* Set up acceptance code and mask to match any frame (software filtering) */
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_ACR0, 0x00);
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_ACR1, 0x00);
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_ACR2, 0x00);
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_ACR3, 0x00);
|
||||
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_AMR0, 0xFF);
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_AMR1, 0xFF);
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_AMR2, 0xFF);
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_AMR3, 0xFF);
|
||||
|
||||
/* Calculate initial timing parameters */
|
||||
data->sjw = config->sjw;
|
||||
timing.sjw = CAN_SJW_NO_CHANGE;
|
||||
|
||||
if (config->sample_point != 0) {
|
||||
err = can_calc_timing(dev, &timing, config->bitrate, config->sample_point);
|
||||
if (err == -EINVAL) {
|
||||
LOG_ERR("bitrate/sample point cannot be met (err %d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
LOG_DBG("initial sample point error: %d", err);
|
||||
} else {
|
||||
timing.prop_seg = 0;
|
||||
timing.phase_seg1 = config->phase_seg1;
|
||||
timing.phase_seg2 = config->phase_seg2;
|
||||
|
||||
err = can_calc_prescaler(dev, &timing, config->bitrate);
|
||||
if (err != 0) {
|
||||
LOG_WRN("initial bitrate error: %d", err);
|
||||
}
|
||||
}
|
||||
|
||||
/* Configure timing */
|
||||
err = can_sja1000_set_timing(dev, &timing);
|
||||
if (err != 0) {
|
||||
LOG_ERR("timing parameters cannot be met (err %d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Set output control */
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_OCR, config->ocr);
|
||||
|
||||
/* Clear error counters */
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_RXERR, 0);
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_TXERR, 0);
|
||||
|
||||
/* Clear error capture */
|
||||
(void)can_sja1000_read_reg(dev, CAN_SJA1000_ECC);
|
||||
|
||||
/* Set error warning limit */
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_EWLR, 96);
|
||||
|
||||
/* Enter normal mode */
|
||||
data->mode = CAN_MODE_NORMAL;
|
||||
err = can_sja1000_set_mode(dev, CAN_MODE_NORMAL);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Enable interrupts */
|
||||
can_sja1000_write_reg(dev, CAN_SJA1000_IER,
|
||||
CAN_SJA1000_IER_RIE | CAN_SJA1000_IER_TIE |
|
||||
CAN_SJA1000_IER_EIE | CAN_SJA1000_IER_EPIE);
|
||||
|
||||
return 0;
|
||||
}
|
153
drivers/can/can_sja1000.h
Normal file
153
drivers/can/can_sja1000.h
Normal file
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Henrik Brix Andersen <henrik@brixandersen.dk>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_DRIVERS_CAN_SJA1000_H_
|
||||
#define ZEPHYR_DRIVERS_CAN_SJA1000_H_
|
||||
|
||||
#include <zephyr/drivers/can.h>
|
||||
|
||||
/* Output Control Register (OCR) bits */
|
||||
#define CAN_SJA1000_OCR_OCMODE_MASK GENMASK(1, 0)
|
||||
#define CAN_SJA1000_OCR_OCPOL0 BIT(2)
|
||||
#define CAN_SJA1000_OCR_OCTN0 BIT(3)
|
||||
#define CAN_SJA1000_OCR_OCTP0 BIT(4)
|
||||
#define CAN_SJA1000_OCR_OCPOL1 BIT(5)
|
||||
#define CAN_SJA1000_OCR_OCTN1 BIT(6)
|
||||
#define CAN_SJA1000_OCR_OCTP1 BIT(7)
|
||||
|
||||
#define CAN_SJA1000_OCR_OCMODE_BIPHASE FIELD_PREP(CAN_SJA1000_OCR_OCMODE_MASK, 0U)
|
||||
#define CAN_SJA1000_OCR_OCMODE_TEST FIELD_PREP(CAN_SJA1000_OCR_OCMODE_MASK, 1U)
|
||||
#define CAN_SJA1000_OCR_OCMODE_NORMAL FIELD_PREP(CAN_SJA1000_OCR_OCMODE_MASK, 2U)
|
||||
#define CAN_SJA1000_OCR_OCMODE_CLOCK FIELD_PREP(CAN_SJA1000_OCR_OCMODE_MASK, 3U)
|
||||
|
||||
/* Clock Divider Register (CDR) bits */
|
||||
#define CAN_SJA1000_CDR_CD_MASK GENMASK(2, 0)
|
||||
#define CAN_SJA1000_CDR_CLOCK_OFF BIT(3)
|
||||
#define CAN_SJA1000_CDR_RXINTEN BIT(5)
|
||||
#define CAN_SJA1000_CDR_CBP BIT(6)
|
||||
#define CAN_SJA1000_CDR_CAN_MODE BIT(7)
|
||||
|
||||
#define CAN_SJA1000_CDR_CD_DIV1 FIELD_PREP(CAN_SJA1000_CDR_CD_MASK, 7U)
|
||||
#define CAN_SJA1000_CDR_CD_DIV2 FIELD_PREP(CAN_SJA1000_CDR_CD_MASK, 0U)
|
||||
#define CAN_SJA1000_CDR_CD_DIV4 FIELD_PREP(CAN_SJA1000_CDR_CD_MASK, 1U)
|
||||
#define CAN_SJA1000_CDR_CD_DIV6 FIELD_PREP(CAN_SJA1000_CDR_CD_MASK, 2U)
|
||||
#define CAN_SJA1000_CDR_CD_DIV8 FIELD_PREP(CAN_SJA1000_CDR_CD_MASK, 3U)
|
||||
#define CAN_SJA1000_CDR_CD_DIV10 FIELD_PREP(CAN_SJA1000_CDR_CD_MASK, 4U)
|
||||
#define CAN_SJA1000_CDR_CD_DIV12 FIELD_PREP(CAN_SJA1000_CDR_CD_MASK, 5U)
|
||||
#define CAN_SJA1000_CDR_CD_DIV14 FIELD_PREP(CAN_SJA1000_CDR_CD_MASK, 6U)
|
||||
|
||||
#define CAN_SJA1000_TIMING_MIN_INITIALIZER \
|
||||
{ \
|
||||
.sjw = 1, \
|
||||
.prop_seg = 0, \
|
||||
.phase_seg1 = 1, \
|
||||
.phase_seg2 = 1, \
|
||||
.prescaler = 1 \
|
||||
}
|
||||
|
||||
#define CAN_SJA1000_TIMING_MAX_INITIALIZER \
|
||||
{ \
|
||||
.sjw = 4, \
|
||||
.prop_seg = 0, \
|
||||
.phase_seg1 = 16, \
|
||||
.phase_seg2 = 8, \
|
||||
.prescaler = 64 \
|
||||
}
|
||||
|
||||
typedef void (*can_sja1000_write_reg_t)(const struct device *dev, uint8_t reg, uint8_t val);
|
||||
|
||||
typedef uint8_t (*can_sja1000_read_reg_t)(const struct device *dev, uint8_t reg);
|
||||
|
||||
struct can_sja1000_config {
|
||||
can_sja1000_read_reg_t read_reg;
|
||||
can_sja1000_write_reg_t write_reg;
|
||||
uint32_t bitrate;
|
||||
uint32_t sample_point;
|
||||
uint32_t sjw;
|
||||
uint32_t phase_seg1;
|
||||
uint32_t phase_seg2;
|
||||
const struct device *phy;
|
||||
uint32_t max_bitrate;
|
||||
uint8_t ocr;
|
||||
uint8_t cdr;
|
||||
const void *custom;
|
||||
};
|
||||
|
||||
#define CAN_SJA1000_DT_CONFIG_GET(node_id, _custom, _read_reg, _write_reg, _ocr, _cdr) \
|
||||
{ \
|
||||
.read_reg = _read_reg, .write_reg = _write_reg, \
|
||||
.bitrate = DT_PROP(node_id, bus_speed), .sjw = DT_PROP(node_id, sjw), \
|
||||
.phase_seg1 = DT_PROP_OR(node_id, phase_seg1, 0), \
|
||||
.phase_seg2 = DT_PROP_OR(node_id, phase_seg2, 0), \
|
||||
.sample_point = DT_PROP_OR(node_id, sample_point, 0), \
|
||||
.max_bitrate = DT_CAN_TRANSCEIVER_MAX_BITRATE(node_id, 1000000), .ocr = _ocr, \
|
||||
.cdr = _cdr, .custom = _custom, \
|
||||
}
|
||||
|
||||
#define CAN_SJA1000_DT_CONFIG_INST_GET(inst, _custom, _read_reg, _write_reg, _ocr, _cdr) \
|
||||
CAN_SJA1000_DT_CONFIG_GET(DT_DRV_INST(inst), _custom, _read_reg, _write_reg, _ocr, _cdr)
|
||||
|
||||
struct can_sja1000_rx_filter {
|
||||
struct zcan_filter filter;
|
||||
can_rx_callback_t callback;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
struct can_sja1000_data {
|
||||
ATOMIC_DEFINE(rx_allocs, CONFIG_CAN_MAX_FILTER);
|
||||
struct can_sja1000_rx_filter filters[CONFIG_CAN_MAX_FILTER];
|
||||
struct k_mutex mod_lock;
|
||||
can_mode_t mode;
|
||||
enum can_state state;
|
||||
can_state_change_callback_t state_change_cb;
|
||||
void *state_change_cb_data;
|
||||
struct k_sem tx_idle;
|
||||
struct k_sem tx_done;
|
||||
can_tx_callback_t tx_callback;
|
||||
void *tx_user_data;
|
||||
int tx_status;
|
||||
uint32_t sjw;
|
||||
void *custom;
|
||||
};
|
||||
|
||||
#define CAN_SJA1000_DATA_INITIALIZER(_custom) \
|
||||
{ \
|
||||
.custom = _custom, \
|
||||
}
|
||||
|
||||
int can_sja1000_set_timing(const struct device *dev, const struct can_timing *timing);
|
||||
|
||||
int can_sja1000_get_capabilities(const struct device *dev, can_mode_t *cap);
|
||||
|
||||
int can_sja1000_set_mode(const struct device *dev, can_mode_t mode);
|
||||
|
||||
int can_sja1000_send(const struct device *dev, const struct zcan_frame *frame, k_timeout_t timeout,
|
||||
can_tx_callback_t callback, void *user_data);
|
||||
|
||||
int can_sja1000_add_rx_filter(const struct device *dev, can_rx_callback_t callback, void *user_data,
|
||||
const struct zcan_filter *filter);
|
||||
|
||||
void can_sja1000_remove_rx_filter(const struct device *dev, int filter_id);
|
||||
|
||||
#ifndef CONFIG_CAN_AUTO_BUS_OFF_RECOVERY
|
||||
int can_sja1000_recover(const struct device *dev, k_timeout_t timeout);
|
||||
#endif /* !CONFIG_CAN_AUTO_BUS_OFF_RECOVERY */
|
||||
|
||||
int can_sja1000_get_state(const struct device *dev, enum can_state *state,
|
||||
struct can_bus_err_cnt *err_cnt);
|
||||
|
||||
void can_sja1000_set_state_change_callback(const struct device *dev,
|
||||
can_state_change_callback_t callback, void *user_data);
|
||||
|
||||
int can_sja1000_get_max_filters(const struct device *dev, enum can_ide id_type);
|
||||
|
||||
int can_sja1000_get_max_bitrate(const struct device *dev, uint32_t *max_bitrate);
|
||||
|
||||
void can_sja1000_isr(const struct device *dev);
|
||||
|
||||
int can_sja1000_init(const struct device *dev);
|
||||
|
||||
#endif /* ZEPHYR_DRIVERS_CAN_SJA1000_H_ */
|
127
drivers/can/can_sja1000_priv.h
Normal file
127
drivers/can/can_sja1000_priv.h
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Henrik Brix Andersen <henrik@brixandersen.dk>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_DRIVERS_CAN_SJA1000_PRIV_H_
|
||||
#define ZEPHYR_DRIVERS_CAN_SJA1000_PRIV_H_
|
||||
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
/* SJA1000 register "CAN addresses", PeliCAN mode */
|
||||
#define CAN_SJA1000_MOD (0U)
|
||||
#define CAN_SJA1000_CMR (1U)
|
||||
#define CAN_SJA1000_SR (2U)
|
||||
#define CAN_SJA1000_IR (3U)
|
||||
#define CAN_SJA1000_IER (4U)
|
||||
#define CAN_SJA1000_BTR0 (6U)
|
||||
#define CAN_SJA1000_BTR1 (7U)
|
||||
#define CAN_SJA1000_OCR (8U)
|
||||
#define CAN_SJA1000_ALC (11U)
|
||||
#define CAN_SJA1000_ECC (12U)
|
||||
#define CAN_SJA1000_EWLR (13U)
|
||||
#define CAN_SJA1000_RXERR (14U)
|
||||
#define CAN_SJA1000_TXERR (15U)
|
||||
|
||||
/* Reset Mode access (acceptance codes/masks) */
|
||||
#define CAN_SJA1000_ACR0 (16U)
|
||||
#define CAN_SJA1000_ACR1 (17U)
|
||||
#define CAN_SJA1000_ACR2 (18U)
|
||||
#define CAN_SJA1000_ACR3 (19U)
|
||||
#define CAN_SJA1000_AMR0 (20U)
|
||||
#define CAN_SJA1000_AMR1 (21U)
|
||||
#define CAN_SJA1000_AMR2 (22U)
|
||||
#define CAN_SJA1000_AMR3 (23U)
|
||||
|
||||
/* Operation Mode access (RX/TX SFF/EFF frame) */
|
||||
#define CAN_SJA1000_FRAME_INFO (16U)
|
||||
#define CAN_SJA1000_XFF_ID1 (17U)
|
||||
#define CAN_SJA1000_XFF_ID2 (18U)
|
||||
#define CAN_SJA1000_EFF_ID3 (19U)
|
||||
#define CAN_SJA1000_EFF_ID4 (20U)
|
||||
#define CAN_SJA1000_SFF_DATA (19U)
|
||||
#define CAN_SJA1000_EFF_DATA (21U)
|
||||
|
||||
#define CAN_SJA1000_RMC (29U)
|
||||
#define CAN_SJA1000_RBSA (30U)
|
||||
#define CAN_SJA1000_CDR (31U)
|
||||
|
||||
/* Mode register (MOD) bits */
|
||||
#define CAN_SJA1000_MOD_RM BIT(0)
|
||||
#define CAN_SJA1000_MOD_LOM BIT(1)
|
||||
#define CAN_SJA1000_MOD_STM BIT(2)
|
||||
#define CAN_SJA1000_MOD_AFM BIT(3)
|
||||
#define CAN_SJA1000_MOD_SM BIT(4)
|
||||
|
||||
/* Command Register (CMR) bits */
|
||||
#define CAN_SJA1000_CMR_TR BIT(0)
|
||||
#define CAN_SJA1000_CMR_AT BIT(1)
|
||||
#define CAN_SJA1000_CMR_RRB BIT(2)
|
||||
#define CAN_SJA1000_CMR_CDO BIT(3)
|
||||
#define CAN_SJA1000_CMR_SRR BIT(4)
|
||||
|
||||
/* Status Register (SR) bits */
|
||||
#define CAN_SJA1000_SR_RBS BIT(0)
|
||||
#define CAN_SJA1000_SR_DOS BIT(1)
|
||||
#define CAN_SJA1000_SR_TBS BIT(2)
|
||||
#define CAN_SJA1000_SR_TCS BIT(3)
|
||||
#define CAN_SJA1000_SR_RS BIT(4)
|
||||
#define CAN_SJA1000_SR_TS BIT(5)
|
||||
#define CAN_SJA1000_SR_ES BIT(6)
|
||||
#define CAN_SJA1000_SR_BS BIT(7)
|
||||
|
||||
/* Interrupt Register (IR) bits */
|
||||
#define CAN_SJA1000_IR_RI BIT(0)
|
||||
#define CAN_SJA1000_IR_TI BIT(1)
|
||||
#define CAN_SJA1000_IR_EI BIT(2)
|
||||
#define CAN_SJA1000_IR_DOI BIT(3)
|
||||
#define CAN_SJA1000_IR_WUI BIT(4)
|
||||
#define CAN_SJA1000_IR_EPI BIT(5)
|
||||
#define CAN_SJA1000_IR_ALI BIT(6)
|
||||
#define CAN_SJA1000_IR_BEI BIT(7)
|
||||
|
||||
/* Interrupt Enable Register (IER) bits */
|
||||
#define CAN_SJA1000_IER_RIE BIT(0)
|
||||
#define CAN_SJA1000_IER_TIE BIT(1)
|
||||
#define CAN_SJA1000_IER_EIE BIT(2)
|
||||
#define CAN_SJA1000_IER_DOIE BIT(3)
|
||||
#define CAN_SJA1000_IER_WUIE BIT(4)
|
||||
#define CAN_SJA1000_IER_EPIE BIT(5)
|
||||
#define CAN_SJA1000_IER_ALIE BIT(6)
|
||||
#define CAN_SJA1000_IER_BEIE BIT(7)
|
||||
|
||||
/* Bus Timing Register 0 (BTR0) bits */
|
||||
#define CAN_SJA1000_BTR0_BRP_MASK GENMASK(5, 0)
|
||||
#define CAN_SJA1000_BTR0_SJW_MASK GENMASK(7, 6)
|
||||
|
||||
#define CAN_SJA1000_BTR0_BRP_PREP(brp) FIELD_PREP(CAN_SJA1000_BTR0_BRP_MASK, brp)
|
||||
#define CAN_SJA1000_BTR0_SJW_PREP(sjw) FIELD_PREP(CAN_SJA1000_BTR0_SJW_MASK, sjw)
|
||||
|
||||
/* Bus Timing Register 1 (BTR1) bits */
|
||||
#define CAN_SJA1000_BTR1_TSEG1_MASK GENMASK(3, 0)
|
||||
#define CAN_SJA1000_BTR1_TSEG2_MASK GENMASK(6, 4)
|
||||
#define CAN_SJA1000_BTR1_SAM BIT(7)
|
||||
|
||||
#define CAN_SJA1000_BTR1_TSEG1_PREP(tseg1) FIELD_PREP(CAN_SJA1000_BTR1_TSEG1_MASK, tseg1)
|
||||
#define CAN_SJA1000_BTR1_TSEG2_PREP(tseg2) FIELD_PREP(CAN_SJA1000_BTR1_TSEG2_MASK, tseg2)
|
||||
|
||||
/* Error Code Capture register (ECC) bits */
|
||||
#define CAN_SJA1000_ECC_SEG_MASK GENMASK(4, 0)
|
||||
#define CAN_SJA1000_ECC_DIR BIT(5)
|
||||
#define CAN_SJA1000_ECC_ERRC_MASK GENMASK(7, 6)
|
||||
|
||||
#define CAN_SJA1000_ECC_ERRC_BIT_ERROR FIELD_PREP(CAN_SJA1000_ECC_ERRC_MASK, 0U)
|
||||
#define CAN_SJA1000_ECC_ERRC_FORM_ERROR FIELD_PREP(CAN_SJA1000_ECC_ERRC_MASK, 1U)
|
||||
#define CAN_SJA1000_ECC_ERRC_STUFF_ERROR FIELD_PREP(CAN_SJA1000_ECC_ERRC_MASK, 2U)
|
||||
#define CAN_SJA1000_ECC_ERRC_OTHER_ERROR FIELD_PREP(CAN_SJA1000_ECC_ERRC_MASK, 3U)
|
||||
|
||||
/* RX/TX SFF/EFF Frame Information bits */
|
||||
#define CAN_SJA1000_FRAME_INFO_DLC_MASK GENMASK(3, 0)
|
||||
#define CAN_SJA1000_FRAME_INFO_RTR BIT(6)
|
||||
#define CAN_SJA1000_FRAME_INFO_FF BIT(7)
|
||||
|
||||
#define CAN_SJA1000_FRAME_INFO_DLC_PREP(dlc) FIELD_PREP(CAN_SJA1000_FRAME_INFO_DLC_MASK, dlc)
|
||||
#define CAN_SJA1000_FRAME_INFO_DLC_GET(info) FIELD_GET(CAN_SJA1000_FRAME_INFO_DLC_MASK, info)
|
||||
|
||||
#endif /* ZEPHYR_DRIVERS_CAN_SJA1000_PRIV_H_ */
|
Loading…
Add table
Add a link
Reference in a new issue