18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * CAN bus driver for the alone generic (as possible as) MSCAN controller. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2005-2006 Andrey Volkov <avolkov@varma-el.com>, 68c2ecf20Sopenharmony_ci * Varma Electronics Oy 78c2ecf20Sopenharmony_ci * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com> 88c2ecf20Sopenharmony_ci * Copyright (C) 2008-2009 Pengutronix <kernel@pengutronix.de> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 148c2ecf20Sopenharmony_ci#include <linux/delay.h> 158c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 168c2ecf20Sopenharmony_ci#include <linux/if_arp.h> 178c2ecf20Sopenharmony_ci#include <linux/if_ether.h> 188c2ecf20Sopenharmony_ci#include <linux/list.h> 198c2ecf20Sopenharmony_ci#include <linux/can/dev.h> 208c2ecf20Sopenharmony_ci#include <linux/can/error.h> 218c2ecf20Sopenharmony_ci#include <linux/io.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "mscan.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic const struct can_bittiming_const mscan_bittiming_const = { 268c2ecf20Sopenharmony_ci .name = "mscan", 278c2ecf20Sopenharmony_ci .tseg1_min = 4, 288c2ecf20Sopenharmony_ci .tseg1_max = 16, 298c2ecf20Sopenharmony_ci .tseg2_min = 2, 308c2ecf20Sopenharmony_ci .tseg2_max = 8, 318c2ecf20Sopenharmony_ci .sjw_max = 4, 328c2ecf20Sopenharmony_ci .brp_min = 1, 338c2ecf20Sopenharmony_ci .brp_max = 64, 348c2ecf20Sopenharmony_ci .brp_inc = 1, 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistruct mscan_state { 388c2ecf20Sopenharmony_ci u8 mode; 398c2ecf20Sopenharmony_ci u8 canrier; 408c2ecf20Sopenharmony_ci u8 cantier; 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic enum can_state state_map[] = { 448c2ecf20Sopenharmony_ci CAN_STATE_ERROR_ACTIVE, 458c2ecf20Sopenharmony_ci CAN_STATE_ERROR_WARNING, 468c2ecf20Sopenharmony_ci CAN_STATE_ERROR_PASSIVE, 478c2ecf20Sopenharmony_ci CAN_STATE_BUS_OFF 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic int mscan_set_mode(struct net_device *dev, u8 mode) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 538c2ecf20Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 548c2ecf20Sopenharmony_ci int ret = 0; 558c2ecf20Sopenharmony_ci int i; 568c2ecf20Sopenharmony_ci u8 canctl1; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci if (mode != MSCAN_NORMAL_MODE) { 598c2ecf20Sopenharmony_ci if (priv->tx_active) { 608c2ecf20Sopenharmony_ci /* Abort transfers before going to sleep */# 618c2ecf20Sopenharmony_ci out_8(®s->cantarq, priv->tx_active); 628c2ecf20Sopenharmony_ci /* Suppress TX done interrupts */ 638c2ecf20Sopenharmony_ci out_8(®s->cantier, 0); 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci canctl1 = in_8(®s->canctl1); 678c2ecf20Sopenharmony_ci if ((mode & MSCAN_SLPRQ) && !(canctl1 & MSCAN_SLPAK)) { 688c2ecf20Sopenharmony_ci setbits8(®s->canctl0, MSCAN_SLPRQ); 698c2ecf20Sopenharmony_ci for (i = 0; i < MSCAN_SET_MODE_RETRIES; i++) { 708c2ecf20Sopenharmony_ci if (in_8(®s->canctl1) & MSCAN_SLPAK) 718c2ecf20Sopenharmony_ci break; 728c2ecf20Sopenharmony_ci udelay(100); 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci /* 758c2ecf20Sopenharmony_ci * The mscan controller will fail to enter sleep mode, 768c2ecf20Sopenharmony_ci * while there are irregular activities on bus, like 778c2ecf20Sopenharmony_ci * somebody keeps retransmitting. This behavior is 788c2ecf20Sopenharmony_ci * undocumented and seems to differ between mscan built 798c2ecf20Sopenharmony_ci * in mpc5200b and mpc5200. We proceed in that case, 808c2ecf20Sopenharmony_ci * since otherwise the slprq will be kept set and the 818c2ecf20Sopenharmony_ci * controller will get stuck. NOTE: INITRQ or CSWAI 828c2ecf20Sopenharmony_ci * will abort all active transmit actions, if still 838c2ecf20Sopenharmony_ci * any, at once. 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_ci if (i >= MSCAN_SET_MODE_RETRIES) 868c2ecf20Sopenharmony_ci netdev_dbg(dev, 878c2ecf20Sopenharmony_ci "device failed to enter sleep mode. " 888c2ecf20Sopenharmony_ci "We proceed anyhow.\n"); 898c2ecf20Sopenharmony_ci else 908c2ecf20Sopenharmony_ci priv->can.state = CAN_STATE_SLEEPING; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if ((mode & MSCAN_INITRQ) && !(canctl1 & MSCAN_INITAK)) { 948c2ecf20Sopenharmony_ci setbits8(®s->canctl0, MSCAN_INITRQ); 958c2ecf20Sopenharmony_ci for (i = 0; i < MSCAN_SET_MODE_RETRIES; i++) { 968c2ecf20Sopenharmony_ci if (in_8(®s->canctl1) & MSCAN_INITAK) 978c2ecf20Sopenharmony_ci break; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci if (i >= MSCAN_SET_MODE_RETRIES) 1008c2ecf20Sopenharmony_ci ret = -ENODEV; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci if (!ret) 1038c2ecf20Sopenharmony_ci priv->can.state = CAN_STATE_STOPPED; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (mode & MSCAN_CSWAI) 1068c2ecf20Sopenharmony_ci setbits8(®s->canctl0, MSCAN_CSWAI); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci } else { 1098c2ecf20Sopenharmony_ci canctl1 = in_8(®s->canctl1); 1108c2ecf20Sopenharmony_ci if (canctl1 & (MSCAN_SLPAK | MSCAN_INITAK)) { 1118c2ecf20Sopenharmony_ci clrbits8(®s->canctl0, MSCAN_SLPRQ | MSCAN_INITRQ); 1128c2ecf20Sopenharmony_ci for (i = 0; i < MSCAN_SET_MODE_RETRIES; i++) { 1138c2ecf20Sopenharmony_ci canctl1 = in_8(®s->canctl1); 1148c2ecf20Sopenharmony_ci if (!(canctl1 & (MSCAN_INITAK | MSCAN_SLPAK))) 1158c2ecf20Sopenharmony_ci break; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci if (i >= MSCAN_SET_MODE_RETRIES) 1188c2ecf20Sopenharmony_ci ret = -ENODEV; 1198c2ecf20Sopenharmony_ci else 1208c2ecf20Sopenharmony_ci priv->can.state = CAN_STATE_ERROR_ACTIVE; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci return ret; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic int mscan_start(struct net_device *dev) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 1298c2ecf20Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 1308c2ecf20Sopenharmony_ci u8 canrflg; 1318c2ecf20Sopenharmony_ci int err; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci out_8(®s->canrier, 0); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&priv->tx_head); 1368c2ecf20Sopenharmony_ci priv->prev_buf_id = 0; 1378c2ecf20Sopenharmony_ci priv->cur_pri = 0; 1388c2ecf20Sopenharmony_ci priv->tx_active = 0; 1398c2ecf20Sopenharmony_ci priv->shadow_canrier = 0; 1408c2ecf20Sopenharmony_ci priv->flags = 0; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (priv->type == MSCAN_TYPE_MPC5121) { 1438c2ecf20Sopenharmony_ci /* Clear pending bus-off condition */ 1448c2ecf20Sopenharmony_ci if (in_8(®s->canmisc) & MSCAN_BOHOLD) 1458c2ecf20Sopenharmony_ci out_8(®s->canmisc, MSCAN_BOHOLD); 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci err = mscan_set_mode(dev, MSCAN_NORMAL_MODE); 1498c2ecf20Sopenharmony_ci if (err) 1508c2ecf20Sopenharmony_ci return err; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci canrflg = in_8(®s->canrflg); 1538c2ecf20Sopenharmony_ci priv->shadow_statflg = canrflg & MSCAN_STAT_MSK; 1548c2ecf20Sopenharmony_ci priv->can.state = state_map[max(MSCAN_STATE_RX(canrflg), 1558c2ecf20Sopenharmony_ci MSCAN_STATE_TX(canrflg))]; 1568c2ecf20Sopenharmony_ci out_8(®s->cantier, 0); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci /* Enable receive interrupts. */ 1598c2ecf20Sopenharmony_ci out_8(®s->canrier, MSCAN_RX_INTS_ENABLE); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci return 0; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic int mscan_restart(struct net_device *dev) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (priv->type == MSCAN_TYPE_MPC5121) { 1698c2ecf20Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci priv->can.state = CAN_STATE_ERROR_ACTIVE; 1728c2ecf20Sopenharmony_ci WARN(!(in_8(®s->canmisc) & MSCAN_BOHOLD), 1738c2ecf20Sopenharmony_ci "bus-off state expected\n"); 1748c2ecf20Sopenharmony_ci out_8(®s->canmisc, MSCAN_BOHOLD); 1758c2ecf20Sopenharmony_ci /* Re-enable receive interrupts. */ 1768c2ecf20Sopenharmony_ci out_8(®s->canrier, MSCAN_RX_INTS_ENABLE); 1778c2ecf20Sopenharmony_ci } else { 1788c2ecf20Sopenharmony_ci if (priv->can.state <= CAN_STATE_BUS_OFF) 1798c2ecf20Sopenharmony_ci mscan_set_mode(dev, MSCAN_INIT_MODE); 1808c2ecf20Sopenharmony_ci return mscan_start(dev); 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci return 0; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci struct can_frame *frame = (struct can_frame *)skb->data; 1898c2ecf20Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 1908c2ecf20Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 1918c2ecf20Sopenharmony_ci int i, rtr, buf_id; 1928c2ecf20Sopenharmony_ci u32 can_id; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (can_dropped_invalid_skb(dev, skb)) 1958c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci out_8(®s->cantier, 0); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci i = ~priv->tx_active & MSCAN_TXE; 2008c2ecf20Sopenharmony_ci buf_id = ffs(i) - 1; 2018c2ecf20Sopenharmony_ci switch (hweight8(i)) { 2028c2ecf20Sopenharmony_ci case 0: 2038c2ecf20Sopenharmony_ci netif_stop_queue(dev); 2048c2ecf20Sopenharmony_ci netdev_err(dev, "Tx Ring full when queue awake!\n"); 2058c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 2068c2ecf20Sopenharmony_ci case 1: 2078c2ecf20Sopenharmony_ci /* 2088c2ecf20Sopenharmony_ci * if buf_id < 3, then current frame will be send out of order, 2098c2ecf20Sopenharmony_ci * since buffer with lower id have higher priority (hell..) 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_ci netif_stop_queue(dev); 2128c2ecf20Sopenharmony_ci fallthrough; 2138c2ecf20Sopenharmony_ci case 2: 2148c2ecf20Sopenharmony_ci if (buf_id < priv->prev_buf_id) { 2158c2ecf20Sopenharmony_ci priv->cur_pri++; 2168c2ecf20Sopenharmony_ci if (priv->cur_pri == 0xff) { 2178c2ecf20Sopenharmony_ci set_bit(F_TX_WAIT_ALL, &priv->flags); 2188c2ecf20Sopenharmony_ci netif_stop_queue(dev); 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci set_bit(F_TX_PROGRESS, &priv->flags); 2228c2ecf20Sopenharmony_ci break; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci priv->prev_buf_id = buf_id; 2258c2ecf20Sopenharmony_ci out_8(®s->cantbsel, i); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci rtr = frame->can_id & CAN_RTR_FLAG; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* RTR is always the lowest bit of interest, then IDs follow */ 2308c2ecf20Sopenharmony_ci if (frame->can_id & CAN_EFF_FLAG) { 2318c2ecf20Sopenharmony_ci can_id = (frame->can_id & CAN_EFF_MASK) 2328c2ecf20Sopenharmony_ci << (MSCAN_EFF_RTR_SHIFT + 1); 2338c2ecf20Sopenharmony_ci if (rtr) 2348c2ecf20Sopenharmony_ci can_id |= 1 << MSCAN_EFF_RTR_SHIFT; 2358c2ecf20Sopenharmony_ci out_be16(®s->tx.idr3_2, can_id); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci can_id >>= 16; 2388c2ecf20Sopenharmony_ci /* EFF_FLAGS are between the IDs :( */ 2398c2ecf20Sopenharmony_ci can_id = (can_id & 0x7) | ((can_id << 2) & 0xffe0) 2408c2ecf20Sopenharmony_ci | MSCAN_EFF_FLAGS; 2418c2ecf20Sopenharmony_ci } else { 2428c2ecf20Sopenharmony_ci can_id = (frame->can_id & CAN_SFF_MASK) 2438c2ecf20Sopenharmony_ci << (MSCAN_SFF_RTR_SHIFT + 1); 2448c2ecf20Sopenharmony_ci if (rtr) 2458c2ecf20Sopenharmony_ci can_id |= 1 << MSCAN_SFF_RTR_SHIFT; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci out_be16(®s->tx.idr1_0, can_id); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (!rtr) { 2508c2ecf20Sopenharmony_ci void __iomem *data = ®s->tx.dsr1_0; 2518c2ecf20Sopenharmony_ci u16 *payload = (u16 *)frame->data; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci for (i = 0; i < frame->can_dlc / 2; i++) { 2548c2ecf20Sopenharmony_ci out_be16(data, *payload++); 2558c2ecf20Sopenharmony_ci data += 2 + _MSCAN_RESERVED_DSR_SIZE; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci /* write remaining byte if necessary */ 2588c2ecf20Sopenharmony_ci if (frame->can_dlc & 1) 2598c2ecf20Sopenharmony_ci out_8(data, frame->data[frame->can_dlc - 1]); 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci out_8(®s->tx.dlr, frame->can_dlc); 2638c2ecf20Sopenharmony_ci out_8(®s->tx.tbpr, priv->cur_pri); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci /* Start transmission. */ 2668c2ecf20Sopenharmony_ci out_8(®s->cantflg, 1 << buf_id); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (!test_bit(F_TX_PROGRESS, &priv->flags)) 2698c2ecf20Sopenharmony_ci netif_trans_update(dev); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci list_add_tail(&priv->tx_queue[buf_id].list, &priv->tx_head); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci can_put_echo_skb(skb, dev, buf_id); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* Enable interrupt. */ 2768c2ecf20Sopenharmony_ci priv->tx_active |= 1 << buf_id; 2778c2ecf20Sopenharmony_ci out_8(®s->cantier, priv->tx_active); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic enum can_state get_new_state(struct net_device *dev, u8 canrflg) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if (unlikely(canrflg & MSCAN_CSCIF)) 2878c2ecf20Sopenharmony_ci return state_map[max(MSCAN_STATE_RX(canrflg), 2888c2ecf20Sopenharmony_ci MSCAN_STATE_TX(canrflg))]; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci return priv->can.state; 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic void mscan_get_rx_frame(struct net_device *dev, struct can_frame *frame) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 2968c2ecf20Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 2978c2ecf20Sopenharmony_ci u32 can_id; 2988c2ecf20Sopenharmony_ci int i; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci can_id = in_be16(®s->rx.idr1_0); 3018c2ecf20Sopenharmony_ci if (can_id & (1 << 3)) { 3028c2ecf20Sopenharmony_ci frame->can_id = CAN_EFF_FLAG; 3038c2ecf20Sopenharmony_ci can_id = ((can_id << 16) | in_be16(®s->rx.idr3_2)); 3048c2ecf20Sopenharmony_ci can_id = ((can_id & 0xffe00000) | 3058c2ecf20Sopenharmony_ci ((can_id & 0x7ffff) << 2)) >> 2; 3068c2ecf20Sopenharmony_ci } else { 3078c2ecf20Sopenharmony_ci can_id >>= 4; 3088c2ecf20Sopenharmony_ci frame->can_id = 0; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci frame->can_id |= can_id >> 1; 3128c2ecf20Sopenharmony_ci if (can_id & 1) 3138c2ecf20Sopenharmony_ci frame->can_id |= CAN_RTR_FLAG; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci frame->can_dlc = get_can_dlc(in_8(®s->rx.dlr) & 0xf); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (!(frame->can_id & CAN_RTR_FLAG)) { 3188c2ecf20Sopenharmony_ci void __iomem *data = ®s->rx.dsr1_0; 3198c2ecf20Sopenharmony_ci u16 *payload = (u16 *)frame->data; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci for (i = 0; i < frame->can_dlc / 2; i++) { 3228c2ecf20Sopenharmony_ci *payload++ = in_be16(data); 3238c2ecf20Sopenharmony_ci data += 2 + _MSCAN_RESERVED_DSR_SIZE; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci /* read remaining byte if necessary */ 3268c2ecf20Sopenharmony_ci if (frame->can_dlc & 1) 3278c2ecf20Sopenharmony_ci frame->data[frame->can_dlc - 1] = in_8(data); 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci out_8(®s->canrflg, MSCAN_RXF); 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic void mscan_get_err_frame(struct net_device *dev, struct can_frame *frame, 3348c2ecf20Sopenharmony_ci u8 canrflg) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 3378c2ecf20Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 3388c2ecf20Sopenharmony_ci struct net_device_stats *stats = &dev->stats; 3398c2ecf20Sopenharmony_ci enum can_state new_state; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci netdev_dbg(dev, "error interrupt (canrflg=%#x)\n", canrflg); 3428c2ecf20Sopenharmony_ci frame->can_id = CAN_ERR_FLAG; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (canrflg & MSCAN_OVRIF) { 3458c2ecf20Sopenharmony_ci frame->can_id |= CAN_ERR_CRTL; 3468c2ecf20Sopenharmony_ci frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; 3478c2ecf20Sopenharmony_ci stats->rx_over_errors++; 3488c2ecf20Sopenharmony_ci stats->rx_errors++; 3498c2ecf20Sopenharmony_ci } else { 3508c2ecf20Sopenharmony_ci frame->data[1] = 0; 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci new_state = get_new_state(dev, canrflg); 3548c2ecf20Sopenharmony_ci if (new_state != priv->can.state) { 3558c2ecf20Sopenharmony_ci can_change_state(dev, frame, 3568c2ecf20Sopenharmony_ci state_map[MSCAN_STATE_TX(canrflg)], 3578c2ecf20Sopenharmony_ci state_map[MSCAN_STATE_RX(canrflg)]); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (priv->can.state == CAN_STATE_BUS_OFF) { 3608c2ecf20Sopenharmony_ci /* 3618c2ecf20Sopenharmony_ci * The MSCAN on the MPC5200 does recover from bus-off 3628c2ecf20Sopenharmony_ci * automatically. To avoid that we stop the chip doing 3638c2ecf20Sopenharmony_ci * a light-weight stop (we are in irq-context). 3648c2ecf20Sopenharmony_ci */ 3658c2ecf20Sopenharmony_ci if (priv->type != MSCAN_TYPE_MPC5121) { 3668c2ecf20Sopenharmony_ci out_8(®s->cantier, 0); 3678c2ecf20Sopenharmony_ci out_8(®s->canrier, 0); 3688c2ecf20Sopenharmony_ci setbits8(®s->canctl0, 3698c2ecf20Sopenharmony_ci MSCAN_SLPRQ | MSCAN_INITRQ); 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci can_bus_off(dev); 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci priv->shadow_statflg = canrflg & MSCAN_STAT_MSK; 3758c2ecf20Sopenharmony_ci frame->can_dlc = CAN_ERR_DLC; 3768c2ecf20Sopenharmony_ci out_8(®s->canrflg, MSCAN_ERR_IF); 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic int mscan_rx_poll(struct napi_struct *napi, int quota) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci struct mscan_priv *priv = container_of(napi, struct mscan_priv, napi); 3828c2ecf20Sopenharmony_ci struct net_device *dev = napi->dev; 3838c2ecf20Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 3848c2ecf20Sopenharmony_ci struct net_device_stats *stats = &dev->stats; 3858c2ecf20Sopenharmony_ci int work_done = 0; 3868c2ecf20Sopenharmony_ci struct sk_buff *skb; 3878c2ecf20Sopenharmony_ci struct can_frame *frame; 3888c2ecf20Sopenharmony_ci u8 canrflg; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci while (work_done < quota) { 3918c2ecf20Sopenharmony_ci canrflg = in_8(®s->canrflg); 3928c2ecf20Sopenharmony_ci if (!(canrflg & (MSCAN_RXF | MSCAN_ERR_IF))) 3938c2ecf20Sopenharmony_ci break; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci skb = alloc_can_skb(dev, &frame); 3968c2ecf20Sopenharmony_ci if (!skb) { 3978c2ecf20Sopenharmony_ci if (printk_ratelimit()) 3988c2ecf20Sopenharmony_ci netdev_notice(dev, "packet dropped\n"); 3998c2ecf20Sopenharmony_ci stats->rx_dropped++; 4008c2ecf20Sopenharmony_ci out_8(®s->canrflg, canrflg); 4018c2ecf20Sopenharmony_ci continue; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (canrflg & MSCAN_RXF) 4058c2ecf20Sopenharmony_ci mscan_get_rx_frame(dev, frame); 4068c2ecf20Sopenharmony_ci else if (canrflg & MSCAN_ERR_IF) 4078c2ecf20Sopenharmony_ci mscan_get_err_frame(dev, frame, canrflg); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci stats->rx_packets++; 4108c2ecf20Sopenharmony_ci stats->rx_bytes += frame->can_dlc; 4118c2ecf20Sopenharmony_ci work_done++; 4128c2ecf20Sopenharmony_ci netif_receive_skb(skb); 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci if (work_done < quota) { 4168c2ecf20Sopenharmony_ci if (likely(napi_complete_done(&priv->napi, work_done))) { 4178c2ecf20Sopenharmony_ci clear_bit(F_RX_PROGRESS, &priv->flags); 4188c2ecf20Sopenharmony_ci if (priv->can.state < CAN_STATE_BUS_OFF) 4198c2ecf20Sopenharmony_ci out_8(®s->canrier, priv->shadow_canrier); 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci return work_done; 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic irqreturn_t mscan_isr(int irq, void *dev_id) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci struct net_device *dev = (struct net_device *)dev_id; 4288c2ecf20Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 4298c2ecf20Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 4308c2ecf20Sopenharmony_ci struct net_device_stats *stats = &dev->stats; 4318c2ecf20Sopenharmony_ci u8 cantier, cantflg, canrflg; 4328c2ecf20Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci cantier = in_8(®s->cantier) & MSCAN_TXE; 4358c2ecf20Sopenharmony_ci cantflg = in_8(®s->cantflg) & cantier; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (cantier && cantflg) { 4388c2ecf20Sopenharmony_ci struct list_head *tmp, *pos; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci list_for_each_safe(pos, tmp, &priv->tx_head) { 4418c2ecf20Sopenharmony_ci struct tx_queue_entry *entry = 4428c2ecf20Sopenharmony_ci list_entry(pos, struct tx_queue_entry, list); 4438c2ecf20Sopenharmony_ci u8 mask = entry->mask; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci if (!(cantflg & mask)) 4468c2ecf20Sopenharmony_ci continue; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci out_8(®s->cantbsel, mask); 4498c2ecf20Sopenharmony_ci stats->tx_bytes += in_8(®s->tx.dlr); 4508c2ecf20Sopenharmony_ci stats->tx_packets++; 4518c2ecf20Sopenharmony_ci can_get_echo_skb(dev, entry->id); 4528c2ecf20Sopenharmony_ci priv->tx_active &= ~mask; 4538c2ecf20Sopenharmony_ci list_del(pos); 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (list_empty(&priv->tx_head)) { 4578c2ecf20Sopenharmony_ci clear_bit(F_TX_WAIT_ALL, &priv->flags); 4588c2ecf20Sopenharmony_ci clear_bit(F_TX_PROGRESS, &priv->flags); 4598c2ecf20Sopenharmony_ci priv->cur_pri = 0; 4608c2ecf20Sopenharmony_ci } else { 4618c2ecf20Sopenharmony_ci netif_trans_update(dev); 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (!test_bit(F_TX_WAIT_ALL, &priv->flags)) 4658c2ecf20Sopenharmony_ci netif_wake_queue(dev); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci out_8(®s->cantier, priv->tx_active); 4688c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci canrflg = in_8(®s->canrflg); 4728c2ecf20Sopenharmony_ci if ((canrflg & ~MSCAN_STAT_MSK) && 4738c2ecf20Sopenharmony_ci !test_and_set_bit(F_RX_PROGRESS, &priv->flags)) { 4748c2ecf20Sopenharmony_ci if (canrflg & ~MSCAN_STAT_MSK) { 4758c2ecf20Sopenharmony_ci priv->shadow_canrier = in_8(®s->canrier); 4768c2ecf20Sopenharmony_ci out_8(®s->canrier, 0); 4778c2ecf20Sopenharmony_ci napi_schedule(&priv->napi); 4788c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 4798c2ecf20Sopenharmony_ci } else { 4808c2ecf20Sopenharmony_ci clear_bit(F_RX_PROGRESS, &priv->flags); 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci return ret; 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cistatic int mscan_do_set_mode(struct net_device *dev, enum can_mode mode) 4878c2ecf20Sopenharmony_ci{ 4888c2ecf20Sopenharmony_ci int ret = 0; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci switch (mode) { 4918c2ecf20Sopenharmony_ci case CAN_MODE_START: 4928c2ecf20Sopenharmony_ci ret = mscan_restart(dev); 4938c2ecf20Sopenharmony_ci if (ret) 4948c2ecf20Sopenharmony_ci break; 4958c2ecf20Sopenharmony_ci if (netif_queue_stopped(dev)) 4968c2ecf20Sopenharmony_ci netif_wake_queue(dev); 4978c2ecf20Sopenharmony_ci break; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci default: 5008c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 5018c2ecf20Sopenharmony_ci break; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci return ret; 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cistatic int mscan_do_set_bittiming(struct net_device *dev) 5078c2ecf20Sopenharmony_ci{ 5088c2ecf20Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 5098c2ecf20Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 5108c2ecf20Sopenharmony_ci struct can_bittiming *bt = &priv->can.bittiming; 5118c2ecf20Sopenharmony_ci u8 btr0, btr1; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci btr0 = BTR0_SET_BRP(bt->brp) | BTR0_SET_SJW(bt->sjw); 5148c2ecf20Sopenharmony_ci btr1 = (BTR1_SET_TSEG1(bt->prop_seg + bt->phase_seg1) | 5158c2ecf20Sopenharmony_ci BTR1_SET_TSEG2(bt->phase_seg2) | 5168c2ecf20Sopenharmony_ci BTR1_SET_SAM(priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci netdev_info(dev, "setting BTR0=0x%02x BTR1=0x%02x\n", btr0, btr1); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci out_8(®s->canbtr0, btr0); 5218c2ecf20Sopenharmony_ci out_8(®s->canbtr1, btr1); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci return 0; 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic int mscan_get_berr_counter(const struct net_device *dev, 5278c2ecf20Sopenharmony_ci struct can_berr_counter *bec) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 5308c2ecf20Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci bec->txerr = in_8(®s->cantxerr); 5338c2ecf20Sopenharmony_ci bec->rxerr = in_8(®s->canrxerr); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci return 0; 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_cistatic int mscan_open(struct net_device *dev) 5398c2ecf20Sopenharmony_ci{ 5408c2ecf20Sopenharmony_ci int ret; 5418c2ecf20Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 5428c2ecf20Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->clk_ipg); 5458c2ecf20Sopenharmony_ci if (ret) 5468c2ecf20Sopenharmony_ci goto exit_retcode; 5478c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->clk_can); 5488c2ecf20Sopenharmony_ci if (ret) 5498c2ecf20Sopenharmony_ci goto exit_dis_ipg_clock; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci /* common open */ 5528c2ecf20Sopenharmony_ci ret = open_candev(dev); 5538c2ecf20Sopenharmony_ci if (ret) 5548c2ecf20Sopenharmony_ci goto exit_dis_can_clock; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci napi_enable(&priv->napi); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci ret = request_irq(dev->irq, mscan_isr, 0, dev->name, dev); 5598c2ecf20Sopenharmony_ci if (ret < 0) { 5608c2ecf20Sopenharmony_ci netdev_err(dev, "failed to attach interrupt\n"); 5618c2ecf20Sopenharmony_ci goto exit_napi_disable; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) 5658c2ecf20Sopenharmony_ci setbits8(®s->canctl1, MSCAN_LISTEN); 5668c2ecf20Sopenharmony_ci else 5678c2ecf20Sopenharmony_ci clrbits8(®s->canctl1, MSCAN_LISTEN); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci ret = mscan_start(dev); 5708c2ecf20Sopenharmony_ci if (ret) 5718c2ecf20Sopenharmony_ci goto exit_free_irq; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci netif_start_queue(dev); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci return 0; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ciexit_free_irq: 5788c2ecf20Sopenharmony_ci free_irq(dev->irq, dev); 5798c2ecf20Sopenharmony_ciexit_napi_disable: 5808c2ecf20Sopenharmony_ci napi_disable(&priv->napi); 5818c2ecf20Sopenharmony_ci close_candev(dev); 5828c2ecf20Sopenharmony_ciexit_dis_can_clock: 5838c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk_can); 5848c2ecf20Sopenharmony_ciexit_dis_ipg_clock: 5858c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk_ipg); 5868c2ecf20Sopenharmony_ciexit_retcode: 5878c2ecf20Sopenharmony_ci return ret; 5888c2ecf20Sopenharmony_ci} 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_cistatic int mscan_close(struct net_device *dev) 5918c2ecf20Sopenharmony_ci{ 5928c2ecf20Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 5938c2ecf20Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci netif_stop_queue(dev); 5968c2ecf20Sopenharmony_ci napi_disable(&priv->napi); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci out_8(®s->cantier, 0); 5998c2ecf20Sopenharmony_ci out_8(®s->canrier, 0); 6008c2ecf20Sopenharmony_ci mscan_set_mode(dev, MSCAN_INIT_MODE); 6018c2ecf20Sopenharmony_ci close_candev(dev); 6028c2ecf20Sopenharmony_ci free_irq(dev->irq, dev); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk_can); 6058c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk_ipg); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci return 0; 6088c2ecf20Sopenharmony_ci} 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_cistatic const struct net_device_ops mscan_netdev_ops = { 6118c2ecf20Sopenharmony_ci .ndo_open = mscan_open, 6128c2ecf20Sopenharmony_ci .ndo_stop = mscan_close, 6138c2ecf20Sopenharmony_ci .ndo_start_xmit = mscan_start_xmit, 6148c2ecf20Sopenharmony_ci .ndo_change_mtu = can_change_mtu, 6158c2ecf20Sopenharmony_ci}; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ciint register_mscandev(struct net_device *dev, int mscan_clksrc) 6188c2ecf20Sopenharmony_ci{ 6198c2ecf20Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 6208c2ecf20Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 6218c2ecf20Sopenharmony_ci u8 ctl1; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci ctl1 = in_8(®s->canctl1); 6248c2ecf20Sopenharmony_ci if (mscan_clksrc) 6258c2ecf20Sopenharmony_ci ctl1 |= MSCAN_CLKSRC; 6268c2ecf20Sopenharmony_ci else 6278c2ecf20Sopenharmony_ci ctl1 &= ~MSCAN_CLKSRC; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci if (priv->type == MSCAN_TYPE_MPC5121) { 6308c2ecf20Sopenharmony_ci priv->can.do_get_berr_counter = mscan_get_berr_counter; 6318c2ecf20Sopenharmony_ci ctl1 |= MSCAN_BORM; /* bus-off recovery upon request */ 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci ctl1 |= MSCAN_CANE; 6358c2ecf20Sopenharmony_ci out_8(®s->canctl1, ctl1); 6368c2ecf20Sopenharmony_ci udelay(100); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci /* acceptance mask/acceptance code (accept everything) */ 6398c2ecf20Sopenharmony_ci out_be16(®s->canidar1_0, 0); 6408c2ecf20Sopenharmony_ci out_be16(®s->canidar3_2, 0); 6418c2ecf20Sopenharmony_ci out_be16(®s->canidar5_4, 0); 6428c2ecf20Sopenharmony_ci out_be16(®s->canidar7_6, 0); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci out_be16(®s->canidmr1_0, 0xffff); 6458c2ecf20Sopenharmony_ci out_be16(®s->canidmr3_2, 0xffff); 6468c2ecf20Sopenharmony_ci out_be16(®s->canidmr5_4, 0xffff); 6478c2ecf20Sopenharmony_ci out_be16(®s->canidmr7_6, 0xffff); 6488c2ecf20Sopenharmony_ci /* Two 32 bit Acceptance Filters */ 6498c2ecf20Sopenharmony_ci out_8(®s->canidac, MSCAN_AF_32BIT); 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci mscan_set_mode(dev, MSCAN_INIT_MODE); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci return register_candev(dev); 6548c2ecf20Sopenharmony_ci} 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_civoid unregister_mscandev(struct net_device *dev) 6578c2ecf20Sopenharmony_ci{ 6588c2ecf20Sopenharmony_ci struct mscan_priv *priv = netdev_priv(dev); 6598c2ecf20Sopenharmony_ci struct mscan_regs __iomem *regs = priv->reg_base; 6608c2ecf20Sopenharmony_ci mscan_set_mode(dev, MSCAN_INIT_MODE); 6618c2ecf20Sopenharmony_ci clrbits8(®s->canctl1, MSCAN_CANE); 6628c2ecf20Sopenharmony_ci unregister_candev(dev); 6638c2ecf20Sopenharmony_ci} 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_cistruct net_device *alloc_mscandev(void) 6668c2ecf20Sopenharmony_ci{ 6678c2ecf20Sopenharmony_ci struct net_device *dev; 6688c2ecf20Sopenharmony_ci struct mscan_priv *priv; 6698c2ecf20Sopenharmony_ci int i; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci dev = alloc_candev(sizeof(struct mscan_priv), MSCAN_ECHO_SKB_MAX); 6728c2ecf20Sopenharmony_ci if (!dev) 6738c2ecf20Sopenharmony_ci return NULL; 6748c2ecf20Sopenharmony_ci priv = netdev_priv(dev); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci dev->netdev_ops = &mscan_netdev_ops; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci dev->flags |= IFF_ECHO; /* we support local echo */ 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci netif_napi_add(dev, &priv->napi, mscan_rx_poll, 8); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci priv->can.bittiming_const = &mscan_bittiming_const; 6838c2ecf20Sopenharmony_ci priv->can.do_set_bittiming = mscan_do_set_bittiming; 6848c2ecf20Sopenharmony_ci priv->can.do_set_mode = mscan_do_set_mode; 6858c2ecf20Sopenharmony_ci priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | 6868c2ecf20Sopenharmony_ci CAN_CTRLMODE_LISTENONLY; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci for (i = 0; i < TX_QUEUE_SIZE; i++) { 6898c2ecf20Sopenharmony_ci priv->tx_queue[i].id = i; 6908c2ecf20Sopenharmony_ci priv->tx_queue[i].mask = 1 << i; 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci return dev; 6948c2ecf20Sopenharmony_ci} 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andrey Volkov <avolkov@varma-el.com>"); 6978c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 6988c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("CAN port driver for a MSCAN based chips"); 699