18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// CAN bus driver for Bosch M_CAN controller 38c2ecf20Sopenharmony_ci// Copyright (C) 2014 Freescale Semiconductor, Inc. 48c2ecf20Sopenharmony_ci// Dong Aisheng <b29396@freescale.com> 58c2ecf20Sopenharmony_ci// Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci/* Bosch M_CAN user manual can be obtained from: 88c2ecf20Sopenharmony_ci * http://www.bosch-semiconductors.de/media/pdf_1/ipmodules_1/m_can/ 98c2ecf20Sopenharmony_ci * mcan_users_manual_v302.pdf 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 138c2ecf20Sopenharmony_ci#include <linux/io.h> 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 178c2ecf20Sopenharmony_ci#include <linux/of.h> 188c2ecf20Sopenharmony_ci#include <linux/of_device.h> 198c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 208c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 218c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 228c2ecf20Sopenharmony_ci#include <linux/can/dev.h> 238c2ecf20Sopenharmony_ci#include <linux/pinctrl/consumer.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "m_can.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* registers definition */ 288c2ecf20Sopenharmony_cienum m_can_reg { 298c2ecf20Sopenharmony_ci M_CAN_CREL = 0x0, 308c2ecf20Sopenharmony_ci M_CAN_ENDN = 0x4, 318c2ecf20Sopenharmony_ci M_CAN_CUST = 0x8, 328c2ecf20Sopenharmony_ci M_CAN_DBTP = 0xc, 338c2ecf20Sopenharmony_ci M_CAN_TEST = 0x10, 348c2ecf20Sopenharmony_ci M_CAN_RWD = 0x14, 358c2ecf20Sopenharmony_ci M_CAN_CCCR = 0x18, 368c2ecf20Sopenharmony_ci M_CAN_NBTP = 0x1c, 378c2ecf20Sopenharmony_ci M_CAN_TSCC = 0x20, 388c2ecf20Sopenharmony_ci M_CAN_TSCV = 0x24, 398c2ecf20Sopenharmony_ci M_CAN_TOCC = 0x28, 408c2ecf20Sopenharmony_ci M_CAN_TOCV = 0x2c, 418c2ecf20Sopenharmony_ci M_CAN_ECR = 0x40, 428c2ecf20Sopenharmony_ci M_CAN_PSR = 0x44, 438c2ecf20Sopenharmony_ci/* TDCR Register only available for version >=3.1.x */ 448c2ecf20Sopenharmony_ci M_CAN_TDCR = 0x48, 458c2ecf20Sopenharmony_ci M_CAN_IR = 0x50, 468c2ecf20Sopenharmony_ci M_CAN_IE = 0x54, 478c2ecf20Sopenharmony_ci M_CAN_ILS = 0x58, 488c2ecf20Sopenharmony_ci M_CAN_ILE = 0x5c, 498c2ecf20Sopenharmony_ci M_CAN_GFC = 0x80, 508c2ecf20Sopenharmony_ci M_CAN_SIDFC = 0x84, 518c2ecf20Sopenharmony_ci M_CAN_XIDFC = 0x88, 528c2ecf20Sopenharmony_ci M_CAN_XIDAM = 0x90, 538c2ecf20Sopenharmony_ci M_CAN_HPMS = 0x94, 548c2ecf20Sopenharmony_ci M_CAN_NDAT1 = 0x98, 558c2ecf20Sopenharmony_ci M_CAN_NDAT2 = 0x9c, 568c2ecf20Sopenharmony_ci M_CAN_RXF0C = 0xa0, 578c2ecf20Sopenharmony_ci M_CAN_RXF0S = 0xa4, 588c2ecf20Sopenharmony_ci M_CAN_RXF0A = 0xa8, 598c2ecf20Sopenharmony_ci M_CAN_RXBC = 0xac, 608c2ecf20Sopenharmony_ci M_CAN_RXF1C = 0xb0, 618c2ecf20Sopenharmony_ci M_CAN_RXF1S = 0xb4, 628c2ecf20Sopenharmony_ci M_CAN_RXF1A = 0xb8, 638c2ecf20Sopenharmony_ci M_CAN_RXESC = 0xbc, 648c2ecf20Sopenharmony_ci M_CAN_TXBC = 0xc0, 658c2ecf20Sopenharmony_ci M_CAN_TXFQS = 0xc4, 668c2ecf20Sopenharmony_ci M_CAN_TXESC = 0xc8, 678c2ecf20Sopenharmony_ci M_CAN_TXBRP = 0xcc, 688c2ecf20Sopenharmony_ci M_CAN_TXBAR = 0xd0, 698c2ecf20Sopenharmony_ci M_CAN_TXBCR = 0xd4, 708c2ecf20Sopenharmony_ci M_CAN_TXBTO = 0xd8, 718c2ecf20Sopenharmony_ci M_CAN_TXBCF = 0xdc, 728c2ecf20Sopenharmony_ci M_CAN_TXBTIE = 0xe0, 738c2ecf20Sopenharmony_ci M_CAN_TXBCIE = 0xe4, 748c2ecf20Sopenharmony_ci M_CAN_TXEFC = 0xf0, 758c2ecf20Sopenharmony_ci M_CAN_TXEFS = 0xf4, 768c2ecf20Sopenharmony_ci M_CAN_TXEFA = 0xf8, 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/* napi related */ 808c2ecf20Sopenharmony_ci#define M_CAN_NAPI_WEIGHT 64 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* message ram configuration data length */ 838c2ecf20Sopenharmony_ci#define MRAM_CFG_LEN 8 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/* Core Release Register (CREL) */ 868c2ecf20Sopenharmony_ci#define CREL_REL_SHIFT 28 878c2ecf20Sopenharmony_ci#define CREL_REL_MASK (0xF << CREL_REL_SHIFT) 888c2ecf20Sopenharmony_ci#define CREL_STEP_SHIFT 24 898c2ecf20Sopenharmony_ci#define CREL_STEP_MASK (0xF << CREL_STEP_SHIFT) 908c2ecf20Sopenharmony_ci#define CREL_SUBSTEP_SHIFT 20 918c2ecf20Sopenharmony_ci#define CREL_SUBSTEP_MASK (0xF << CREL_SUBSTEP_SHIFT) 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/* Data Bit Timing & Prescaler Register (DBTP) */ 948c2ecf20Sopenharmony_ci#define DBTP_TDC BIT(23) 958c2ecf20Sopenharmony_ci#define DBTP_DBRP_SHIFT 16 968c2ecf20Sopenharmony_ci#define DBTP_DBRP_MASK (0x1f << DBTP_DBRP_SHIFT) 978c2ecf20Sopenharmony_ci#define DBTP_DTSEG1_SHIFT 8 988c2ecf20Sopenharmony_ci#define DBTP_DTSEG1_MASK (0x1f << DBTP_DTSEG1_SHIFT) 998c2ecf20Sopenharmony_ci#define DBTP_DTSEG2_SHIFT 4 1008c2ecf20Sopenharmony_ci#define DBTP_DTSEG2_MASK (0xf << DBTP_DTSEG2_SHIFT) 1018c2ecf20Sopenharmony_ci#define DBTP_DSJW_SHIFT 0 1028c2ecf20Sopenharmony_ci#define DBTP_DSJW_MASK (0xf << DBTP_DSJW_SHIFT) 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* Transmitter Delay Compensation Register (TDCR) */ 1058c2ecf20Sopenharmony_ci#define TDCR_TDCO_SHIFT 8 1068c2ecf20Sopenharmony_ci#define TDCR_TDCO_MASK (0x7F << TDCR_TDCO_SHIFT) 1078c2ecf20Sopenharmony_ci#define TDCR_TDCF_SHIFT 0 1088c2ecf20Sopenharmony_ci#define TDCR_TDCF_MASK (0x7F << TDCR_TDCF_SHIFT) 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci/* Test Register (TEST) */ 1118c2ecf20Sopenharmony_ci#define TEST_LBCK BIT(4) 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/* CC Control Register(CCCR) */ 1148c2ecf20Sopenharmony_ci#define CCCR_CMR_MASK 0x3 1158c2ecf20Sopenharmony_ci#define CCCR_CMR_SHIFT 10 1168c2ecf20Sopenharmony_ci#define CCCR_CMR_CANFD 0x1 1178c2ecf20Sopenharmony_ci#define CCCR_CMR_CANFD_BRS 0x2 1188c2ecf20Sopenharmony_ci#define CCCR_CMR_CAN 0x3 1198c2ecf20Sopenharmony_ci#define CCCR_CME_MASK 0x3 1208c2ecf20Sopenharmony_ci#define CCCR_CME_SHIFT 8 1218c2ecf20Sopenharmony_ci#define CCCR_CME_CAN 0 1228c2ecf20Sopenharmony_ci#define CCCR_CME_CANFD 0x1 1238c2ecf20Sopenharmony_ci#define CCCR_CME_CANFD_BRS 0x2 1248c2ecf20Sopenharmony_ci#define CCCR_TXP BIT(14) 1258c2ecf20Sopenharmony_ci#define CCCR_TEST BIT(7) 1268c2ecf20Sopenharmony_ci#define CCCR_DAR BIT(6) 1278c2ecf20Sopenharmony_ci#define CCCR_MON BIT(5) 1288c2ecf20Sopenharmony_ci#define CCCR_CSR BIT(4) 1298c2ecf20Sopenharmony_ci#define CCCR_CSA BIT(3) 1308c2ecf20Sopenharmony_ci#define CCCR_ASM BIT(2) 1318c2ecf20Sopenharmony_ci#define CCCR_CCE BIT(1) 1328c2ecf20Sopenharmony_ci#define CCCR_INIT BIT(0) 1338c2ecf20Sopenharmony_ci#define CCCR_CANFD 0x10 1348c2ecf20Sopenharmony_ci/* for version >=3.1.x */ 1358c2ecf20Sopenharmony_ci#define CCCR_EFBI BIT(13) 1368c2ecf20Sopenharmony_ci#define CCCR_PXHD BIT(12) 1378c2ecf20Sopenharmony_ci#define CCCR_BRSE BIT(9) 1388c2ecf20Sopenharmony_ci#define CCCR_FDOE BIT(8) 1398c2ecf20Sopenharmony_ci/* only for version >=3.2.x */ 1408c2ecf20Sopenharmony_ci#define CCCR_NISO BIT(15) 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci/* Nominal Bit Timing & Prescaler Register (NBTP) */ 1438c2ecf20Sopenharmony_ci#define NBTP_NSJW_SHIFT 25 1448c2ecf20Sopenharmony_ci#define NBTP_NSJW_MASK (0x7f << NBTP_NSJW_SHIFT) 1458c2ecf20Sopenharmony_ci#define NBTP_NBRP_SHIFT 16 1468c2ecf20Sopenharmony_ci#define NBTP_NBRP_MASK (0x1ff << NBTP_NBRP_SHIFT) 1478c2ecf20Sopenharmony_ci#define NBTP_NTSEG1_SHIFT 8 1488c2ecf20Sopenharmony_ci#define NBTP_NTSEG1_MASK (0xff << NBTP_NTSEG1_SHIFT) 1498c2ecf20Sopenharmony_ci#define NBTP_NTSEG2_SHIFT 0 1508c2ecf20Sopenharmony_ci#define NBTP_NTSEG2_MASK (0x7f << NBTP_NTSEG2_SHIFT) 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci/* Error Counter Register(ECR) */ 1538c2ecf20Sopenharmony_ci#define ECR_RP BIT(15) 1548c2ecf20Sopenharmony_ci#define ECR_REC_SHIFT 8 1558c2ecf20Sopenharmony_ci#define ECR_REC_MASK (0x7f << ECR_REC_SHIFT) 1568c2ecf20Sopenharmony_ci#define ECR_TEC_SHIFT 0 1578c2ecf20Sopenharmony_ci#define ECR_TEC_MASK 0xff 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci/* Protocol Status Register(PSR) */ 1608c2ecf20Sopenharmony_ci#define PSR_BO BIT(7) 1618c2ecf20Sopenharmony_ci#define PSR_EW BIT(6) 1628c2ecf20Sopenharmony_ci#define PSR_EP BIT(5) 1638c2ecf20Sopenharmony_ci#define PSR_LEC_MASK 0x7 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/* Interrupt Register(IR) */ 1668c2ecf20Sopenharmony_ci#define IR_ALL_INT 0xffffffff 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci/* Renamed bits for versions > 3.1.x */ 1698c2ecf20Sopenharmony_ci#define IR_ARA BIT(29) 1708c2ecf20Sopenharmony_ci#define IR_PED BIT(28) 1718c2ecf20Sopenharmony_ci#define IR_PEA BIT(27) 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci/* Bits for version 3.0.x */ 1748c2ecf20Sopenharmony_ci#define IR_STE BIT(31) 1758c2ecf20Sopenharmony_ci#define IR_FOE BIT(30) 1768c2ecf20Sopenharmony_ci#define IR_ACKE BIT(29) 1778c2ecf20Sopenharmony_ci#define IR_BE BIT(28) 1788c2ecf20Sopenharmony_ci#define IR_CRCE BIT(27) 1798c2ecf20Sopenharmony_ci#define IR_WDI BIT(26) 1808c2ecf20Sopenharmony_ci#define IR_BO BIT(25) 1818c2ecf20Sopenharmony_ci#define IR_EW BIT(24) 1828c2ecf20Sopenharmony_ci#define IR_EP BIT(23) 1838c2ecf20Sopenharmony_ci#define IR_ELO BIT(22) 1848c2ecf20Sopenharmony_ci#define IR_BEU BIT(21) 1858c2ecf20Sopenharmony_ci#define IR_BEC BIT(20) 1868c2ecf20Sopenharmony_ci#define IR_DRX BIT(19) 1878c2ecf20Sopenharmony_ci#define IR_TOO BIT(18) 1888c2ecf20Sopenharmony_ci#define IR_MRAF BIT(17) 1898c2ecf20Sopenharmony_ci#define IR_TSW BIT(16) 1908c2ecf20Sopenharmony_ci#define IR_TEFL BIT(15) 1918c2ecf20Sopenharmony_ci#define IR_TEFF BIT(14) 1928c2ecf20Sopenharmony_ci#define IR_TEFW BIT(13) 1938c2ecf20Sopenharmony_ci#define IR_TEFN BIT(12) 1948c2ecf20Sopenharmony_ci#define IR_TFE BIT(11) 1958c2ecf20Sopenharmony_ci#define IR_TCF BIT(10) 1968c2ecf20Sopenharmony_ci#define IR_TC BIT(9) 1978c2ecf20Sopenharmony_ci#define IR_HPM BIT(8) 1988c2ecf20Sopenharmony_ci#define IR_RF1L BIT(7) 1998c2ecf20Sopenharmony_ci#define IR_RF1F BIT(6) 2008c2ecf20Sopenharmony_ci#define IR_RF1W BIT(5) 2018c2ecf20Sopenharmony_ci#define IR_RF1N BIT(4) 2028c2ecf20Sopenharmony_ci#define IR_RF0L BIT(3) 2038c2ecf20Sopenharmony_ci#define IR_RF0F BIT(2) 2048c2ecf20Sopenharmony_ci#define IR_RF0W BIT(1) 2058c2ecf20Sopenharmony_ci#define IR_RF0N BIT(0) 2068c2ecf20Sopenharmony_ci#define IR_ERR_STATE (IR_BO | IR_EW | IR_EP) 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci/* Interrupts for version 3.0.x */ 2098c2ecf20Sopenharmony_ci#define IR_ERR_LEC_30X (IR_STE | IR_FOE | IR_ACKE | IR_BE | IR_CRCE) 2108c2ecf20Sopenharmony_ci#define IR_ERR_BUS_30X (IR_ERR_LEC_30X | IR_WDI | IR_BEU | IR_BEC | \ 2118c2ecf20Sopenharmony_ci IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | IR_RF1L | \ 2128c2ecf20Sopenharmony_ci IR_RF0L) 2138c2ecf20Sopenharmony_ci#define IR_ERR_ALL_30X (IR_ERR_STATE | IR_ERR_BUS_30X) 2148c2ecf20Sopenharmony_ci/* Interrupts for version >= 3.1.x */ 2158c2ecf20Sopenharmony_ci#define IR_ERR_LEC_31X (IR_PED | IR_PEA) 2168c2ecf20Sopenharmony_ci#define IR_ERR_BUS_31X (IR_ERR_LEC_31X | IR_WDI | IR_BEU | IR_BEC | \ 2178c2ecf20Sopenharmony_ci IR_TOO | IR_MRAF | IR_TSW | IR_TEFL | IR_RF1L | \ 2188c2ecf20Sopenharmony_ci IR_RF0L) 2198c2ecf20Sopenharmony_ci#define IR_ERR_ALL_31X (IR_ERR_STATE | IR_ERR_BUS_31X) 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci/* Interrupt Line Select (ILS) */ 2228c2ecf20Sopenharmony_ci#define ILS_ALL_INT0 0x0 2238c2ecf20Sopenharmony_ci#define ILS_ALL_INT1 0xFFFFFFFF 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci/* Interrupt Line Enable (ILE) */ 2268c2ecf20Sopenharmony_ci#define ILE_EINT1 BIT(1) 2278c2ecf20Sopenharmony_ci#define ILE_EINT0 BIT(0) 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci/* Rx FIFO 0/1 Configuration (RXF0C/RXF1C) */ 2308c2ecf20Sopenharmony_ci#define RXFC_FWM_SHIFT 24 2318c2ecf20Sopenharmony_ci#define RXFC_FWM_MASK (0x7f << RXFC_FWM_SHIFT) 2328c2ecf20Sopenharmony_ci#define RXFC_FS_SHIFT 16 2338c2ecf20Sopenharmony_ci#define RXFC_FS_MASK (0x7f << RXFC_FS_SHIFT) 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci/* Rx FIFO 0/1 Status (RXF0S/RXF1S) */ 2368c2ecf20Sopenharmony_ci#define RXFS_RFL BIT(25) 2378c2ecf20Sopenharmony_ci#define RXFS_FF BIT(24) 2388c2ecf20Sopenharmony_ci#define RXFS_FPI_SHIFT 16 2398c2ecf20Sopenharmony_ci#define RXFS_FPI_MASK 0x3f0000 2408c2ecf20Sopenharmony_ci#define RXFS_FGI_SHIFT 8 2418c2ecf20Sopenharmony_ci#define RXFS_FGI_MASK 0x3f00 2428c2ecf20Sopenharmony_ci#define RXFS_FFL_MASK 0x7f 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci/* Rx Buffer / FIFO Element Size Configuration (RXESC) */ 2458c2ecf20Sopenharmony_ci#define M_CAN_RXESC_8BYTES 0x0 2468c2ecf20Sopenharmony_ci#define M_CAN_RXESC_64BYTES 0x777 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci/* Tx Buffer Configuration(TXBC) */ 2498c2ecf20Sopenharmony_ci#define TXBC_NDTB_SHIFT 16 2508c2ecf20Sopenharmony_ci#define TXBC_NDTB_MASK (0x3f << TXBC_NDTB_SHIFT) 2518c2ecf20Sopenharmony_ci#define TXBC_TFQS_SHIFT 24 2528c2ecf20Sopenharmony_ci#define TXBC_TFQS_MASK (0x3f << TXBC_TFQS_SHIFT) 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci/* Tx FIFO/Queue Status (TXFQS) */ 2558c2ecf20Sopenharmony_ci#define TXFQS_TFQF BIT(21) 2568c2ecf20Sopenharmony_ci#define TXFQS_TFQPI_SHIFT 16 2578c2ecf20Sopenharmony_ci#define TXFQS_TFQPI_MASK (0x1f << TXFQS_TFQPI_SHIFT) 2588c2ecf20Sopenharmony_ci#define TXFQS_TFGI_SHIFT 8 2598c2ecf20Sopenharmony_ci#define TXFQS_TFGI_MASK (0x1f << TXFQS_TFGI_SHIFT) 2608c2ecf20Sopenharmony_ci#define TXFQS_TFFL_SHIFT 0 2618c2ecf20Sopenharmony_ci#define TXFQS_TFFL_MASK (0x3f << TXFQS_TFFL_SHIFT) 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci/* Tx Buffer Element Size Configuration(TXESC) */ 2648c2ecf20Sopenharmony_ci#define TXESC_TBDS_8BYTES 0x0 2658c2ecf20Sopenharmony_ci#define TXESC_TBDS_64BYTES 0x7 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci/* Tx Event FIFO Configuration (TXEFC) */ 2688c2ecf20Sopenharmony_ci#define TXEFC_EFS_SHIFT 16 2698c2ecf20Sopenharmony_ci#define TXEFC_EFS_MASK (0x3f << TXEFC_EFS_SHIFT) 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci/* Tx Event FIFO Status (TXEFS) */ 2728c2ecf20Sopenharmony_ci#define TXEFS_TEFL BIT(25) 2738c2ecf20Sopenharmony_ci#define TXEFS_EFF BIT(24) 2748c2ecf20Sopenharmony_ci#define TXEFS_EFGI_SHIFT 8 2758c2ecf20Sopenharmony_ci#define TXEFS_EFGI_MASK (0x1f << TXEFS_EFGI_SHIFT) 2768c2ecf20Sopenharmony_ci#define TXEFS_EFFL_SHIFT 0 2778c2ecf20Sopenharmony_ci#define TXEFS_EFFL_MASK (0x3f << TXEFS_EFFL_SHIFT) 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci/* Tx Event FIFO Acknowledge (TXEFA) */ 2808c2ecf20Sopenharmony_ci#define TXEFA_EFAI_SHIFT 0 2818c2ecf20Sopenharmony_ci#define TXEFA_EFAI_MASK (0x1f << TXEFA_EFAI_SHIFT) 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci/* Message RAM Configuration (in bytes) */ 2848c2ecf20Sopenharmony_ci#define SIDF_ELEMENT_SIZE 4 2858c2ecf20Sopenharmony_ci#define XIDF_ELEMENT_SIZE 8 2868c2ecf20Sopenharmony_ci#define RXF0_ELEMENT_SIZE 72 2878c2ecf20Sopenharmony_ci#define RXF1_ELEMENT_SIZE 72 2888c2ecf20Sopenharmony_ci#define RXB_ELEMENT_SIZE 72 2898c2ecf20Sopenharmony_ci#define TXE_ELEMENT_SIZE 8 2908c2ecf20Sopenharmony_ci#define TXB_ELEMENT_SIZE 72 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci/* Message RAM Elements */ 2938c2ecf20Sopenharmony_ci#define M_CAN_FIFO_ID 0x0 2948c2ecf20Sopenharmony_ci#define M_CAN_FIFO_DLC 0x4 2958c2ecf20Sopenharmony_ci#define M_CAN_FIFO_DATA(n) (0x8 + ((n) << 2)) 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci/* Rx Buffer Element */ 2988c2ecf20Sopenharmony_ci/* R0 */ 2998c2ecf20Sopenharmony_ci#define RX_BUF_ESI BIT(31) 3008c2ecf20Sopenharmony_ci#define RX_BUF_XTD BIT(30) 3018c2ecf20Sopenharmony_ci#define RX_BUF_RTR BIT(29) 3028c2ecf20Sopenharmony_ci/* R1 */ 3038c2ecf20Sopenharmony_ci#define RX_BUF_ANMF BIT(31) 3048c2ecf20Sopenharmony_ci#define RX_BUF_FDF BIT(21) 3058c2ecf20Sopenharmony_ci#define RX_BUF_BRS BIT(20) 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci/* Tx Buffer Element */ 3088c2ecf20Sopenharmony_ci/* T0 */ 3098c2ecf20Sopenharmony_ci#define TX_BUF_ESI BIT(31) 3108c2ecf20Sopenharmony_ci#define TX_BUF_XTD BIT(30) 3118c2ecf20Sopenharmony_ci#define TX_BUF_RTR BIT(29) 3128c2ecf20Sopenharmony_ci/* T1 */ 3138c2ecf20Sopenharmony_ci#define TX_BUF_EFC BIT(23) 3148c2ecf20Sopenharmony_ci#define TX_BUF_FDF BIT(21) 3158c2ecf20Sopenharmony_ci#define TX_BUF_BRS BIT(20) 3168c2ecf20Sopenharmony_ci#define TX_BUF_MM_SHIFT 24 3178c2ecf20Sopenharmony_ci#define TX_BUF_MM_MASK (0xff << TX_BUF_MM_SHIFT) 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci/* Tx event FIFO Element */ 3208c2ecf20Sopenharmony_ci/* E1 */ 3218c2ecf20Sopenharmony_ci#define TX_EVENT_MM_SHIFT TX_BUF_MM_SHIFT 3228c2ecf20Sopenharmony_ci#define TX_EVENT_MM_MASK (0xff << TX_EVENT_MM_SHIFT) 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic inline u32 m_can_read(struct m_can_classdev *cdev, enum m_can_reg reg) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci return cdev->ops->read_reg(cdev, reg); 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic inline void m_can_write(struct m_can_classdev *cdev, enum m_can_reg reg, 3308c2ecf20Sopenharmony_ci u32 val) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci cdev->ops->write_reg(cdev, reg, val); 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic u32 m_can_fifo_read(struct m_can_classdev *cdev, 3368c2ecf20Sopenharmony_ci u32 fgi, unsigned int offset) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci u32 addr_offset = cdev->mcfg[MRAM_RXF0].off + fgi * RXF0_ELEMENT_SIZE + 3398c2ecf20Sopenharmony_ci offset; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci return cdev->ops->read_fifo(cdev, addr_offset); 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic void m_can_fifo_write(struct m_can_classdev *cdev, 3458c2ecf20Sopenharmony_ci u32 fpi, unsigned int offset, u32 val) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci u32 addr_offset = cdev->mcfg[MRAM_TXB].off + fpi * TXB_ELEMENT_SIZE + 3488c2ecf20Sopenharmony_ci offset; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci cdev->ops->write_fifo(cdev, addr_offset, val); 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cistatic inline void m_can_fifo_write_no_off(struct m_can_classdev *cdev, 3548c2ecf20Sopenharmony_ci u32 fpi, u32 val) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci cdev->ops->write_fifo(cdev, fpi, val); 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic u32 m_can_txe_fifo_read(struct m_can_classdev *cdev, u32 fgi, u32 offset) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci u32 addr_offset = cdev->mcfg[MRAM_TXE].off + fgi * TXE_ELEMENT_SIZE + 3628c2ecf20Sopenharmony_ci offset; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci return cdev->ops->read_fifo(cdev, addr_offset); 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistatic inline bool m_can_tx_fifo_full(struct m_can_classdev *cdev) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci return !!(m_can_read(cdev, M_CAN_TXFQS) & TXFQS_TFQF); 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_civoid m_can_config_endisable(struct m_can_classdev *cdev, bool enable) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci u32 cccr = m_can_read(cdev, M_CAN_CCCR); 3758c2ecf20Sopenharmony_ci u32 timeout = 10; 3768c2ecf20Sopenharmony_ci u32 val = 0; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci /* Clear the Clock stop request if it was set */ 3798c2ecf20Sopenharmony_ci if (cccr & CCCR_CSR) 3808c2ecf20Sopenharmony_ci cccr &= ~CCCR_CSR; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci if (enable) { 3838c2ecf20Sopenharmony_ci /* enable m_can configuration */ 3848c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_CCCR, cccr | CCCR_INIT); 3858c2ecf20Sopenharmony_ci udelay(5); 3868c2ecf20Sopenharmony_ci /* CCCR.CCE can only be set/reset while CCCR.INIT = '1' */ 3878c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_CCCR, cccr | CCCR_INIT | CCCR_CCE); 3888c2ecf20Sopenharmony_ci } else { 3898c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_CCCR, cccr & ~(CCCR_INIT | CCCR_CCE)); 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci /* there's a delay for module initialization */ 3938c2ecf20Sopenharmony_ci if (enable) 3948c2ecf20Sopenharmony_ci val = CCCR_INIT | CCCR_CCE; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci while ((m_can_read(cdev, M_CAN_CCCR) & (CCCR_INIT | CCCR_CCE)) != val) { 3978c2ecf20Sopenharmony_ci if (timeout == 0) { 3988c2ecf20Sopenharmony_ci netdev_warn(cdev->net, "Failed to init module\n"); 3998c2ecf20Sopenharmony_ci return; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci timeout--; 4028c2ecf20Sopenharmony_ci udelay(1); 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic inline void m_can_enable_all_interrupts(struct m_can_classdev *cdev) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci /* Only interrupt line 0 is used in this driver */ 4098c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_ILE, ILE_EINT0); 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_cistatic inline void m_can_disable_all_interrupts(struct m_can_classdev *cdev) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_ILE, 0x0); 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic void m_can_clean(struct net_device *net) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci struct m_can_classdev *cdev = netdev_priv(net); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci if (cdev->tx_skb) { 4228c2ecf20Sopenharmony_ci int putidx = 0; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci net->stats.tx_errors++; 4258c2ecf20Sopenharmony_ci if (cdev->version > 30) 4268c2ecf20Sopenharmony_ci putidx = ((m_can_read(cdev, M_CAN_TXFQS) & 4278c2ecf20Sopenharmony_ci TXFQS_TFQPI_MASK) >> TXFQS_TFQPI_SHIFT); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci can_free_echo_skb(cdev->net, putidx); 4308c2ecf20Sopenharmony_ci cdev->tx_skb = NULL; 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_cistatic void m_can_read_fifo(struct net_device *dev, u32 rxfs) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci struct net_device_stats *stats = &dev->stats; 4378c2ecf20Sopenharmony_ci struct m_can_classdev *cdev = netdev_priv(dev); 4388c2ecf20Sopenharmony_ci struct canfd_frame *cf; 4398c2ecf20Sopenharmony_ci struct sk_buff *skb; 4408c2ecf20Sopenharmony_ci u32 id, fgi, dlc; 4418c2ecf20Sopenharmony_ci int i; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci /* calculate the fifo get index for where to read data */ 4448c2ecf20Sopenharmony_ci fgi = (rxfs & RXFS_FGI_MASK) >> RXFS_FGI_SHIFT; 4458c2ecf20Sopenharmony_ci dlc = m_can_fifo_read(cdev, fgi, M_CAN_FIFO_DLC); 4468c2ecf20Sopenharmony_ci if (dlc & RX_BUF_FDF) 4478c2ecf20Sopenharmony_ci skb = alloc_canfd_skb(dev, &cf); 4488c2ecf20Sopenharmony_ci else 4498c2ecf20Sopenharmony_ci skb = alloc_can_skb(dev, (struct can_frame **)&cf); 4508c2ecf20Sopenharmony_ci if (!skb) { 4518c2ecf20Sopenharmony_ci stats->rx_dropped++; 4528c2ecf20Sopenharmony_ci return; 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci if (dlc & RX_BUF_FDF) 4568c2ecf20Sopenharmony_ci cf->len = can_dlc2len((dlc >> 16) & 0x0F); 4578c2ecf20Sopenharmony_ci else 4588c2ecf20Sopenharmony_ci cf->len = get_can_dlc((dlc >> 16) & 0x0F); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci id = m_can_fifo_read(cdev, fgi, M_CAN_FIFO_ID); 4618c2ecf20Sopenharmony_ci if (id & RX_BUF_XTD) 4628c2ecf20Sopenharmony_ci cf->can_id = (id & CAN_EFF_MASK) | CAN_EFF_FLAG; 4638c2ecf20Sopenharmony_ci else 4648c2ecf20Sopenharmony_ci cf->can_id = (id >> 18) & CAN_SFF_MASK; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (id & RX_BUF_ESI) { 4678c2ecf20Sopenharmony_ci cf->flags |= CANFD_ESI; 4688c2ecf20Sopenharmony_ci netdev_dbg(dev, "ESI Error\n"); 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (!(dlc & RX_BUF_FDF) && (id & RX_BUF_RTR)) { 4728c2ecf20Sopenharmony_ci cf->can_id |= CAN_RTR_FLAG; 4738c2ecf20Sopenharmony_ci } else { 4748c2ecf20Sopenharmony_ci if (dlc & RX_BUF_BRS) 4758c2ecf20Sopenharmony_ci cf->flags |= CANFD_BRS; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci for (i = 0; i < cf->len; i += 4) 4788c2ecf20Sopenharmony_ci *(u32 *)(cf->data + i) = 4798c2ecf20Sopenharmony_ci m_can_fifo_read(cdev, fgi, 4808c2ecf20Sopenharmony_ci M_CAN_FIFO_DATA(i / 4)); 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci /* acknowledge rx fifo 0 */ 4848c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_RXF0A, fgi); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci stats->rx_packets++; 4878c2ecf20Sopenharmony_ci stats->rx_bytes += cf->len; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci netif_receive_skb(skb); 4908c2ecf20Sopenharmony_ci} 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_cistatic int m_can_do_rx_poll(struct net_device *dev, int quota) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci struct m_can_classdev *cdev = netdev_priv(dev); 4958c2ecf20Sopenharmony_ci u32 pkts = 0; 4968c2ecf20Sopenharmony_ci u32 rxfs; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci rxfs = m_can_read(cdev, M_CAN_RXF0S); 4998c2ecf20Sopenharmony_ci if (!(rxfs & RXFS_FFL_MASK)) { 5008c2ecf20Sopenharmony_ci netdev_dbg(dev, "no messages in fifo0\n"); 5018c2ecf20Sopenharmony_ci return 0; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci while ((rxfs & RXFS_FFL_MASK) && (quota > 0)) { 5058c2ecf20Sopenharmony_ci m_can_read_fifo(dev, rxfs); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci quota--; 5088c2ecf20Sopenharmony_ci pkts++; 5098c2ecf20Sopenharmony_ci rxfs = m_can_read(cdev, M_CAN_RXF0S); 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci if (pkts) 5138c2ecf20Sopenharmony_ci can_led_event(dev, CAN_LED_EVENT_RX); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci return pkts; 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_cistatic int m_can_handle_lost_msg(struct net_device *dev) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci struct net_device_stats *stats = &dev->stats; 5218c2ecf20Sopenharmony_ci struct sk_buff *skb; 5228c2ecf20Sopenharmony_ci struct can_frame *frame; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci netdev_err(dev, "msg lost in rxf0\n"); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci stats->rx_errors++; 5278c2ecf20Sopenharmony_ci stats->rx_over_errors++; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci skb = alloc_can_err_skb(dev, &frame); 5308c2ecf20Sopenharmony_ci if (unlikely(!skb)) 5318c2ecf20Sopenharmony_ci return 0; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci frame->can_id |= CAN_ERR_CRTL; 5348c2ecf20Sopenharmony_ci frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci netif_receive_skb(skb); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci return 1; 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_cistatic int m_can_handle_lec_err(struct net_device *dev, 5428c2ecf20Sopenharmony_ci enum m_can_lec_type lec_type) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci struct m_can_classdev *cdev = netdev_priv(dev); 5458c2ecf20Sopenharmony_ci struct net_device_stats *stats = &dev->stats; 5468c2ecf20Sopenharmony_ci struct can_frame *cf; 5478c2ecf20Sopenharmony_ci struct sk_buff *skb; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci cdev->can.can_stats.bus_error++; 5508c2ecf20Sopenharmony_ci stats->rx_errors++; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci /* propagate the error condition to the CAN stack */ 5538c2ecf20Sopenharmony_ci skb = alloc_can_err_skb(dev, &cf); 5548c2ecf20Sopenharmony_ci if (unlikely(!skb)) 5558c2ecf20Sopenharmony_ci return 0; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci /* check for 'last error code' which tells us the 5588c2ecf20Sopenharmony_ci * type of the last error to occur on the CAN bus 5598c2ecf20Sopenharmony_ci */ 5608c2ecf20Sopenharmony_ci cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci switch (lec_type) { 5638c2ecf20Sopenharmony_ci case LEC_STUFF_ERROR: 5648c2ecf20Sopenharmony_ci netdev_dbg(dev, "stuff error\n"); 5658c2ecf20Sopenharmony_ci cf->data[2] |= CAN_ERR_PROT_STUFF; 5668c2ecf20Sopenharmony_ci break; 5678c2ecf20Sopenharmony_ci case LEC_FORM_ERROR: 5688c2ecf20Sopenharmony_ci netdev_dbg(dev, "form error\n"); 5698c2ecf20Sopenharmony_ci cf->data[2] |= CAN_ERR_PROT_FORM; 5708c2ecf20Sopenharmony_ci break; 5718c2ecf20Sopenharmony_ci case LEC_ACK_ERROR: 5728c2ecf20Sopenharmony_ci netdev_dbg(dev, "ack error\n"); 5738c2ecf20Sopenharmony_ci cf->data[3] = CAN_ERR_PROT_LOC_ACK; 5748c2ecf20Sopenharmony_ci break; 5758c2ecf20Sopenharmony_ci case LEC_BIT1_ERROR: 5768c2ecf20Sopenharmony_ci netdev_dbg(dev, "bit1 error\n"); 5778c2ecf20Sopenharmony_ci cf->data[2] |= CAN_ERR_PROT_BIT1; 5788c2ecf20Sopenharmony_ci break; 5798c2ecf20Sopenharmony_ci case LEC_BIT0_ERROR: 5808c2ecf20Sopenharmony_ci netdev_dbg(dev, "bit0 error\n"); 5818c2ecf20Sopenharmony_ci cf->data[2] |= CAN_ERR_PROT_BIT0; 5828c2ecf20Sopenharmony_ci break; 5838c2ecf20Sopenharmony_ci case LEC_CRC_ERROR: 5848c2ecf20Sopenharmony_ci netdev_dbg(dev, "CRC error\n"); 5858c2ecf20Sopenharmony_ci cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; 5868c2ecf20Sopenharmony_ci break; 5878c2ecf20Sopenharmony_ci default: 5888c2ecf20Sopenharmony_ci break; 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci stats->rx_packets++; 5928c2ecf20Sopenharmony_ci stats->rx_bytes += cf->can_dlc; 5938c2ecf20Sopenharmony_ci netif_receive_skb(skb); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci return 1; 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_cistatic int __m_can_get_berr_counter(const struct net_device *dev, 5998c2ecf20Sopenharmony_ci struct can_berr_counter *bec) 6008c2ecf20Sopenharmony_ci{ 6018c2ecf20Sopenharmony_ci struct m_can_classdev *cdev = netdev_priv(dev); 6028c2ecf20Sopenharmony_ci unsigned int ecr; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci ecr = m_can_read(cdev, M_CAN_ECR); 6058c2ecf20Sopenharmony_ci bec->rxerr = (ecr & ECR_REC_MASK) >> ECR_REC_SHIFT; 6068c2ecf20Sopenharmony_ci bec->txerr = (ecr & ECR_TEC_MASK) >> ECR_TEC_SHIFT; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci return 0; 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_cistatic int m_can_clk_start(struct m_can_classdev *cdev) 6128c2ecf20Sopenharmony_ci{ 6138c2ecf20Sopenharmony_ci int err; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci if (cdev->pm_clock_support == 0) 6168c2ecf20Sopenharmony_ci return 0; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci err = pm_runtime_get_sync(cdev->dev); 6198c2ecf20Sopenharmony_ci if (err < 0) { 6208c2ecf20Sopenharmony_ci pm_runtime_put_noidle(cdev->dev); 6218c2ecf20Sopenharmony_ci return err; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci return 0; 6258c2ecf20Sopenharmony_ci} 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_cistatic void m_can_clk_stop(struct m_can_classdev *cdev) 6288c2ecf20Sopenharmony_ci{ 6298c2ecf20Sopenharmony_ci if (cdev->pm_clock_support) 6308c2ecf20Sopenharmony_ci pm_runtime_put_sync(cdev->dev); 6318c2ecf20Sopenharmony_ci} 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cistatic int m_can_get_berr_counter(const struct net_device *dev, 6348c2ecf20Sopenharmony_ci struct can_berr_counter *bec) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci struct m_can_classdev *cdev = netdev_priv(dev); 6378c2ecf20Sopenharmony_ci int err; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci err = m_can_clk_start(cdev); 6408c2ecf20Sopenharmony_ci if (err) 6418c2ecf20Sopenharmony_ci return err; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci __m_can_get_berr_counter(dev, bec); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci m_can_clk_stop(cdev); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci return 0; 6488c2ecf20Sopenharmony_ci} 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_cistatic int m_can_handle_state_change(struct net_device *dev, 6518c2ecf20Sopenharmony_ci enum can_state new_state) 6528c2ecf20Sopenharmony_ci{ 6538c2ecf20Sopenharmony_ci struct m_can_classdev *cdev = netdev_priv(dev); 6548c2ecf20Sopenharmony_ci struct net_device_stats *stats = &dev->stats; 6558c2ecf20Sopenharmony_ci struct can_frame *cf; 6568c2ecf20Sopenharmony_ci struct sk_buff *skb; 6578c2ecf20Sopenharmony_ci struct can_berr_counter bec; 6588c2ecf20Sopenharmony_ci unsigned int ecr; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci switch (new_state) { 6618c2ecf20Sopenharmony_ci case CAN_STATE_ERROR_WARNING: 6628c2ecf20Sopenharmony_ci /* error warning state */ 6638c2ecf20Sopenharmony_ci cdev->can.can_stats.error_warning++; 6648c2ecf20Sopenharmony_ci cdev->can.state = CAN_STATE_ERROR_WARNING; 6658c2ecf20Sopenharmony_ci break; 6668c2ecf20Sopenharmony_ci case CAN_STATE_ERROR_PASSIVE: 6678c2ecf20Sopenharmony_ci /* error passive state */ 6688c2ecf20Sopenharmony_ci cdev->can.can_stats.error_passive++; 6698c2ecf20Sopenharmony_ci cdev->can.state = CAN_STATE_ERROR_PASSIVE; 6708c2ecf20Sopenharmony_ci break; 6718c2ecf20Sopenharmony_ci case CAN_STATE_BUS_OFF: 6728c2ecf20Sopenharmony_ci /* bus-off state */ 6738c2ecf20Sopenharmony_ci cdev->can.state = CAN_STATE_BUS_OFF; 6748c2ecf20Sopenharmony_ci m_can_disable_all_interrupts(cdev); 6758c2ecf20Sopenharmony_ci cdev->can.can_stats.bus_off++; 6768c2ecf20Sopenharmony_ci can_bus_off(dev); 6778c2ecf20Sopenharmony_ci break; 6788c2ecf20Sopenharmony_ci default: 6798c2ecf20Sopenharmony_ci break; 6808c2ecf20Sopenharmony_ci } 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci /* propagate the error condition to the CAN stack */ 6838c2ecf20Sopenharmony_ci skb = alloc_can_err_skb(dev, &cf); 6848c2ecf20Sopenharmony_ci if (unlikely(!skb)) 6858c2ecf20Sopenharmony_ci return 0; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci __m_can_get_berr_counter(dev, &bec); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci switch (new_state) { 6908c2ecf20Sopenharmony_ci case CAN_STATE_ERROR_WARNING: 6918c2ecf20Sopenharmony_ci /* error warning state */ 6928c2ecf20Sopenharmony_ci cf->can_id |= CAN_ERR_CRTL; 6938c2ecf20Sopenharmony_ci cf->data[1] = (bec.txerr > bec.rxerr) ? 6948c2ecf20Sopenharmony_ci CAN_ERR_CRTL_TX_WARNING : 6958c2ecf20Sopenharmony_ci CAN_ERR_CRTL_RX_WARNING; 6968c2ecf20Sopenharmony_ci cf->data[6] = bec.txerr; 6978c2ecf20Sopenharmony_ci cf->data[7] = bec.rxerr; 6988c2ecf20Sopenharmony_ci break; 6998c2ecf20Sopenharmony_ci case CAN_STATE_ERROR_PASSIVE: 7008c2ecf20Sopenharmony_ci /* error passive state */ 7018c2ecf20Sopenharmony_ci cf->can_id |= CAN_ERR_CRTL; 7028c2ecf20Sopenharmony_ci ecr = m_can_read(cdev, M_CAN_ECR); 7038c2ecf20Sopenharmony_ci if (ecr & ECR_RP) 7048c2ecf20Sopenharmony_ci cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE; 7058c2ecf20Sopenharmony_ci if (bec.txerr > 127) 7068c2ecf20Sopenharmony_ci cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE; 7078c2ecf20Sopenharmony_ci cf->data[6] = bec.txerr; 7088c2ecf20Sopenharmony_ci cf->data[7] = bec.rxerr; 7098c2ecf20Sopenharmony_ci break; 7108c2ecf20Sopenharmony_ci case CAN_STATE_BUS_OFF: 7118c2ecf20Sopenharmony_ci /* bus-off state */ 7128c2ecf20Sopenharmony_ci cf->can_id |= CAN_ERR_BUSOFF; 7138c2ecf20Sopenharmony_ci break; 7148c2ecf20Sopenharmony_ci default: 7158c2ecf20Sopenharmony_ci break; 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci stats->rx_packets++; 7198c2ecf20Sopenharmony_ci stats->rx_bytes += cf->can_dlc; 7208c2ecf20Sopenharmony_ci netif_receive_skb(skb); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci return 1; 7238c2ecf20Sopenharmony_ci} 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_cistatic int m_can_handle_state_errors(struct net_device *dev, u32 psr) 7268c2ecf20Sopenharmony_ci{ 7278c2ecf20Sopenharmony_ci struct m_can_classdev *cdev = netdev_priv(dev); 7288c2ecf20Sopenharmony_ci int work_done = 0; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci if (psr & PSR_EW && cdev->can.state != CAN_STATE_ERROR_WARNING) { 7318c2ecf20Sopenharmony_ci netdev_dbg(dev, "entered error warning state\n"); 7328c2ecf20Sopenharmony_ci work_done += m_can_handle_state_change(dev, 7338c2ecf20Sopenharmony_ci CAN_STATE_ERROR_WARNING); 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci if (psr & PSR_EP && cdev->can.state != CAN_STATE_ERROR_PASSIVE) { 7378c2ecf20Sopenharmony_ci netdev_dbg(dev, "entered error passive state\n"); 7388c2ecf20Sopenharmony_ci work_done += m_can_handle_state_change(dev, 7398c2ecf20Sopenharmony_ci CAN_STATE_ERROR_PASSIVE); 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci if (psr & PSR_BO && cdev->can.state != CAN_STATE_BUS_OFF) { 7438c2ecf20Sopenharmony_ci netdev_dbg(dev, "entered error bus off state\n"); 7448c2ecf20Sopenharmony_ci work_done += m_can_handle_state_change(dev, 7458c2ecf20Sopenharmony_ci CAN_STATE_BUS_OFF); 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci return work_done; 7498c2ecf20Sopenharmony_ci} 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_cistatic void m_can_handle_other_err(struct net_device *dev, u32 irqstatus) 7528c2ecf20Sopenharmony_ci{ 7538c2ecf20Sopenharmony_ci if (irqstatus & IR_WDI) 7548c2ecf20Sopenharmony_ci netdev_err(dev, "Message RAM Watchdog event due to missing READY\n"); 7558c2ecf20Sopenharmony_ci if (irqstatus & IR_BEU) 7568c2ecf20Sopenharmony_ci netdev_err(dev, "Bit Error Uncorrected\n"); 7578c2ecf20Sopenharmony_ci if (irqstatus & IR_BEC) 7588c2ecf20Sopenharmony_ci netdev_err(dev, "Bit Error Corrected\n"); 7598c2ecf20Sopenharmony_ci if (irqstatus & IR_TOO) 7608c2ecf20Sopenharmony_ci netdev_err(dev, "Timeout reached\n"); 7618c2ecf20Sopenharmony_ci if (irqstatus & IR_MRAF) 7628c2ecf20Sopenharmony_ci netdev_err(dev, "Message RAM access failure occurred\n"); 7638c2ecf20Sopenharmony_ci} 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_cistatic inline bool is_lec_err(u32 psr) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci psr &= LEC_UNUSED; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci return psr && (psr != LEC_UNUSED); 7708c2ecf20Sopenharmony_ci} 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_cistatic inline bool m_can_is_protocol_err(u32 irqstatus) 7738c2ecf20Sopenharmony_ci{ 7748c2ecf20Sopenharmony_ci return irqstatus & IR_ERR_LEC_31X; 7758c2ecf20Sopenharmony_ci} 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_cistatic int m_can_handle_protocol_error(struct net_device *dev, u32 irqstatus) 7788c2ecf20Sopenharmony_ci{ 7798c2ecf20Sopenharmony_ci struct net_device_stats *stats = &dev->stats; 7808c2ecf20Sopenharmony_ci struct m_can_classdev *cdev = netdev_priv(dev); 7818c2ecf20Sopenharmony_ci struct can_frame *cf; 7828c2ecf20Sopenharmony_ci struct sk_buff *skb; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci /* propagate the error condition to the CAN stack */ 7858c2ecf20Sopenharmony_ci skb = alloc_can_err_skb(dev, &cf); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci /* update tx error stats since there is protocol error */ 7888c2ecf20Sopenharmony_ci stats->tx_errors++; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci /* update arbitration lost status */ 7918c2ecf20Sopenharmony_ci if (cdev->version >= 31 && (irqstatus & IR_PEA)) { 7928c2ecf20Sopenharmony_ci netdev_dbg(dev, "Protocol error in Arbitration fail\n"); 7938c2ecf20Sopenharmony_ci cdev->can.can_stats.arbitration_lost++; 7948c2ecf20Sopenharmony_ci if (skb) { 7958c2ecf20Sopenharmony_ci cf->can_id |= CAN_ERR_LOSTARB; 7968c2ecf20Sopenharmony_ci cf->data[0] |= CAN_ERR_LOSTARB_UNSPEC; 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci if (unlikely(!skb)) { 8018c2ecf20Sopenharmony_ci netdev_dbg(dev, "allocation of skb failed\n"); 8028c2ecf20Sopenharmony_ci return 0; 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci netif_receive_skb(skb); 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci return 1; 8078c2ecf20Sopenharmony_ci} 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_cistatic int m_can_handle_bus_errors(struct net_device *dev, u32 irqstatus, 8108c2ecf20Sopenharmony_ci u32 psr) 8118c2ecf20Sopenharmony_ci{ 8128c2ecf20Sopenharmony_ci struct m_can_classdev *cdev = netdev_priv(dev); 8138c2ecf20Sopenharmony_ci int work_done = 0; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci if (irqstatus & IR_RF0L) 8168c2ecf20Sopenharmony_ci work_done += m_can_handle_lost_msg(dev); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci /* handle lec errors on the bus */ 8198c2ecf20Sopenharmony_ci if ((cdev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) && 8208c2ecf20Sopenharmony_ci is_lec_err(psr)) 8218c2ecf20Sopenharmony_ci work_done += m_can_handle_lec_err(dev, psr & LEC_UNUSED); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci /* handle protocol errors in arbitration phase */ 8248c2ecf20Sopenharmony_ci if ((cdev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) && 8258c2ecf20Sopenharmony_ci m_can_is_protocol_err(irqstatus)) 8268c2ecf20Sopenharmony_ci work_done += m_can_handle_protocol_error(dev, irqstatus); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci /* other unproccessed error interrupts */ 8298c2ecf20Sopenharmony_ci m_can_handle_other_err(dev, irqstatus); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci return work_done; 8328c2ecf20Sopenharmony_ci} 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_cistatic int m_can_rx_handler(struct net_device *dev, int quota) 8358c2ecf20Sopenharmony_ci{ 8368c2ecf20Sopenharmony_ci struct m_can_classdev *cdev = netdev_priv(dev); 8378c2ecf20Sopenharmony_ci int work_done = 0; 8388c2ecf20Sopenharmony_ci u32 irqstatus, psr; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci irqstatus = cdev->irqstatus | m_can_read(cdev, M_CAN_IR); 8418c2ecf20Sopenharmony_ci if (!irqstatus) 8428c2ecf20Sopenharmony_ci goto end; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci /* Errata workaround for issue "Needless activation of MRAF irq" 8458c2ecf20Sopenharmony_ci * During frame reception while the MCAN is in Error Passive state 8468c2ecf20Sopenharmony_ci * and the Receive Error Counter has the value MCAN_ECR.REC = 127, 8478c2ecf20Sopenharmony_ci * it may happen that MCAN_IR.MRAF is set although there was no 8488c2ecf20Sopenharmony_ci * Message RAM access failure. 8498c2ecf20Sopenharmony_ci * If MCAN_IR.MRAF is enabled, an interrupt to the Host CPU is generated 8508c2ecf20Sopenharmony_ci * The Message RAM Access Failure interrupt routine needs to check 8518c2ecf20Sopenharmony_ci * whether MCAN_ECR.RP = ’1’ and MCAN_ECR.REC = 127. 8528c2ecf20Sopenharmony_ci * In this case, reset MCAN_IR.MRAF. No further action is required. 8538c2ecf20Sopenharmony_ci */ 8548c2ecf20Sopenharmony_ci if (cdev->version <= 31 && irqstatus & IR_MRAF && 8558c2ecf20Sopenharmony_ci m_can_read(cdev, M_CAN_ECR) & ECR_RP) { 8568c2ecf20Sopenharmony_ci struct can_berr_counter bec; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci __m_can_get_berr_counter(dev, &bec); 8598c2ecf20Sopenharmony_ci if (bec.rxerr == 127) { 8608c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_IR, IR_MRAF); 8618c2ecf20Sopenharmony_ci irqstatus &= ~IR_MRAF; 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci } 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci psr = m_can_read(cdev, M_CAN_PSR); 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci if (irqstatus & IR_ERR_STATE) 8688c2ecf20Sopenharmony_ci work_done += m_can_handle_state_errors(dev, psr); 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci if (irqstatus & IR_ERR_BUS_30X) 8718c2ecf20Sopenharmony_ci work_done += m_can_handle_bus_errors(dev, irqstatus, psr); 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci if (irqstatus & IR_RF0N) 8748c2ecf20Sopenharmony_ci work_done += m_can_do_rx_poll(dev, (quota - work_done)); 8758c2ecf20Sopenharmony_ciend: 8768c2ecf20Sopenharmony_ci return work_done; 8778c2ecf20Sopenharmony_ci} 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_cistatic int m_can_rx_peripheral(struct net_device *dev) 8808c2ecf20Sopenharmony_ci{ 8818c2ecf20Sopenharmony_ci struct m_can_classdev *cdev = netdev_priv(dev); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci m_can_rx_handler(dev, M_CAN_NAPI_WEIGHT); 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci m_can_enable_all_interrupts(cdev); 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci return 0; 8888c2ecf20Sopenharmony_ci} 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_cistatic int m_can_poll(struct napi_struct *napi, int quota) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci struct net_device *dev = napi->dev; 8938c2ecf20Sopenharmony_ci struct m_can_classdev *cdev = netdev_priv(dev); 8948c2ecf20Sopenharmony_ci int work_done; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci work_done = m_can_rx_handler(dev, quota); 8978c2ecf20Sopenharmony_ci if (work_done < quota) { 8988c2ecf20Sopenharmony_ci napi_complete_done(napi, work_done); 8998c2ecf20Sopenharmony_ci m_can_enable_all_interrupts(cdev); 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci return work_done; 9038c2ecf20Sopenharmony_ci} 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_cistatic void m_can_echo_tx_event(struct net_device *dev) 9068c2ecf20Sopenharmony_ci{ 9078c2ecf20Sopenharmony_ci u32 txe_count = 0; 9088c2ecf20Sopenharmony_ci u32 m_can_txefs; 9098c2ecf20Sopenharmony_ci u32 fgi = 0; 9108c2ecf20Sopenharmony_ci int i = 0; 9118c2ecf20Sopenharmony_ci unsigned int msg_mark; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci struct m_can_classdev *cdev = netdev_priv(dev); 9148c2ecf20Sopenharmony_ci struct net_device_stats *stats = &dev->stats; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci /* read tx event fifo status */ 9178c2ecf20Sopenharmony_ci m_can_txefs = m_can_read(cdev, M_CAN_TXEFS); 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci /* Get Tx Event fifo element count */ 9208c2ecf20Sopenharmony_ci txe_count = (m_can_txefs & TXEFS_EFFL_MASK) 9218c2ecf20Sopenharmony_ci >> TXEFS_EFFL_SHIFT; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci /* Get and process all sent elements */ 9248c2ecf20Sopenharmony_ci for (i = 0; i < txe_count; i++) { 9258c2ecf20Sopenharmony_ci /* retrieve get index */ 9268c2ecf20Sopenharmony_ci fgi = (m_can_read(cdev, M_CAN_TXEFS) & TXEFS_EFGI_MASK) 9278c2ecf20Sopenharmony_ci >> TXEFS_EFGI_SHIFT; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci /* get message marker */ 9308c2ecf20Sopenharmony_ci msg_mark = (m_can_txe_fifo_read(cdev, fgi, 4) & 9318c2ecf20Sopenharmony_ci TX_EVENT_MM_MASK) >> TX_EVENT_MM_SHIFT; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci /* ack txe element */ 9348c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_TXEFA, (TXEFA_EFAI_MASK & 9358c2ecf20Sopenharmony_ci (fgi << TXEFA_EFAI_SHIFT))); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci /* update stats */ 9388c2ecf20Sopenharmony_ci stats->tx_bytes += can_get_echo_skb(dev, msg_mark); 9398c2ecf20Sopenharmony_ci stats->tx_packets++; 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci} 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_cistatic irqreturn_t m_can_isr(int irq, void *dev_id) 9448c2ecf20Sopenharmony_ci{ 9458c2ecf20Sopenharmony_ci struct net_device *dev = (struct net_device *)dev_id; 9468c2ecf20Sopenharmony_ci struct m_can_classdev *cdev = netdev_priv(dev); 9478c2ecf20Sopenharmony_ci struct net_device_stats *stats = &dev->stats; 9488c2ecf20Sopenharmony_ci u32 ir; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci if (pm_runtime_suspended(cdev->dev)) 9518c2ecf20Sopenharmony_ci return IRQ_NONE; 9528c2ecf20Sopenharmony_ci ir = m_can_read(cdev, M_CAN_IR); 9538c2ecf20Sopenharmony_ci if (!ir) 9548c2ecf20Sopenharmony_ci return IRQ_NONE; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci /* ACK all irqs */ 9578c2ecf20Sopenharmony_ci if (ir & IR_ALL_INT) 9588c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_IR, ir); 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci if (cdev->ops->clear_interrupts) 9618c2ecf20Sopenharmony_ci cdev->ops->clear_interrupts(cdev); 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci /* schedule NAPI in case of 9648c2ecf20Sopenharmony_ci * - rx IRQ 9658c2ecf20Sopenharmony_ci * - state change IRQ 9668c2ecf20Sopenharmony_ci * - bus error IRQ and bus error reporting 9678c2ecf20Sopenharmony_ci */ 9688c2ecf20Sopenharmony_ci if ((ir & IR_RF0N) || (ir & IR_ERR_ALL_30X)) { 9698c2ecf20Sopenharmony_ci cdev->irqstatus = ir; 9708c2ecf20Sopenharmony_ci m_can_disable_all_interrupts(cdev); 9718c2ecf20Sopenharmony_ci if (!cdev->is_peripheral) 9728c2ecf20Sopenharmony_ci napi_schedule(&cdev->napi); 9738c2ecf20Sopenharmony_ci else 9748c2ecf20Sopenharmony_ci m_can_rx_peripheral(dev); 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci if (cdev->version == 30) { 9788c2ecf20Sopenharmony_ci if (ir & IR_TC) { 9798c2ecf20Sopenharmony_ci /* Transmission Complete Interrupt*/ 9808c2ecf20Sopenharmony_ci stats->tx_bytes += can_get_echo_skb(dev, 0); 9818c2ecf20Sopenharmony_ci stats->tx_packets++; 9828c2ecf20Sopenharmony_ci can_led_event(dev, CAN_LED_EVENT_TX); 9838c2ecf20Sopenharmony_ci netif_wake_queue(dev); 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci } else { 9868c2ecf20Sopenharmony_ci if (ir & IR_TEFN) { 9878c2ecf20Sopenharmony_ci /* New TX FIFO Element arrived */ 9888c2ecf20Sopenharmony_ci m_can_echo_tx_event(dev); 9898c2ecf20Sopenharmony_ci can_led_event(dev, CAN_LED_EVENT_TX); 9908c2ecf20Sopenharmony_ci if (netif_queue_stopped(dev) && 9918c2ecf20Sopenharmony_ci !m_can_tx_fifo_full(cdev)) 9928c2ecf20Sopenharmony_ci netif_wake_queue(dev); 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci return IRQ_HANDLED; 9978c2ecf20Sopenharmony_ci} 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_cistatic const struct can_bittiming_const m_can_bittiming_const_30X = { 10008c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 10018c2ecf20Sopenharmony_ci .tseg1_min = 2, /* Time segment 1 = prop_seg + phase_seg1 */ 10028c2ecf20Sopenharmony_ci .tseg1_max = 64, 10038c2ecf20Sopenharmony_ci .tseg2_min = 1, /* Time segment 2 = phase_seg2 */ 10048c2ecf20Sopenharmony_ci .tseg2_max = 16, 10058c2ecf20Sopenharmony_ci .sjw_max = 16, 10068c2ecf20Sopenharmony_ci .brp_min = 1, 10078c2ecf20Sopenharmony_ci .brp_max = 1024, 10088c2ecf20Sopenharmony_ci .brp_inc = 1, 10098c2ecf20Sopenharmony_ci}; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_cistatic const struct can_bittiming_const m_can_data_bittiming_const_30X = { 10128c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 10138c2ecf20Sopenharmony_ci .tseg1_min = 2, /* Time segment 1 = prop_seg + phase_seg1 */ 10148c2ecf20Sopenharmony_ci .tseg1_max = 16, 10158c2ecf20Sopenharmony_ci .tseg2_min = 1, /* Time segment 2 = phase_seg2 */ 10168c2ecf20Sopenharmony_ci .tseg2_max = 8, 10178c2ecf20Sopenharmony_ci .sjw_max = 4, 10188c2ecf20Sopenharmony_ci .brp_min = 1, 10198c2ecf20Sopenharmony_ci .brp_max = 32, 10208c2ecf20Sopenharmony_ci .brp_inc = 1, 10218c2ecf20Sopenharmony_ci}; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_cistatic const struct can_bittiming_const m_can_bittiming_const_31X = { 10248c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 10258c2ecf20Sopenharmony_ci .tseg1_min = 2, /* Time segment 1 = prop_seg + phase_seg1 */ 10268c2ecf20Sopenharmony_ci .tseg1_max = 256, 10278c2ecf20Sopenharmony_ci .tseg2_min = 2, /* Time segment 2 = phase_seg2 */ 10288c2ecf20Sopenharmony_ci .tseg2_max = 128, 10298c2ecf20Sopenharmony_ci .sjw_max = 128, 10308c2ecf20Sopenharmony_ci .brp_min = 1, 10318c2ecf20Sopenharmony_ci .brp_max = 512, 10328c2ecf20Sopenharmony_ci .brp_inc = 1, 10338c2ecf20Sopenharmony_ci}; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_cistatic const struct can_bittiming_const m_can_data_bittiming_const_31X = { 10368c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 10378c2ecf20Sopenharmony_ci .tseg1_min = 1, /* Time segment 1 = prop_seg + phase_seg1 */ 10388c2ecf20Sopenharmony_ci .tseg1_max = 32, 10398c2ecf20Sopenharmony_ci .tseg2_min = 1, /* Time segment 2 = phase_seg2 */ 10408c2ecf20Sopenharmony_ci .tseg2_max = 16, 10418c2ecf20Sopenharmony_ci .sjw_max = 16, 10428c2ecf20Sopenharmony_ci .brp_min = 1, 10438c2ecf20Sopenharmony_ci .brp_max = 32, 10448c2ecf20Sopenharmony_ci .brp_inc = 1, 10458c2ecf20Sopenharmony_ci}; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_cistatic int m_can_set_bittiming(struct net_device *dev) 10488c2ecf20Sopenharmony_ci{ 10498c2ecf20Sopenharmony_ci struct m_can_classdev *cdev = netdev_priv(dev); 10508c2ecf20Sopenharmony_ci const struct can_bittiming *bt = &cdev->can.bittiming; 10518c2ecf20Sopenharmony_ci const struct can_bittiming *dbt = &cdev->can.data_bittiming; 10528c2ecf20Sopenharmony_ci u16 brp, sjw, tseg1, tseg2; 10538c2ecf20Sopenharmony_ci u32 reg_btp; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci brp = bt->brp - 1; 10568c2ecf20Sopenharmony_ci sjw = bt->sjw - 1; 10578c2ecf20Sopenharmony_ci tseg1 = bt->prop_seg + bt->phase_seg1 - 1; 10588c2ecf20Sopenharmony_ci tseg2 = bt->phase_seg2 - 1; 10598c2ecf20Sopenharmony_ci reg_btp = (brp << NBTP_NBRP_SHIFT) | (sjw << NBTP_NSJW_SHIFT) | 10608c2ecf20Sopenharmony_ci (tseg1 << NBTP_NTSEG1_SHIFT) | (tseg2 << NBTP_NTSEG2_SHIFT); 10618c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_NBTP, reg_btp); 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci if (cdev->can.ctrlmode & CAN_CTRLMODE_FD) { 10648c2ecf20Sopenharmony_ci reg_btp = 0; 10658c2ecf20Sopenharmony_ci brp = dbt->brp - 1; 10668c2ecf20Sopenharmony_ci sjw = dbt->sjw - 1; 10678c2ecf20Sopenharmony_ci tseg1 = dbt->prop_seg + dbt->phase_seg1 - 1; 10688c2ecf20Sopenharmony_ci tseg2 = dbt->phase_seg2 - 1; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci /* TDC is only needed for bitrates beyond 2.5 MBit/s. 10718c2ecf20Sopenharmony_ci * This is mentioned in the "Bit Time Requirements for CAN FD" 10728c2ecf20Sopenharmony_ci * paper presented at the International CAN Conference 2013 10738c2ecf20Sopenharmony_ci */ 10748c2ecf20Sopenharmony_ci if (dbt->bitrate > 2500000) { 10758c2ecf20Sopenharmony_ci u32 tdco, ssp; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci /* Use the same value of secondary sampling point 10788c2ecf20Sopenharmony_ci * as the data sampling point 10798c2ecf20Sopenharmony_ci */ 10808c2ecf20Sopenharmony_ci ssp = dbt->sample_point; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci /* Equation based on Bosch's M_CAN User Manual's 10838c2ecf20Sopenharmony_ci * Transmitter Delay Compensation Section 10848c2ecf20Sopenharmony_ci */ 10858c2ecf20Sopenharmony_ci tdco = (cdev->can.clock.freq / 1000) * 10868c2ecf20Sopenharmony_ci ssp / dbt->bitrate; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci /* Max valid TDCO value is 127 */ 10898c2ecf20Sopenharmony_ci if (tdco > 127) { 10908c2ecf20Sopenharmony_ci netdev_warn(dev, "TDCO value of %u is beyond maximum. Using maximum possible value\n", 10918c2ecf20Sopenharmony_ci tdco); 10928c2ecf20Sopenharmony_ci tdco = 127; 10938c2ecf20Sopenharmony_ci } 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci reg_btp |= DBTP_TDC; 10968c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_TDCR, 10978c2ecf20Sopenharmony_ci tdco << TDCR_TDCO_SHIFT); 10988c2ecf20Sopenharmony_ci } 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci reg_btp |= (brp << DBTP_DBRP_SHIFT) | 11018c2ecf20Sopenharmony_ci (sjw << DBTP_DSJW_SHIFT) | 11028c2ecf20Sopenharmony_ci (tseg1 << DBTP_DTSEG1_SHIFT) | 11038c2ecf20Sopenharmony_ci (tseg2 << DBTP_DTSEG2_SHIFT); 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_DBTP, reg_btp); 11068c2ecf20Sopenharmony_ci } 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci return 0; 11098c2ecf20Sopenharmony_ci} 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci/* Configure M_CAN chip: 11128c2ecf20Sopenharmony_ci * - set rx buffer/fifo element size 11138c2ecf20Sopenharmony_ci * - configure rx fifo 11148c2ecf20Sopenharmony_ci * - accept non-matching frame into fifo 0 11158c2ecf20Sopenharmony_ci * - configure tx buffer 11168c2ecf20Sopenharmony_ci * - >= v3.1.x: TX FIFO is used 11178c2ecf20Sopenharmony_ci * - configure mode 11188c2ecf20Sopenharmony_ci * - setup bittiming 11198c2ecf20Sopenharmony_ci */ 11208c2ecf20Sopenharmony_cistatic void m_can_chip_config(struct net_device *dev) 11218c2ecf20Sopenharmony_ci{ 11228c2ecf20Sopenharmony_ci struct m_can_classdev *cdev = netdev_priv(dev); 11238c2ecf20Sopenharmony_ci u32 cccr, test; 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci m_can_config_endisable(cdev, true); 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci /* RX Buffer/FIFO Element Size 64 bytes data field */ 11288c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_RXESC, M_CAN_RXESC_64BYTES); 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci /* Accept Non-matching Frames Into FIFO 0 */ 11318c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_GFC, 0x0); 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci if (cdev->version == 30) { 11348c2ecf20Sopenharmony_ci /* only support one Tx Buffer currently */ 11358c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_TXBC, (1 << TXBC_NDTB_SHIFT) | 11368c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_TXB].off); 11378c2ecf20Sopenharmony_ci } else { 11388c2ecf20Sopenharmony_ci /* TX FIFO is used for newer IP Core versions */ 11398c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_TXBC, 11408c2ecf20Sopenharmony_ci (cdev->mcfg[MRAM_TXB].num << TXBC_TFQS_SHIFT) | 11418c2ecf20Sopenharmony_ci (cdev->mcfg[MRAM_TXB].off)); 11428c2ecf20Sopenharmony_ci } 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci /* support 64 bytes payload */ 11458c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_TXESC, TXESC_TBDS_64BYTES); 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci /* TX Event FIFO */ 11488c2ecf20Sopenharmony_ci if (cdev->version == 30) { 11498c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_TXEFC, (1 << TXEFC_EFS_SHIFT) | 11508c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_TXE].off); 11518c2ecf20Sopenharmony_ci } else { 11528c2ecf20Sopenharmony_ci /* Full TX Event FIFO is used */ 11538c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_TXEFC, 11548c2ecf20Sopenharmony_ci ((cdev->mcfg[MRAM_TXE].num << TXEFC_EFS_SHIFT) 11558c2ecf20Sopenharmony_ci & TXEFC_EFS_MASK) | 11568c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_TXE].off); 11578c2ecf20Sopenharmony_ci } 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci /* rx fifo configuration, blocking mode, fifo size 1 */ 11608c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_RXF0C, 11618c2ecf20Sopenharmony_ci (cdev->mcfg[MRAM_RXF0].num << RXFC_FS_SHIFT) | 11628c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_RXF0].off); 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_RXF1C, 11658c2ecf20Sopenharmony_ci (cdev->mcfg[MRAM_RXF1].num << RXFC_FS_SHIFT) | 11668c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_RXF1].off); 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci cccr = m_can_read(cdev, M_CAN_CCCR); 11698c2ecf20Sopenharmony_ci test = m_can_read(cdev, M_CAN_TEST); 11708c2ecf20Sopenharmony_ci test &= ~TEST_LBCK; 11718c2ecf20Sopenharmony_ci if (cdev->version == 30) { 11728c2ecf20Sopenharmony_ci /* Version 3.0.x */ 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci cccr &= ~(CCCR_TEST | CCCR_MON | CCCR_DAR | 11758c2ecf20Sopenharmony_ci (CCCR_CMR_MASK << CCCR_CMR_SHIFT) | 11768c2ecf20Sopenharmony_ci (CCCR_CME_MASK << CCCR_CME_SHIFT)); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci if (cdev->can.ctrlmode & CAN_CTRLMODE_FD) 11798c2ecf20Sopenharmony_ci cccr |= CCCR_CME_CANFD_BRS << CCCR_CME_SHIFT; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci } else { 11828c2ecf20Sopenharmony_ci /* Version 3.1.x or 3.2.x */ 11838c2ecf20Sopenharmony_ci cccr &= ~(CCCR_TEST | CCCR_MON | CCCR_BRSE | CCCR_FDOE | 11848c2ecf20Sopenharmony_ci CCCR_NISO | CCCR_DAR); 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci /* Only 3.2.x has NISO Bit implemented */ 11878c2ecf20Sopenharmony_ci if (cdev->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO) 11888c2ecf20Sopenharmony_ci cccr |= CCCR_NISO; 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci if (cdev->can.ctrlmode & CAN_CTRLMODE_FD) 11918c2ecf20Sopenharmony_ci cccr |= (CCCR_BRSE | CCCR_FDOE); 11928c2ecf20Sopenharmony_ci } 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci /* Loopback Mode */ 11958c2ecf20Sopenharmony_ci if (cdev->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) { 11968c2ecf20Sopenharmony_ci cccr |= CCCR_TEST | CCCR_MON; 11978c2ecf20Sopenharmony_ci test |= TEST_LBCK; 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci /* Enable Monitoring (all versions) */ 12018c2ecf20Sopenharmony_ci if (cdev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) 12028c2ecf20Sopenharmony_ci cccr |= CCCR_MON; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci /* Disable Auto Retransmission (all versions) */ 12058c2ecf20Sopenharmony_ci if (cdev->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT) 12068c2ecf20Sopenharmony_ci cccr |= CCCR_DAR; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci /* Write config */ 12098c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_CCCR, cccr); 12108c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_TEST, test); 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci /* Enable interrupts */ 12138c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_IR, IR_ALL_INT); 12148c2ecf20Sopenharmony_ci if (!(cdev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)) 12158c2ecf20Sopenharmony_ci if (cdev->version == 30) 12168c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_IE, IR_ALL_INT & 12178c2ecf20Sopenharmony_ci ~(IR_ERR_LEC_30X)); 12188c2ecf20Sopenharmony_ci else 12198c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_IE, IR_ALL_INT & 12208c2ecf20Sopenharmony_ci ~(IR_ERR_LEC_31X)); 12218c2ecf20Sopenharmony_ci else 12228c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_IE, IR_ALL_INT); 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci /* route all interrupts to INT0 */ 12258c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_ILS, ILS_ALL_INT0); 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci /* set bittiming params */ 12288c2ecf20Sopenharmony_ci m_can_set_bittiming(dev); 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci m_can_config_endisable(cdev, false); 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci if (cdev->ops->init) 12338c2ecf20Sopenharmony_ci cdev->ops->init(cdev); 12348c2ecf20Sopenharmony_ci} 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_cistatic void m_can_start(struct net_device *dev) 12378c2ecf20Sopenharmony_ci{ 12388c2ecf20Sopenharmony_ci struct m_can_classdev *cdev = netdev_priv(dev); 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci /* basic m_can configuration */ 12418c2ecf20Sopenharmony_ci m_can_chip_config(dev); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci cdev->can.state = CAN_STATE_ERROR_ACTIVE; 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci m_can_enable_all_interrupts(cdev); 12468c2ecf20Sopenharmony_ci} 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_cistatic int m_can_set_mode(struct net_device *dev, enum can_mode mode) 12498c2ecf20Sopenharmony_ci{ 12508c2ecf20Sopenharmony_ci switch (mode) { 12518c2ecf20Sopenharmony_ci case CAN_MODE_START: 12528c2ecf20Sopenharmony_ci m_can_clean(dev); 12538c2ecf20Sopenharmony_ci m_can_start(dev); 12548c2ecf20Sopenharmony_ci netif_wake_queue(dev); 12558c2ecf20Sopenharmony_ci break; 12568c2ecf20Sopenharmony_ci default: 12578c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 12588c2ecf20Sopenharmony_ci } 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci return 0; 12618c2ecf20Sopenharmony_ci} 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci/* Checks core release number of M_CAN 12648c2ecf20Sopenharmony_ci * returns 0 if an unsupported device is detected 12658c2ecf20Sopenharmony_ci * else it returns the release and step coded as: 12668c2ecf20Sopenharmony_ci * return value = 10 * <release> + 1 * <step> 12678c2ecf20Sopenharmony_ci */ 12688c2ecf20Sopenharmony_cistatic int m_can_check_core_release(struct m_can_classdev *cdev) 12698c2ecf20Sopenharmony_ci{ 12708c2ecf20Sopenharmony_ci u32 crel_reg; 12718c2ecf20Sopenharmony_ci u8 rel; 12728c2ecf20Sopenharmony_ci u8 step; 12738c2ecf20Sopenharmony_ci int res; 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci /* Read Core Release Version and split into version number 12768c2ecf20Sopenharmony_ci * Example: Version 3.2.1 => rel = 3; step = 2; substep = 1; 12778c2ecf20Sopenharmony_ci */ 12788c2ecf20Sopenharmony_ci crel_reg = m_can_read(cdev, M_CAN_CREL); 12798c2ecf20Sopenharmony_ci rel = (u8)((crel_reg & CREL_REL_MASK) >> CREL_REL_SHIFT); 12808c2ecf20Sopenharmony_ci step = (u8)((crel_reg & CREL_STEP_MASK) >> CREL_STEP_SHIFT); 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci if (rel == 3) { 12838c2ecf20Sopenharmony_ci /* M_CAN v3.x.y: create return value */ 12848c2ecf20Sopenharmony_ci res = 30 + step; 12858c2ecf20Sopenharmony_ci } else { 12868c2ecf20Sopenharmony_ci /* Unsupported M_CAN version */ 12878c2ecf20Sopenharmony_ci res = 0; 12888c2ecf20Sopenharmony_ci } 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci return res; 12918c2ecf20Sopenharmony_ci} 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci/* Selectable Non ISO support only in version 3.2.x 12948c2ecf20Sopenharmony_ci * This function checks if the bit is writable. 12958c2ecf20Sopenharmony_ci */ 12968c2ecf20Sopenharmony_cistatic bool m_can_niso_supported(struct m_can_classdev *cdev) 12978c2ecf20Sopenharmony_ci{ 12988c2ecf20Sopenharmony_ci u32 cccr_reg, cccr_poll = 0; 12998c2ecf20Sopenharmony_ci int niso_timeout = -ETIMEDOUT; 13008c2ecf20Sopenharmony_ci int i; 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci m_can_config_endisable(cdev, true); 13038c2ecf20Sopenharmony_ci cccr_reg = m_can_read(cdev, M_CAN_CCCR); 13048c2ecf20Sopenharmony_ci cccr_reg |= CCCR_NISO; 13058c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_CCCR, cccr_reg); 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci for (i = 0; i <= 10; i++) { 13088c2ecf20Sopenharmony_ci cccr_poll = m_can_read(cdev, M_CAN_CCCR); 13098c2ecf20Sopenharmony_ci if (cccr_poll == cccr_reg) { 13108c2ecf20Sopenharmony_ci niso_timeout = 0; 13118c2ecf20Sopenharmony_ci break; 13128c2ecf20Sopenharmony_ci } 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci usleep_range(1, 5); 13158c2ecf20Sopenharmony_ci } 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci /* Clear NISO */ 13188c2ecf20Sopenharmony_ci cccr_reg &= ~(CCCR_NISO); 13198c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_CCCR, cccr_reg); 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci m_can_config_endisable(cdev, false); 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci /* return false if time out (-ETIMEDOUT), else return true */ 13248c2ecf20Sopenharmony_ci return !niso_timeout; 13258c2ecf20Sopenharmony_ci} 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_cistatic int m_can_dev_setup(struct m_can_classdev *m_can_dev) 13288c2ecf20Sopenharmony_ci{ 13298c2ecf20Sopenharmony_ci struct net_device *dev = m_can_dev->net; 13308c2ecf20Sopenharmony_ci int m_can_version; 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci m_can_version = m_can_check_core_release(m_can_dev); 13338c2ecf20Sopenharmony_ci /* return if unsupported version */ 13348c2ecf20Sopenharmony_ci if (!m_can_version) { 13358c2ecf20Sopenharmony_ci dev_err(m_can_dev->dev, "Unsupported version number: %2d", 13368c2ecf20Sopenharmony_ci m_can_version); 13378c2ecf20Sopenharmony_ci return -EINVAL; 13388c2ecf20Sopenharmony_ci } 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci if (!m_can_dev->is_peripheral) 13418c2ecf20Sopenharmony_ci netif_napi_add(dev, &m_can_dev->napi, 13428c2ecf20Sopenharmony_ci m_can_poll, M_CAN_NAPI_WEIGHT); 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci /* Shared properties of all M_CAN versions */ 13458c2ecf20Sopenharmony_ci m_can_dev->version = m_can_version; 13468c2ecf20Sopenharmony_ci m_can_dev->can.do_set_mode = m_can_set_mode; 13478c2ecf20Sopenharmony_ci m_can_dev->can.do_get_berr_counter = m_can_get_berr_counter; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci /* Set M_CAN supported operations */ 13508c2ecf20Sopenharmony_ci m_can_dev->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | 13518c2ecf20Sopenharmony_ci CAN_CTRLMODE_LISTENONLY | 13528c2ecf20Sopenharmony_ci CAN_CTRLMODE_BERR_REPORTING | 13538c2ecf20Sopenharmony_ci CAN_CTRLMODE_FD | 13548c2ecf20Sopenharmony_ci CAN_CTRLMODE_ONE_SHOT; 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci /* Set properties depending on M_CAN version */ 13578c2ecf20Sopenharmony_ci switch (m_can_dev->version) { 13588c2ecf20Sopenharmony_ci case 30: 13598c2ecf20Sopenharmony_ci /* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.0.x */ 13608c2ecf20Sopenharmony_ci can_set_static_ctrlmode(dev, CAN_CTRLMODE_FD_NON_ISO); 13618c2ecf20Sopenharmony_ci m_can_dev->can.bittiming_const = m_can_dev->bit_timing ? 13628c2ecf20Sopenharmony_ci m_can_dev->bit_timing : &m_can_bittiming_const_30X; 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci m_can_dev->can.data_bittiming_const = m_can_dev->data_timing ? 13658c2ecf20Sopenharmony_ci m_can_dev->data_timing : 13668c2ecf20Sopenharmony_ci &m_can_data_bittiming_const_30X; 13678c2ecf20Sopenharmony_ci break; 13688c2ecf20Sopenharmony_ci case 31: 13698c2ecf20Sopenharmony_ci /* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.1.x */ 13708c2ecf20Sopenharmony_ci can_set_static_ctrlmode(dev, CAN_CTRLMODE_FD_NON_ISO); 13718c2ecf20Sopenharmony_ci m_can_dev->can.bittiming_const = m_can_dev->bit_timing ? 13728c2ecf20Sopenharmony_ci m_can_dev->bit_timing : &m_can_bittiming_const_31X; 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci m_can_dev->can.data_bittiming_const = m_can_dev->data_timing ? 13758c2ecf20Sopenharmony_ci m_can_dev->data_timing : 13768c2ecf20Sopenharmony_ci &m_can_data_bittiming_const_31X; 13778c2ecf20Sopenharmony_ci break; 13788c2ecf20Sopenharmony_ci case 32: 13798c2ecf20Sopenharmony_ci case 33: 13808c2ecf20Sopenharmony_ci /* Support both MCAN version v3.2.x and v3.3.0 */ 13818c2ecf20Sopenharmony_ci m_can_dev->can.bittiming_const = m_can_dev->bit_timing ? 13828c2ecf20Sopenharmony_ci m_can_dev->bit_timing : &m_can_bittiming_const_31X; 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci m_can_dev->can.data_bittiming_const = m_can_dev->data_timing ? 13858c2ecf20Sopenharmony_ci m_can_dev->data_timing : 13868c2ecf20Sopenharmony_ci &m_can_data_bittiming_const_31X; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci m_can_dev->can.ctrlmode_supported |= 13898c2ecf20Sopenharmony_ci (m_can_niso_supported(m_can_dev) 13908c2ecf20Sopenharmony_ci ? CAN_CTRLMODE_FD_NON_ISO 13918c2ecf20Sopenharmony_ci : 0); 13928c2ecf20Sopenharmony_ci break; 13938c2ecf20Sopenharmony_ci default: 13948c2ecf20Sopenharmony_ci dev_err(m_can_dev->dev, "Unsupported version number: %2d", 13958c2ecf20Sopenharmony_ci m_can_dev->version); 13968c2ecf20Sopenharmony_ci return -EINVAL; 13978c2ecf20Sopenharmony_ci } 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci if (m_can_dev->ops->init) 14008c2ecf20Sopenharmony_ci m_can_dev->ops->init(m_can_dev); 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci return 0; 14038c2ecf20Sopenharmony_ci} 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_cistatic void m_can_stop(struct net_device *dev) 14068c2ecf20Sopenharmony_ci{ 14078c2ecf20Sopenharmony_ci struct m_can_classdev *cdev = netdev_priv(dev); 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci /* disable all interrupts */ 14108c2ecf20Sopenharmony_ci m_can_disable_all_interrupts(cdev); 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci /* Set init mode to disengage from the network */ 14138c2ecf20Sopenharmony_ci m_can_config_endisable(cdev, true); 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci /* set the state as STOPPED */ 14168c2ecf20Sopenharmony_ci cdev->can.state = CAN_STATE_STOPPED; 14178c2ecf20Sopenharmony_ci} 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_cistatic int m_can_close(struct net_device *dev) 14208c2ecf20Sopenharmony_ci{ 14218c2ecf20Sopenharmony_ci struct m_can_classdev *cdev = netdev_priv(dev); 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci netif_stop_queue(dev); 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci if (!cdev->is_peripheral) 14268c2ecf20Sopenharmony_ci napi_disable(&cdev->napi); 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci m_can_stop(dev); 14298c2ecf20Sopenharmony_ci m_can_clk_stop(cdev); 14308c2ecf20Sopenharmony_ci free_irq(dev->irq, dev); 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci if (cdev->is_peripheral) { 14338c2ecf20Sopenharmony_ci cdev->tx_skb = NULL; 14348c2ecf20Sopenharmony_ci destroy_workqueue(cdev->tx_wq); 14358c2ecf20Sopenharmony_ci cdev->tx_wq = NULL; 14368c2ecf20Sopenharmony_ci } 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci close_candev(dev); 14398c2ecf20Sopenharmony_ci can_led_event(dev, CAN_LED_EVENT_STOP); 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci return 0; 14428c2ecf20Sopenharmony_ci} 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_cistatic int m_can_next_echo_skb_occupied(struct net_device *dev, int putidx) 14458c2ecf20Sopenharmony_ci{ 14468c2ecf20Sopenharmony_ci struct m_can_classdev *cdev = netdev_priv(dev); 14478c2ecf20Sopenharmony_ci /*get wrap around for loopback skb index */ 14488c2ecf20Sopenharmony_ci unsigned int wrap = cdev->can.echo_skb_max; 14498c2ecf20Sopenharmony_ci int next_idx; 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci /* calculate next index */ 14528c2ecf20Sopenharmony_ci next_idx = (++putidx >= wrap ? 0 : putidx); 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci /* check if occupied */ 14558c2ecf20Sopenharmony_ci return !!cdev->can.echo_skb[next_idx]; 14568c2ecf20Sopenharmony_ci} 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_cistatic netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev) 14598c2ecf20Sopenharmony_ci{ 14608c2ecf20Sopenharmony_ci struct canfd_frame *cf = (struct canfd_frame *)cdev->tx_skb->data; 14618c2ecf20Sopenharmony_ci struct net_device *dev = cdev->net; 14628c2ecf20Sopenharmony_ci struct sk_buff *skb = cdev->tx_skb; 14638c2ecf20Sopenharmony_ci u32 id, cccr, fdflags; 14648c2ecf20Sopenharmony_ci int i; 14658c2ecf20Sopenharmony_ci int putidx; 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci cdev->tx_skb = NULL; 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci /* Generate ID field for TX buffer Element */ 14708c2ecf20Sopenharmony_ci /* Common to all supported M_CAN versions */ 14718c2ecf20Sopenharmony_ci if (cf->can_id & CAN_EFF_FLAG) { 14728c2ecf20Sopenharmony_ci id = cf->can_id & CAN_EFF_MASK; 14738c2ecf20Sopenharmony_ci id |= TX_BUF_XTD; 14748c2ecf20Sopenharmony_ci } else { 14758c2ecf20Sopenharmony_ci id = ((cf->can_id & CAN_SFF_MASK) << 18); 14768c2ecf20Sopenharmony_ci } 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci if (cf->can_id & CAN_RTR_FLAG) 14798c2ecf20Sopenharmony_ci id |= TX_BUF_RTR; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci if (cdev->version == 30) { 14828c2ecf20Sopenharmony_ci netif_stop_queue(dev); 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci /* message ram configuration */ 14858c2ecf20Sopenharmony_ci m_can_fifo_write(cdev, 0, M_CAN_FIFO_ID, id); 14868c2ecf20Sopenharmony_ci m_can_fifo_write(cdev, 0, M_CAN_FIFO_DLC, 14878c2ecf20Sopenharmony_ci can_len2dlc(cf->len) << 16); 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci for (i = 0; i < cf->len; i += 4) 14908c2ecf20Sopenharmony_ci m_can_fifo_write(cdev, 0, 14918c2ecf20Sopenharmony_ci M_CAN_FIFO_DATA(i / 4), 14928c2ecf20Sopenharmony_ci *(u32 *)(cf->data + i)); 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci if (cdev->can.ctrlmode & CAN_CTRLMODE_FD) { 14958c2ecf20Sopenharmony_ci cccr = m_can_read(cdev, M_CAN_CCCR); 14968c2ecf20Sopenharmony_ci cccr &= ~(CCCR_CMR_MASK << CCCR_CMR_SHIFT); 14978c2ecf20Sopenharmony_ci if (can_is_canfd_skb(skb)) { 14988c2ecf20Sopenharmony_ci if (cf->flags & CANFD_BRS) 14998c2ecf20Sopenharmony_ci cccr |= CCCR_CMR_CANFD_BRS << 15008c2ecf20Sopenharmony_ci CCCR_CMR_SHIFT; 15018c2ecf20Sopenharmony_ci else 15028c2ecf20Sopenharmony_ci cccr |= CCCR_CMR_CANFD << 15038c2ecf20Sopenharmony_ci CCCR_CMR_SHIFT; 15048c2ecf20Sopenharmony_ci } else { 15058c2ecf20Sopenharmony_ci cccr |= CCCR_CMR_CAN << CCCR_CMR_SHIFT; 15068c2ecf20Sopenharmony_ci } 15078c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_CCCR, cccr); 15088c2ecf20Sopenharmony_ci } 15098c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_TXBTIE, 0x1); 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci can_put_echo_skb(skb, dev, 0); 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_TXBAR, 0x1); 15148c2ecf20Sopenharmony_ci /* End of xmit function for version 3.0.x */ 15158c2ecf20Sopenharmony_ci } else { 15168c2ecf20Sopenharmony_ci /* Transmit routine for version >= v3.1.x */ 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci /* Check if FIFO full */ 15198c2ecf20Sopenharmony_ci if (m_can_tx_fifo_full(cdev)) { 15208c2ecf20Sopenharmony_ci /* This shouldn't happen */ 15218c2ecf20Sopenharmony_ci netif_stop_queue(dev); 15228c2ecf20Sopenharmony_ci netdev_warn(dev, 15238c2ecf20Sopenharmony_ci "TX queue active although FIFO is full."); 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci if (cdev->is_peripheral) { 15268c2ecf20Sopenharmony_ci kfree_skb(skb); 15278c2ecf20Sopenharmony_ci dev->stats.tx_dropped++; 15288c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 15298c2ecf20Sopenharmony_ci } else { 15308c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 15318c2ecf20Sopenharmony_ci } 15328c2ecf20Sopenharmony_ci } 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci /* get put index for frame */ 15358c2ecf20Sopenharmony_ci putidx = ((m_can_read(cdev, M_CAN_TXFQS) & TXFQS_TFQPI_MASK) 15368c2ecf20Sopenharmony_ci >> TXFQS_TFQPI_SHIFT); 15378c2ecf20Sopenharmony_ci /* Write ID Field to FIFO Element */ 15388c2ecf20Sopenharmony_ci m_can_fifo_write(cdev, putidx, M_CAN_FIFO_ID, id); 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci /* get CAN FD configuration of frame */ 15418c2ecf20Sopenharmony_ci fdflags = 0; 15428c2ecf20Sopenharmony_ci if (can_is_canfd_skb(skb)) { 15438c2ecf20Sopenharmony_ci fdflags |= TX_BUF_FDF; 15448c2ecf20Sopenharmony_ci if (cf->flags & CANFD_BRS) 15458c2ecf20Sopenharmony_ci fdflags |= TX_BUF_BRS; 15468c2ecf20Sopenharmony_ci } 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci /* Construct DLC Field. Also contains CAN-FD configuration 15498c2ecf20Sopenharmony_ci * use put index of fifo as message marker 15508c2ecf20Sopenharmony_ci * it is used in TX interrupt for 15518c2ecf20Sopenharmony_ci * sending the correct echo frame 15528c2ecf20Sopenharmony_ci */ 15538c2ecf20Sopenharmony_ci m_can_fifo_write(cdev, putidx, M_CAN_FIFO_DLC, 15548c2ecf20Sopenharmony_ci ((putidx << TX_BUF_MM_SHIFT) & 15558c2ecf20Sopenharmony_ci TX_BUF_MM_MASK) | 15568c2ecf20Sopenharmony_ci (can_len2dlc(cf->len) << 16) | 15578c2ecf20Sopenharmony_ci fdflags | TX_BUF_EFC); 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci for (i = 0; i < cf->len; i += 4) 15608c2ecf20Sopenharmony_ci m_can_fifo_write(cdev, putidx, M_CAN_FIFO_DATA(i / 4), 15618c2ecf20Sopenharmony_ci *(u32 *)(cf->data + i)); 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci /* Push loopback echo. 15648c2ecf20Sopenharmony_ci * Will be looped back on TX interrupt based on message marker 15658c2ecf20Sopenharmony_ci */ 15668c2ecf20Sopenharmony_ci can_put_echo_skb(skb, dev, putidx); 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci /* Enable TX FIFO element to start transfer */ 15698c2ecf20Sopenharmony_ci m_can_write(cdev, M_CAN_TXBAR, (1 << putidx)); 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci /* stop network queue if fifo full */ 15728c2ecf20Sopenharmony_ci if (m_can_tx_fifo_full(cdev) || 15738c2ecf20Sopenharmony_ci m_can_next_echo_skb_occupied(dev, putidx)) 15748c2ecf20Sopenharmony_ci netif_stop_queue(dev); 15758c2ecf20Sopenharmony_ci } 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 15788c2ecf20Sopenharmony_ci} 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_cistatic void m_can_tx_work_queue(struct work_struct *ws) 15818c2ecf20Sopenharmony_ci{ 15828c2ecf20Sopenharmony_ci struct m_can_classdev *cdev = container_of(ws, struct m_can_classdev, 15838c2ecf20Sopenharmony_ci tx_work); 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci m_can_tx_handler(cdev); 15868c2ecf20Sopenharmony_ci} 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_cistatic netdev_tx_t m_can_start_xmit(struct sk_buff *skb, 15898c2ecf20Sopenharmony_ci struct net_device *dev) 15908c2ecf20Sopenharmony_ci{ 15918c2ecf20Sopenharmony_ci struct m_can_classdev *cdev = netdev_priv(dev); 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci if (can_dropped_invalid_skb(dev, skb)) 15948c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci if (cdev->is_peripheral) { 15978c2ecf20Sopenharmony_ci if (cdev->tx_skb) { 15988c2ecf20Sopenharmony_ci netdev_err(dev, "hard_xmit called while tx busy\n"); 15998c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 16008c2ecf20Sopenharmony_ci } 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci if (cdev->can.state == CAN_STATE_BUS_OFF) { 16038c2ecf20Sopenharmony_ci m_can_clean(dev); 16048c2ecf20Sopenharmony_ci } else { 16058c2ecf20Sopenharmony_ci /* Need to stop the queue to avoid numerous requests 16068c2ecf20Sopenharmony_ci * from being sent. Suggested improvement is to create 16078c2ecf20Sopenharmony_ci * a queueing mechanism that will queue the skbs and 16088c2ecf20Sopenharmony_ci * process them in order. 16098c2ecf20Sopenharmony_ci */ 16108c2ecf20Sopenharmony_ci cdev->tx_skb = skb; 16118c2ecf20Sopenharmony_ci netif_stop_queue(cdev->net); 16128c2ecf20Sopenharmony_ci queue_work(cdev->tx_wq, &cdev->tx_work); 16138c2ecf20Sopenharmony_ci } 16148c2ecf20Sopenharmony_ci } else { 16158c2ecf20Sopenharmony_ci cdev->tx_skb = skb; 16168c2ecf20Sopenharmony_ci return m_can_tx_handler(cdev); 16178c2ecf20Sopenharmony_ci } 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 16208c2ecf20Sopenharmony_ci} 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_cistatic int m_can_open(struct net_device *dev) 16238c2ecf20Sopenharmony_ci{ 16248c2ecf20Sopenharmony_ci struct m_can_classdev *cdev = netdev_priv(dev); 16258c2ecf20Sopenharmony_ci int err; 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci err = m_can_clk_start(cdev); 16288c2ecf20Sopenharmony_ci if (err) 16298c2ecf20Sopenharmony_ci return err; 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci /* open the can device */ 16328c2ecf20Sopenharmony_ci err = open_candev(dev); 16338c2ecf20Sopenharmony_ci if (err) { 16348c2ecf20Sopenharmony_ci netdev_err(dev, "failed to open can device\n"); 16358c2ecf20Sopenharmony_ci goto exit_disable_clks; 16368c2ecf20Sopenharmony_ci } 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci /* register interrupt handler */ 16398c2ecf20Sopenharmony_ci if (cdev->is_peripheral) { 16408c2ecf20Sopenharmony_ci cdev->tx_skb = NULL; 16418c2ecf20Sopenharmony_ci cdev->tx_wq = alloc_workqueue("mcan_wq", 16428c2ecf20Sopenharmony_ci WQ_FREEZABLE | WQ_MEM_RECLAIM, 0); 16438c2ecf20Sopenharmony_ci if (!cdev->tx_wq) { 16448c2ecf20Sopenharmony_ci err = -ENOMEM; 16458c2ecf20Sopenharmony_ci goto out_wq_fail; 16468c2ecf20Sopenharmony_ci } 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci INIT_WORK(&cdev->tx_work, m_can_tx_work_queue); 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci err = request_threaded_irq(dev->irq, NULL, m_can_isr, 16518c2ecf20Sopenharmony_ci IRQF_ONESHOT, 16528c2ecf20Sopenharmony_ci dev->name, dev); 16538c2ecf20Sopenharmony_ci } else { 16548c2ecf20Sopenharmony_ci err = request_irq(dev->irq, m_can_isr, IRQF_SHARED, dev->name, 16558c2ecf20Sopenharmony_ci dev); 16568c2ecf20Sopenharmony_ci } 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci if (err < 0) { 16598c2ecf20Sopenharmony_ci netdev_err(dev, "failed to request interrupt\n"); 16608c2ecf20Sopenharmony_ci goto exit_irq_fail; 16618c2ecf20Sopenharmony_ci } 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci /* start the m_can controller */ 16648c2ecf20Sopenharmony_ci m_can_start(dev); 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci can_led_event(dev, CAN_LED_EVENT_OPEN); 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci if (!cdev->is_peripheral) 16698c2ecf20Sopenharmony_ci napi_enable(&cdev->napi); 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci netif_start_queue(dev); 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci return 0; 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ciexit_irq_fail: 16768c2ecf20Sopenharmony_ci if (cdev->is_peripheral) 16778c2ecf20Sopenharmony_ci destroy_workqueue(cdev->tx_wq); 16788c2ecf20Sopenharmony_ciout_wq_fail: 16798c2ecf20Sopenharmony_ci close_candev(dev); 16808c2ecf20Sopenharmony_ciexit_disable_clks: 16818c2ecf20Sopenharmony_ci m_can_clk_stop(cdev); 16828c2ecf20Sopenharmony_ci return err; 16838c2ecf20Sopenharmony_ci} 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_cistatic const struct net_device_ops m_can_netdev_ops = { 16868c2ecf20Sopenharmony_ci .ndo_open = m_can_open, 16878c2ecf20Sopenharmony_ci .ndo_stop = m_can_close, 16888c2ecf20Sopenharmony_ci .ndo_start_xmit = m_can_start_xmit, 16898c2ecf20Sopenharmony_ci .ndo_change_mtu = can_change_mtu, 16908c2ecf20Sopenharmony_ci}; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_cistatic int register_m_can_dev(struct net_device *dev) 16938c2ecf20Sopenharmony_ci{ 16948c2ecf20Sopenharmony_ci dev->flags |= IFF_ECHO; /* we support local echo */ 16958c2ecf20Sopenharmony_ci dev->netdev_ops = &m_can_netdev_ops; 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci return register_candev(dev); 16988c2ecf20Sopenharmony_ci} 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_cistatic void m_can_of_parse_mram(struct m_can_classdev *cdev, 17018c2ecf20Sopenharmony_ci const u32 *mram_config_vals) 17028c2ecf20Sopenharmony_ci{ 17038c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_SIDF].off = mram_config_vals[0]; 17048c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_SIDF].num = mram_config_vals[1]; 17058c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_XIDF].off = cdev->mcfg[MRAM_SIDF].off + 17068c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_SIDF].num * SIDF_ELEMENT_SIZE; 17078c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_XIDF].num = mram_config_vals[2]; 17088c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_RXF0].off = cdev->mcfg[MRAM_XIDF].off + 17098c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_XIDF].num * XIDF_ELEMENT_SIZE; 17108c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_RXF0].num = mram_config_vals[3] & 17118c2ecf20Sopenharmony_ci (RXFC_FS_MASK >> RXFC_FS_SHIFT); 17128c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_RXF1].off = cdev->mcfg[MRAM_RXF0].off + 17138c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_RXF0].num * RXF0_ELEMENT_SIZE; 17148c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_RXF1].num = mram_config_vals[4] & 17158c2ecf20Sopenharmony_ci (RXFC_FS_MASK >> RXFC_FS_SHIFT); 17168c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_RXB].off = cdev->mcfg[MRAM_RXF1].off + 17178c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_RXF1].num * RXF1_ELEMENT_SIZE; 17188c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_RXB].num = mram_config_vals[5]; 17198c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_TXE].off = cdev->mcfg[MRAM_RXB].off + 17208c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_RXB].num * RXB_ELEMENT_SIZE; 17218c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_TXE].num = mram_config_vals[6]; 17228c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_TXB].off = cdev->mcfg[MRAM_TXE].off + 17238c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_TXE].num * TXE_ELEMENT_SIZE; 17248c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_TXB].num = mram_config_vals[7] & 17258c2ecf20Sopenharmony_ci (TXBC_NDTB_MASK >> TXBC_NDTB_SHIFT); 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci dev_dbg(cdev->dev, 17288c2ecf20Sopenharmony_ci "sidf 0x%x %d xidf 0x%x %d rxf0 0x%x %d rxf1 0x%x %d rxb 0x%x %d txe 0x%x %d txb 0x%x %d\n", 17298c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_SIDF].off, cdev->mcfg[MRAM_SIDF].num, 17308c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_XIDF].off, cdev->mcfg[MRAM_XIDF].num, 17318c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_RXF0].off, cdev->mcfg[MRAM_RXF0].num, 17328c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_RXF1].off, cdev->mcfg[MRAM_RXF1].num, 17338c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_RXB].off, cdev->mcfg[MRAM_RXB].num, 17348c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_TXE].off, cdev->mcfg[MRAM_TXE].num, 17358c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_TXB].off, cdev->mcfg[MRAM_TXB].num); 17368c2ecf20Sopenharmony_ci} 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_civoid m_can_init_ram(struct m_can_classdev *cdev) 17398c2ecf20Sopenharmony_ci{ 17408c2ecf20Sopenharmony_ci int end, i, start; 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci /* initialize the entire Message RAM in use to avoid possible 17438c2ecf20Sopenharmony_ci * ECC/parity checksum errors when reading an uninitialized buffer 17448c2ecf20Sopenharmony_ci */ 17458c2ecf20Sopenharmony_ci start = cdev->mcfg[MRAM_SIDF].off; 17468c2ecf20Sopenharmony_ci end = cdev->mcfg[MRAM_TXB].off + 17478c2ecf20Sopenharmony_ci cdev->mcfg[MRAM_TXB].num * TXB_ELEMENT_SIZE; 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci for (i = start; i < end; i += 4) 17508c2ecf20Sopenharmony_ci m_can_fifo_write_no_off(cdev, i, 0x0); 17518c2ecf20Sopenharmony_ci} 17528c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(m_can_init_ram); 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ciint m_can_class_get_clocks(struct m_can_classdev *m_can_dev) 17558c2ecf20Sopenharmony_ci{ 17568c2ecf20Sopenharmony_ci int ret = 0; 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci m_can_dev->hclk = devm_clk_get(m_can_dev->dev, "hclk"); 17598c2ecf20Sopenharmony_ci m_can_dev->cclk = devm_clk_get(m_can_dev->dev, "cclk"); 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci if (IS_ERR(m_can_dev->cclk)) { 17628c2ecf20Sopenharmony_ci dev_err(m_can_dev->dev, "no clock found\n"); 17638c2ecf20Sopenharmony_ci ret = -ENODEV; 17648c2ecf20Sopenharmony_ci } 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci return ret; 17678c2ecf20Sopenharmony_ci} 17688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(m_can_class_get_clocks); 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_cistruct m_can_classdev *m_can_class_allocate_dev(struct device *dev) 17718c2ecf20Sopenharmony_ci{ 17728c2ecf20Sopenharmony_ci struct m_can_classdev *class_dev = NULL; 17738c2ecf20Sopenharmony_ci u32 mram_config_vals[MRAM_CFG_LEN]; 17748c2ecf20Sopenharmony_ci struct net_device *net_dev; 17758c2ecf20Sopenharmony_ci u32 tx_fifo_size; 17768c2ecf20Sopenharmony_ci int ret; 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci ret = fwnode_property_read_u32_array(dev_fwnode(dev), 17798c2ecf20Sopenharmony_ci "bosch,mram-cfg", 17808c2ecf20Sopenharmony_ci mram_config_vals, 17818c2ecf20Sopenharmony_ci sizeof(mram_config_vals) / 4); 17828c2ecf20Sopenharmony_ci if (ret) { 17838c2ecf20Sopenharmony_ci dev_err(dev, "Could not get Message RAM configuration."); 17848c2ecf20Sopenharmony_ci goto out; 17858c2ecf20Sopenharmony_ci } 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci /* Get TX FIFO size 17888c2ecf20Sopenharmony_ci * Defines the total amount of echo buffers for loopback 17898c2ecf20Sopenharmony_ci */ 17908c2ecf20Sopenharmony_ci tx_fifo_size = mram_config_vals[7]; 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci /* allocate the m_can device */ 17938c2ecf20Sopenharmony_ci net_dev = alloc_candev(sizeof(*class_dev), tx_fifo_size); 17948c2ecf20Sopenharmony_ci if (!net_dev) { 17958c2ecf20Sopenharmony_ci dev_err(dev, "Failed to allocate CAN device"); 17968c2ecf20Sopenharmony_ci goto out; 17978c2ecf20Sopenharmony_ci } 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci class_dev = netdev_priv(net_dev); 18008c2ecf20Sopenharmony_ci if (!class_dev) { 18018c2ecf20Sopenharmony_ci dev_err(dev, "Failed to init netdev cdevate"); 18028c2ecf20Sopenharmony_ci goto out; 18038c2ecf20Sopenharmony_ci } 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci class_dev->net = net_dev; 18068c2ecf20Sopenharmony_ci class_dev->dev = dev; 18078c2ecf20Sopenharmony_ci SET_NETDEV_DEV(net_dev, dev); 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci m_can_of_parse_mram(class_dev, mram_config_vals); 18108c2ecf20Sopenharmony_ciout: 18118c2ecf20Sopenharmony_ci return class_dev; 18128c2ecf20Sopenharmony_ci} 18138c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(m_can_class_allocate_dev); 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_civoid m_can_class_free_dev(struct net_device *net) 18168c2ecf20Sopenharmony_ci{ 18178c2ecf20Sopenharmony_ci free_candev(net); 18188c2ecf20Sopenharmony_ci} 18198c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(m_can_class_free_dev); 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ciint m_can_class_register(struct m_can_classdev *m_can_dev) 18228c2ecf20Sopenharmony_ci{ 18238c2ecf20Sopenharmony_ci int ret; 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci if (m_can_dev->pm_clock_support) { 18268c2ecf20Sopenharmony_ci pm_runtime_enable(m_can_dev->dev); 18278c2ecf20Sopenharmony_ci ret = m_can_clk_start(m_can_dev); 18288c2ecf20Sopenharmony_ci if (ret) 18298c2ecf20Sopenharmony_ci goto pm_runtime_fail; 18308c2ecf20Sopenharmony_ci } 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci ret = m_can_dev_setup(m_can_dev); 18338c2ecf20Sopenharmony_ci if (ret) 18348c2ecf20Sopenharmony_ci goto clk_disable; 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci ret = register_m_can_dev(m_can_dev->net); 18378c2ecf20Sopenharmony_ci if (ret) { 18388c2ecf20Sopenharmony_ci dev_err(m_can_dev->dev, "registering %s failed (err=%d)\n", 18398c2ecf20Sopenharmony_ci m_can_dev->net->name, ret); 18408c2ecf20Sopenharmony_ci goto clk_disable; 18418c2ecf20Sopenharmony_ci } 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci devm_can_led_init(m_can_dev->net); 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci of_can_transceiver(m_can_dev->net); 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci dev_info(m_can_dev->dev, "%s device registered (irq=%d, version=%d)\n", 18488c2ecf20Sopenharmony_ci KBUILD_MODNAME, m_can_dev->net->irq, m_can_dev->version); 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci /* Probe finished 18518c2ecf20Sopenharmony_ci * Stop clocks. They will be reactivated once the M_CAN device is opened 18528c2ecf20Sopenharmony_ci */ 18538c2ecf20Sopenharmony_ciclk_disable: 18548c2ecf20Sopenharmony_ci m_can_clk_stop(m_can_dev); 18558c2ecf20Sopenharmony_cipm_runtime_fail: 18568c2ecf20Sopenharmony_ci if (ret) { 18578c2ecf20Sopenharmony_ci if (m_can_dev->pm_clock_support) 18588c2ecf20Sopenharmony_ci pm_runtime_disable(m_can_dev->dev); 18598c2ecf20Sopenharmony_ci } 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci return ret; 18628c2ecf20Sopenharmony_ci} 18638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(m_can_class_register); 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ciint m_can_class_suspend(struct device *dev) 18668c2ecf20Sopenharmony_ci{ 18678c2ecf20Sopenharmony_ci struct net_device *ndev = dev_get_drvdata(dev); 18688c2ecf20Sopenharmony_ci struct m_can_classdev *cdev = netdev_priv(ndev); 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci if (netif_running(ndev)) { 18718c2ecf20Sopenharmony_ci netif_stop_queue(ndev); 18728c2ecf20Sopenharmony_ci netif_device_detach(ndev); 18738c2ecf20Sopenharmony_ci m_can_stop(ndev); 18748c2ecf20Sopenharmony_ci m_can_clk_stop(cdev); 18758c2ecf20Sopenharmony_ci } 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci pinctrl_pm_select_sleep_state(dev); 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci cdev->can.state = CAN_STATE_SLEEPING; 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci return 0; 18828c2ecf20Sopenharmony_ci} 18838c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(m_can_class_suspend); 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ciint m_can_class_resume(struct device *dev) 18868c2ecf20Sopenharmony_ci{ 18878c2ecf20Sopenharmony_ci struct net_device *ndev = dev_get_drvdata(dev); 18888c2ecf20Sopenharmony_ci struct m_can_classdev *cdev = netdev_priv(ndev); 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci pinctrl_pm_select_default_state(dev); 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_ci cdev->can.state = CAN_STATE_ERROR_ACTIVE; 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci if (netif_running(ndev)) { 18958c2ecf20Sopenharmony_ci int ret; 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_ci ret = m_can_clk_start(cdev); 18988c2ecf20Sopenharmony_ci if (ret) 18998c2ecf20Sopenharmony_ci return ret; 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci m_can_init_ram(cdev); 19028c2ecf20Sopenharmony_ci m_can_start(ndev); 19038c2ecf20Sopenharmony_ci netif_device_attach(ndev); 19048c2ecf20Sopenharmony_ci netif_start_queue(ndev); 19058c2ecf20Sopenharmony_ci } 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci return 0; 19088c2ecf20Sopenharmony_ci} 19098c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(m_can_class_resume); 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_civoid m_can_class_unregister(struct m_can_classdev *m_can_dev) 19128c2ecf20Sopenharmony_ci{ 19138c2ecf20Sopenharmony_ci unregister_candev(m_can_dev->net); 19148c2ecf20Sopenharmony_ci} 19158c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(m_can_class_unregister); 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ciMODULE_AUTHOR("Dong Aisheng <b29396@freescale.com>"); 19188c2ecf20Sopenharmony_ciMODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>"); 19198c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 19208c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("CAN bus driver for Bosch M_CAN controller"); 1921