18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* Xilinx CAN device driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2012 - 2014 Xilinx, Inc. 58c2ecf20Sopenharmony_ci * Copyright (C) 2009 PetaLogix. All rights reserved. 68c2ecf20Sopenharmony_ci * Copyright (C) 2017 - 2018 Sandvik Mining and Construction Oy 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Description: 98c2ecf20Sopenharmony_ci * This driver is developed for Axi CAN IP and for Zynq CANPS Controller. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/clk.h> 138c2ecf20Sopenharmony_ci#include <linux/errno.h> 148c2ecf20Sopenharmony_ci#include <linux/init.h> 158c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 168c2ecf20Sopenharmony_ci#include <linux/io.h> 178c2ecf20Sopenharmony_ci#include <linux/kernel.h> 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 208c2ecf20Sopenharmony_ci#include <linux/of.h> 218c2ecf20Sopenharmony_ci#include <linux/of_device.h> 228c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 238c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 248c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 258c2ecf20Sopenharmony_ci#include <linux/string.h> 268c2ecf20Sopenharmony_ci#include <linux/types.h> 278c2ecf20Sopenharmony_ci#include <linux/can/dev.h> 288c2ecf20Sopenharmony_ci#include <linux/can/error.h> 298c2ecf20Sopenharmony_ci#include <linux/can/led.h> 308c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define DRIVER_NAME "xilinx_can" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* CAN registers set */ 358c2ecf20Sopenharmony_cienum xcan_reg { 368c2ecf20Sopenharmony_ci XCAN_SRR_OFFSET = 0x00, /* Software reset */ 378c2ecf20Sopenharmony_ci XCAN_MSR_OFFSET = 0x04, /* Mode select */ 388c2ecf20Sopenharmony_ci XCAN_BRPR_OFFSET = 0x08, /* Baud rate prescaler */ 398c2ecf20Sopenharmony_ci XCAN_BTR_OFFSET = 0x0C, /* Bit timing */ 408c2ecf20Sopenharmony_ci XCAN_ECR_OFFSET = 0x10, /* Error counter */ 418c2ecf20Sopenharmony_ci XCAN_ESR_OFFSET = 0x14, /* Error status */ 428c2ecf20Sopenharmony_ci XCAN_SR_OFFSET = 0x18, /* Status */ 438c2ecf20Sopenharmony_ci XCAN_ISR_OFFSET = 0x1C, /* Interrupt status */ 448c2ecf20Sopenharmony_ci XCAN_IER_OFFSET = 0x20, /* Interrupt enable */ 458c2ecf20Sopenharmony_ci XCAN_ICR_OFFSET = 0x24, /* Interrupt clear */ 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci /* not on CAN FD cores */ 488c2ecf20Sopenharmony_ci XCAN_TXFIFO_OFFSET = 0x30, /* TX FIFO base */ 498c2ecf20Sopenharmony_ci XCAN_RXFIFO_OFFSET = 0x50, /* RX FIFO base */ 508c2ecf20Sopenharmony_ci XCAN_AFR_OFFSET = 0x60, /* Acceptance Filter */ 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci /* only on CAN FD cores */ 538c2ecf20Sopenharmony_ci XCAN_F_BRPR_OFFSET = 0x088, /* Data Phase Baud Rate 548c2ecf20Sopenharmony_ci * Prescalar 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_ci XCAN_F_BTR_OFFSET = 0x08C, /* Data Phase Bit Timing */ 578c2ecf20Sopenharmony_ci XCAN_TRR_OFFSET = 0x0090, /* TX Buffer Ready Request */ 588c2ecf20Sopenharmony_ci XCAN_AFR_EXT_OFFSET = 0x00E0, /* Acceptance Filter */ 598c2ecf20Sopenharmony_ci XCAN_FSR_OFFSET = 0x00E8, /* RX FIFO Status */ 608c2ecf20Sopenharmony_ci XCAN_TXMSG_BASE_OFFSET = 0x0100, /* TX Message Space */ 618c2ecf20Sopenharmony_ci XCAN_RXMSG_BASE_OFFSET = 0x1100, /* RX Message Space */ 628c2ecf20Sopenharmony_ci XCAN_RXMSG_2_BASE_OFFSET = 0x2100, /* RX Message Space */ 638c2ecf20Sopenharmony_ci XCAN_AFR_2_MASK_OFFSET = 0x0A00, /* Acceptance Filter MASK */ 648c2ecf20Sopenharmony_ci XCAN_AFR_2_ID_OFFSET = 0x0A04, /* Acceptance Filter ID */ 658c2ecf20Sopenharmony_ci}; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#define XCAN_FRAME_ID_OFFSET(frame_base) ((frame_base) + 0x00) 688c2ecf20Sopenharmony_ci#define XCAN_FRAME_DLC_OFFSET(frame_base) ((frame_base) + 0x04) 698c2ecf20Sopenharmony_ci#define XCAN_FRAME_DW1_OFFSET(frame_base) ((frame_base) + 0x08) 708c2ecf20Sopenharmony_ci#define XCAN_FRAME_DW2_OFFSET(frame_base) ((frame_base) + 0x0C) 718c2ecf20Sopenharmony_ci#define XCANFD_FRAME_DW_OFFSET(frame_base) ((frame_base) + 0x08) 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci#define XCAN_CANFD_FRAME_SIZE 0x48 748c2ecf20Sopenharmony_ci#define XCAN_TXMSG_FRAME_OFFSET(n) (XCAN_TXMSG_BASE_OFFSET + \ 758c2ecf20Sopenharmony_ci XCAN_CANFD_FRAME_SIZE * (n)) 768c2ecf20Sopenharmony_ci#define XCAN_RXMSG_FRAME_OFFSET(n) (XCAN_RXMSG_BASE_OFFSET + \ 778c2ecf20Sopenharmony_ci XCAN_CANFD_FRAME_SIZE * (n)) 788c2ecf20Sopenharmony_ci#define XCAN_RXMSG_2_FRAME_OFFSET(n) (XCAN_RXMSG_2_BASE_OFFSET + \ 798c2ecf20Sopenharmony_ci XCAN_CANFD_FRAME_SIZE * (n)) 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/* the single TX mailbox used by this driver on CAN FD HW */ 828c2ecf20Sopenharmony_ci#define XCAN_TX_MAILBOX_IDX 0 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* CAN register bit masks - XCAN_<REG>_<BIT>_MASK */ 858c2ecf20Sopenharmony_ci#define XCAN_SRR_CEN_MASK 0x00000002 /* CAN enable */ 868c2ecf20Sopenharmony_ci#define XCAN_SRR_RESET_MASK 0x00000001 /* Soft Reset the CAN core */ 878c2ecf20Sopenharmony_ci#define XCAN_MSR_LBACK_MASK 0x00000002 /* Loop back mode select */ 888c2ecf20Sopenharmony_ci#define XCAN_MSR_SLEEP_MASK 0x00000001 /* Sleep mode select */ 898c2ecf20Sopenharmony_ci#define XCAN_BRPR_BRP_MASK 0x000000FF /* Baud rate prescaler */ 908c2ecf20Sopenharmony_ci#define XCAN_BTR_SJW_MASK 0x00000180 /* Synchronous jump width */ 918c2ecf20Sopenharmony_ci#define XCAN_BTR_TS2_MASK 0x00000070 /* Time segment 2 */ 928c2ecf20Sopenharmony_ci#define XCAN_BTR_TS1_MASK 0x0000000F /* Time segment 1 */ 938c2ecf20Sopenharmony_ci#define XCAN_BTR_SJW_MASK_CANFD 0x000F0000 /* Synchronous jump width */ 948c2ecf20Sopenharmony_ci#define XCAN_BTR_TS2_MASK_CANFD 0x00000F00 /* Time segment 2 */ 958c2ecf20Sopenharmony_ci#define XCAN_BTR_TS1_MASK_CANFD 0x0000003F /* Time segment 1 */ 968c2ecf20Sopenharmony_ci#define XCAN_ECR_REC_MASK 0x0000FF00 /* Receive error counter */ 978c2ecf20Sopenharmony_ci#define XCAN_ECR_TEC_MASK 0x000000FF /* Transmit error counter */ 988c2ecf20Sopenharmony_ci#define XCAN_ESR_ACKER_MASK 0x00000010 /* ACK error */ 998c2ecf20Sopenharmony_ci#define XCAN_ESR_BERR_MASK 0x00000008 /* Bit error */ 1008c2ecf20Sopenharmony_ci#define XCAN_ESR_STER_MASK 0x00000004 /* Stuff error */ 1018c2ecf20Sopenharmony_ci#define XCAN_ESR_FMER_MASK 0x00000002 /* Form error */ 1028c2ecf20Sopenharmony_ci#define XCAN_ESR_CRCER_MASK 0x00000001 /* CRC error */ 1038c2ecf20Sopenharmony_ci#define XCAN_SR_TXFLL_MASK 0x00000400 /* TX FIFO is full */ 1048c2ecf20Sopenharmony_ci#define XCAN_SR_ESTAT_MASK 0x00000180 /* Error status */ 1058c2ecf20Sopenharmony_ci#define XCAN_SR_ERRWRN_MASK 0x00000040 /* Error warning */ 1068c2ecf20Sopenharmony_ci#define XCAN_SR_NORMAL_MASK 0x00000008 /* Normal mode */ 1078c2ecf20Sopenharmony_ci#define XCAN_SR_LBACK_MASK 0x00000002 /* Loop back mode */ 1088c2ecf20Sopenharmony_ci#define XCAN_SR_CONFIG_MASK 0x00000001 /* Configuration mode */ 1098c2ecf20Sopenharmony_ci#define XCAN_IXR_RXMNF_MASK 0x00020000 /* RX match not finished */ 1108c2ecf20Sopenharmony_ci#define XCAN_IXR_TXFEMP_MASK 0x00004000 /* TX FIFO Empty */ 1118c2ecf20Sopenharmony_ci#define XCAN_IXR_WKUP_MASK 0x00000800 /* Wake up interrupt */ 1128c2ecf20Sopenharmony_ci#define XCAN_IXR_SLP_MASK 0x00000400 /* Sleep interrupt */ 1138c2ecf20Sopenharmony_ci#define XCAN_IXR_BSOFF_MASK 0x00000200 /* Bus off interrupt */ 1148c2ecf20Sopenharmony_ci#define XCAN_IXR_ERROR_MASK 0x00000100 /* Error interrupt */ 1158c2ecf20Sopenharmony_ci#define XCAN_IXR_RXNEMP_MASK 0x00000080 /* RX FIFO NotEmpty intr */ 1168c2ecf20Sopenharmony_ci#define XCAN_IXR_RXOFLW_MASK 0x00000040 /* RX FIFO Overflow intr */ 1178c2ecf20Sopenharmony_ci#define XCAN_IXR_RXOK_MASK 0x00000010 /* Message received intr */ 1188c2ecf20Sopenharmony_ci#define XCAN_IXR_TXFLL_MASK 0x00000004 /* Tx FIFO Full intr */ 1198c2ecf20Sopenharmony_ci#define XCAN_IXR_TXOK_MASK 0x00000002 /* TX successful intr */ 1208c2ecf20Sopenharmony_ci#define XCAN_IXR_ARBLST_MASK 0x00000001 /* Arbitration lost intr */ 1218c2ecf20Sopenharmony_ci#define XCAN_IDR_ID1_MASK 0xFFE00000 /* Standard msg identifier */ 1228c2ecf20Sopenharmony_ci#define XCAN_IDR_SRR_MASK 0x00100000 /* Substitute remote TXreq */ 1238c2ecf20Sopenharmony_ci#define XCAN_IDR_IDE_MASK 0x00080000 /* Identifier extension */ 1248c2ecf20Sopenharmony_ci#define XCAN_IDR_ID2_MASK 0x0007FFFE /* Extended message ident */ 1258c2ecf20Sopenharmony_ci#define XCAN_IDR_RTR_MASK 0x00000001 /* Remote TX request */ 1268c2ecf20Sopenharmony_ci#define XCAN_DLCR_DLC_MASK 0xF0000000 /* Data length code */ 1278c2ecf20Sopenharmony_ci#define XCAN_FSR_FL_MASK 0x00003F00 /* RX Fill Level */ 1288c2ecf20Sopenharmony_ci#define XCAN_2_FSR_FL_MASK 0x00007F00 /* RX Fill Level */ 1298c2ecf20Sopenharmony_ci#define XCAN_FSR_IRI_MASK 0x00000080 /* RX Increment Read Index */ 1308c2ecf20Sopenharmony_ci#define XCAN_FSR_RI_MASK 0x0000001F /* RX Read Index */ 1318c2ecf20Sopenharmony_ci#define XCAN_2_FSR_RI_MASK 0x0000003F /* RX Read Index */ 1328c2ecf20Sopenharmony_ci#define XCAN_DLCR_EDL_MASK 0x08000000 /* EDL Mask in DLC */ 1338c2ecf20Sopenharmony_ci#define XCAN_DLCR_BRS_MASK 0x04000000 /* BRS Mask in DLC */ 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci/* CAN register bit shift - XCAN_<REG>_<BIT>_SHIFT */ 1368c2ecf20Sopenharmony_ci#define XCAN_BTR_SJW_SHIFT 7 /* Synchronous jump width */ 1378c2ecf20Sopenharmony_ci#define XCAN_BTR_TS2_SHIFT 4 /* Time segment 2 */ 1388c2ecf20Sopenharmony_ci#define XCAN_BTR_SJW_SHIFT_CANFD 16 /* Synchronous jump width */ 1398c2ecf20Sopenharmony_ci#define XCAN_BTR_TS2_SHIFT_CANFD 8 /* Time segment 2 */ 1408c2ecf20Sopenharmony_ci#define XCAN_IDR_ID1_SHIFT 21 /* Standard Messg Identifier */ 1418c2ecf20Sopenharmony_ci#define XCAN_IDR_ID2_SHIFT 1 /* Extended Message Identifier */ 1428c2ecf20Sopenharmony_ci#define XCAN_DLCR_DLC_SHIFT 28 /* Data length code */ 1438c2ecf20Sopenharmony_ci#define XCAN_ESR_REC_SHIFT 8 /* Rx Error Count */ 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci/* CAN frame length constants */ 1468c2ecf20Sopenharmony_ci#define XCAN_FRAME_MAX_DATA_LEN 8 1478c2ecf20Sopenharmony_ci#define XCANFD_DW_BYTES 4 1488c2ecf20Sopenharmony_ci#define XCAN_TIMEOUT (1 * HZ) 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci/* TX-FIFO-empty interrupt available */ 1518c2ecf20Sopenharmony_ci#define XCAN_FLAG_TXFEMP 0x0001 1528c2ecf20Sopenharmony_ci/* RX Match Not Finished interrupt available */ 1538c2ecf20Sopenharmony_ci#define XCAN_FLAG_RXMNF 0x0002 1548c2ecf20Sopenharmony_ci/* Extended acceptance filters with control at 0xE0 */ 1558c2ecf20Sopenharmony_ci#define XCAN_FLAG_EXT_FILTERS 0x0004 1568c2ecf20Sopenharmony_ci/* TX mailboxes instead of TX FIFO */ 1578c2ecf20Sopenharmony_ci#define XCAN_FLAG_TX_MAILBOXES 0x0008 1588c2ecf20Sopenharmony_ci/* RX FIFO with each buffer in separate registers at 0x1100 1598c2ecf20Sopenharmony_ci * instead of the regular FIFO at 0x50 1608c2ecf20Sopenharmony_ci */ 1618c2ecf20Sopenharmony_ci#define XCAN_FLAG_RX_FIFO_MULTI 0x0010 1628c2ecf20Sopenharmony_ci#define XCAN_FLAG_CANFD_2 0x0020 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cienum xcan_ip_type { 1658c2ecf20Sopenharmony_ci XAXI_CAN = 0, 1668c2ecf20Sopenharmony_ci XZYNQ_CANPS, 1678c2ecf20Sopenharmony_ci XAXI_CANFD, 1688c2ecf20Sopenharmony_ci XAXI_CANFD_2_0, 1698c2ecf20Sopenharmony_ci}; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistruct xcan_devtype_data { 1728c2ecf20Sopenharmony_ci enum xcan_ip_type cantype; 1738c2ecf20Sopenharmony_ci unsigned int flags; 1748c2ecf20Sopenharmony_ci const struct can_bittiming_const *bittiming_const; 1758c2ecf20Sopenharmony_ci const char *bus_clk_name; 1768c2ecf20Sopenharmony_ci unsigned int btr_ts2_shift; 1778c2ecf20Sopenharmony_ci unsigned int btr_sjw_shift; 1788c2ecf20Sopenharmony_ci}; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci/** 1818c2ecf20Sopenharmony_ci * struct xcan_priv - This definition define CAN driver instance 1828c2ecf20Sopenharmony_ci * @can: CAN private data structure. 1838c2ecf20Sopenharmony_ci * @tx_lock: Lock for synchronizing TX interrupt handling 1848c2ecf20Sopenharmony_ci * @tx_head: Tx CAN packets ready to send on the queue 1858c2ecf20Sopenharmony_ci * @tx_tail: Tx CAN packets successfully sended on the queue 1868c2ecf20Sopenharmony_ci * @tx_max: Maximum number packets the driver can send 1878c2ecf20Sopenharmony_ci * @napi: NAPI structure 1888c2ecf20Sopenharmony_ci * @read_reg: For reading data from CAN registers 1898c2ecf20Sopenharmony_ci * @write_reg: For writing data to CAN registers 1908c2ecf20Sopenharmony_ci * @dev: Network device data structure 1918c2ecf20Sopenharmony_ci * @reg_base: Ioremapped address to registers 1928c2ecf20Sopenharmony_ci * @irq_flags: For request_irq() 1938c2ecf20Sopenharmony_ci * @bus_clk: Pointer to struct clk 1948c2ecf20Sopenharmony_ci * @can_clk: Pointer to struct clk 1958c2ecf20Sopenharmony_ci * @devtype: Device type specific constants 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_cistruct xcan_priv { 1988c2ecf20Sopenharmony_ci struct can_priv can; 1998c2ecf20Sopenharmony_ci spinlock_t tx_lock; /* Lock for synchronizing TX interrupt handling */ 2008c2ecf20Sopenharmony_ci unsigned int tx_head; 2018c2ecf20Sopenharmony_ci unsigned int tx_tail; 2028c2ecf20Sopenharmony_ci unsigned int tx_max; 2038c2ecf20Sopenharmony_ci struct napi_struct napi; 2048c2ecf20Sopenharmony_ci u32 (*read_reg)(const struct xcan_priv *priv, enum xcan_reg reg); 2058c2ecf20Sopenharmony_ci void (*write_reg)(const struct xcan_priv *priv, enum xcan_reg reg, 2068c2ecf20Sopenharmony_ci u32 val); 2078c2ecf20Sopenharmony_ci struct device *dev; 2088c2ecf20Sopenharmony_ci void __iomem *reg_base; 2098c2ecf20Sopenharmony_ci unsigned long irq_flags; 2108c2ecf20Sopenharmony_ci struct clk *bus_clk; 2118c2ecf20Sopenharmony_ci struct clk *can_clk; 2128c2ecf20Sopenharmony_ci struct xcan_devtype_data devtype; 2138c2ecf20Sopenharmony_ci}; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci/* CAN Bittiming constants as per Xilinx CAN specs */ 2168c2ecf20Sopenharmony_cistatic const struct can_bittiming_const xcan_bittiming_const = { 2178c2ecf20Sopenharmony_ci .name = DRIVER_NAME, 2188c2ecf20Sopenharmony_ci .tseg1_min = 1, 2198c2ecf20Sopenharmony_ci .tseg1_max = 16, 2208c2ecf20Sopenharmony_ci .tseg2_min = 1, 2218c2ecf20Sopenharmony_ci .tseg2_max = 8, 2228c2ecf20Sopenharmony_ci .sjw_max = 4, 2238c2ecf20Sopenharmony_ci .brp_min = 1, 2248c2ecf20Sopenharmony_ci .brp_max = 256, 2258c2ecf20Sopenharmony_ci .brp_inc = 1, 2268c2ecf20Sopenharmony_ci}; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci/* AXI CANFD Arbitration Bittiming constants as per AXI CANFD 1.0 spec */ 2298c2ecf20Sopenharmony_cistatic const struct can_bittiming_const xcan_bittiming_const_canfd = { 2308c2ecf20Sopenharmony_ci .name = DRIVER_NAME, 2318c2ecf20Sopenharmony_ci .tseg1_min = 1, 2328c2ecf20Sopenharmony_ci .tseg1_max = 64, 2338c2ecf20Sopenharmony_ci .tseg2_min = 1, 2348c2ecf20Sopenharmony_ci .tseg2_max = 16, 2358c2ecf20Sopenharmony_ci .sjw_max = 16, 2368c2ecf20Sopenharmony_ci .brp_min = 1, 2378c2ecf20Sopenharmony_ci .brp_max = 256, 2388c2ecf20Sopenharmony_ci .brp_inc = 1, 2398c2ecf20Sopenharmony_ci}; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci/* AXI CANFD Data Bittiming constants as per AXI CANFD 1.0 specs */ 2428c2ecf20Sopenharmony_cistatic const struct can_bittiming_const xcan_data_bittiming_const_canfd = { 2438c2ecf20Sopenharmony_ci .name = DRIVER_NAME, 2448c2ecf20Sopenharmony_ci .tseg1_min = 1, 2458c2ecf20Sopenharmony_ci .tseg1_max = 16, 2468c2ecf20Sopenharmony_ci .tseg2_min = 1, 2478c2ecf20Sopenharmony_ci .tseg2_max = 8, 2488c2ecf20Sopenharmony_ci .sjw_max = 8, 2498c2ecf20Sopenharmony_ci .brp_min = 1, 2508c2ecf20Sopenharmony_ci .brp_max = 256, 2518c2ecf20Sopenharmony_ci .brp_inc = 1, 2528c2ecf20Sopenharmony_ci}; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci/* AXI CANFD 2.0 Arbitration Bittiming constants as per AXI CANFD 2.0 spec */ 2558c2ecf20Sopenharmony_cistatic const struct can_bittiming_const xcan_bittiming_const_canfd2 = { 2568c2ecf20Sopenharmony_ci .name = DRIVER_NAME, 2578c2ecf20Sopenharmony_ci .tseg1_min = 1, 2588c2ecf20Sopenharmony_ci .tseg1_max = 256, 2598c2ecf20Sopenharmony_ci .tseg2_min = 1, 2608c2ecf20Sopenharmony_ci .tseg2_max = 128, 2618c2ecf20Sopenharmony_ci .sjw_max = 128, 2628c2ecf20Sopenharmony_ci .brp_min = 1, 2638c2ecf20Sopenharmony_ci .brp_max = 256, 2648c2ecf20Sopenharmony_ci .brp_inc = 1, 2658c2ecf20Sopenharmony_ci}; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci/* AXI CANFD 2.0 Data Bittiming constants as per AXI CANFD 2.0 spec */ 2688c2ecf20Sopenharmony_cistatic const struct can_bittiming_const xcan_data_bittiming_const_canfd2 = { 2698c2ecf20Sopenharmony_ci .name = DRIVER_NAME, 2708c2ecf20Sopenharmony_ci .tseg1_min = 1, 2718c2ecf20Sopenharmony_ci .tseg1_max = 32, 2728c2ecf20Sopenharmony_ci .tseg2_min = 1, 2738c2ecf20Sopenharmony_ci .tseg2_max = 16, 2748c2ecf20Sopenharmony_ci .sjw_max = 16, 2758c2ecf20Sopenharmony_ci .brp_min = 1, 2768c2ecf20Sopenharmony_ci .brp_max = 256, 2778c2ecf20Sopenharmony_ci .brp_inc = 1, 2788c2ecf20Sopenharmony_ci}; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci/** 2818c2ecf20Sopenharmony_ci * xcan_write_reg_le - Write a value to the device register little endian 2828c2ecf20Sopenharmony_ci * @priv: Driver private data structure 2838c2ecf20Sopenharmony_ci * @reg: Register offset 2848c2ecf20Sopenharmony_ci * @val: Value to write at the Register offset 2858c2ecf20Sopenharmony_ci * 2868c2ecf20Sopenharmony_ci * Write data to the paricular CAN register 2878c2ecf20Sopenharmony_ci */ 2888c2ecf20Sopenharmony_cistatic void xcan_write_reg_le(const struct xcan_priv *priv, enum xcan_reg reg, 2898c2ecf20Sopenharmony_ci u32 val) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci iowrite32(val, priv->reg_base + reg); 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci/** 2958c2ecf20Sopenharmony_ci * xcan_read_reg_le - Read a value from the device register little endian 2968c2ecf20Sopenharmony_ci * @priv: Driver private data structure 2978c2ecf20Sopenharmony_ci * @reg: Register offset 2988c2ecf20Sopenharmony_ci * 2998c2ecf20Sopenharmony_ci * Read data from the particular CAN register 3008c2ecf20Sopenharmony_ci * Return: value read from the CAN register 3018c2ecf20Sopenharmony_ci */ 3028c2ecf20Sopenharmony_cistatic u32 xcan_read_reg_le(const struct xcan_priv *priv, enum xcan_reg reg) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci return ioread32(priv->reg_base + reg); 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci/** 3088c2ecf20Sopenharmony_ci * xcan_write_reg_be - Write a value to the device register big endian 3098c2ecf20Sopenharmony_ci * @priv: Driver private data structure 3108c2ecf20Sopenharmony_ci * @reg: Register offset 3118c2ecf20Sopenharmony_ci * @val: Value to write at the Register offset 3128c2ecf20Sopenharmony_ci * 3138c2ecf20Sopenharmony_ci * Write data to the paricular CAN register 3148c2ecf20Sopenharmony_ci */ 3158c2ecf20Sopenharmony_cistatic void xcan_write_reg_be(const struct xcan_priv *priv, enum xcan_reg reg, 3168c2ecf20Sopenharmony_ci u32 val) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci iowrite32be(val, priv->reg_base + reg); 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci/** 3228c2ecf20Sopenharmony_ci * xcan_read_reg_be - Read a value from the device register big endian 3238c2ecf20Sopenharmony_ci * @priv: Driver private data structure 3248c2ecf20Sopenharmony_ci * @reg: Register offset 3258c2ecf20Sopenharmony_ci * 3268c2ecf20Sopenharmony_ci * Read data from the particular CAN register 3278c2ecf20Sopenharmony_ci * Return: value read from the CAN register 3288c2ecf20Sopenharmony_ci */ 3298c2ecf20Sopenharmony_cistatic u32 xcan_read_reg_be(const struct xcan_priv *priv, enum xcan_reg reg) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci return ioread32be(priv->reg_base + reg); 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci/** 3358c2ecf20Sopenharmony_ci * xcan_rx_int_mask - Get the mask for the receive interrupt 3368c2ecf20Sopenharmony_ci * @priv: Driver private data structure 3378c2ecf20Sopenharmony_ci * 3388c2ecf20Sopenharmony_ci * Return: The receive interrupt mask used by the driver on this HW 3398c2ecf20Sopenharmony_ci */ 3408c2ecf20Sopenharmony_cistatic u32 xcan_rx_int_mask(const struct xcan_priv *priv) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci /* RXNEMP is better suited for our use case as it cannot be cleared 3438c2ecf20Sopenharmony_ci * while the FIFO is non-empty, but CAN FD HW does not have it 3448c2ecf20Sopenharmony_ci */ 3458c2ecf20Sopenharmony_ci if (priv->devtype.flags & XCAN_FLAG_RX_FIFO_MULTI) 3468c2ecf20Sopenharmony_ci return XCAN_IXR_RXOK_MASK; 3478c2ecf20Sopenharmony_ci else 3488c2ecf20Sopenharmony_ci return XCAN_IXR_RXNEMP_MASK; 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci/** 3528c2ecf20Sopenharmony_ci * set_reset_mode - Resets the CAN device mode 3538c2ecf20Sopenharmony_ci * @ndev: Pointer to net_device structure 3548c2ecf20Sopenharmony_ci * 3558c2ecf20Sopenharmony_ci * This is the driver reset mode routine.The driver 3568c2ecf20Sopenharmony_ci * enters into configuration mode. 3578c2ecf20Sopenharmony_ci * 3588c2ecf20Sopenharmony_ci * Return: 0 on success and failure value on error 3598c2ecf20Sopenharmony_ci */ 3608c2ecf20Sopenharmony_cistatic int set_reset_mode(struct net_device *ndev) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci struct xcan_priv *priv = netdev_priv(ndev); 3638c2ecf20Sopenharmony_ci unsigned long timeout; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci timeout = jiffies + XCAN_TIMEOUT; 3688c2ecf20Sopenharmony_ci while (!(priv->read_reg(priv, XCAN_SR_OFFSET) & XCAN_SR_CONFIG_MASK)) { 3698c2ecf20Sopenharmony_ci if (time_after(jiffies, timeout)) { 3708c2ecf20Sopenharmony_ci netdev_warn(ndev, "timed out for config mode\n"); 3718c2ecf20Sopenharmony_ci return -ETIMEDOUT; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci usleep_range(500, 10000); 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci /* reset clears FIFOs */ 3778c2ecf20Sopenharmony_ci priv->tx_head = 0; 3788c2ecf20Sopenharmony_ci priv->tx_tail = 0; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci return 0; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci/** 3848c2ecf20Sopenharmony_ci * xcan_set_bittiming - CAN set bit timing routine 3858c2ecf20Sopenharmony_ci * @ndev: Pointer to net_device structure 3868c2ecf20Sopenharmony_ci * 3878c2ecf20Sopenharmony_ci * This is the driver set bittiming routine. 3888c2ecf20Sopenharmony_ci * Return: 0 on success and failure value on error 3898c2ecf20Sopenharmony_ci */ 3908c2ecf20Sopenharmony_cistatic int xcan_set_bittiming(struct net_device *ndev) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci struct xcan_priv *priv = netdev_priv(ndev); 3938c2ecf20Sopenharmony_ci struct can_bittiming *bt = &priv->can.bittiming; 3948c2ecf20Sopenharmony_ci struct can_bittiming *dbt = &priv->can.data_bittiming; 3958c2ecf20Sopenharmony_ci u32 btr0, btr1; 3968c2ecf20Sopenharmony_ci u32 is_config_mode; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci /* Check whether Xilinx CAN is in configuration mode. 3998c2ecf20Sopenharmony_ci * It cannot set bit timing if Xilinx CAN is not in configuration mode. 4008c2ecf20Sopenharmony_ci */ 4018c2ecf20Sopenharmony_ci is_config_mode = priv->read_reg(priv, XCAN_SR_OFFSET) & 4028c2ecf20Sopenharmony_ci XCAN_SR_CONFIG_MASK; 4038c2ecf20Sopenharmony_ci if (!is_config_mode) { 4048c2ecf20Sopenharmony_ci netdev_alert(ndev, 4058c2ecf20Sopenharmony_ci "BUG! Cannot set bittiming - CAN is not in config mode\n"); 4068c2ecf20Sopenharmony_ci return -EPERM; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci /* Setting Baud Rate prescalar value in BRPR Register */ 4108c2ecf20Sopenharmony_ci btr0 = (bt->brp - 1); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci /* Setting Time Segment 1 in BTR Register */ 4138c2ecf20Sopenharmony_ci btr1 = (bt->prop_seg + bt->phase_seg1 - 1); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci /* Setting Time Segment 2 in BTR Register */ 4168c2ecf20Sopenharmony_ci btr1 |= (bt->phase_seg2 - 1) << priv->devtype.btr_ts2_shift; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci /* Setting Synchronous jump width in BTR Register */ 4198c2ecf20Sopenharmony_ci btr1 |= (bt->sjw - 1) << priv->devtype.btr_sjw_shift; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_BRPR_OFFSET, btr0); 4228c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_BTR_OFFSET, btr1); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci if (priv->devtype.cantype == XAXI_CANFD || 4258c2ecf20Sopenharmony_ci priv->devtype.cantype == XAXI_CANFD_2_0) { 4268c2ecf20Sopenharmony_ci /* Setting Baud Rate prescalar value in F_BRPR Register */ 4278c2ecf20Sopenharmony_ci btr0 = dbt->brp - 1; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci /* Setting Time Segment 1 in BTR Register */ 4308c2ecf20Sopenharmony_ci btr1 = dbt->prop_seg + dbt->phase_seg1 - 1; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci /* Setting Time Segment 2 in BTR Register */ 4338c2ecf20Sopenharmony_ci btr1 |= (dbt->phase_seg2 - 1) << priv->devtype.btr_ts2_shift; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci /* Setting Synchronous jump width in BTR Register */ 4368c2ecf20Sopenharmony_ci btr1 |= (dbt->sjw - 1) << priv->devtype.btr_sjw_shift; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_F_BRPR_OFFSET, btr0); 4398c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_F_BTR_OFFSET, btr1); 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci netdev_dbg(ndev, "BRPR=0x%08x, BTR=0x%08x\n", 4438c2ecf20Sopenharmony_ci priv->read_reg(priv, XCAN_BRPR_OFFSET), 4448c2ecf20Sopenharmony_ci priv->read_reg(priv, XCAN_BTR_OFFSET)); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci return 0; 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci/** 4508c2ecf20Sopenharmony_ci * xcan_chip_start - This the drivers start routine 4518c2ecf20Sopenharmony_ci * @ndev: Pointer to net_device structure 4528c2ecf20Sopenharmony_ci * 4538c2ecf20Sopenharmony_ci * This is the drivers start routine. 4548c2ecf20Sopenharmony_ci * Based on the State of the CAN device it puts 4558c2ecf20Sopenharmony_ci * the CAN device into a proper mode. 4568c2ecf20Sopenharmony_ci * 4578c2ecf20Sopenharmony_ci * Return: 0 on success and failure value on error 4588c2ecf20Sopenharmony_ci */ 4598c2ecf20Sopenharmony_cistatic int xcan_chip_start(struct net_device *ndev) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci struct xcan_priv *priv = netdev_priv(ndev); 4628c2ecf20Sopenharmony_ci u32 reg_msr; 4638c2ecf20Sopenharmony_ci int err; 4648c2ecf20Sopenharmony_ci u32 ier; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci /* Check if it is in reset mode */ 4678c2ecf20Sopenharmony_ci err = set_reset_mode(ndev); 4688c2ecf20Sopenharmony_ci if (err < 0) 4698c2ecf20Sopenharmony_ci return err; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci err = xcan_set_bittiming(ndev); 4728c2ecf20Sopenharmony_ci if (err < 0) 4738c2ecf20Sopenharmony_ci return err; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci /* Enable interrupts 4768c2ecf20Sopenharmony_ci * 4778c2ecf20Sopenharmony_ci * We enable the ERROR interrupt even with 4788c2ecf20Sopenharmony_ci * CAN_CTRLMODE_BERR_REPORTING disabled as there is no 4798c2ecf20Sopenharmony_ci * dedicated interrupt for a state change to 4808c2ecf20Sopenharmony_ci * ERROR_WARNING/ERROR_PASSIVE. 4818c2ecf20Sopenharmony_ci */ 4828c2ecf20Sopenharmony_ci ier = XCAN_IXR_TXOK_MASK | XCAN_IXR_BSOFF_MASK | 4838c2ecf20Sopenharmony_ci XCAN_IXR_WKUP_MASK | XCAN_IXR_SLP_MASK | 4848c2ecf20Sopenharmony_ci XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK | 4858c2ecf20Sopenharmony_ci XCAN_IXR_ARBLST_MASK | xcan_rx_int_mask(priv); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci if (priv->devtype.flags & XCAN_FLAG_RXMNF) 4888c2ecf20Sopenharmony_ci ier |= XCAN_IXR_RXMNF_MASK; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_IER_OFFSET, ier); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci /* Check whether it is loopback mode or normal mode */ 4938c2ecf20Sopenharmony_ci if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) 4948c2ecf20Sopenharmony_ci reg_msr = XCAN_MSR_LBACK_MASK; 4958c2ecf20Sopenharmony_ci else 4968c2ecf20Sopenharmony_ci reg_msr = 0x0; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci /* enable the first extended filter, if any, as cores with extended 4998c2ecf20Sopenharmony_ci * filtering default to non-receipt if all filters are disabled 5008c2ecf20Sopenharmony_ci */ 5018c2ecf20Sopenharmony_ci if (priv->devtype.flags & XCAN_FLAG_EXT_FILTERS) 5028c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_AFR_EXT_OFFSET, 0x00000001); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_MSR_OFFSET, reg_msr); 5058c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_CEN_MASK); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci netdev_dbg(ndev, "status:#x%08x\n", 5088c2ecf20Sopenharmony_ci priv->read_reg(priv, XCAN_SR_OFFSET)); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci priv->can.state = CAN_STATE_ERROR_ACTIVE; 5118c2ecf20Sopenharmony_ci return 0; 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci/** 5158c2ecf20Sopenharmony_ci * xcan_do_set_mode - This sets the mode of the driver 5168c2ecf20Sopenharmony_ci * @ndev: Pointer to net_device structure 5178c2ecf20Sopenharmony_ci * @mode: Tells the mode of the driver 5188c2ecf20Sopenharmony_ci * 5198c2ecf20Sopenharmony_ci * This check the drivers state and calls the 5208c2ecf20Sopenharmony_ci * the corresponding modes to set. 5218c2ecf20Sopenharmony_ci * 5228c2ecf20Sopenharmony_ci * Return: 0 on success and failure value on error 5238c2ecf20Sopenharmony_ci */ 5248c2ecf20Sopenharmony_cistatic int xcan_do_set_mode(struct net_device *ndev, enum can_mode mode) 5258c2ecf20Sopenharmony_ci{ 5268c2ecf20Sopenharmony_ci int ret; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci switch (mode) { 5298c2ecf20Sopenharmony_ci case CAN_MODE_START: 5308c2ecf20Sopenharmony_ci ret = xcan_chip_start(ndev); 5318c2ecf20Sopenharmony_ci if (ret < 0) { 5328c2ecf20Sopenharmony_ci netdev_err(ndev, "xcan_chip_start failed!\n"); 5338c2ecf20Sopenharmony_ci return ret; 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci netif_wake_queue(ndev); 5368c2ecf20Sopenharmony_ci break; 5378c2ecf20Sopenharmony_ci default: 5388c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 5398c2ecf20Sopenharmony_ci break; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci return ret; 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci/** 5468c2ecf20Sopenharmony_ci * xcan_write_frame - Write a frame to HW 5478c2ecf20Sopenharmony_ci * @ndev: Pointer to net_device structure 5488c2ecf20Sopenharmony_ci * @skb: sk_buff pointer that contains data to be Txed 5498c2ecf20Sopenharmony_ci * @frame_offset: Register offset to write the frame to 5508c2ecf20Sopenharmony_ci */ 5518c2ecf20Sopenharmony_cistatic void xcan_write_frame(struct net_device *ndev, struct sk_buff *skb, 5528c2ecf20Sopenharmony_ci int frame_offset) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci u32 id, dlc, data[2] = {0, 0}; 5558c2ecf20Sopenharmony_ci struct canfd_frame *cf = (struct canfd_frame *)skb->data; 5568c2ecf20Sopenharmony_ci u32 ramoff, dwindex = 0, i; 5578c2ecf20Sopenharmony_ci struct xcan_priv *priv = netdev_priv(ndev); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci /* Watch carefully on the bit sequence */ 5608c2ecf20Sopenharmony_ci if (cf->can_id & CAN_EFF_FLAG) { 5618c2ecf20Sopenharmony_ci /* Extended CAN ID format */ 5628c2ecf20Sopenharmony_ci id = ((cf->can_id & CAN_EFF_MASK) << XCAN_IDR_ID2_SHIFT) & 5638c2ecf20Sopenharmony_ci XCAN_IDR_ID2_MASK; 5648c2ecf20Sopenharmony_ci id |= (((cf->can_id & CAN_EFF_MASK) >> 5658c2ecf20Sopenharmony_ci (CAN_EFF_ID_BITS - CAN_SFF_ID_BITS)) << 5668c2ecf20Sopenharmony_ci XCAN_IDR_ID1_SHIFT) & XCAN_IDR_ID1_MASK; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci /* The substibute remote TX request bit should be "1" 5698c2ecf20Sopenharmony_ci * for extended frames as in the Xilinx CAN datasheet 5708c2ecf20Sopenharmony_ci */ 5718c2ecf20Sopenharmony_ci id |= XCAN_IDR_IDE_MASK | XCAN_IDR_SRR_MASK; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci if (cf->can_id & CAN_RTR_FLAG) 5748c2ecf20Sopenharmony_ci /* Extended frames remote TX request */ 5758c2ecf20Sopenharmony_ci id |= XCAN_IDR_RTR_MASK; 5768c2ecf20Sopenharmony_ci } else { 5778c2ecf20Sopenharmony_ci /* Standard CAN ID format */ 5788c2ecf20Sopenharmony_ci id = ((cf->can_id & CAN_SFF_MASK) << XCAN_IDR_ID1_SHIFT) & 5798c2ecf20Sopenharmony_ci XCAN_IDR_ID1_MASK; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci if (cf->can_id & CAN_RTR_FLAG) 5828c2ecf20Sopenharmony_ci /* Standard frames remote TX request */ 5838c2ecf20Sopenharmony_ci id |= XCAN_IDR_SRR_MASK; 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci dlc = can_len2dlc(cf->len) << XCAN_DLCR_DLC_SHIFT; 5878c2ecf20Sopenharmony_ci if (can_is_canfd_skb(skb)) { 5888c2ecf20Sopenharmony_ci if (cf->flags & CANFD_BRS) 5898c2ecf20Sopenharmony_ci dlc |= XCAN_DLCR_BRS_MASK; 5908c2ecf20Sopenharmony_ci dlc |= XCAN_DLCR_EDL_MASK; 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci if (!(priv->devtype.flags & XCAN_FLAG_TX_MAILBOXES) && 5948c2ecf20Sopenharmony_ci (priv->devtype.flags & XCAN_FLAG_TXFEMP)) 5958c2ecf20Sopenharmony_ci can_put_echo_skb(skb, ndev, priv->tx_head % priv->tx_max); 5968c2ecf20Sopenharmony_ci else 5978c2ecf20Sopenharmony_ci can_put_echo_skb(skb, ndev, 0); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci priv->tx_head++; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_FRAME_ID_OFFSET(frame_offset), id); 6028c2ecf20Sopenharmony_ci /* If the CAN frame is RTR frame this write triggers transmission 6038c2ecf20Sopenharmony_ci * (not on CAN FD) 6048c2ecf20Sopenharmony_ci */ 6058c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_FRAME_DLC_OFFSET(frame_offset), dlc); 6068c2ecf20Sopenharmony_ci if (priv->devtype.cantype == XAXI_CANFD || 6078c2ecf20Sopenharmony_ci priv->devtype.cantype == XAXI_CANFD_2_0) { 6088c2ecf20Sopenharmony_ci for (i = 0; i < cf->len; i += 4) { 6098c2ecf20Sopenharmony_ci ramoff = XCANFD_FRAME_DW_OFFSET(frame_offset) + 6108c2ecf20Sopenharmony_ci (dwindex * XCANFD_DW_BYTES); 6118c2ecf20Sopenharmony_ci priv->write_reg(priv, ramoff, 6128c2ecf20Sopenharmony_ci be32_to_cpup((__be32 *)(cf->data + i))); 6138c2ecf20Sopenharmony_ci dwindex++; 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci } else { 6168c2ecf20Sopenharmony_ci if (cf->len > 0) 6178c2ecf20Sopenharmony_ci data[0] = be32_to_cpup((__be32 *)(cf->data + 0)); 6188c2ecf20Sopenharmony_ci if (cf->len > 4) 6198c2ecf20Sopenharmony_ci data[1] = be32_to_cpup((__be32 *)(cf->data + 4)); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci if (!(cf->can_id & CAN_RTR_FLAG)) { 6228c2ecf20Sopenharmony_ci priv->write_reg(priv, 6238c2ecf20Sopenharmony_ci XCAN_FRAME_DW1_OFFSET(frame_offset), 6248c2ecf20Sopenharmony_ci data[0]); 6258c2ecf20Sopenharmony_ci /* If the CAN frame is Standard/Extended frame this 6268c2ecf20Sopenharmony_ci * write triggers transmission (not on CAN FD) 6278c2ecf20Sopenharmony_ci */ 6288c2ecf20Sopenharmony_ci priv->write_reg(priv, 6298c2ecf20Sopenharmony_ci XCAN_FRAME_DW2_OFFSET(frame_offset), 6308c2ecf20Sopenharmony_ci data[1]); 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci/** 6368c2ecf20Sopenharmony_ci * xcan_start_xmit_fifo - Starts the transmission (FIFO mode) 6378c2ecf20Sopenharmony_ci * @skb: sk_buff pointer that contains data to be Txed 6388c2ecf20Sopenharmony_ci * @ndev: Pointer to net_device structure 6398c2ecf20Sopenharmony_ci * 6408c2ecf20Sopenharmony_ci * Return: 0 on success, -ENOSPC if FIFO is full. 6418c2ecf20Sopenharmony_ci */ 6428c2ecf20Sopenharmony_cistatic int xcan_start_xmit_fifo(struct sk_buff *skb, struct net_device *ndev) 6438c2ecf20Sopenharmony_ci{ 6448c2ecf20Sopenharmony_ci struct xcan_priv *priv = netdev_priv(ndev); 6458c2ecf20Sopenharmony_ci unsigned long flags; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci /* Check if the TX buffer is full */ 6488c2ecf20Sopenharmony_ci if (unlikely(priv->read_reg(priv, XCAN_SR_OFFSET) & 6498c2ecf20Sopenharmony_ci XCAN_SR_TXFLL_MASK)) 6508c2ecf20Sopenharmony_ci return -ENOSPC; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->tx_lock, flags); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci xcan_write_frame(ndev, skb, XCAN_TXFIFO_OFFSET); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci /* Clear TX-FIFO-empty interrupt for xcan_tx_interrupt() */ 6578c2ecf20Sopenharmony_ci if (priv->tx_max > 1) 6588c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXFEMP_MASK); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci /* Check if the TX buffer is full */ 6618c2ecf20Sopenharmony_ci if ((priv->tx_head - priv->tx_tail) == priv->tx_max) 6628c2ecf20Sopenharmony_ci netif_stop_queue(ndev); 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->tx_lock, flags); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci return 0; 6678c2ecf20Sopenharmony_ci} 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci/** 6708c2ecf20Sopenharmony_ci * xcan_start_xmit_mailbox - Starts the transmission (mailbox mode) 6718c2ecf20Sopenharmony_ci * @skb: sk_buff pointer that contains data to be Txed 6728c2ecf20Sopenharmony_ci * @ndev: Pointer to net_device structure 6738c2ecf20Sopenharmony_ci * 6748c2ecf20Sopenharmony_ci * Return: 0 on success, -ENOSPC if there is no space 6758c2ecf20Sopenharmony_ci */ 6768c2ecf20Sopenharmony_cistatic int xcan_start_xmit_mailbox(struct sk_buff *skb, struct net_device *ndev) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci struct xcan_priv *priv = netdev_priv(ndev); 6798c2ecf20Sopenharmony_ci unsigned long flags; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci if (unlikely(priv->read_reg(priv, XCAN_TRR_OFFSET) & 6828c2ecf20Sopenharmony_ci BIT(XCAN_TX_MAILBOX_IDX))) 6838c2ecf20Sopenharmony_ci return -ENOSPC; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->tx_lock, flags); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci xcan_write_frame(ndev, skb, 6888c2ecf20Sopenharmony_ci XCAN_TXMSG_FRAME_OFFSET(XCAN_TX_MAILBOX_IDX)); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci /* Mark buffer as ready for transmit */ 6918c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_TRR_OFFSET, BIT(XCAN_TX_MAILBOX_IDX)); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci netif_stop_queue(ndev); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->tx_lock, flags); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci return 0; 6988c2ecf20Sopenharmony_ci} 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci/** 7018c2ecf20Sopenharmony_ci * xcan_start_xmit - Starts the transmission 7028c2ecf20Sopenharmony_ci * @skb: sk_buff pointer that contains data to be Txed 7038c2ecf20Sopenharmony_ci * @ndev: Pointer to net_device structure 7048c2ecf20Sopenharmony_ci * 7058c2ecf20Sopenharmony_ci * This function is invoked from upper layers to initiate transmission. 7068c2ecf20Sopenharmony_ci * 7078c2ecf20Sopenharmony_ci * Return: NETDEV_TX_OK on success and NETDEV_TX_BUSY when the tx queue is full 7088c2ecf20Sopenharmony_ci */ 7098c2ecf20Sopenharmony_cistatic netdev_tx_t xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev) 7108c2ecf20Sopenharmony_ci{ 7118c2ecf20Sopenharmony_ci struct xcan_priv *priv = netdev_priv(ndev); 7128c2ecf20Sopenharmony_ci int ret; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci if (can_dropped_invalid_skb(ndev, skb)) 7158c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci if (priv->devtype.flags & XCAN_FLAG_TX_MAILBOXES) 7188c2ecf20Sopenharmony_ci ret = xcan_start_xmit_mailbox(skb, ndev); 7198c2ecf20Sopenharmony_ci else 7208c2ecf20Sopenharmony_ci ret = xcan_start_xmit_fifo(skb, ndev); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci if (ret < 0) { 7238c2ecf20Sopenharmony_ci netdev_err(ndev, "BUG!, TX full when queue awake!\n"); 7248c2ecf20Sopenharmony_ci netif_stop_queue(ndev); 7258c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 7298c2ecf20Sopenharmony_ci} 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci/** 7328c2ecf20Sopenharmony_ci * xcan_rx - Is called from CAN isr to complete the received 7338c2ecf20Sopenharmony_ci * frame processing 7348c2ecf20Sopenharmony_ci * @ndev: Pointer to net_device structure 7358c2ecf20Sopenharmony_ci * @frame_base: Register offset to the frame to be read 7368c2ecf20Sopenharmony_ci * 7378c2ecf20Sopenharmony_ci * This function is invoked from the CAN isr(poll) to process the Rx frames. It 7388c2ecf20Sopenharmony_ci * does minimal processing and invokes "netif_receive_skb" to complete further 7398c2ecf20Sopenharmony_ci * processing. 7408c2ecf20Sopenharmony_ci * Return: 1 on success and 0 on failure. 7418c2ecf20Sopenharmony_ci */ 7428c2ecf20Sopenharmony_cistatic int xcan_rx(struct net_device *ndev, int frame_base) 7438c2ecf20Sopenharmony_ci{ 7448c2ecf20Sopenharmony_ci struct xcan_priv *priv = netdev_priv(ndev); 7458c2ecf20Sopenharmony_ci struct net_device_stats *stats = &ndev->stats; 7468c2ecf20Sopenharmony_ci struct can_frame *cf; 7478c2ecf20Sopenharmony_ci struct sk_buff *skb; 7488c2ecf20Sopenharmony_ci u32 id_xcan, dlc, data[2] = {0, 0}; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci skb = alloc_can_skb(ndev, &cf); 7518c2ecf20Sopenharmony_ci if (unlikely(!skb)) { 7528c2ecf20Sopenharmony_ci stats->rx_dropped++; 7538c2ecf20Sopenharmony_ci return 0; 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci /* Read a frame from Xilinx zynq CANPS */ 7578c2ecf20Sopenharmony_ci id_xcan = priv->read_reg(priv, XCAN_FRAME_ID_OFFSET(frame_base)); 7588c2ecf20Sopenharmony_ci dlc = priv->read_reg(priv, XCAN_FRAME_DLC_OFFSET(frame_base)) >> 7598c2ecf20Sopenharmony_ci XCAN_DLCR_DLC_SHIFT; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci /* Change Xilinx CAN data length format to socketCAN data format */ 7628c2ecf20Sopenharmony_ci cf->can_dlc = get_can_dlc(dlc); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci /* Change Xilinx CAN ID format to socketCAN ID format */ 7658c2ecf20Sopenharmony_ci if (id_xcan & XCAN_IDR_IDE_MASK) { 7668c2ecf20Sopenharmony_ci /* The received frame is an Extended format frame */ 7678c2ecf20Sopenharmony_ci cf->can_id = (id_xcan & XCAN_IDR_ID1_MASK) >> 3; 7688c2ecf20Sopenharmony_ci cf->can_id |= (id_xcan & XCAN_IDR_ID2_MASK) >> 7698c2ecf20Sopenharmony_ci XCAN_IDR_ID2_SHIFT; 7708c2ecf20Sopenharmony_ci cf->can_id |= CAN_EFF_FLAG; 7718c2ecf20Sopenharmony_ci if (id_xcan & XCAN_IDR_RTR_MASK) 7728c2ecf20Sopenharmony_ci cf->can_id |= CAN_RTR_FLAG; 7738c2ecf20Sopenharmony_ci } else { 7748c2ecf20Sopenharmony_ci /* The received frame is a standard format frame */ 7758c2ecf20Sopenharmony_ci cf->can_id = (id_xcan & XCAN_IDR_ID1_MASK) >> 7768c2ecf20Sopenharmony_ci XCAN_IDR_ID1_SHIFT; 7778c2ecf20Sopenharmony_ci if (id_xcan & XCAN_IDR_SRR_MASK) 7788c2ecf20Sopenharmony_ci cf->can_id |= CAN_RTR_FLAG; 7798c2ecf20Sopenharmony_ci } 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci /* DW1/DW2 must always be read to remove message from RXFIFO */ 7828c2ecf20Sopenharmony_ci data[0] = priv->read_reg(priv, XCAN_FRAME_DW1_OFFSET(frame_base)); 7838c2ecf20Sopenharmony_ci data[1] = priv->read_reg(priv, XCAN_FRAME_DW2_OFFSET(frame_base)); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci if (!(cf->can_id & CAN_RTR_FLAG)) { 7868c2ecf20Sopenharmony_ci /* Change Xilinx CAN data format to socketCAN data format */ 7878c2ecf20Sopenharmony_ci if (cf->can_dlc > 0) 7888c2ecf20Sopenharmony_ci *(__be32 *)(cf->data) = cpu_to_be32(data[0]); 7898c2ecf20Sopenharmony_ci if (cf->can_dlc > 4) 7908c2ecf20Sopenharmony_ci *(__be32 *)(cf->data + 4) = cpu_to_be32(data[1]); 7918c2ecf20Sopenharmony_ci } 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci stats->rx_bytes += cf->can_dlc; 7948c2ecf20Sopenharmony_ci stats->rx_packets++; 7958c2ecf20Sopenharmony_ci netif_receive_skb(skb); 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci return 1; 7988c2ecf20Sopenharmony_ci} 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci/** 8018c2ecf20Sopenharmony_ci * xcanfd_rx - Is called from CAN isr to complete the received 8028c2ecf20Sopenharmony_ci * frame processing 8038c2ecf20Sopenharmony_ci * @ndev: Pointer to net_device structure 8048c2ecf20Sopenharmony_ci * @frame_base: Register offset to the frame to be read 8058c2ecf20Sopenharmony_ci * 8068c2ecf20Sopenharmony_ci * This function is invoked from the CAN isr(poll) to process the Rx frames. It 8078c2ecf20Sopenharmony_ci * does minimal processing and invokes "netif_receive_skb" to complete further 8088c2ecf20Sopenharmony_ci * processing. 8098c2ecf20Sopenharmony_ci * Return: 1 on success and 0 on failure. 8108c2ecf20Sopenharmony_ci */ 8118c2ecf20Sopenharmony_cistatic int xcanfd_rx(struct net_device *ndev, int frame_base) 8128c2ecf20Sopenharmony_ci{ 8138c2ecf20Sopenharmony_ci struct xcan_priv *priv = netdev_priv(ndev); 8148c2ecf20Sopenharmony_ci struct net_device_stats *stats = &ndev->stats; 8158c2ecf20Sopenharmony_ci struct canfd_frame *cf; 8168c2ecf20Sopenharmony_ci struct sk_buff *skb; 8178c2ecf20Sopenharmony_ci u32 id_xcan, dlc, data[2] = {0, 0}, dwindex = 0, i, dw_offset; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci id_xcan = priv->read_reg(priv, XCAN_FRAME_ID_OFFSET(frame_base)); 8208c2ecf20Sopenharmony_ci dlc = priv->read_reg(priv, XCAN_FRAME_DLC_OFFSET(frame_base)); 8218c2ecf20Sopenharmony_ci if (dlc & XCAN_DLCR_EDL_MASK) 8228c2ecf20Sopenharmony_ci skb = alloc_canfd_skb(ndev, &cf); 8238c2ecf20Sopenharmony_ci else 8248c2ecf20Sopenharmony_ci skb = alloc_can_skb(ndev, (struct can_frame **)&cf); 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci if (unlikely(!skb)) { 8278c2ecf20Sopenharmony_ci stats->rx_dropped++; 8288c2ecf20Sopenharmony_ci return 0; 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci /* Change Xilinx CANFD data length format to socketCAN data 8328c2ecf20Sopenharmony_ci * format 8338c2ecf20Sopenharmony_ci */ 8348c2ecf20Sopenharmony_ci if (dlc & XCAN_DLCR_EDL_MASK) 8358c2ecf20Sopenharmony_ci cf->len = can_dlc2len((dlc & XCAN_DLCR_DLC_MASK) >> 8368c2ecf20Sopenharmony_ci XCAN_DLCR_DLC_SHIFT); 8378c2ecf20Sopenharmony_ci else 8388c2ecf20Sopenharmony_ci cf->len = get_can_dlc((dlc & XCAN_DLCR_DLC_MASK) >> 8398c2ecf20Sopenharmony_ci XCAN_DLCR_DLC_SHIFT); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci /* Change Xilinx CAN ID format to socketCAN ID format */ 8428c2ecf20Sopenharmony_ci if (id_xcan & XCAN_IDR_IDE_MASK) { 8438c2ecf20Sopenharmony_ci /* The received frame is an Extended format frame */ 8448c2ecf20Sopenharmony_ci cf->can_id = (id_xcan & XCAN_IDR_ID1_MASK) >> 3; 8458c2ecf20Sopenharmony_ci cf->can_id |= (id_xcan & XCAN_IDR_ID2_MASK) >> 8468c2ecf20Sopenharmony_ci XCAN_IDR_ID2_SHIFT; 8478c2ecf20Sopenharmony_ci cf->can_id |= CAN_EFF_FLAG; 8488c2ecf20Sopenharmony_ci if (id_xcan & XCAN_IDR_RTR_MASK) 8498c2ecf20Sopenharmony_ci cf->can_id |= CAN_RTR_FLAG; 8508c2ecf20Sopenharmony_ci } else { 8518c2ecf20Sopenharmony_ci /* The received frame is a standard format frame */ 8528c2ecf20Sopenharmony_ci cf->can_id = (id_xcan & XCAN_IDR_ID1_MASK) >> 8538c2ecf20Sopenharmony_ci XCAN_IDR_ID1_SHIFT; 8548c2ecf20Sopenharmony_ci if (!(dlc & XCAN_DLCR_EDL_MASK) && (id_xcan & 8558c2ecf20Sopenharmony_ci XCAN_IDR_SRR_MASK)) 8568c2ecf20Sopenharmony_ci cf->can_id |= CAN_RTR_FLAG; 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci /* Check the frame received is FD or not*/ 8608c2ecf20Sopenharmony_ci if (dlc & XCAN_DLCR_EDL_MASK) { 8618c2ecf20Sopenharmony_ci for (i = 0; i < cf->len; i += 4) { 8628c2ecf20Sopenharmony_ci dw_offset = XCANFD_FRAME_DW_OFFSET(frame_base) + 8638c2ecf20Sopenharmony_ci (dwindex * XCANFD_DW_BYTES); 8648c2ecf20Sopenharmony_ci data[0] = priv->read_reg(priv, dw_offset); 8658c2ecf20Sopenharmony_ci *(__be32 *)(cf->data + i) = cpu_to_be32(data[0]); 8668c2ecf20Sopenharmony_ci dwindex++; 8678c2ecf20Sopenharmony_ci } 8688c2ecf20Sopenharmony_ci } else { 8698c2ecf20Sopenharmony_ci for (i = 0; i < cf->len; i += 4) { 8708c2ecf20Sopenharmony_ci dw_offset = XCANFD_FRAME_DW_OFFSET(frame_base); 8718c2ecf20Sopenharmony_ci data[0] = priv->read_reg(priv, dw_offset + i); 8728c2ecf20Sopenharmony_ci *(__be32 *)(cf->data + i) = cpu_to_be32(data[0]); 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci stats->rx_bytes += cf->len; 8768c2ecf20Sopenharmony_ci stats->rx_packets++; 8778c2ecf20Sopenharmony_ci netif_receive_skb(skb); 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci return 1; 8808c2ecf20Sopenharmony_ci} 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci/** 8838c2ecf20Sopenharmony_ci * xcan_current_error_state - Get current error state from HW 8848c2ecf20Sopenharmony_ci * @ndev: Pointer to net_device structure 8858c2ecf20Sopenharmony_ci * 8868c2ecf20Sopenharmony_ci * Checks the current CAN error state from the HW. Note that this 8878c2ecf20Sopenharmony_ci * only checks for ERROR_PASSIVE and ERROR_WARNING. 8888c2ecf20Sopenharmony_ci * 8898c2ecf20Sopenharmony_ci * Return: 8908c2ecf20Sopenharmony_ci * ERROR_PASSIVE or ERROR_WARNING if either is active, ERROR_ACTIVE 8918c2ecf20Sopenharmony_ci * otherwise. 8928c2ecf20Sopenharmony_ci */ 8938c2ecf20Sopenharmony_cistatic enum can_state xcan_current_error_state(struct net_device *ndev) 8948c2ecf20Sopenharmony_ci{ 8958c2ecf20Sopenharmony_ci struct xcan_priv *priv = netdev_priv(ndev); 8968c2ecf20Sopenharmony_ci u32 status = priv->read_reg(priv, XCAN_SR_OFFSET); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci if ((status & XCAN_SR_ESTAT_MASK) == XCAN_SR_ESTAT_MASK) 8998c2ecf20Sopenharmony_ci return CAN_STATE_ERROR_PASSIVE; 9008c2ecf20Sopenharmony_ci else if (status & XCAN_SR_ERRWRN_MASK) 9018c2ecf20Sopenharmony_ci return CAN_STATE_ERROR_WARNING; 9028c2ecf20Sopenharmony_ci else 9038c2ecf20Sopenharmony_ci return CAN_STATE_ERROR_ACTIVE; 9048c2ecf20Sopenharmony_ci} 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci/** 9078c2ecf20Sopenharmony_ci * xcan_set_error_state - Set new CAN error state 9088c2ecf20Sopenharmony_ci * @ndev: Pointer to net_device structure 9098c2ecf20Sopenharmony_ci * @new_state: The new CAN state to be set 9108c2ecf20Sopenharmony_ci * @cf: Error frame to be populated or NULL 9118c2ecf20Sopenharmony_ci * 9128c2ecf20Sopenharmony_ci * Set new CAN error state for the device, updating statistics and 9138c2ecf20Sopenharmony_ci * populating the error frame if given. 9148c2ecf20Sopenharmony_ci */ 9158c2ecf20Sopenharmony_cistatic void xcan_set_error_state(struct net_device *ndev, 9168c2ecf20Sopenharmony_ci enum can_state new_state, 9178c2ecf20Sopenharmony_ci struct can_frame *cf) 9188c2ecf20Sopenharmony_ci{ 9198c2ecf20Sopenharmony_ci struct xcan_priv *priv = netdev_priv(ndev); 9208c2ecf20Sopenharmony_ci u32 ecr = priv->read_reg(priv, XCAN_ECR_OFFSET); 9218c2ecf20Sopenharmony_ci u32 txerr = ecr & XCAN_ECR_TEC_MASK; 9228c2ecf20Sopenharmony_ci u32 rxerr = (ecr & XCAN_ECR_REC_MASK) >> XCAN_ESR_REC_SHIFT; 9238c2ecf20Sopenharmony_ci enum can_state tx_state = txerr >= rxerr ? new_state : 0; 9248c2ecf20Sopenharmony_ci enum can_state rx_state = txerr <= rxerr ? new_state : 0; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci /* non-ERROR states are handled elsewhere */ 9278c2ecf20Sopenharmony_ci if (WARN_ON(new_state > CAN_STATE_ERROR_PASSIVE)) 9288c2ecf20Sopenharmony_ci return; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci can_change_state(ndev, cf, tx_state, rx_state); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci if (cf) { 9338c2ecf20Sopenharmony_ci cf->data[6] = txerr; 9348c2ecf20Sopenharmony_ci cf->data[7] = rxerr; 9358c2ecf20Sopenharmony_ci } 9368c2ecf20Sopenharmony_ci} 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci/** 9398c2ecf20Sopenharmony_ci * xcan_update_error_state_after_rxtx - Update CAN error state after RX/TX 9408c2ecf20Sopenharmony_ci * @ndev: Pointer to net_device structure 9418c2ecf20Sopenharmony_ci * 9428c2ecf20Sopenharmony_ci * If the device is in a ERROR-WARNING or ERROR-PASSIVE state, check if 9438c2ecf20Sopenharmony_ci * the performed RX/TX has caused it to drop to a lesser state and set 9448c2ecf20Sopenharmony_ci * the interface state accordingly. 9458c2ecf20Sopenharmony_ci */ 9468c2ecf20Sopenharmony_cistatic void xcan_update_error_state_after_rxtx(struct net_device *ndev) 9478c2ecf20Sopenharmony_ci{ 9488c2ecf20Sopenharmony_ci struct xcan_priv *priv = netdev_priv(ndev); 9498c2ecf20Sopenharmony_ci enum can_state old_state = priv->can.state; 9508c2ecf20Sopenharmony_ci enum can_state new_state; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci /* changing error state due to successful frame RX/TX can only 9538c2ecf20Sopenharmony_ci * occur from these states 9548c2ecf20Sopenharmony_ci */ 9558c2ecf20Sopenharmony_ci if (old_state != CAN_STATE_ERROR_WARNING && 9568c2ecf20Sopenharmony_ci old_state != CAN_STATE_ERROR_PASSIVE) 9578c2ecf20Sopenharmony_ci return; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci new_state = xcan_current_error_state(ndev); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci if (new_state != old_state) { 9628c2ecf20Sopenharmony_ci struct sk_buff *skb; 9638c2ecf20Sopenharmony_ci struct can_frame *cf; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci skb = alloc_can_err_skb(ndev, &cf); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci xcan_set_error_state(ndev, new_state, skb ? cf : NULL); 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci if (skb) { 9708c2ecf20Sopenharmony_ci struct net_device_stats *stats = &ndev->stats; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci stats->rx_packets++; 9738c2ecf20Sopenharmony_ci stats->rx_bytes += cf->can_dlc; 9748c2ecf20Sopenharmony_ci netif_rx(skb); 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci } 9778c2ecf20Sopenharmony_ci} 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci/** 9808c2ecf20Sopenharmony_ci * xcan_err_interrupt - error frame Isr 9818c2ecf20Sopenharmony_ci * @ndev: net_device pointer 9828c2ecf20Sopenharmony_ci * @isr: interrupt status register value 9838c2ecf20Sopenharmony_ci * 9848c2ecf20Sopenharmony_ci * This is the CAN error interrupt and it will 9858c2ecf20Sopenharmony_ci * check the the type of error and forward the error 9868c2ecf20Sopenharmony_ci * frame to upper layers. 9878c2ecf20Sopenharmony_ci */ 9888c2ecf20Sopenharmony_cistatic void xcan_err_interrupt(struct net_device *ndev, u32 isr) 9898c2ecf20Sopenharmony_ci{ 9908c2ecf20Sopenharmony_ci struct xcan_priv *priv = netdev_priv(ndev); 9918c2ecf20Sopenharmony_ci struct net_device_stats *stats = &ndev->stats; 9928c2ecf20Sopenharmony_ci struct can_frame cf = { }; 9938c2ecf20Sopenharmony_ci u32 err_status; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci err_status = priv->read_reg(priv, XCAN_ESR_OFFSET); 9968c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_ESR_OFFSET, err_status); 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci if (isr & XCAN_IXR_BSOFF_MASK) { 9998c2ecf20Sopenharmony_ci priv->can.state = CAN_STATE_BUS_OFF; 10008c2ecf20Sopenharmony_ci priv->can.can_stats.bus_off++; 10018c2ecf20Sopenharmony_ci /* Leave device in Config Mode in bus-off state */ 10028c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK); 10038c2ecf20Sopenharmony_ci can_bus_off(ndev); 10048c2ecf20Sopenharmony_ci cf.can_id |= CAN_ERR_BUSOFF; 10058c2ecf20Sopenharmony_ci } else { 10068c2ecf20Sopenharmony_ci enum can_state new_state = xcan_current_error_state(ndev); 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci if (new_state != priv->can.state) 10098c2ecf20Sopenharmony_ci xcan_set_error_state(ndev, new_state, &cf); 10108c2ecf20Sopenharmony_ci } 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci /* Check for Arbitration lost interrupt */ 10138c2ecf20Sopenharmony_ci if (isr & XCAN_IXR_ARBLST_MASK) { 10148c2ecf20Sopenharmony_ci priv->can.can_stats.arbitration_lost++; 10158c2ecf20Sopenharmony_ci cf.can_id |= CAN_ERR_LOSTARB; 10168c2ecf20Sopenharmony_ci cf.data[0] = CAN_ERR_LOSTARB_UNSPEC; 10178c2ecf20Sopenharmony_ci } 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci /* Check for RX FIFO Overflow interrupt */ 10208c2ecf20Sopenharmony_ci if (isr & XCAN_IXR_RXOFLW_MASK) { 10218c2ecf20Sopenharmony_ci stats->rx_over_errors++; 10228c2ecf20Sopenharmony_ci stats->rx_errors++; 10238c2ecf20Sopenharmony_ci cf.can_id |= CAN_ERR_CRTL; 10248c2ecf20Sopenharmony_ci cf.data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci /* Check for RX Match Not Finished interrupt */ 10288c2ecf20Sopenharmony_ci if (isr & XCAN_IXR_RXMNF_MASK) { 10298c2ecf20Sopenharmony_ci stats->rx_dropped++; 10308c2ecf20Sopenharmony_ci stats->rx_errors++; 10318c2ecf20Sopenharmony_ci netdev_err(ndev, "RX match not finished, frame discarded\n"); 10328c2ecf20Sopenharmony_ci cf.can_id |= CAN_ERR_CRTL; 10338c2ecf20Sopenharmony_ci cf.data[1] |= CAN_ERR_CRTL_UNSPEC; 10348c2ecf20Sopenharmony_ci } 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci /* Check for error interrupt */ 10378c2ecf20Sopenharmony_ci if (isr & XCAN_IXR_ERROR_MASK) { 10388c2ecf20Sopenharmony_ci bool berr_reporting = false; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) { 10418c2ecf20Sopenharmony_ci berr_reporting = true; 10428c2ecf20Sopenharmony_ci cf.can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; 10438c2ecf20Sopenharmony_ci } 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci /* Check for Ack error interrupt */ 10468c2ecf20Sopenharmony_ci if (err_status & XCAN_ESR_ACKER_MASK) { 10478c2ecf20Sopenharmony_ci stats->tx_errors++; 10488c2ecf20Sopenharmony_ci if (berr_reporting) { 10498c2ecf20Sopenharmony_ci cf.can_id |= CAN_ERR_ACK; 10508c2ecf20Sopenharmony_ci cf.data[3] = CAN_ERR_PROT_LOC_ACK; 10518c2ecf20Sopenharmony_ci } 10528c2ecf20Sopenharmony_ci } 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci /* Check for Bit error interrupt */ 10558c2ecf20Sopenharmony_ci if (err_status & XCAN_ESR_BERR_MASK) { 10568c2ecf20Sopenharmony_ci stats->tx_errors++; 10578c2ecf20Sopenharmony_ci if (berr_reporting) { 10588c2ecf20Sopenharmony_ci cf.can_id |= CAN_ERR_PROT; 10598c2ecf20Sopenharmony_ci cf.data[2] = CAN_ERR_PROT_BIT; 10608c2ecf20Sopenharmony_ci } 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci /* Check for Stuff error interrupt */ 10648c2ecf20Sopenharmony_ci if (err_status & XCAN_ESR_STER_MASK) { 10658c2ecf20Sopenharmony_ci stats->rx_errors++; 10668c2ecf20Sopenharmony_ci if (berr_reporting) { 10678c2ecf20Sopenharmony_ci cf.can_id |= CAN_ERR_PROT; 10688c2ecf20Sopenharmony_ci cf.data[2] = CAN_ERR_PROT_STUFF; 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci /* Check for Form error interrupt */ 10738c2ecf20Sopenharmony_ci if (err_status & XCAN_ESR_FMER_MASK) { 10748c2ecf20Sopenharmony_ci stats->rx_errors++; 10758c2ecf20Sopenharmony_ci if (berr_reporting) { 10768c2ecf20Sopenharmony_ci cf.can_id |= CAN_ERR_PROT; 10778c2ecf20Sopenharmony_ci cf.data[2] = CAN_ERR_PROT_FORM; 10788c2ecf20Sopenharmony_ci } 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci /* Check for CRC error interrupt */ 10828c2ecf20Sopenharmony_ci if (err_status & XCAN_ESR_CRCER_MASK) { 10838c2ecf20Sopenharmony_ci stats->rx_errors++; 10848c2ecf20Sopenharmony_ci if (berr_reporting) { 10858c2ecf20Sopenharmony_ci cf.can_id |= CAN_ERR_PROT; 10868c2ecf20Sopenharmony_ci cf.data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; 10878c2ecf20Sopenharmony_ci } 10888c2ecf20Sopenharmony_ci } 10898c2ecf20Sopenharmony_ci priv->can.can_stats.bus_error++; 10908c2ecf20Sopenharmony_ci } 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci if (cf.can_id) { 10938c2ecf20Sopenharmony_ci struct can_frame *skb_cf; 10948c2ecf20Sopenharmony_ci struct sk_buff *skb = alloc_can_err_skb(ndev, &skb_cf); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci if (skb) { 10978c2ecf20Sopenharmony_ci skb_cf->can_id |= cf.can_id; 10988c2ecf20Sopenharmony_ci memcpy(skb_cf->data, cf.data, CAN_ERR_DLC); 10998c2ecf20Sopenharmony_ci stats->rx_packets++; 11008c2ecf20Sopenharmony_ci stats->rx_bytes += CAN_ERR_DLC; 11018c2ecf20Sopenharmony_ci netif_rx(skb); 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci netdev_dbg(ndev, "%s: error status register:0x%x\n", 11068c2ecf20Sopenharmony_ci __func__, priv->read_reg(priv, XCAN_ESR_OFFSET)); 11078c2ecf20Sopenharmony_ci} 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci/** 11108c2ecf20Sopenharmony_ci * xcan_state_interrupt - It will check the state of the CAN device 11118c2ecf20Sopenharmony_ci * @ndev: net_device pointer 11128c2ecf20Sopenharmony_ci * @isr: interrupt status register value 11138c2ecf20Sopenharmony_ci * 11148c2ecf20Sopenharmony_ci * This will checks the state of the CAN device 11158c2ecf20Sopenharmony_ci * and puts the device into appropriate state. 11168c2ecf20Sopenharmony_ci */ 11178c2ecf20Sopenharmony_cistatic void xcan_state_interrupt(struct net_device *ndev, u32 isr) 11188c2ecf20Sopenharmony_ci{ 11198c2ecf20Sopenharmony_ci struct xcan_priv *priv = netdev_priv(ndev); 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci /* Check for Sleep interrupt if set put CAN device in sleep state */ 11228c2ecf20Sopenharmony_ci if (isr & XCAN_IXR_SLP_MASK) 11238c2ecf20Sopenharmony_ci priv->can.state = CAN_STATE_SLEEPING; 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci /* Check for Wake up interrupt if set put CAN device in Active state */ 11268c2ecf20Sopenharmony_ci if (isr & XCAN_IXR_WKUP_MASK) 11278c2ecf20Sopenharmony_ci priv->can.state = CAN_STATE_ERROR_ACTIVE; 11288c2ecf20Sopenharmony_ci} 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci/** 11318c2ecf20Sopenharmony_ci * xcan_rx_fifo_get_next_frame - Get register offset of next RX frame 11328c2ecf20Sopenharmony_ci * @priv: Driver private data structure 11338c2ecf20Sopenharmony_ci * 11348c2ecf20Sopenharmony_ci * Return: Register offset of the next frame in RX FIFO. 11358c2ecf20Sopenharmony_ci */ 11368c2ecf20Sopenharmony_cistatic int xcan_rx_fifo_get_next_frame(struct xcan_priv *priv) 11378c2ecf20Sopenharmony_ci{ 11388c2ecf20Sopenharmony_ci int offset; 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci if (priv->devtype.flags & XCAN_FLAG_RX_FIFO_MULTI) { 11418c2ecf20Sopenharmony_ci u32 fsr, mask; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci /* clear RXOK before the is-empty check so that any newly 11448c2ecf20Sopenharmony_ci * received frame will reassert it without a race 11458c2ecf20Sopenharmony_ci */ 11468c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_RXOK_MASK); 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci fsr = priv->read_reg(priv, XCAN_FSR_OFFSET); 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci /* check if RX FIFO is empty */ 11518c2ecf20Sopenharmony_ci if (priv->devtype.flags & XCAN_FLAG_CANFD_2) 11528c2ecf20Sopenharmony_ci mask = XCAN_2_FSR_FL_MASK; 11538c2ecf20Sopenharmony_ci else 11548c2ecf20Sopenharmony_ci mask = XCAN_FSR_FL_MASK; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci if (!(fsr & mask)) 11578c2ecf20Sopenharmony_ci return -ENOENT; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci if (priv->devtype.flags & XCAN_FLAG_CANFD_2) 11608c2ecf20Sopenharmony_ci offset = 11618c2ecf20Sopenharmony_ci XCAN_RXMSG_2_FRAME_OFFSET(fsr & XCAN_2_FSR_RI_MASK); 11628c2ecf20Sopenharmony_ci else 11638c2ecf20Sopenharmony_ci offset = 11648c2ecf20Sopenharmony_ci XCAN_RXMSG_FRAME_OFFSET(fsr & XCAN_FSR_RI_MASK); 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci } else { 11678c2ecf20Sopenharmony_ci /* check if RX FIFO is empty */ 11688c2ecf20Sopenharmony_ci if (!(priv->read_reg(priv, XCAN_ISR_OFFSET) & 11698c2ecf20Sopenharmony_ci XCAN_IXR_RXNEMP_MASK)) 11708c2ecf20Sopenharmony_ci return -ENOENT; 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci /* frames are read from a static offset */ 11738c2ecf20Sopenharmony_ci offset = XCAN_RXFIFO_OFFSET; 11748c2ecf20Sopenharmony_ci } 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci return offset; 11778c2ecf20Sopenharmony_ci} 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci/** 11808c2ecf20Sopenharmony_ci * xcan_rx_poll - Poll routine for rx packets (NAPI) 11818c2ecf20Sopenharmony_ci * @napi: napi structure pointer 11828c2ecf20Sopenharmony_ci * @quota: Max number of rx packets to be processed. 11838c2ecf20Sopenharmony_ci * 11848c2ecf20Sopenharmony_ci * This is the poll routine for rx part. 11858c2ecf20Sopenharmony_ci * It will process the packets maximux quota value. 11868c2ecf20Sopenharmony_ci * 11878c2ecf20Sopenharmony_ci * Return: number of packets received 11888c2ecf20Sopenharmony_ci */ 11898c2ecf20Sopenharmony_cistatic int xcan_rx_poll(struct napi_struct *napi, int quota) 11908c2ecf20Sopenharmony_ci{ 11918c2ecf20Sopenharmony_ci struct net_device *ndev = napi->dev; 11928c2ecf20Sopenharmony_ci struct xcan_priv *priv = netdev_priv(ndev); 11938c2ecf20Sopenharmony_ci u32 ier; 11948c2ecf20Sopenharmony_ci int work_done = 0; 11958c2ecf20Sopenharmony_ci int frame_offset; 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci while ((frame_offset = xcan_rx_fifo_get_next_frame(priv)) >= 0 && 11988c2ecf20Sopenharmony_ci (work_done < quota)) { 11998c2ecf20Sopenharmony_ci if (xcan_rx_int_mask(priv) & XCAN_IXR_RXOK_MASK) 12008c2ecf20Sopenharmony_ci work_done += xcanfd_rx(ndev, frame_offset); 12018c2ecf20Sopenharmony_ci else 12028c2ecf20Sopenharmony_ci work_done += xcan_rx(ndev, frame_offset); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci if (priv->devtype.flags & XCAN_FLAG_RX_FIFO_MULTI) 12058c2ecf20Sopenharmony_ci /* increment read index */ 12068c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_FSR_OFFSET, 12078c2ecf20Sopenharmony_ci XCAN_FSR_IRI_MASK); 12088c2ecf20Sopenharmony_ci else 12098c2ecf20Sopenharmony_ci /* clear rx-not-empty (will actually clear only if 12108c2ecf20Sopenharmony_ci * empty) 12118c2ecf20Sopenharmony_ci */ 12128c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_ICR_OFFSET, 12138c2ecf20Sopenharmony_ci XCAN_IXR_RXNEMP_MASK); 12148c2ecf20Sopenharmony_ci } 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci if (work_done) { 12178c2ecf20Sopenharmony_ci can_led_event(ndev, CAN_LED_EVENT_RX); 12188c2ecf20Sopenharmony_ci xcan_update_error_state_after_rxtx(ndev); 12198c2ecf20Sopenharmony_ci } 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci if (work_done < quota) { 12228c2ecf20Sopenharmony_ci napi_complete_done(napi, work_done); 12238c2ecf20Sopenharmony_ci ier = priv->read_reg(priv, XCAN_IER_OFFSET); 12248c2ecf20Sopenharmony_ci ier |= xcan_rx_int_mask(priv); 12258c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_IER_OFFSET, ier); 12268c2ecf20Sopenharmony_ci } 12278c2ecf20Sopenharmony_ci return work_done; 12288c2ecf20Sopenharmony_ci} 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci/** 12318c2ecf20Sopenharmony_ci * xcan_tx_interrupt - Tx Done Isr 12328c2ecf20Sopenharmony_ci * @ndev: net_device pointer 12338c2ecf20Sopenharmony_ci * @isr: Interrupt status register value 12348c2ecf20Sopenharmony_ci */ 12358c2ecf20Sopenharmony_cistatic void xcan_tx_interrupt(struct net_device *ndev, u32 isr) 12368c2ecf20Sopenharmony_ci{ 12378c2ecf20Sopenharmony_ci struct xcan_priv *priv = netdev_priv(ndev); 12388c2ecf20Sopenharmony_ci struct net_device_stats *stats = &ndev->stats; 12398c2ecf20Sopenharmony_ci unsigned int frames_in_fifo; 12408c2ecf20Sopenharmony_ci int frames_sent = 1; /* TXOK => at least 1 frame was sent */ 12418c2ecf20Sopenharmony_ci unsigned long flags; 12428c2ecf20Sopenharmony_ci int retries = 0; 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci /* Synchronize with xmit as we need to know the exact number 12458c2ecf20Sopenharmony_ci * of frames in the FIFO to stay in sync due to the TXFEMP 12468c2ecf20Sopenharmony_ci * handling. 12478c2ecf20Sopenharmony_ci * This also prevents a race between netif_wake_queue() and 12488c2ecf20Sopenharmony_ci * netif_stop_queue(). 12498c2ecf20Sopenharmony_ci */ 12508c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->tx_lock, flags); 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci frames_in_fifo = priv->tx_head - priv->tx_tail; 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(frames_in_fifo == 0)) { 12558c2ecf20Sopenharmony_ci /* clear TXOK anyway to avoid getting back here */ 12568c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXOK_MASK); 12578c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->tx_lock, flags); 12588c2ecf20Sopenharmony_ci return; 12598c2ecf20Sopenharmony_ci } 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci /* Check if 2 frames were sent (TXOK only means that at least 1 12628c2ecf20Sopenharmony_ci * frame was sent). 12638c2ecf20Sopenharmony_ci */ 12648c2ecf20Sopenharmony_ci if (frames_in_fifo > 1) { 12658c2ecf20Sopenharmony_ci WARN_ON(frames_in_fifo > priv->tx_max); 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci /* Synchronize TXOK and isr so that after the loop: 12688c2ecf20Sopenharmony_ci * (1) isr variable is up-to-date at least up to TXOK clear 12698c2ecf20Sopenharmony_ci * time. This avoids us clearing a TXOK of a second frame 12708c2ecf20Sopenharmony_ci * but not noticing that the FIFO is now empty and thus 12718c2ecf20Sopenharmony_ci * marking only a single frame as sent. 12728c2ecf20Sopenharmony_ci * (2) No TXOK is left. Having one could mean leaving a 12738c2ecf20Sopenharmony_ci * stray TXOK as we might process the associated frame 12748c2ecf20Sopenharmony_ci * via TXFEMP handling as we read TXFEMP *after* TXOK 12758c2ecf20Sopenharmony_ci * clear to satisfy (1). 12768c2ecf20Sopenharmony_ci */ 12778c2ecf20Sopenharmony_ci while ((isr & XCAN_IXR_TXOK_MASK) && 12788c2ecf20Sopenharmony_ci !WARN_ON(++retries == 100)) { 12798c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_ICR_OFFSET, 12808c2ecf20Sopenharmony_ci XCAN_IXR_TXOK_MASK); 12818c2ecf20Sopenharmony_ci isr = priv->read_reg(priv, XCAN_ISR_OFFSET); 12828c2ecf20Sopenharmony_ci } 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci if (isr & XCAN_IXR_TXFEMP_MASK) { 12858c2ecf20Sopenharmony_ci /* nothing in FIFO anymore */ 12868c2ecf20Sopenharmony_ci frames_sent = frames_in_fifo; 12878c2ecf20Sopenharmony_ci } 12888c2ecf20Sopenharmony_ci } else { 12898c2ecf20Sopenharmony_ci /* single frame in fifo, just clear TXOK */ 12908c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_TXOK_MASK); 12918c2ecf20Sopenharmony_ci } 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci while (frames_sent--) { 12948c2ecf20Sopenharmony_ci stats->tx_bytes += can_get_echo_skb(ndev, priv->tx_tail % 12958c2ecf20Sopenharmony_ci priv->tx_max); 12968c2ecf20Sopenharmony_ci priv->tx_tail++; 12978c2ecf20Sopenharmony_ci stats->tx_packets++; 12988c2ecf20Sopenharmony_ci } 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci netif_wake_queue(ndev); 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->tx_lock, flags); 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci can_led_event(ndev, CAN_LED_EVENT_TX); 13058c2ecf20Sopenharmony_ci xcan_update_error_state_after_rxtx(ndev); 13068c2ecf20Sopenharmony_ci} 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci/** 13098c2ecf20Sopenharmony_ci * xcan_interrupt - CAN Isr 13108c2ecf20Sopenharmony_ci * @irq: irq number 13118c2ecf20Sopenharmony_ci * @dev_id: device id pointer 13128c2ecf20Sopenharmony_ci * 13138c2ecf20Sopenharmony_ci * This is the xilinx CAN Isr. It checks for the type of interrupt 13148c2ecf20Sopenharmony_ci * and invokes the corresponding ISR. 13158c2ecf20Sopenharmony_ci * 13168c2ecf20Sopenharmony_ci * Return: 13178c2ecf20Sopenharmony_ci * IRQ_NONE - If CAN device is in sleep mode, IRQ_HANDLED otherwise 13188c2ecf20Sopenharmony_ci */ 13198c2ecf20Sopenharmony_cistatic irqreturn_t xcan_interrupt(int irq, void *dev_id) 13208c2ecf20Sopenharmony_ci{ 13218c2ecf20Sopenharmony_ci struct net_device *ndev = (struct net_device *)dev_id; 13228c2ecf20Sopenharmony_ci struct xcan_priv *priv = netdev_priv(ndev); 13238c2ecf20Sopenharmony_ci u32 isr, ier; 13248c2ecf20Sopenharmony_ci u32 isr_errors; 13258c2ecf20Sopenharmony_ci u32 rx_int_mask = xcan_rx_int_mask(priv); 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci /* Get the interrupt status from Xilinx CAN */ 13288c2ecf20Sopenharmony_ci isr = priv->read_reg(priv, XCAN_ISR_OFFSET); 13298c2ecf20Sopenharmony_ci if (!isr) 13308c2ecf20Sopenharmony_ci return IRQ_NONE; 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci /* Check for the type of interrupt and Processing it */ 13338c2ecf20Sopenharmony_ci if (isr & (XCAN_IXR_SLP_MASK | XCAN_IXR_WKUP_MASK)) { 13348c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_ICR_OFFSET, (XCAN_IXR_SLP_MASK | 13358c2ecf20Sopenharmony_ci XCAN_IXR_WKUP_MASK)); 13368c2ecf20Sopenharmony_ci xcan_state_interrupt(ndev, isr); 13378c2ecf20Sopenharmony_ci } 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci /* Check for Tx interrupt and Processing it */ 13408c2ecf20Sopenharmony_ci if (isr & XCAN_IXR_TXOK_MASK) 13418c2ecf20Sopenharmony_ci xcan_tx_interrupt(ndev, isr); 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci /* Check for the type of error interrupt and Processing it */ 13448c2ecf20Sopenharmony_ci isr_errors = isr & (XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK | 13458c2ecf20Sopenharmony_ci XCAN_IXR_BSOFF_MASK | XCAN_IXR_ARBLST_MASK | 13468c2ecf20Sopenharmony_ci XCAN_IXR_RXMNF_MASK); 13478c2ecf20Sopenharmony_ci if (isr_errors) { 13488c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_ICR_OFFSET, isr_errors); 13498c2ecf20Sopenharmony_ci xcan_err_interrupt(ndev, isr); 13508c2ecf20Sopenharmony_ci } 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci /* Check for the type of receive interrupt and Processing it */ 13538c2ecf20Sopenharmony_ci if (isr & rx_int_mask) { 13548c2ecf20Sopenharmony_ci ier = priv->read_reg(priv, XCAN_IER_OFFSET); 13558c2ecf20Sopenharmony_ci ier &= ~rx_int_mask; 13568c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_IER_OFFSET, ier); 13578c2ecf20Sopenharmony_ci napi_schedule(&priv->napi); 13588c2ecf20Sopenharmony_ci } 13598c2ecf20Sopenharmony_ci return IRQ_HANDLED; 13608c2ecf20Sopenharmony_ci} 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci/** 13638c2ecf20Sopenharmony_ci * xcan_chip_stop - Driver stop routine 13648c2ecf20Sopenharmony_ci * @ndev: Pointer to net_device structure 13658c2ecf20Sopenharmony_ci * 13668c2ecf20Sopenharmony_ci * This is the drivers stop routine. It will disable the 13678c2ecf20Sopenharmony_ci * interrupts and put the device into configuration mode. 13688c2ecf20Sopenharmony_ci */ 13698c2ecf20Sopenharmony_cistatic void xcan_chip_stop(struct net_device *ndev) 13708c2ecf20Sopenharmony_ci{ 13718c2ecf20Sopenharmony_ci struct xcan_priv *priv = netdev_priv(ndev); 13728c2ecf20Sopenharmony_ci int ret; 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci /* Disable interrupts and leave the can in configuration mode */ 13758c2ecf20Sopenharmony_ci ret = set_reset_mode(ndev); 13768c2ecf20Sopenharmony_ci if (ret < 0) 13778c2ecf20Sopenharmony_ci netdev_dbg(ndev, "set_reset_mode() Failed\n"); 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci priv->can.state = CAN_STATE_STOPPED; 13808c2ecf20Sopenharmony_ci} 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci/** 13838c2ecf20Sopenharmony_ci * xcan_open - Driver open routine 13848c2ecf20Sopenharmony_ci * @ndev: Pointer to net_device structure 13858c2ecf20Sopenharmony_ci * 13868c2ecf20Sopenharmony_ci * This is the driver open routine. 13878c2ecf20Sopenharmony_ci * Return: 0 on success and failure value on error 13888c2ecf20Sopenharmony_ci */ 13898c2ecf20Sopenharmony_cistatic int xcan_open(struct net_device *ndev) 13908c2ecf20Sopenharmony_ci{ 13918c2ecf20Sopenharmony_ci struct xcan_priv *priv = netdev_priv(ndev); 13928c2ecf20Sopenharmony_ci int ret; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(priv->dev); 13958c2ecf20Sopenharmony_ci if (ret < 0) { 13968c2ecf20Sopenharmony_ci netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n", 13978c2ecf20Sopenharmony_ci __func__, ret); 13988c2ecf20Sopenharmony_ci goto err; 13998c2ecf20Sopenharmony_ci } 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci ret = request_irq(ndev->irq, xcan_interrupt, priv->irq_flags, 14028c2ecf20Sopenharmony_ci ndev->name, ndev); 14038c2ecf20Sopenharmony_ci if (ret < 0) { 14048c2ecf20Sopenharmony_ci netdev_err(ndev, "irq allocation for CAN failed\n"); 14058c2ecf20Sopenharmony_ci goto err; 14068c2ecf20Sopenharmony_ci } 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci /* Set chip into reset mode */ 14098c2ecf20Sopenharmony_ci ret = set_reset_mode(ndev); 14108c2ecf20Sopenharmony_ci if (ret < 0) { 14118c2ecf20Sopenharmony_ci netdev_err(ndev, "mode resetting failed!\n"); 14128c2ecf20Sopenharmony_ci goto err_irq; 14138c2ecf20Sopenharmony_ci } 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci /* Common open */ 14168c2ecf20Sopenharmony_ci ret = open_candev(ndev); 14178c2ecf20Sopenharmony_ci if (ret) 14188c2ecf20Sopenharmony_ci goto err_irq; 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci ret = xcan_chip_start(ndev); 14218c2ecf20Sopenharmony_ci if (ret < 0) { 14228c2ecf20Sopenharmony_ci netdev_err(ndev, "xcan_chip_start failed!\n"); 14238c2ecf20Sopenharmony_ci goto err_candev; 14248c2ecf20Sopenharmony_ci } 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci can_led_event(ndev, CAN_LED_EVENT_OPEN); 14278c2ecf20Sopenharmony_ci napi_enable(&priv->napi); 14288c2ecf20Sopenharmony_ci netif_start_queue(ndev); 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci return 0; 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_cierr_candev: 14338c2ecf20Sopenharmony_ci close_candev(ndev); 14348c2ecf20Sopenharmony_cierr_irq: 14358c2ecf20Sopenharmony_ci free_irq(ndev->irq, ndev); 14368c2ecf20Sopenharmony_cierr: 14378c2ecf20Sopenharmony_ci pm_runtime_put(priv->dev); 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci return ret; 14408c2ecf20Sopenharmony_ci} 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci/** 14438c2ecf20Sopenharmony_ci * xcan_close - Driver close routine 14448c2ecf20Sopenharmony_ci * @ndev: Pointer to net_device structure 14458c2ecf20Sopenharmony_ci * 14468c2ecf20Sopenharmony_ci * Return: 0 always 14478c2ecf20Sopenharmony_ci */ 14488c2ecf20Sopenharmony_cistatic int xcan_close(struct net_device *ndev) 14498c2ecf20Sopenharmony_ci{ 14508c2ecf20Sopenharmony_ci struct xcan_priv *priv = netdev_priv(ndev); 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci netif_stop_queue(ndev); 14538c2ecf20Sopenharmony_ci napi_disable(&priv->napi); 14548c2ecf20Sopenharmony_ci xcan_chip_stop(ndev); 14558c2ecf20Sopenharmony_ci free_irq(ndev->irq, ndev); 14568c2ecf20Sopenharmony_ci close_candev(ndev); 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci can_led_event(ndev, CAN_LED_EVENT_STOP); 14598c2ecf20Sopenharmony_ci pm_runtime_put(priv->dev); 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci return 0; 14628c2ecf20Sopenharmony_ci} 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci/** 14658c2ecf20Sopenharmony_ci * xcan_get_berr_counter - error counter routine 14668c2ecf20Sopenharmony_ci * @ndev: Pointer to net_device structure 14678c2ecf20Sopenharmony_ci * @bec: Pointer to can_berr_counter structure 14688c2ecf20Sopenharmony_ci * 14698c2ecf20Sopenharmony_ci * This is the driver error counter routine. 14708c2ecf20Sopenharmony_ci * Return: 0 on success and failure value on error 14718c2ecf20Sopenharmony_ci */ 14728c2ecf20Sopenharmony_cistatic int xcan_get_berr_counter(const struct net_device *ndev, 14738c2ecf20Sopenharmony_ci struct can_berr_counter *bec) 14748c2ecf20Sopenharmony_ci{ 14758c2ecf20Sopenharmony_ci struct xcan_priv *priv = netdev_priv(ndev); 14768c2ecf20Sopenharmony_ci int ret; 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(priv->dev); 14798c2ecf20Sopenharmony_ci if (ret < 0) { 14808c2ecf20Sopenharmony_ci netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n", 14818c2ecf20Sopenharmony_ci __func__, ret); 14828c2ecf20Sopenharmony_ci pm_runtime_put(priv->dev); 14838c2ecf20Sopenharmony_ci return ret; 14848c2ecf20Sopenharmony_ci } 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci bec->txerr = priv->read_reg(priv, XCAN_ECR_OFFSET) & XCAN_ECR_TEC_MASK; 14878c2ecf20Sopenharmony_ci bec->rxerr = ((priv->read_reg(priv, XCAN_ECR_OFFSET) & 14888c2ecf20Sopenharmony_ci XCAN_ECR_REC_MASK) >> XCAN_ESR_REC_SHIFT); 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci pm_runtime_put(priv->dev); 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci return 0; 14938c2ecf20Sopenharmony_ci} 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_cistatic const struct net_device_ops xcan_netdev_ops = { 14968c2ecf20Sopenharmony_ci .ndo_open = xcan_open, 14978c2ecf20Sopenharmony_ci .ndo_stop = xcan_close, 14988c2ecf20Sopenharmony_ci .ndo_start_xmit = xcan_start_xmit, 14998c2ecf20Sopenharmony_ci .ndo_change_mtu = can_change_mtu, 15008c2ecf20Sopenharmony_ci}; 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci/** 15038c2ecf20Sopenharmony_ci * xcan_suspend - Suspend method for the driver 15048c2ecf20Sopenharmony_ci * @dev: Address of the device structure 15058c2ecf20Sopenharmony_ci * 15068c2ecf20Sopenharmony_ci * Put the driver into low power mode. 15078c2ecf20Sopenharmony_ci * Return: 0 on success and failure value on error 15088c2ecf20Sopenharmony_ci */ 15098c2ecf20Sopenharmony_cistatic int __maybe_unused xcan_suspend(struct device *dev) 15108c2ecf20Sopenharmony_ci{ 15118c2ecf20Sopenharmony_ci struct net_device *ndev = dev_get_drvdata(dev); 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci if (netif_running(ndev)) { 15148c2ecf20Sopenharmony_ci netif_stop_queue(ndev); 15158c2ecf20Sopenharmony_ci netif_device_detach(ndev); 15168c2ecf20Sopenharmony_ci xcan_chip_stop(ndev); 15178c2ecf20Sopenharmony_ci } 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci return pm_runtime_force_suspend(dev); 15208c2ecf20Sopenharmony_ci} 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci/** 15238c2ecf20Sopenharmony_ci * xcan_resume - Resume from suspend 15248c2ecf20Sopenharmony_ci * @dev: Address of the device structure 15258c2ecf20Sopenharmony_ci * 15268c2ecf20Sopenharmony_ci * Resume operation after suspend. 15278c2ecf20Sopenharmony_ci * Return: 0 on success and failure value on error 15288c2ecf20Sopenharmony_ci */ 15298c2ecf20Sopenharmony_cistatic int __maybe_unused xcan_resume(struct device *dev) 15308c2ecf20Sopenharmony_ci{ 15318c2ecf20Sopenharmony_ci struct net_device *ndev = dev_get_drvdata(dev); 15328c2ecf20Sopenharmony_ci int ret; 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci ret = pm_runtime_force_resume(dev); 15358c2ecf20Sopenharmony_ci if (ret) { 15368c2ecf20Sopenharmony_ci dev_err(dev, "pm_runtime_force_resume failed on resume\n"); 15378c2ecf20Sopenharmony_ci return ret; 15388c2ecf20Sopenharmony_ci } 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci if (netif_running(ndev)) { 15418c2ecf20Sopenharmony_ci ret = xcan_chip_start(ndev); 15428c2ecf20Sopenharmony_ci if (ret) { 15438c2ecf20Sopenharmony_ci dev_err(dev, "xcan_chip_start failed on resume\n"); 15448c2ecf20Sopenharmony_ci return ret; 15458c2ecf20Sopenharmony_ci } 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci netif_device_attach(ndev); 15488c2ecf20Sopenharmony_ci netif_start_queue(ndev); 15498c2ecf20Sopenharmony_ci } 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci return 0; 15528c2ecf20Sopenharmony_ci} 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci/** 15558c2ecf20Sopenharmony_ci * xcan_runtime_suspend - Runtime suspend method for the driver 15568c2ecf20Sopenharmony_ci * @dev: Address of the device structure 15578c2ecf20Sopenharmony_ci * 15588c2ecf20Sopenharmony_ci * Put the driver into low power mode. 15598c2ecf20Sopenharmony_ci * Return: 0 always 15608c2ecf20Sopenharmony_ci */ 15618c2ecf20Sopenharmony_cistatic int __maybe_unused xcan_runtime_suspend(struct device *dev) 15628c2ecf20Sopenharmony_ci{ 15638c2ecf20Sopenharmony_ci struct net_device *ndev = dev_get_drvdata(dev); 15648c2ecf20Sopenharmony_ci struct xcan_priv *priv = netdev_priv(ndev); 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->bus_clk); 15678c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->can_clk); 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci return 0; 15708c2ecf20Sopenharmony_ci} 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci/** 15738c2ecf20Sopenharmony_ci * xcan_runtime_resume - Runtime resume from suspend 15748c2ecf20Sopenharmony_ci * @dev: Address of the device structure 15758c2ecf20Sopenharmony_ci * 15768c2ecf20Sopenharmony_ci * Resume operation after suspend. 15778c2ecf20Sopenharmony_ci * Return: 0 on success and failure value on error 15788c2ecf20Sopenharmony_ci */ 15798c2ecf20Sopenharmony_cistatic int __maybe_unused xcan_runtime_resume(struct device *dev) 15808c2ecf20Sopenharmony_ci{ 15818c2ecf20Sopenharmony_ci struct net_device *ndev = dev_get_drvdata(dev); 15828c2ecf20Sopenharmony_ci struct xcan_priv *priv = netdev_priv(ndev); 15838c2ecf20Sopenharmony_ci int ret; 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->bus_clk); 15868c2ecf20Sopenharmony_ci if (ret) { 15878c2ecf20Sopenharmony_ci dev_err(dev, "Cannot enable clock.\n"); 15888c2ecf20Sopenharmony_ci return ret; 15898c2ecf20Sopenharmony_ci } 15908c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->can_clk); 15918c2ecf20Sopenharmony_ci if (ret) { 15928c2ecf20Sopenharmony_ci dev_err(dev, "Cannot enable clock.\n"); 15938c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->bus_clk); 15948c2ecf20Sopenharmony_ci return ret; 15958c2ecf20Sopenharmony_ci } 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci return 0; 15988c2ecf20Sopenharmony_ci} 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_cistatic const struct dev_pm_ops xcan_dev_pm_ops = { 16018c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(xcan_suspend, xcan_resume) 16028c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(xcan_runtime_suspend, xcan_runtime_resume, NULL) 16038c2ecf20Sopenharmony_ci}; 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_cistatic const struct xcan_devtype_data xcan_zynq_data = { 16068c2ecf20Sopenharmony_ci .cantype = XZYNQ_CANPS, 16078c2ecf20Sopenharmony_ci .flags = XCAN_FLAG_TXFEMP, 16088c2ecf20Sopenharmony_ci .bittiming_const = &xcan_bittiming_const, 16098c2ecf20Sopenharmony_ci .btr_ts2_shift = XCAN_BTR_TS2_SHIFT, 16108c2ecf20Sopenharmony_ci .btr_sjw_shift = XCAN_BTR_SJW_SHIFT, 16118c2ecf20Sopenharmony_ci .bus_clk_name = "pclk", 16128c2ecf20Sopenharmony_ci}; 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_cistatic const struct xcan_devtype_data xcan_axi_data = { 16158c2ecf20Sopenharmony_ci .cantype = XAXI_CAN, 16168c2ecf20Sopenharmony_ci .bittiming_const = &xcan_bittiming_const, 16178c2ecf20Sopenharmony_ci .btr_ts2_shift = XCAN_BTR_TS2_SHIFT, 16188c2ecf20Sopenharmony_ci .btr_sjw_shift = XCAN_BTR_SJW_SHIFT, 16198c2ecf20Sopenharmony_ci .bus_clk_name = "s_axi_aclk", 16208c2ecf20Sopenharmony_ci}; 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_cistatic const struct xcan_devtype_data xcan_canfd_data = { 16238c2ecf20Sopenharmony_ci .cantype = XAXI_CANFD, 16248c2ecf20Sopenharmony_ci .flags = XCAN_FLAG_EXT_FILTERS | 16258c2ecf20Sopenharmony_ci XCAN_FLAG_RXMNF | 16268c2ecf20Sopenharmony_ci XCAN_FLAG_TX_MAILBOXES | 16278c2ecf20Sopenharmony_ci XCAN_FLAG_RX_FIFO_MULTI, 16288c2ecf20Sopenharmony_ci .bittiming_const = &xcan_bittiming_const_canfd, 16298c2ecf20Sopenharmony_ci .btr_ts2_shift = XCAN_BTR_TS2_SHIFT_CANFD, 16308c2ecf20Sopenharmony_ci .btr_sjw_shift = XCAN_BTR_SJW_SHIFT_CANFD, 16318c2ecf20Sopenharmony_ci .bus_clk_name = "s_axi_aclk", 16328c2ecf20Sopenharmony_ci}; 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_cistatic const struct xcan_devtype_data xcan_canfd2_data = { 16358c2ecf20Sopenharmony_ci .cantype = XAXI_CANFD_2_0, 16368c2ecf20Sopenharmony_ci .flags = XCAN_FLAG_EXT_FILTERS | 16378c2ecf20Sopenharmony_ci XCAN_FLAG_RXMNF | 16388c2ecf20Sopenharmony_ci XCAN_FLAG_TX_MAILBOXES | 16398c2ecf20Sopenharmony_ci XCAN_FLAG_CANFD_2 | 16408c2ecf20Sopenharmony_ci XCAN_FLAG_RX_FIFO_MULTI, 16418c2ecf20Sopenharmony_ci .bittiming_const = &xcan_bittiming_const_canfd2, 16428c2ecf20Sopenharmony_ci .btr_ts2_shift = XCAN_BTR_TS2_SHIFT_CANFD, 16438c2ecf20Sopenharmony_ci .btr_sjw_shift = XCAN_BTR_SJW_SHIFT_CANFD, 16448c2ecf20Sopenharmony_ci .bus_clk_name = "s_axi_aclk", 16458c2ecf20Sopenharmony_ci}; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci/* Match table for OF platform binding */ 16488c2ecf20Sopenharmony_cistatic const struct of_device_id xcan_of_match[] = { 16498c2ecf20Sopenharmony_ci { .compatible = "xlnx,zynq-can-1.0", .data = &xcan_zynq_data }, 16508c2ecf20Sopenharmony_ci { .compatible = "xlnx,axi-can-1.00.a", .data = &xcan_axi_data }, 16518c2ecf20Sopenharmony_ci { .compatible = "xlnx,canfd-1.0", .data = &xcan_canfd_data }, 16528c2ecf20Sopenharmony_ci { .compatible = "xlnx,canfd-2.0", .data = &xcan_canfd2_data }, 16538c2ecf20Sopenharmony_ci { /* end of list */ }, 16548c2ecf20Sopenharmony_ci}; 16558c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, xcan_of_match); 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci/** 16588c2ecf20Sopenharmony_ci * xcan_probe - Platform registration call 16598c2ecf20Sopenharmony_ci * @pdev: Handle to the platform device structure 16608c2ecf20Sopenharmony_ci * 16618c2ecf20Sopenharmony_ci * This function does all the memory allocation and registration for the CAN 16628c2ecf20Sopenharmony_ci * device. 16638c2ecf20Sopenharmony_ci * 16648c2ecf20Sopenharmony_ci * Return: 0 on success and failure value on error 16658c2ecf20Sopenharmony_ci */ 16668c2ecf20Sopenharmony_cistatic int xcan_probe(struct platform_device *pdev) 16678c2ecf20Sopenharmony_ci{ 16688c2ecf20Sopenharmony_ci struct net_device *ndev; 16698c2ecf20Sopenharmony_ci struct xcan_priv *priv; 16708c2ecf20Sopenharmony_ci const struct of_device_id *of_id; 16718c2ecf20Sopenharmony_ci const struct xcan_devtype_data *devtype = &xcan_axi_data; 16728c2ecf20Sopenharmony_ci void __iomem *addr; 16738c2ecf20Sopenharmony_ci int ret; 16748c2ecf20Sopenharmony_ci int rx_max, tx_max; 16758c2ecf20Sopenharmony_ci u32 hw_tx_max = 0, hw_rx_max = 0; 16768c2ecf20Sopenharmony_ci const char *hw_tx_max_property; 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci /* Get the virtual base address for the device */ 16798c2ecf20Sopenharmony_ci addr = devm_platform_ioremap_resource(pdev, 0); 16808c2ecf20Sopenharmony_ci if (IS_ERR(addr)) { 16818c2ecf20Sopenharmony_ci ret = PTR_ERR(addr); 16828c2ecf20Sopenharmony_ci goto err; 16838c2ecf20Sopenharmony_ci } 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci of_id = of_match_device(xcan_of_match, &pdev->dev); 16868c2ecf20Sopenharmony_ci if (of_id && of_id->data) 16878c2ecf20Sopenharmony_ci devtype = of_id->data; 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci hw_tx_max_property = devtype->flags & XCAN_FLAG_TX_MAILBOXES ? 16908c2ecf20Sopenharmony_ci "tx-mailbox-count" : "tx-fifo-depth"; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci ret = of_property_read_u32(pdev->dev.of_node, hw_tx_max_property, 16938c2ecf20Sopenharmony_ci &hw_tx_max); 16948c2ecf20Sopenharmony_ci if (ret < 0) { 16958c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "missing %s property\n", 16968c2ecf20Sopenharmony_ci hw_tx_max_property); 16978c2ecf20Sopenharmony_ci goto err; 16988c2ecf20Sopenharmony_ci } 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci ret = of_property_read_u32(pdev->dev.of_node, "rx-fifo-depth", 17018c2ecf20Sopenharmony_ci &hw_rx_max); 17028c2ecf20Sopenharmony_ci if (ret < 0) { 17038c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 17048c2ecf20Sopenharmony_ci "missing rx-fifo-depth property (mailbox mode is not supported)\n"); 17058c2ecf20Sopenharmony_ci goto err; 17068c2ecf20Sopenharmony_ci } 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci /* With TX FIFO: 17098c2ecf20Sopenharmony_ci * 17108c2ecf20Sopenharmony_ci * There is no way to directly figure out how many frames have been 17118c2ecf20Sopenharmony_ci * sent when the TXOK interrupt is processed. If TXFEMP 17128c2ecf20Sopenharmony_ci * is supported, we can have 2 frames in the FIFO and use TXFEMP 17138c2ecf20Sopenharmony_ci * to determine if 1 or 2 frames have been sent. 17148c2ecf20Sopenharmony_ci * Theoretically we should be able to use TXFWMEMP to determine up 17158c2ecf20Sopenharmony_ci * to 3 frames, but it seems that after putting a second frame in the 17168c2ecf20Sopenharmony_ci * FIFO, with watermark at 2 frames, it can happen that TXFWMEMP (less 17178c2ecf20Sopenharmony_ci * than 2 frames in FIFO) is set anyway with no TXOK (a frame was 17188c2ecf20Sopenharmony_ci * sent), which is not a sensible state - possibly TXFWMEMP is not 17198c2ecf20Sopenharmony_ci * completely synchronized with the rest of the bits? 17208c2ecf20Sopenharmony_ci * 17218c2ecf20Sopenharmony_ci * With TX mailboxes: 17228c2ecf20Sopenharmony_ci * 17238c2ecf20Sopenharmony_ci * HW sends frames in CAN ID priority order. To preserve FIFO ordering 17248c2ecf20Sopenharmony_ci * we submit frames one at a time. 17258c2ecf20Sopenharmony_ci */ 17268c2ecf20Sopenharmony_ci if (!(devtype->flags & XCAN_FLAG_TX_MAILBOXES) && 17278c2ecf20Sopenharmony_ci (devtype->flags & XCAN_FLAG_TXFEMP)) 17288c2ecf20Sopenharmony_ci tx_max = min(hw_tx_max, 2U); 17298c2ecf20Sopenharmony_ci else 17308c2ecf20Sopenharmony_ci tx_max = 1; 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci rx_max = hw_rx_max; 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci /* Create a CAN device instance */ 17358c2ecf20Sopenharmony_ci ndev = alloc_candev(sizeof(struct xcan_priv), tx_max); 17368c2ecf20Sopenharmony_ci if (!ndev) 17378c2ecf20Sopenharmony_ci return -ENOMEM; 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci priv = netdev_priv(ndev); 17408c2ecf20Sopenharmony_ci priv->dev = &pdev->dev; 17418c2ecf20Sopenharmony_ci priv->can.bittiming_const = devtype->bittiming_const; 17428c2ecf20Sopenharmony_ci priv->can.do_set_mode = xcan_do_set_mode; 17438c2ecf20Sopenharmony_ci priv->can.do_get_berr_counter = xcan_get_berr_counter; 17448c2ecf20Sopenharmony_ci priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | 17458c2ecf20Sopenharmony_ci CAN_CTRLMODE_BERR_REPORTING; 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci if (devtype->cantype == XAXI_CANFD) 17488c2ecf20Sopenharmony_ci priv->can.data_bittiming_const = 17498c2ecf20Sopenharmony_ci &xcan_data_bittiming_const_canfd; 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci if (devtype->cantype == XAXI_CANFD_2_0) 17528c2ecf20Sopenharmony_ci priv->can.data_bittiming_const = 17538c2ecf20Sopenharmony_ci &xcan_data_bittiming_const_canfd2; 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci if (devtype->cantype == XAXI_CANFD || 17568c2ecf20Sopenharmony_ci devtype->cantype == XAXI_CANFD_2_0) 17578c2ecf20Sopenharmony_ci priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD; 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci priv->reg_base = addr; 17608c2ecf20Sopenharmony_ci priv->tx_max = tx_max; 17618c2ecf20Sopenharmony_ci priv->devtype = *devtype; 17628c2ecf20Sopenharmony_ci spin_lock_init(&priv->tx_lock); 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci /* Get IRQ for the device */ 17658c2ecf20Sopenharmony_ci ret = platform_get_irq(pdev, 0); 17668c2ecf20Sopenharmony_ci if (ret < 0) 17678c2ecf20Sopenharmony_ci goto err_free; 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci ndev->irq = ret; 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci ndev->flags |= IFF_ECHO; /* We support local echo */ 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, ndev); 17748c2ecf20Sopenharmony_ci SET_NETDEV_DEV(ndev, &pdev->dev); 17758c2ecf20Sopenharmony_ci ndev->netdev_ops = &xcan_netdev_ops; 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci /* Getting the CAN can_clk info */ 17788c2ecf20Sopenharmony_ci priv->can_clk = devm_clk_get(&pdev->dev, "can_clk"); 17798c2ecf20Sopenharmony_ci if (IS_ERR(priv->can_clk)) { 17808c2ecf20Sopenharmony_ci if (PTR_ERR(priv->can_clk) != -EPROBE_DEFER) 17818c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Device clock not found.\n"); 17828c2ecf20Sopenharmony_ci ret = PTR_ERR(priv->can_clk); 17838c2ecf20Sopenharmony_ci goto err_free; 17848c2ecf20Sopenharmony_ci } 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci priv->bus_clk = devm_clk_get(&pdev->dev, devtype->bus_clk_name); 17878c2ecf20Sopenharmony_ci if (IS_ERR(priv->bus_clk)) { 17888c2ecf20Sopenharmony_ci if (PTR_ERR(priv->bus_clk) != -EPROBE_DEFER) 17898c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "bus clock not found\n"); 17908c2ecf20Sopenharmony_ci ret = PTR_ERR(priv->bus_clk); 17918c2ecf20Sopenharmony_ci goto err_free; 17928c2ecf20Sopenharmony_ci } 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci priv->write_reg = xcan_write_reg_le; 17958c2ecf20Sopenharmony_ci priv->read_reg = xcan_read_reg_le; 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci pm_runtime_enable(&pdev->dev); 17988c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(&pdev->dev); 17998c2ecf20Sopenharmony_ci if (ret < 0) { 18008c2ecf20Sopenharmony_ci netdev_err(ndev, "%s: pm_runtime_get failed(%d)\n", 18018c2ecf20Sopenharmony_ci __func__, ret); 18028c2ecf20Sopenharmony_ci goto err_disableclks; 18038c2ecf20Sopenharmony_ci } 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci if (priv->read_reg(priv, XCAN_SR_OFFSET) != XCAN_SR_CONFIG_MASK) { 18068c2ecf20Sopenharmony_ci priv->write_reg = xcan_write_reg_be; 18078c2ecf20Sopenharmony_ci priv->read_reg = xcan_read_reg_be; 18088c2ecf20Sopenharmony_ci } 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci priv->can.clock.freq = clk_get_rate(priv->can_clk); 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci netif_napi_add(ndev, &priv->napi, xcan_rx_poll, rx_max); 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_ci ret = register_candev(ndev); 18158c2ecf20Sopenharmony_ci if (ret) { 18168c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "fail to register failed (err=%d)\n", ret); 18178c2ecf20Sopenharmony_ci goto err_disableclks; 18188c2ecf20Sopenharmony_ci } 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_ci devm_can_led_init(ndev); 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci pm_runtime_put(&pdev->dev); 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci if (priv->devtype.flags & XCAN_FLAG_CANFD_2) { 18258c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_AFR_2_ID_OFFSET, 0x00000000); 18268c2ecf20Sopenharmony_ci priv->write_reg(priv, XCAN_AFR_2_MASK_OFFSET, 0x00000000); 18278c2ecf20Sopenharmony_ci } 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci netdev_dbg(ndev, "reg_base=0x%p irq=%d clock=%d, tx buffers: actual %d, using %d\n", 18308c2ecf20Sopenharmony_ci priv->reg_base, ndev->irq, priv->can.clock.freq, 18318c2ecf20Sopenharmony_ci hw_tx_max, priv->tx_max); 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci return 0; 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_cierr_disableclks: 18368c2ecf20Sopenharmony_ci pm_runtime_put(priv->dev); 18378c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 18388c2ecf20Sopenharmony_cierr_free: 18398c2ecf20Sopenharmony_ci free_candev(ndev); 18408c2ecf20Sopenharmony_cierr: 18418c2ecf20Sopenharmony_ci return ret; 18428c2ecf20Sopenharmony_ci} 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci/** 18458c2ecf20Sopenharmony_ci * xcan_remove - Unregister the device after releasing the resources 18468c2ecf20Sopenharmony_ci * @pdev: Handle to the platform device structure 18478c2ecf20Sopenharmony_ci * 18488c2ecf20Sopenharmony_ci * This function frees all the resources allocated to the device. 18498c2ecf20Sopenharmony_ci * Return: 0 always 18508c2ecf20Sopenharmony_ci */ 18518c2ecf20Sopenharmony_cistatic int xcan_remove(struct platform_device *pdev) 18528c2ecf20Sopenharmony_ci{ 18538c2ecf20Sopenharmony_ci struct net_device *ndev = platform_get_drvdata(pdev); 18548c2ecf20Sopenharmony_ci struct xcan_priv *priv = netdev_priv(ndev); 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci unregister_candev(ndev); 18578c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 18588c2ecf20Sopenharmony_ci netif_napi_del(&priv->napi); 18598c2ecf20Sopenharmony_ci free_candev(ndev); 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci return 0; 18628c2ecf20Sopenharmony_ci} 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_cistatic struct platform_driver xcan_driver = { 18658c2ecf20Sopenharmony_ci .probe = xcan_probe, 18668c2ecf20Sopenharmony_ci .remove = xcan_remove, 18678c2ecf20Sopenharmony_ci .driver = { 18688c2ecf20Sopenharmony_ci .name = DRIVER_NAME, 18698c2ecf20Sopenharmony_ci .pm = &xcan_dev_pm_ops, 18708c2ecf20Sopenharmony_ci .of_match_table = xcan_of_match, 18718c2ecf20Sopenharmony_ci }, 18728c2ecf20Sopenharmony_ci}; 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_cimodule_platform_driver(xcan_driver); 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 18778c2ecf20Sopenharmony_ciMODULE_AUTHOR("Xilinx Inc"); 18788c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Xilinx CAN interface"); 1879