Skip to content

Commit 6d08944

Browse files
henrikbrixandersenfabiobaltieri
authored andcommitted
drivers: can: mcp2515: abort transfers before entering configuration mode
Abort any pending transmissions before entering configuration mode and notify the senders. Poll for mode change completion instead of assuming mode changes take immediate effect. This is needed for successfully entering configuration mode with recently aborted transmissions. Fixes: #50545 Signed-off-by: Henrik Brix Andersen <[email protected]>
1 parent f239c3d commit 6d08944

File tree

2 files changed

+54
-20
lines changed

2 files changed

+54
-20
lines changed

drivers/can/can_mcp2515.c

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ LOG_MODULE_REGISTER(can_mcp2515, CONFIG_CAN_LOG_LEVEL);
3535
#error You must either set a sampling-point or timings (phase-seg* and prop-seg)
3636
#endif
3737

38+
/* Timeout for changing mode */
39+
#define MCP2515_MODE_CHANGE_TIMEOUT_USEC 1000
40+
#define MCP2515_MODE_CHANGE_RETRIES 100
41+
#define MCP2515_MODE_CHANGE_DELAY \
42+
K_USEC(MCP2515_MODE_CHANGE_TIMEOUT_USEC / MCP2515_MODE_CHANGE_RETRIES)
43+
3844
static int mcp2515_cmd_soft_reset(const struct device *dev)
3945
{
4046
const struct mcp2515_config *dev_cfg = dev->config;
@@ -271,22 +277,44 @@ static void mcp2515_convert_mcp2515frame_to_canframe(const uint8_t *source,
271277

272278
const int mcp2515_set_mode_int(const struct device *dev, uint8_t mcp2515_mode)
273279
{
280+
int retries = MCP2515_MODE_CHANGE_RETRIES;
274281
uint8_t canstat;
275282

276283
mcp2515_cmd_bit_modify(dev, MCP2515_ADDR_CANCTRL,
277284
MCP2515_CANCTRL_MODE_MASK,
278285
mcp2515_mode << MCP2515_CANCTRL_MODE_POS);
279286
mcp2515_cmd_read_reg(dev, MCP2515_ADDR_CANSTAT, &canstat, 1);
280287

281-
if (((canstat & MCP2515_CANSTAT_MODE_MASK) >> MCP2515_CANSTAT_MODE_POS)
282-
!= mcp2515_mode) {
283-
LOG_ERR("Failed to set MCP2515 operation mode");
284-
return -EIO;
288+
while (((canstat & MCP2515_CANSTAT_MODE_MASK) >> MCP2515_CANSTAT_MODE_POS)
289+
!= mcp2515_mode) {
290+
if (--retries < 0) {
291+
LOG_ERR("Timeout trying to set MCP2515 operation mode");
292+
return -EIO;
293+
}
294+
295+
k_sleep(MCP2515_MODE_CHANGE_DELAY);
296+
mcp2515_cmd_read_reg(dev, MCP2515_ADDR_CANSTAT, &canstat, 1);
285297
}
286298

287299
return 0;
288300
}
289301

302+
static void mcp2515_tx_done(const struct device *dev, uint8_t tx_idx, int status)
303+
{
304+
struct mcp2515_data *dev_data = dev->data;
305+
can_tx_callback_t callback = dev_data->tx_cb[tx_idx].cb;
306+
307+
if (callback != NULL) {
308+
callback(dev, status, dev_data->tx_cb[tx_idx].cb_arg);
309+
dev_data->tx_cb[tx_idx].cb = NULL;
310+
311+
k_mutex_lock(&dev_data->mutex, K_FOREVER);
312+
dev_data->tx_busy_map &= ~BIT(tx_idx);
313+
k_mutex_unlock(&dev_data->mutex);
314+
k_sem_give(&dev_data->tx_sem);
315+
}
316+
}
317+
290318
static int mcp2515_get_core_clock(const struct device *dev, uint32_t *rate)
291319
{
292320
const struct mcp2515_config *dev_cfg = dev->config;
@@ -457,13 +485,26 @@ static int mcp2515_stop(const struct device *dev)
457485
const struct mcp2515_config *dev_cfg = dev->config;
458486
struct mcp2515_data *dev_data = dev->data;
459487
int ret;
488+
int i;
460489

461490
if (!dev_data->started) {
462491
return -EALREADY;
463492
}
464493

465494
k_mutex_lock(&dev_data->mutex, K_FOREVER);
466495

496+
/* Abort any pending transmissions before entering configuration mode */
497+
mcp2515_cmd_bit_modify(dev, MCP2515_ADDR_TXB0CTRL,
498+
MCP2515_TXBNCTRL_TXREQ_MASK, 0);
499+
#if MCP2515_TX_CNT == 2
500+
mcp2515_cmd_bit_modify(dev, MCP2515_ADDR_TXB1CTRL,
501+
MCP2515_TXBNCTRL_TXREQ_MASK, 0);
502+
#endif /* MCP2515_TX_CNT == 2 */
503+
#if MCP2515_TX_CNT == 3
504+
mcp2515_cmd_bit_modify(dev, MCP2515_ADDR_TXB2CTRL,
505+
MCP2515_TXBNCTRL_TXREQ_MASK, 0);
506+
#endif /* MCP2515_TX_CNT == 3 */
507+
467508
ret = mcp2515_set_mode_int(dev, MCP2515_MODE_CONFIGURATION);
468509
if (ret < 0) {
469510
LOG_ERR("Failed to enter configuration mode [%d]", ret);
@@ -475,6 +516,10 @@ static int mcp2515_stop(const struct device *dev)
475516

476517
k_mutex_unlock(&dev_data->mutex);
477518

519+
for (i = 0; i < MCP2515_TX_CNT; i++) {
520+
mcp2515_tx_done(dev, i, -ENETDOWN);
521+
}
522+
478523
if (dev_cfg->phy != NULL) {
479524
ret = can_transceiver_disable(dev_cfg->phy);
480525
if (ret != 0) {
@@ -678,19 +723,6 @@ static void mcp2515_rx(const struct device *dev, uint8_t rx_idx)
678723
mcp2515_rx_filter(dev, &frame);
679724
}
680725

681-
static void mcp2515_tx_done(const struct device *dev, uint8_t tx_idx)
682-
{
683-
struct mcp2515_data *dev_data = dev->data;
684-
685-
dev_data->tx_cb[tx_idx].cb(dev, 0, dev_data->tx_cb[tx_idx].cb_arg);
686-
dev_data->tx_cb[tx_idx].cb = NULL;
687-
688-
k_mutex_lock(&dev_data->mutex, K_FOREVER);
689-
dev_data->tx_busy_map &= ~BIT(tx_idx);
690-
k_mutex_unlock(&dev_data->mutex);
691-
k_sem_give(&dev_data->tx_sem);
692-
}
693-
694726
static int mcp2515_get_state(const struct device *dev, enum can_state *state,
695727
struct can_bus_err_cnt *err_cnt)
696728
{
@@ -805,15 +837,15 @@ static void mcp2515_handle_interrupts(const struct device *dev)
805837
}
806838

807839
if (canintf & MCP2515_CANINTF_TX0IF) {
808-
mcp2515_tx_done(dev, 0);
840+
mcp2515_tx_done(dev, 0, 0);
809841
}
810842

811843
if (canintf & MCP2515_CANINTF_TX1IF) {
812-
mcp2515_tx_done(dev, 1);
844+
mcp2515_tx_done(dev, 1, 0);
813845
}
814846

815847
if (canintf & MCP2515_CANINTF_TX2IF) {
816-
mcp2515_tx_done(dev, 2);
848+
mcp2515_tx_done(dev, 2, 0);
817849
}
818850

819851
if (canintf & MCP2515_CANINTF_ERRIF) {

drivers/can/can_mcp2515.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,5 +156,7 @@ struct mcp2515_config {
156156
#define MCP2515_CANSTAT_MODE_MASK (0x07 << MCP2515_CANSTAT_MODE_POS)
157157
#define MCP2515_CANCTRL_MODE_POS 5
158158
#define MCP2515_CANCTRL_MODE_MASK (0x07 << MCP2515_CANCTRL_MODE_POS)
159+
#define MCP2515_TXBNCTRL_TXREQ_POS 3
160+
#define MCP2515_TXBNCTRL_TXREQ_MASK (0x01 << MCP2515_TXBNCTRL_TXREQ_POS)
159161

160162
#endif /*_MCP2515_H_*/

0 commit comments

Comments
 (0)