18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// flexcan.c - FLEXCAN CAN controller driver 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Copyright (c) 2005-2006 Varma Electronics Oy 68c2ecf20Sopenharmony_ci// Copyright (c) 2009 Sascha Hauer, Pengutronix 78c2ecf20Sopenharmony_ci// Copyright (c) 2010-2017 Pengutronix, Marc Kleine-Budde <kernel@pengutronix.de> 88c2ecf20Sopenharmony_ci// Copyright (c) 2014 David Jander, Protonic Holland 98c2ecf20Sopenharmony_ci// 108c2ecf20Sopenharmony_ci// Based on code originally by Andrey Volkov <avolkov@varma-el.com> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 138c2ecf20Sopenharmony_ci#include <linux/can.h> 148c2ecf20Sopenharmony_ci#include <linux/can/dev.h> 158c2ecf20Sopenharmony_ci#include <linux/can/error.h> 168c2ecf20Sopenharmony_ci#include <linux/can/led.h> 178c2ecf20Sopenharmony_ci#include <linux/can/rx-offload.h> 188c2ecf20Sopenharmony_ci#include <linux/clk.h> 198c2ecf20Sopenharmony_ci#include <linux/delay.h> 208c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 218c2ecf20Sopenharmony_ci#include <linux/io.h> 228c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 238c2ecf20Sopenharmony_ci#include <linux/module.h> 248c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 258c2ecf20Sopenharmony_ci#include <linux/of.h> 268c2ecf20Sopenharmony_ci#include <linux/of_device.h> 278c2ecf20Sopenharmony_ci#include <linux/pinctrl/consumer.h> 288c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 298c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 308c2ecf20Sopenharmony_ci#include <linux/regmap.h> 318c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define DRV_NAME "flexcan" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* 8 for RX fifo and 2 error handling */ 368c2ecf20Sopenharmony_ci#define FLEXCAN_NAPI_WEIGHT (8 + 2) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* FLEXCAN module configuration register (CANMCR) bits */ 398c2ecf20Sopenharmony_ci#define FLEXCAN_MCR_MDIS BIT(31) 408c2ecf20Sopenharmony_ci#define FLEXCAN_MCR_FRZ BIT(30) 418c2ecf20Sopenharmony_ci#define FLEXCAN_MCR_FEN BIT(29) 428c2ecf20Sopenharmony_ci#define FLEXCAN_MCR_HALT BIT(28) 438c2ecf20Sopenharmony_ci#define FLEXCAN_MCR_NOT_RDY BIT(27) 448c2ecf20Sopenharmony_ci#define FLEXCAN_MCR_WAK_MSK BIT(26) 458c2ecf20Sopenharmony_ci#define FLEXCAN_MCR_SOFTRST BIT(25) 468c2ecf20Sopenharmony_ci#define FLEXCAN_MCR_FRZ_ACK BIT(24) 478c2ecf20Sopenharmony_ci#define FLEXCAN_MCR_SUPV BIT(23) 488c2ecf20Sopenharmony_ci#define FLEXCAN_MCR_SLF_WAK BIT(22) 498c2ecf20Sopenharmony_ci#define FLEXCAN_MCR_WRN_EN BIT(21) 508c2ecf20Sopenharmony_ci#define FLEXCAN_MCR_LPM_ACK BIT(20) 518c2ecf20Sopenharmony_ci#define FLEXCAN_MCR_WAK_SRC BIT(19) 528c2ecf20Sopenharmony_ci#define FLEXCAN_MCR_DOZE BIT(18) 538c2ecf20Sopenharmony_ci#define FLEXCAN_MCR_SRX_DIS BIT(17) 548c2ecf20Sopenharmony_ci#define FLEXCAN_MCR_IRMQ BIT(16) 558c2ecf20Sopenharmony_ci#define FLEXCAN_MCR_LPRIO_EN BIT(13) 568c2ecf20Sopenharmony_ci#define FLEXCAN_MCR_AEN BIT(12) 578c2ecf20Sopenharmony_ci#define FLEXCAN_MCR_FDEN BIT(11) 588c2ecf20Sopenharmony_ci/* MCR_MAXMB: maximum used MBs is MAXMB + 1 */ 598c2ecf20Sopenharmony_ci#define FLEXCAN_MCR_MAXMB(x) ((x) & 0x7f) 608c2ecf20Sopenharmony_ci#define FLEXCAN_MCR_IDAM_A (0x0 << 8) 618c2ecf20Sopenharmony_ci#define FLEXCAN_MCR_IDAM_B (0x1 << 8) 628c2ecf20Sopenharmony_ci#define FLEXCAN_MCR_IDAM_C (0x2 << 8) 638c2ecf20Sopenharmony_ci#define FLEXCAN_MCR_IDAM_D (0x3 << 8) 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* FLEXCAN control register (CANCTRL) bits */ 668c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL_PRESDIV(x) (((x) & 0xff) << 24) 678c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL_RJW(x) (((x) & 0x03) << 22) 688c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL_PSEG1(x) (((x) & 0x07) << 19) 698c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL_PSEG2(x) (((x) & 0x07) << 16) 708c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL_BOFF_MSK BIT(15) 718c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL_ERR_MSK BIT(14) 728c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL_CLK_SRC BIT(13) 738c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL_LPB BIT(12) 748c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL_TWRN_MSK BIT(11) 758c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL_RWRN_MSK BIT(10) 768c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL_SMP BIT(7) 778c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL_BOFF_REC BIT(6) 788c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL_TSYN BIT(5) 798c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL_LBUF BIT(4) 808c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL_LOM BIT(3) 818c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL_PROPSEG(x) ((x) & 0x07) 828c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL_ERR_BUS (FLEXCAN_CTRL_ERR_MSK) 838c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL_ERR_STATE \ 848c2ecf20Sopenharmony_ci (FLEXCAN_CTRL_TWRN_MSK | FLEXCAN_CTRL_RWRN_MSK | \ 858c2ecf20Sopenharmony_ci FLEXCAN_CTRL_BOFF_MSK) 868c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL_ERR_ALL \ 878c2ecf20Sopenharmony_ci (FLEXCAN_CTRL_ERR_BUS | FLEXCAN_CTRL_ERR_STATE) 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* FLEXCAN control register 2 (CTRL2) bits */ 908c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL2_ECRWRE BIT(29) 918c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL2_WRMFRZ BIT(28) 928c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL2_RFFN(x) (((x) & 0x0f) << 24) 938c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL2_TASD(x) (((x) & 0x1f) << 19) 948c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL2_MRP BIT(18) 958c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL2_RRS BIT(17) 968c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL2_EACEN BIT(16) 978c2ecf20Sopenharmony_ci#define FLEXCAN_CTRL2_ISOCANFDEN BIT(12) 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* FLEXCAN memory error control register (MECR) bits */ 1008c2ecf20Sopenharmony_ci#define FLEXCAN_MECR_ECRWRDIS BIT(31) 1018c2ecf20Sopenharmony_ci#define FLEXCAN_MECR_HANCEI_MSK BIT(19) 1028c2ecf20Sopenharmony_ci#define FLEXCAN_MECR_FANCEI_MSK BIT(18) 1038c2ecf20Sopenharmony_ci#define FLEXCAN_MECR_CEI_MSK BIT(16) 1048c2ecf20Sopenharmony_ci#define FLEXCAN_MECR_HAERRIE BIT(15) 1058c2ecf20Sopenharmony_ci#define FLEXCAN_MECR_FAERRIE BIT(14) 1068c2ecf20Sopenharmony_ci#define FLEXCAN_MECR_EXTERRIE BIT(13) 1078c2ecf20Sopenharmony_ci#define FLEXCAN_MECR_RERRDIS BIT(9) 1088c2ecf20Sopenharmony_ci#define FLEXCAN_MECR_ECCDIS BIT(8) 1098c2ecf20Sopenharmony_ci#define FLEXCAN_MECR_NCEFAFRZ BIT(7) 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci/* FLEXCAN error and status register (ESR) bits */ 1128c2ecf20Sopenharmony_ci#define FLEXCAN_ESR_TWRN_INT BIT(17) 1138c2ecf20Sopenharmony_ci#define FLEXCAN_ESR_RWRN_INT BIT(16) 1148c2ecf20Sopenharmony_ci#define FLEXCAN_ESR_BIT1_ERR BIT(15) 1158c2ecf20Sopenharmony_ci#define FLEXCAN_ESR_BIT0_ERR BIT(14) 1168c2ecf20Sopenharmony_ci#define FLEXCAN_ESR_ACK_ERR BIT(13) 1178c2ecf20Sopenharmony_ci#define FLEXCAN_ESR_CRC_ERR BIT(12) 1188c2ecf20Sopenharmony_ci#define FLEXCAN_ESR_FRM_ERR BIT(11) 1198c2ecf20Sopenharmony_ci#define FLEXCAN_ESR_STF_ERR BIT(10) 1208c2ecf20Sopenharmony_ci#define FLEXCAN_ESR_TX_WRN BIT(9) 1218c2ecf20Sopenharmony_ci#define FLEXCAN_ESR_RX_WRN BIT(8) 1228c2ecf20Sopenharmony_ci#define FLEXCAN_ESR_IDLE BIT(7) 1238c2ecf20Sopenharmony_ci#define FLEXCAN_ESR_TXRX BIT(6) 1248c2ecf20Sopenharmony_ci#define FLEXCAN_EST_FLT_CONF_SHIFT (4) 1258c2ecf20Sopenharmony_ci#define FLEXCAN_ESR_FLT_CONF_MASK (0x3 << FLEXCAN_EST_FLT_CONF_SHIFT) 1268c2ecf20Sopenharmony_ci#define FLEXCAN_ESR_FLT_CONF_ACTIVE (0x0 << FLEXCAN_EST_FLT_CONF_SHIFT) 1278c2ecf20Sopenharmony_ci#define FLEXCAN_ESR_FLT_CONF_PASSIVE (0x1 << FLEXCAN_EST_FLT_CONF_SHIFT) 1288c2ecf20Sopenharmony_ci#define FLEXCAN_ESR_BOFF_INT BIT(2) 1298c2ecf20Sopenharmony_ci#define FLEXCAN_ESR_ERR_INT BIT(1) 1308c2ecf20Sopenharmony_ci#define FLEXCAN_ESR_WAK_INT BIT(0) 1318c2ecf20Sopenharmony_ci#define FLEXCAN_ESR_ERR_BUS \ 1328c2ecf20Sopenharmony_ci (FLEXCAN_ESR_BIT1_ERR | FLEXCAN_ESR_BIT0_ERR | \ 1338c2ecf20Sopenharmony_ci FLEXCAN_ESR_ACK_ERR | FLEXCAN_ESR_CRC_ERR | \ 1348c2ecf20Sopenharmony_ci FLEXCAN_ESR_FRM_ERR | FLEXCAN_ESR_STF_ERR) 1358c2ecf20Sopenharmony_ci#define FLEXCAN_ESR_ERR_STATE \ 1368c2ecf20Sopenharmony_ci (FLEXCAN_ESR_TWRN_INT | FLEXCAN_ESR_RWRN_INT | FLEXCAN_ESR_BOFF_INT) 1378c2ecf20Sopenharmony_ci#define FLEXCAN_ESR_ERR_ALL \ 1388c2ecf20Sopenharmony_ci (FLEXCAN_ESR_ERR_BUS | FLEXCAN_ESR_ERR_STATE) 1398c2ecf20Sopenharmony_ci#define FLEXCAN_ESR_ALL_INT \ 1408c2ecf20Sopenharmony_ci (FLEXCAN_ESR_TWRN_INT | FLEXCAN_ESR_RWRN_INT | \ 1418c2ecf20Sopenharmony_ci FLEXCAN_ESR_BOFF_INT | FLEXCAN_ESR_ERR_INT) 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/* FLEXCAN Bit Timing register (CBT) bits */ 1448c2ecf20Sopenharmony_ci#define FLEXCAN_CBT_BTF BIT(31) 1458c2ecf20Sopenharmony_ci#define FLEXCAN_CBT_EPRESDIV_MASK GENMASK(30, 21) 1468c2ecf20Sopenharmony_ci#define FLEXCAN_CBT_ERJW_MASK GENMASK(20, 16) 1478c2ecf20Sopenharmony_ci#define FLEXCAN_CBT_EPROPSEG_MASK GENMASK(15, 10) 1488c2ecf20Sopenharmony_ci#define FLEXCAN_CBT_EPSEG1_MASK GENMASK(9, 5) 1498c2ecf20Sopenharmony_ci#define FLEXCAN_CBT_EPSEG2_MASK GENMASK(4, 0) 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci/* FLEXCAN FD control register (FDCTRL) bits */ 1528c2ecf20Sopenharmony_ci#define FLEXCAN_FDCTRL_FDRATE BIT(31) 1538c2ecf20Sopenharmony_ci#define FLEXCAN_FDCTRL_MBDSR1 GENMASK(20, 19) 1548c2ecf20Sopenharmony_ci#define FLEXCAN_FDCTRL_MBDSR0 GENMASK(17, 16) 1558c2ecf20Sopenharmony_ci#define FLEXCAN_FDCTRL_MBDSR_8 0x0 1568c2ecf20Sopenharmony_ci#define FLEXCAN_FDCTRL_MBDSR_12 0x1 1578c2ecf20Sopenharmony_ci#define FLEXCAN_FDCTRL_MBDSR_32 0x2 1588c2ecf20Sopenharmony_ci#define FLEXCAN_FDCTRL_MBDSR_64 0x3 1598c2ecf20Sopenharmony_ci#define FLEXCAN_FDCTRL_TDCEN BIT(15) 1608c2ecf20Sopenharmony_ci#define FLEXCAN_FDCTRL_TDCFAIL BIT(14) 1618c2ecf20Sopenharmony_ci#define FLEXCAN_FDCTRL_TDCOFF GENMASK(12, 8) 1628c2ecf20Sopenharmony_ci#define FLEXCAN_FDCTRL_TDCVAL GENMASK(5, 0) 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci/* FLEXCAN FD Bit Timing register (FDCBT) bits */ 1658c2ecf20Sopenharmony_ci#define FLEXCAN_FDCBT_FPRESDIV_MASK GENMASK(29, 20) 1668c2ecf20Sopenharmony_ci#define FLEXCAN_FDCBT_FRJW_MASK GENMASK(18, 16) 1678c2ecf20Sopenharmony_ci#define FLEXCAN_FDCBT_FPROPSEG_MASK GENMASK(14, 10) 1688c2ecf20Sopenharmony_ci#define FLEXCAN_FDCBT_FPSEG1_MASK GENMASK(7, 5) 1698c2ecf20Sopenharmony_ci#define FLEXCAN_FDCBT_FPSEG2_MASK GENMASK(2, 0) 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci/* FLEXCAN interrupt flag register (IFLAG) bits */ 1728c2ecf20Sopenharmony_ci/* Errata ERR005829 step7: Reserve first valid MB */ 1738c2ecf20Sopenharmony_ci#define FLEXCAN_TX_MB_RESERVED_OFF_FIFO 8 1748c2ecf20Sopenharmony_ci#define FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP 0 1758c2ecf20Sopenharmony_ci#define FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST (FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP + 1) 1768c2ecf20Sopenharmony_ci#define FLEXCAN_IFLAG_MB(x) BIT_ULL(x) 1778c2ecf20Sopenharmony_ci#define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW BIT(7) 1788c2ecf20Sopenharmony_ci#define FLEXCAN_IFLAG_RX_FIFO_WARN BIT(6) 1798c2ecf20Sopenharmony_ci#define FLEXCAN_IFLAG_RX_FIFO_AVAILABLE BIT(5) 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci/* FLEXCAN message buffers */ 1828c2ecf20Sopenharmony_ci#define FLEXCAN_MB_CODE_MASK (0xf << 24) 1838c2ecf20Sopenharmony_ci#define FLEXCAN_MB_CODE_RX_BUSY_BIT (0x1 << 24) 1848c2ecf20Sopenharmony_ci#define FLEXCAN_MB_CODE_RX_INACTIVE (0x0 << 24) 1858c2ecf20Sopenharmony_ci#define FLEXCAN_MB_CODE_RX_EMPTY (0x4 << 24) 1868c2ecf20Sopenharmony_ci#define FLEXCAN_MB_CODE_RX_FULL (0x2 << 24) 1878c2ecf20Sopenharmony_ci#define FLEXCAN_MB_CODE_RX_OVERRUN (0x6 << 24) 1888c2ecf20Sopenharmony_ci#define FLEXCAN_MB_CODE_RX_RANSWER (0xa << 24) 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci#define FLEXCAN_MB_CODE_TX_INACTIVE (0x8 << 24) 1918c2ecf20Sopenharmony_ci#define FLEXCAN_MB_CODE_TX_ABORT (0x9 << 24) 1928c2ecf20Sopenharmony_ci#define FLEXCAN_MB_CODE_TX_DATA (0xc << 24) 1938c2ecf20Sopenharmony_ci#define FLEXCAN_MB_CODE_TX_TANSWER (0xe << 24) 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci#define FLEXCAN_MB_CNT_EDL BIT(31) 1968c2ecf20Sopenharmony_ci#define FLEXCAN_MB_CNT_BRS BIT(30) 1978c2ecf20Sopenharmony_ci#define FLEXCAN_MB_CNT_ESI BIT(29) 1988c2ecf20Sopenharmony_ci#define FLEXCAN_MB_CNT_SRR BIT(22) 1998c2ecf20Sopenharmony_ci#define FLEXCAN_MB_CNT_IDE BIT(21) 2008c2ecf20Sopenharmony_ci#define FLEXCAN_MB_CNT_RTR BIT(20) 2018c2ecf20Sopenharmony_ci#define FLEXCAN_MB_CNT_LENGTH(x) (((x) & 0xf) << 16) 2028c2ecf20Sopenharmony_ci#define FLEXCAN_MB_CNT_TIMESTAMP(x) ((x) & 0xffff) 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci#define FLEXCAN_TIMEOUT_US (250) 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci/* FLEXCAN hardware feature flags 2078c2ecf20Sopenharmony_ci * 2088c2ecf20Sopenharmony_ci * Below is some version info we got: 2098c2ecf20Sopenharmony_ci * SOC Version IP-Version Glitch- [TR]WRN_INT IRQ Err Memory err RTR rece- FD Mode 2108c2ecf20Sopenharmony_ci * Filter? connected? Passive detection ption in MB Supported? 2118c2ecf20Sopenharmony_ci * MX25 FlexCAN2 03.00.00.00 no no no no no no 2128c2ecf20Sopenharmony_ci * MX28 FlexCAN2 03.00.04.00 yes yes no no no no 2138c2ecf20Sopenharmony_ci * MX35 FlexCAN2 03.00.00.00 no no no no no no 2148c2ecf20Sopenharmony_ci * MX53 FlexCAN2 03.00.00.00 yes no no no no no 2158c2ecf20Sopenharmony_ci * MX6s FlexCAN3 10.00.12.00 yes yes no no yes no 2168c2ecf20Sopenharmony_ci * MX8QM FlexCAN3 03.00.23.00 yes yes no no yes yes 2178c2ecf20Sopenharmony_ci * MX8MP FlexCAN3 03.00.17.01 yes yes no yes yes yes 2188c2ecf20Sopenharmony_ci * VF610 FlexCAN3 ? no yes no yes yes? no 2198c2ecf20Sopenharmony_ci * LS1021A FlexCAN2 03.00.04.00 no yes no no yes no 2208c2ecf20Sopenharmony_ci * LX2160A FlexCAN3 03.00.23.00 no yes no yes yes yes 2218c2ecf20Sopenharmony_ci * 2228c2ecf20Sopenharmony_ci * Some SOCs do not have the RX_WARN & TX_WARN interrupt line connected. 2238c2ecf20Sopenharmony_ci */ 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci/* [TR]WRN_INT not connected */ 2268c2ecf20Sopenharmony_ci#define FLEXCAN_QUIRK_BROKEN_WERR_STATE BIT(1) 2278c2ecf20Sopenharmony_ci /* Disable RX FIFO Global mask */ 2288c2ecf20Sopenharmony_ci#define FLEXCAN_QUIRK_DISABLE_RXFG BIT(2) 2298c2ecf20Sopenharmony_ci/* Enable EACEN and RRS bit in ctrl2 */ 2308c2ecf20Sopenharmony_ci#define FLEXCAN_QUIRK_ENABLE_EACEN_RRS BIT(3) 2318c2ecf20Sopenharmony_ci/* Disable non-correctable errors interrupt and freeze mode */ 2328c2ecf20Sopenharmony_ci#define FLEXCAN_QUIRK_DISABLE_MECR BIT(4) 2338c2ecf20Sopenharmony_ci/* Use timestamp based offloading */ 2348c2ecf20Sopenharmony_ci#define FLEXCAN_QUIRK_USE_OFF_TIMESTAMP BIT(5) 2358c2ecf20Sopenharmony_ci/* No interrupt for error passive */ 2368c2ecf20Sopenharmony_ci#define FLEXCAN_QUIRK_BROKEN_PERR_STATE BIT(6) 2378c2ecf20Sopenharmony_ci/* default to BE register access */ 2388c2ecf20Sopenharmony_ci#define FLEXCAN_QUIRK_DEFAULT_BIG_ENDIAN BIT(7) 2398c2ecf20Sopenharmony_ci/* Setup stop mode to support wakeup */ 2408c2ecf20Sopenharmony_ci#define FLEXCAN_QUIRK_SETUP_STOP_MODE BIT(8) 2418c2ecf20Sopenharmony_ci/* Support CAN-FD mode */ 2428c2ecf20Sopenharmony_ci#define FLEXCAN_QUIRK_SUPPORT_FD BIT(9) 2438c2ecf20Sopenharmony_ci/* support memory detection and correction */ 2448c2ecf20Sopenharmony_ci#define FLEXCAN_QUIRK_SUPPORT_ECC BIT(10) 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci/* Structure of the message buffer */ 2478c2ecf20Sopenharmony_cistruct flexcan_mb { 2488c2ecf20Sopenharmony_ci u32 can_ctrl; 2498c2ecf20Sopenharmony_ci u32 can_id; 2508c2ecf20Sopenharmony_ci u32 data[]; 2518c2ecf20Sopenharmony_ci}; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci/* Structure of the hardware registers */ 2548c2ecf20Sopenharmony_cistruct flexcan_regs { 2558c2ecf20Sopenharmony_ci u32 mcr; /* 0x00 */ 2568c2ecf20Sopenharmony_ci u32 ctrl; /* 0x04 - Not affected by Soft Reset */ 2578c2ecf20Sopenharmony_ci u32 timer; /* 0x08 */ 2588c2ecf20Sopenharmony_ci u32 tcr; /* 0x0c */ 2598c2ecf20Sopenharmony_ci u32 rxgmask; /* 0x10 - Not affected by Soft Reset */ 2608c2ecf20Sopenharmony_ci u32 rx14mask; /* 0x14 - Not affected by Soft Reset */ 2618c2ecf20Sopenharmony_ci u32 rx15mask; /* 0x18 - Not affected by Soft Reset */ 2628c2ecf20Sopenharmony_ci u32 ecr; /* 0x1c */ 2638c2ecf20Sopenharmony_ci u32 esr; /* 0x20 */ 2648c2ecf20Sopenharmony_ci u32 imask2; /* 0x24 */ 2658c2ecf20Sopenharmony_ci u32 imask1; /* 0x28 */ 2668c2ecf20Sopenharmony_ci u32 iflag2; /* 0x2c */ 2678c2ecf20Sopenharmony_ci u32 iflag1; /* 0x30 */ 2688c2ecf20Sopenharmony_ci union { /* 0x34 */ 2698c2ecf20Sopenharmony_ci u32 gfwr_mx28; /* MX28, MX53 */ 2708c2ecf20Sopenharmony_ci u32 ctrl2; /* MX6, VF610 - Not affected by Soft Reset */ 2718c2ecf20Sopenharmony_ci }; 2728c2ecf20Sopenharmony_ci u32 esr2; /* 0x38 */ 2738c2ecf20Sopenharmony_ci u32 imeur; /* 0x3c */ 2748c2ecf20Sopenharmony_ci u32 lrfr; /* 0x40 */ 2758c2ecf20Sopenharmony_ci u32 crcr; /* 0x44 */ 2768c2ecf20Sopenharmony_ci u32 rxfgmask; /* 0x48 */ 2778c2ecf20Sopenharmony_ci u32 rxfir; /* 0x4c - Not affected by Soft Reset */ 2788c2ecf20Sopenharmony_ci u32 cbt; /* 0x50 - Not affected by Soft Reset */ 2798c2ecf20Sopenharmony_ci u32 _reserved2; /* 0x54 */ 2808c2ecf20Sopenharmony_ci u32 dbg1; /* 0x58 */ 2818c2ecf20Sopenharmony_ci u32 dbg2; /* 0x5c */ 2828c2ecf20Sopenharmony_ci u32 _reserved3[8]; /* 0x60 */ 2838c2ecf20Sopenharmony_ci u8 mb[2][512]; /* 0x80 - Not affected by Soft Reset */ 2848c2ecf20Sopenharmony_ci /* FIFO-mode: 2858c2ecf20Sopenharmony_ci * MB 2868c2ecf20Sopenharmony_ci * 0x080...0x08f 0 RX message buffer 2878c2ecf20Sopenharmony_ci * 0x090...0x0df 1-5 reserved 2888c2ecf20Sopenharmony_ci * 0x0e0...0x0ff 6-7 8 entry ID table 2898c2ecf20Sopenharmony_ci * (mx25, mx28, mx35, mx53) 2908c2ecf20Sopenharmony_ci * 0x0e0...0x2df 6-7..37 8..128 entry ID table 2918c2ecf20Sopenharmony_ci * size conf'ed via ctrl2::RFFN 2928c2ecf20Sopenharmony_ci * (mx6, vf610) 2938c2ecf20Sopenharmony_ci */ 2948c2ecf20Sopenharmony_ci u32 _reserved4[256]; /* 0x480 */ 2958c2ecf20Sopenharmony_ci u32 rximr[64]; /* 0x880 - Not affected by Soft Reset */ 2968c2ecf20Sopenharmony_ci u32 _reserved5[24]; /* 0x980 */ 2978c2ecf20Sopenharmony_ci u32 gfwr_mx6; /* 0x9e0 - MX6 */ 2988c2ecf20Sopenharmony_ci u32 _reserved6[39]; /* 0x9e4 */ 2998c2ecf20Sopenharmony_ci u32 _rxfir[6]; /* 0xa80 */ 3008c2ecf20Sopenharmony_ci u32 _reserved8[2]; /* 0xa98 */ 3018c2ecf20Sopenharmony_ci u32 _rxmgmask; /* 0xaa0 */ 3028c2ecf20Sopenharmony_ci u32 _rxfgmask; /* 0xaa4 */ 3038c2ecf20Sopenharmony_ci u32 _rx14mask; /* 0xaa8 */ 3048c2ecf20Sopenharmony_ci u32 _rx15mask; /* 0xaac */ 3058c2ecf20Sopenharmony_ci u32 tx_smb[4]; /* 0xab0 */ 3068c2ecf20Sopenharmony_ci u32 rx_smb0[4]; /* 0xac0 */ 3078c2ecf20Sopenharmony_ci u32 rx_smb1[4]; /* 0xad0 */ 3088c2ecf20Sopenharmony_ci u32 mecr; /* 0xae0 */ 3098c2ecf20Sopenharmony_ci u32 erriar; /* 0xae4 */ 3108c2ecf20Sopenharmony_ci u32 erridpr; /* 0xae8 */ 3118c2ecf20Sopenharmony_ci u32 errippr; /* 0xaec */ 3128c2ecf20Sopenharmony_ci u32 rerrar; /* 0xaf0 */ 3138c2ecf20Sopenharmony_ci u32 rerrdr; /* 0xaf4 */ 3148c2ecf20Sopenharmony_ci u32 rerrsynr; /* 0xaf8 */ 3158c2ecf20Sopenharmony_ci u32 errsr; /* 0xafc */ 3168c2ecf20Sopenharmony_ci u32 _reserved7[64]; /* 0xb00 */ 3178c2ecf20Sopenharmony_ci u32 fdctrl; /* 0xc00 - Not affected by Soft Reset */ 3188c2ecf20Sopenharmony_ci u32 fdcbt; /* 0xc04 - Not affected by Soft Reset */ 3198c2ecf20Sopenharmony_ci u32 fdcrc; /* 0xc08 */ 3208c2ecf20Sopenharmony_ci u32 _reserved9[199]; /* 0xc0c */ 3218c2ecf20Sopenharmony_ci u32 tx_smb_fd[18]; /* 0xf28 */ 3228c2ecf20Sopenharmony_ci u32 rx_smb0_fd[18]; /* 0xf70 */ 3238c2ecf20Sopenharmony_ci u32 rx_smb1_fd[18]; /* 0xfb8 */ 3248c2ecf20Sopenharmony_ci}; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic_assert(sizeof(struct flexcan_regs) == 0x4 * 18 + 0xfb8); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistruct flexcan_devtype_data { 3298c2ecf20Sopenharmony_ci u32 quirks; /* quirks needed for different IP cores */ 3308c2ecf20Sopenharmony_ci}; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistruct flexcan_stop_mode { 3338c2ecf20Sopenharmony_ci struct regmap *gpr; 3348c2ecf20Sopenharmony_ci u8 req_gpr; 3358c2ecf20Sopenharmony_ci u8 req_bit; 3368c2ecf20Sopenharmony_ci}; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistruct flexcan_priv { 3398c2ecf20Sopenharmony_ci struct can_priv can; 3408c2ecf20Sopenharmony_ci struct can_rx_offload offload; 3418c2ecf20Sopenharmony_ci struct device *dev; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci struct flexcan_regs __iomem *regs; 3448c2ecf20Sopenharmony_ci struct flexcan_mb __iomem *tx_mb; 3458c2ecf20Sopenharmony_ci struct flexcan_mb __iomem *tx_mb_reserved; 3468c2ecf20Sopenharmony_ci u8 tx_mb_idx; 3478c2ecf20Sopenharmony_ci u8 mb_count; 3488c2ecf20Sopenharmony_ci u8 mb_size; 3498c2ecf20Sopenharmony_ci u8 clk_src; /* clock source of CAN Protocol Engine */ 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci u64 rx_mask; 3528c2ecf20Sopenharmony_ci u64 tx_mask; 3538c2ecf20Sopenharmony_ci u32 reg_ctrl_default; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci struct clk *clk_ipg; 3568c2ecf20Sopenharmony_ci struct clk *clk_per; 3578c2ecf20Sopenharmony_ci const struct flexcan_devtype_data *devtype_data; 3588c2ecf20Sopenharmony_ci struct regulator *reg_xceiver; 3598c2ecf20Sopenharmony_ci struct flexcan_stop_mode stm; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* Read and Write APIs */ 3628c2ecf20Sopenharmony_ci u32 (*read)(void __iomem *addr); 3638c2ecf20Sopenharmony_ci void (*write)(u32 val, void __iomem *addr); 3648c2ecf20Sopenharmony_ci}; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic const struct flexcan_devtype_data fsl_p1010_devtype_data = { 3678c2ecf20Sopenharmony_ci .quirks = FLEXCAN_QUIRK_BROKEN_WERR_STATE | 3688c2ecf20Sopenharmony_ci FLEXCAN_QUIRK_BROKEN_PERR_STATE | 3698c2ecf20Sopenharmony_ci FLEXCAN_QUIRK_DEFAULT_BIG_ENDIAN, 3708c2ecf20Sopenharmony_ci}; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic const struct flexcan_devtype_data fsl_imx25_devtype_data = { 3738c2ecf20Sopenharmony_ci .quirks = FLEXCAN_QUIRK_BROKEN_WERR_STATE | 3748c2ecf20Sopenharmony_ci FLEXCAN_QUIRK_BROKEN_PERR_STATE, 3758c2ecf20Sopenharmony_ci}; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic const struct flexcan_devtype_data fsl_imx28_devtype_data = { 3788c2ecf20Sopenharmony_ci .quirks = FLEXCAN_QUIRK_BROKEN_PERR_STATE, 3798c2ecf20Sopenharmony_ci}; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic const struct flexcan_devtype_data fsl_imx6q_devtype_data = { 3828c2ecf20Sopenharmony_ci .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS | 3838c2ecf20Sopenharmony_ci FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_BROKEN_PERR_STATE | 3848c2ecf20Sopenharmony_ci FLEXCAN_QUIRK_SETUP_STOP_MODE, 3858c2ecf20Sopenharmony_ci}; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic const struct flexcan_devtype_data fsl_imx8qm_devtype_data = { 3888c2ecf20Sopenharmony_ci .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS | 3898c2ecf20Sopenharmony_ci FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_BROKEN_PERR_STATE | 3908c2ecf20Sopenharmony_ci FLEXCAN_QUIRK_SUPPORT_FD, 3918c2ecf20Sopenharmony_ci}; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_cistatic struct flexcan_devtype_data fsl_imx8mp_devtype_data = { 3948c2ecf20Sopenharmony_ci .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS | 3958c2ecf20Sopenharmony_ci FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | 3968c2ecf20Sopenharmony_ci FLEXCAN_QUIRK_BROKEN_PERR_STATE | FLEXCAN_QUIRK_SETUP_STOP_MODE | 3978c2ecf20Sopenharmony_ci FLEXCAN_QUIRK_SUPPORT_FD | FLEXCAN_QUIRK_SUPPORT_ECC, 3988c2ecf20Sopenharmony_ci}; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic const struct flexcan_devtype_data fsl_vf610_devtype_data = { 4018c2ecf20Sopenharmony_ci .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS | 4028c2ecf20Sopenharmony_ci FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | 4038c2ecf20Sopenharmony_ci FLEXCAN_QUIRK_BROKEN_PERR_STATE | FLEXCAN_QUIRK_SUPPORT_ECC, 4048c2ecf20Sopenharmony_ci}; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic const struct flexcan_devtype_data fsl_ls1021a_r2_devtype_data = { 4078c2ecf20Sopenharmony_ci .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS | 4088c2ecf20Sopenharmony_ci FLEXCAN_QUIRK_BROKEN_PERR_STATE | FLEXCAN_QUIRK_USE_OFF_TIMESTAMP, 4098c2ecf20Sopenharmony_ci}; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cistatic const struct flexcan_devtype_data fsl_lx2160a_r1_devtype_data = { 4128c2ecf20Sopenharmony_ci .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS | 4138c2ecf20Sopenharmony_ci FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_BROKEN_PERR_STATE | 4148c2ecf20Sopenharmony_ci FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_SUPPORT_FD | 4158c2ecf20Sopenharmony_ci FLEXCAN_QUIRK_SUPPORT_ECC, 4168c2ecf20Sopenharmony_ci}; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cistatic const struct can_bittiming_const flexcan_bittiming_const = { 4198c2ecf20Sopenharmony_ci .name = DRV_NAME, 4208c2ecf20Sopenharmony_ci .tseg1_min = 4, 4218c2ecf20Sopenharmony_ci .tseg1_max = 16, 4228c2ecf20Sopenharmony_ci .tseg2_min = 2, 4238c2ecf20Sopenharmony_ci .tseg2_max = 8, 4248c2ecf20Sopenharmony_ci .sjw_max = 4, 4258c2ecf20Sopenharmony_ci .brp_min = 1, 4268c2ecf20Sopenharmony_ci .brp_max = 256, 4278c2ecf20Sopenharmony_ci .brp_inc = 1, 4288c2ecf20Sopenharmony_ci}; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic const struct can_bittiming_const flexcan_fd_bittiming_const = { 4318c2ecf20Sopenharmony_ci .name = DRV_NAME, 4328c2ecf20Sopenharmony_ci .tseg1_min = 2, 4338c2ecf20Sopenharmony_ci .tseg1_max = 96, 4348c2ecf20Sopenharmony_ci .tseg2_min = 2, 4358c2ecf20Sopenharmony_ci .tseg2_max = 32, 4368c2ecf20Sopenharmony_ci .sjw_max = 16, 4378c2ecf20Sopenharmony_ci .brp_min = 1, 4388c2ecf20Sopenharmony_ci .brp_max = 1024, 4398c2ecf20Sopenharmony_ci .brp_inc = 1, 4408c2ecf20Sopenharmony_ci}; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic const struct can_bittiming_const flexcan_fd_data_bittiming_const = { 4438c2ecf20Sopenharmony_ci .name = DRV_NAME, 4448c2ecf20Sopenharmony_ci .tseg1_min = 2, 4458c2ecf20Sopenharmony_ci .tseg1_max = 39, 4468c2ecf20Sopenharmony_ci .tseg2_min = 2, 4478c2ecf20Sopenharmony_ci .tseg2_max = 8, 4488c2ecf20Sopenharmony_ci .sjw_max = 4, 4498c2ecf20Sopenharmony_ci .brp_min = 1, 4508c2ecf20Sopenharmony_ci .brp_max = 1024, 4518c2ecf20Sopenharmony_ci .brp_inc = 1, 4528c2ecf20Sopenharmony_ci}; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci/* FlexCAN module is essentially modelled as a little-endian IP in most 4558c2ecf20Sopenharmony_ci * SoCs, i.e the registers as well as the message buffer areas are 4568c2ecf20Sopenharmony_ci * implemented in a little-endian fashion. 4578c2ecf20Sopenharmony_ci * 4588c2ecf20Sopenharmony_ci * However there are some SoCs (e.g. LS1021A) which implement the FlexCAN 4598c2ecf20Sopenharmony_ci * module in a big-endian fashion (i.e the registers as well as the 4608c2ecf20Sopenharmony_ci * message buffer areas are implemented in a big-endian way). 4618c2ecf20Sopenharmony_ci * 4628c2ecf20Sopenharmony_ci * In addition, the FlexCAN module can be found on SoCs having ARM or 4638c2ecf20Sopenharmony_ci * PPC cores. So, we need to abstract off the register read/write 4648c2ecf20Sopenharmony_ci * functions, ensuring that these cater to all the combinations of module 4658c2ecf20Sopenharmony_ci * endianness and underlying CPU endianness. 4668c2ecf20Sopenharmony_ci */ 4678c2ecf20Sopenharmony_cistatic inline u32 flexcan_read_be(void __iomem *addr) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci return ioread32be(addr); 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic inline void flexcan_write_be(u32 val, void __iomem *addr) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci iowrite32be(val, addr); 4758c2ecf20Sopenharmony_ci} 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_cistatic inline u32 flexcan_read_le(void __iomem *addr) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci return ioread32(addr); 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic inline void flexcan_write_le(u32 val, void __iomem *addr) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci iowrite32(val, addr); 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cistatic struct flexcan_mb __iomem *flexcan_get_mb(const struct flexcan_priv *priv, 4888c2ecf20Sopenharmony_ci u8 mb_index) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci u8 bank_size; 4918c2ecf20Sopenharmony_ci bool bank; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci if (WARN_ON(mb_index >= priv->mb_count)) 4948c2ecf20Sopenharmony_ci return NULL; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci bank_size = sizeof(priv->regs->mb[0]) / priv->mb_size; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci bank = mb_index >= bank_size; 4998c2ecf20Sopenharmony_ci if (bank) 5008c2ecf20Sopenharmony_ci mb_index -= bank_size; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci return (struct flexcan_mb __iomem *) 5038c2ecf20Sopenharmony_ci (&priv->regs->mb[bank][priv->mb_size * mb_index]); 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cistatic int flexcan_low_power_enter_ack(struct flexcan_priv *priv) 5078c2ecf20Sopenharmony_ci{ 5088c2ecf20Sopenharmony_ci struct flexcan_regs __iomem *regs = priv->regs; 5098c2ecf20Sopenharmony_ci unsigned int timeout = FLEXCAN_TIMEOUT_US / 10; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci while (timeout-- && !(priv->read(®s->mcr) & FLEXCAN_MCR_LPM_ACK)) 5128c2ecf20Sopenharmony_ci udelay(10); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci if (!(priv->read(®s->mcr) & FLEXCAN_MCR_LPM_ACK)) 5158c2ecf20Sopenharmony_ci return -ETIMEDOUT; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci return 0; 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic int flexcan_low_power_exit_ack(struct flexcan_priv *priv) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci struct flexcan_regs __iomem *regs = priv->regs; 5238c2ecf20Sopenharmony_ci unsigned int timeout = FLEXCAN_TIMEOUT_US / 10; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci while (timeout-- && (priv->read(®s->mcr) & FLEXCAN_MCR_LPM_ACK)) 5268c2ecf20Sopenharmony_ci udelay(10); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci if (priv->read(®s->mcr) & FLEXCAN_MCR_LPM_ACK) 5298c2ecf20Sopenharmony_ci return -ETIMEDOUT; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci return 0; 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_cistatic void flexcan_enable_wakeup_irq(struct flexcan_priv *priv, bool enable) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci struct flexcan_regs __iomem *regs = priv->regs; 5378c2ecf20Sopenharmony_ci u32 reg_mcr; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci reg_mcr = priv->read(®s->mcr); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci if (enable) 5428c2ecf20Sopenharmony_ci reg_mcr |= FLEXCAN_MCR_WAK_MSK; 5438c2ecf20Sopenharmony_ci else 5448c2ecf20Sopenharmony_ci reg_mcr &= ~FLEXCAN_MCR_WAK_MSK; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci priv->write(reg_mcr, ®s->mcr); 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_cistatic inline int flexcan_enter_stop_mode(struct flexcan_priv *priv) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci struct flexcan_regs __iomem *regs = priv->regs; 5528c2ecf20Sopenharmony_ci u32 reg_mcr; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci reg_mcr = priv->read(®s->mcr); 5558c2ecf20Sopenharmony_ci reg_mcr |= FLEXCAN_MCR_SLF_WAK; 5568c2ecf20Sopenharmony_ci priv->write(reg_mcr, ®s->mcr); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci /* enable stop request */ 5598c2ecf20Sopenharmony_ci regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr, 5608c2ecf20Sopenharmony_ci 1 << priv->stm.req_bit, 1 << priv->stm.req_bit); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci return flexcan_low_power_enter_ack(priv); 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic inline int flexcan_exit_stop_mode(struct flexcan_priv *priv) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci struct flexcan_regs __iomem *regs = priv->regs; 5688c2ecf20Sopenharmony_ci u32 reg_mcr; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci /* remove stop request */ 5718c2ecf20Sopenharmony_ci regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr, 5728c2ecf20Sopenharmony_ci 1 << priv->stm.req_bit, 0); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci reg_mcr = priv->read(®s->mcr); 5758c2ecf20Sopenharmony_ci reg_mcr &= ~FLEXCAN_MCR_SLF_WAK; 5768c2ecf20Sopenharmony_ci priv->write(reg_mcr, ®s->mcr); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci return flexcan_low_power_exit_ack(priv); 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_cistatic inline void flexcan_error_irq_enable(const struct flexcan_priv *priv) 5828c2ecf20Sopenharmony_ci{ 5838c2ecf20Sopenharmony_ci struct flexcan_regs __iomem *regs = priv->regs; 5848c2ecf20Sopenharmony_ci u32 reg_ctrl = (priv->reg_ctrl_default | FLEXCAN_CTRL_ERR_MSK); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci priv->write(reg_ctrl, ®s->ctrl); 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_cistatic inline void flexcan_error_irq_disable(const struct flexcan_priv *priv) 5908c2ecf20Sopenharmony_ci{ 5918c2ecf20Sopenharmony_ci struct flexcan_regs __iomem *regs = priv->regs; 5928c2ecf20Sopenharmony_ci u32 reg_ctrl = (priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_MSK); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci priv->write(reg_ctrl, ®s->ctrl); 5958c2ecf20Sopenharmony_ci} 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_cistatic int flexcan_clks_enable(const struct flexcan_priv *priv) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci int err; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci err = clk_prepare_enable(priv->clk_ipg); 6028c2ecf20Sopenharmony_ci if (err) 6038c2ecf20Sopenharmony_ci return err; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci err = clk_prepare_enable(priv->clk_per); 6068c2ecf20Sopenharmony_ci if (err) 6078c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk_ipg); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci return err; 6108c2ecf20Sopenharmony_ci} 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_cistatic void flexcan_clks_disable(const struct flexcan_priv *priv) 6138c2ecf20Sopenharmony_ci{ 6148c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk_per); 6158c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk_ipg); 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_cistatic inline int flexcan_transceiver_enable(const struct flexcan_priv *priv) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci if (!priv->reg_xceiver) 6218c2ecf20Sopenharmony_ci return 0; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci return regulator_enable(priv->reg_xceiver); 6248c2ecf20Sopenharmony_ci} 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_cistatic inline int flexcan_transceiver_disable(const struct flexcan_priv *priv) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci if (!priv->reg_xceiver) 6298c2ecf20Sopenharmony_ci return 0; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci return regulator_disable(priv->reg_xceiver); 6328c2ecf20Sopenharmony_ci} 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_cistatic int flexcan_chip_enable(struct flexcan_priv *priv) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci struct flexcan_regs __iomem *regs = priv->regs; 6378c2ecf20Sopenharmony_ci u32 reg; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci reg = priv->read(®s->mcr); 6408c2ecf20Sopenharmony_ci reg &= ~FLEXCAN_MCR_MDIS; 6418c2ecf20Sopenharmony_ci priv->write(reg, ®s->mcr); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci return flexcan_low_power_exit_ack(priv); 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_cistatic int flexcan_chip_disable(struct flexcan_priv *priv) 6478c2ecf20Sopenharmony_ci{ 6488c2ecf20Sopenharmony_ci struct flexcan_regs __iomem *regs = priv->regs; 6498c2ecf20Sopenharmony_ci u32 reg; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci reg = priv->read(®s->mcr); 6528c2ecf20Sopenharmony_ci reg |= FLEXCAN_MCR_MDIS; 6538c2ecf20Sopenharmony_ci priv->write(reg, ®s->mcr); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci return flexcan_low_power_enter_ack(priv); 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic int flexcan_chip_freeze(struct flexcan_priv *priv) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci struct flexcan_regs __iomem *regs = priv->regs; 6618c2ecf20Sopenharmony_ci unsigned int timeout; 6628c2ecf20Sopenharmony_ci u32 bitrate = priv->can.bittiming.bitrate; 6638c2ecf20Sopenharmony_ci u32 reg; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci if (bitrate) 6668c2ecf20Sopenharmony_ci timeout = 1000 * 1000 * 10 / bitrate; 6678c2ecf20Sopenharmony_ci else 6688c2ecf20Sopenharmony_ci timeout = FLEXCAN_TIMEOUT_US / 10; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci reg = priv->read(®s->mcr); 6718c2ecf20Sopenharmony_ci reg |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT; 6728c2ecf20Sopenharmony_ci priv->write(reg, ®s->mcr); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci while (timeout-- && !(priv->read(®s->mcr) & FLEXCAN_MCR_FRZ_ACK)) 6758c2ecf20Sopenharmony_ci udelay(100); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci if (!(priv->read(®s->mcr) & FLEXCAN_MCR_FRZ_ACK)) 6788c2ecf20Sopenharmony_ci return -ETIMEDOUT; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci return 0; 6818c2ecf20Sopenharmony_ci} 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_cistatic int flexcan_chip_unfreeze(struct flexcan_priv *priv) 6848c2ecf20Sopenharmony_ci{ 6858c2ecf20Sopenharmony_ci struct flexcan_regs __iomem *regs = priv->regs; 6868c2ecf20Sopenharmony_ci unsigned int timeout = FLEXCAN_TIMEOUT_US / 10; 6878c2ecf20Sopenharmony_ci u32 reg; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci reg = priv->read(®s->mcr); 6908c2ecf20Sopenharmony_ci reg &= ~FLEXCAN_MCR_HALT; 6918c2ecf20Sopenharmony_ci priv->write(reg, ®s->mcr); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci while (timeout-- && (priv->read(®s->mcr) & FLEXCAN_MCR_FRZ_ACK)) 6948c2ecf20Sopenharmony_ci udelay(10); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci if (priv->read(®s->mcr) & FLEXCAN_MCR_FRZ_ACK) 6978c2ecf20Sopenharmony_ci return -ETIMEDOUT; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci return 0; 7008c2ecf20Sopenharmony_ci} 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_cistatic int flexcan_chip_softreset(struct flexcan_priv *priv) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci struct flexcan_regs __iomem *regs = priv->regs; 7058c2ecf20Sopenharmony_ci unsigned int timeout = FLEXCAN_TIMEOUT_US / 10; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci priv->write(FLEXCAN_MCR_SOFTRST, ®s->mcr); 7088c2ecf20Sopenharmony_ci while (timeout-- && (priv->read(®s->mcr) & FLEXCAN_MCR_SOFTRST)) 7098c2ecf20Sopenharmony_ci udelay(10); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci if (priv->read(®s->mcr) & FLEXCAN_MCR_SOFTRST) 7128c2ecf20Sopenharmony_ci return -ETIMEDOUT; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci return 0; 7158c2ecf20Sopenharmony_ci} 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_cistatic int __flexcan_get_berr_counter(const struct net_device *dev, 7188c2ecf20Sopenharmony_ci struct can_berr_counter *bec) 7198c2ecf20Sopenharmony_ci{ 7208c2ecf20Sopenharmony_ci const struct flexcan_priv *priv = netdev_priv(dev); 7218c2ecf20Sopenharmony_ci struct flexcan_regs __iomem *regs = priv->regs; 7228c2ecf20Sopenharmony_ci u32 reg = priv->read(®s->ecr); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci bec->txerr = (reg >> 0) & 0xff; 7258c2ecf20Sopenharmony_ci bec->rxerr = (reg >> 8) & 0xff; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci return 0; 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_cistatic int flexcan_get_berr_counter(const struct net_device *dev, 7318c2ecf20Sopenharmony_ci struct can_berr_counter *bec) 7328c2ecf20Sopenharmony_ci{ 7338c2ecf20Sopenharmony_ci const struct flexcan_priv *priv = netdev_priv(dev); 7348c2ecf20Sopenharmony_ci int err; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci err = pm_runtime_get_sync(priv->dev); 7378c2ecf20Sopenharmony_ci if (err < 0) { 7388c2ecf20Sopenharmony_ci pm_runtime_put_noidle(priv->dev); 7398c2ecf20Sopenharmony_ci return err; 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci err = __flexcan_get_berr_counter(dev, bec); 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci pm_runtime_put(priv->dev); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci return err; 7478c2ecf20Sopenharmony_ci} 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_cistatic netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev) 7508c2ecf20Sopenharmony_ci{ 7518c2ecf20Sopenharmony_ci const struct flexcan_priv *priv = netdev_priv(dev); 7528c2ecf20Sopenharmony_ci struct canfd_frame *cfd = (struct canfd_frame *)skb->data; 7538c2ecf20Sopenharmony_ci u32 can_id; 7548c2ecf20Sopenharmony_ci u32 data; 7558c2ecf20Sopenharmony_ci u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | ((can_len2dlc(cfd->len)) << 16); 7568c2ecf20Sopenharmony_ci int i; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci if (can_dropped_invalid_skb(dev, skb)) 7598c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci netif_stop_queue(dev); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci if (cfd->can_id & CAN_EFF_FLAG) { 7648c2ecf20Sopenharmony_ci can_id = cfd->can_id & CAN_EFF_MASK; 7658c2ecf20Sopenharmony_ci ctrl |= FLEXCAN_MB_CNT_IDE | FLEXCAN_MB_CNT_SRR; 7668c2ecf20Sopenharmony_ci } else { 7678c2ecf20Sopenharmony_ci can_id = (cfd->can_id & CAN_SFF_MASK) << 18; 7688c2ecf20Sopenharmony_ci } 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci if (cfd->can_id & CAN_RTR_FLAG) 7718c2ecf20Sopenharmony_ci ctrl |= FLEXCAN_MB_CNT_RTR; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci if (can_is_canfd_skb(skb)) { 7748c2ecf20Sopenharmony_ci ctrl |= FLEXCAN_MB_CNT_EDL; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci if (cfd->flags & CANFD_BRS) 7778c2ecf20Sopenharmony_ci ctrl |= FLEXCAN_MB_CNT_BRS; 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci for (i = 0; i < cfd->len; i += sizeof(u32)) { 7818c2ecf20Sopenharmony_ci data = be32_to_cpup((__be32 *)&cfd->data[i]); 7828c2ecf20Sopenharmony_ci priv->write(data, &priv->tx_mb->data[i / sizeof(u32)]); 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci can_put_echo_skb(skb, dev, 0); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci priv->write(can_id, &priv->tx_mb->can_id); 7888c2ecf20Sopenharmony_ci priv->write(ctrl, &priv->tx_mb->can_ctrl); 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci /* Errata ERR005829 step8: 7918c2ecf20Sopenharmony_ci * Write twice INACTIVE(0x8) code to first MB. 7928c2ecf20Sopenharmony_ci */ 7938c2ecf20Sopenharmony_ci priv->write(FLEXCAN_MB_CODE_TX_INACTIVE, 7948c2ecf20Sopenharmony_ci &priv->tx_mb_reserved->can_ctrl); 7958c2ecf20Sopenharmony_ci priv->write(FLEXCAN_MB_CODE_TX_INACTIVE, 7968c2ecf20Sopenharmony_ci &priv->tx_mb_reserved->can_ctrl); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 7998c2ecf20Sopenharmony_ci} 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_cistatic void flexcan_irq_bus_err(struct net_device *dev, u32 reg_esr) 8028c2ecf20Sopenharmony_ci{ 8038c2ecf20Sopenharmony_ci struct flexcan_priv *priv = netdev_priv(dev); 8048c2ecf20Sopenharmony_ci struct flexcan_regs __iomem *regs = priv->regs; 8058c2ecf20Sopenharmony_ci struct sk_buff *skb; 8068c2ecf20Sopenharmony_ci struct can_frame *cf; 8078c2ecf20Sopenharmony_ci bool rx_errors = false, tx_errors = false; 8088c2ecf20Sopenharmony_ci u32 timestamp; 8098c2ecf20Sopenharmony_ci int err; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci timestamp = priv->read(®s->timer) << 16; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci skb = alloc_can_err_skb(dev, &cf); 8148c2ecf20Sopenharmony_ci if (unlikely(!skb)) 8158c2ecf20Sopenharmony_ci return; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci if (reg_esr & FLEXCAN_ESR_BIT1_ERR) { 8208c2ecf20Sopenharmony_ci netdev_dbg(dev, "BIT1_ERR irq\n"); 8218c2ecf20Sopenharmony_ci cf->data[2] |= CAN_ERR_PROT_BIT1; 8228c2ecf20Sopenharmony_ci tx_errors = true; 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci if (reg_esr & FLEXCAN_ESR_BIT0_ERR) { 8258c2ecf20Sopenharmony_ci netdev_dbg(dev, "BIT0_ERR irq\n"); 8268c2ecf20Sopenharmony_ci cf->data[2] |= CAN_ERR_PROT_BIT0; 8278c2ecf20Sopenharmony_ci tx_errors = true; 8288c2ecf20Sopenharmony_ci } 8298c2ecf20Sopenharmony_ci if (reg_esr & FLEXCAN_ESR_ACK_ERR) { 8308c2ecf20Sopenharmony_ci netdev_dbg(dev, "ACK_ERR irq\n"); 8318c2ecf20Sopenharmony_ci cf->can_id |= CAN_ERR_ACK; 8328c2ecf20Sopenharmony_ci cf->data[3] = CAN_ERR_PROT_LOC_ACK; 8338c2ecf20Sopenharmony_ci tx_errors = true; 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci if (reg_esr & FLEXCAN_ESR_CRC_ERR) { 8368c2ecf20Sopenharmony_ci netdev_dbg(dev, "CRC_ERR irq\n"); 8378c2ecf20Sopenharmony_ci cf->data[2] |= CAN_ERR_PROT_BIT; 8388c2ecf20Sopenharmony_ci cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; 8398c2ecf20Sopenharmony_ci rx_errors = true; 8408c2ecf20Sopenharmony_ci } 8418c2ecf20Sopenharmony_ci if (reg_esr & FLEXCAN_ESR_FRM_ERR) { 8428c2ecf20Sopenharmony_ci netdev_dbg(dev, "FRM_ERR irq\n"); 8438c2ecf20Sopenharmony_ci cf->data[2] |= CAN_ERR_PROT_FORM; 8448c2ecf20Sopenharmony_ci rx_errors = true; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci if (reg_esr & FLEXCAN_ESR_STF_ERR) { 8478c2ecf20Sopenharmony_ci netdev_dbg(dev, "STF_ERR irq\n"); 8488c2ecf20Sopenharmony_ci cf->data[2] |= CAN_ERR_PROT_STUFF; 8498c2ecf20Sopenharmony_ci rx_errors = true; 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci priv->can.can_stats.bus_error++; 8538c2ecf20Sopenharmony_ci if (rx_errors) 8548c2ecf20Sopenharmony_ci dev->stats.rx_errors++; 8558c2ecf20Sopenharmony_ci if (tx_errors) 8568c2ecf20Sopenharmony_ci dev->stats.tx_errors++; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp); 8598c2ecf20Sopenharmony_ci if (err) 8608c2ecf20Sopenharmony_ci dev->stats.rx_fifo_errors++; 8618c2ecf20Sopenharmony_ci} 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_cistatic void flexcan_irq_state(struct net_device *dev, u32 reg_esr) 8648c2ecf20Sopenharmony_ci{ 8658c2ecf20Sopenharmony_ci struct flexcan_priv *priv = netdev_priv(dev); 8668c2ecf20Sopenharmony_ci struct flexcan_regs __iomem *regs = priv->regs; 8678c2ecf20Sopenharmony_ci struct sk_buff *skb; 8688c2ecf20Sopenharmony_ci struct can_frame *cf; 8698c2ecf20Sopenharmony_ci enum can_state new_state, rx_state, tx_state; 8708c2ecf20Sopenharmony_ci int flt; 8718c2ecf20Sopenharmony_ci struct can_berr_counter bec; 8728c2ecf20Sopenharmony_ci u32 timestamp; 8738c2ecf20Sopenharmony_ci int err; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci flt = reg_esr & FLEXCAN_ESR_FLT_CONF_MASK; 8768c2ecf20Sopenharmony_ci if (likely(flt == FLEXCAN_ESR_FLT_CONF_ACTIVE)) { 8778c2ecf20Sopenharmony_ci tx_state = unlikely(reg_esr & FLEXCAN_ESR_TX_WRN) ? 8788c2ecf20Sopenharmony_ci CAN_STATE_ERROR_WARNING : CAN_STATE_ERROR_ACTIVE; 8798c2ecf20Sopenharmony_ci rx_state = unlikely(reg_esr & FLEXCAN_ESR_RX_WRN) ? 8808c2ecf20Sopenharmony_ci CAN_STATE_ERROR_WARNING : CAN_STATE_ERROR_ACTIVE; 8818c2ecf20Sopenharmony_ci new_state = max(tx_state, rx_state); 8828c2ecf20Sopenharmony_ci } else { 8838c2ecf20Sopenharmony_ci __flexcan_get_berr_counter(dev, &bec); 8848c2ecf20Sopenharmony_ci new_state = flt == FLEXCAN_ESR_FLT_CONF_PASSIVE ? 8858c2ecf20Sopenharmony_ci CAN_STATE_ERROR_PASSIVE : CAN_STATE_BUS_OFF; 8868c2ecf20Sopenharmony_ci rx_state = bec.rxerr >= bec.txerr ? new_state : 0; 8878c2ecf20Sopenharmony_ci tx_state = bec.rxerr <= bec.txerr ? new_state : 0; 8888c2ecf20Sopenharmony_ci } 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci /* state hasn't changed */ 8918c2ecf20Sopenharmony_ci if (likely(new_state == priv->can.state)) 8928c2ecf20Sopenharmony_ci return; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci timestamp = priv->read(®s->timer) << 16; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci skb = alloc_can_err_skb(dev, &cf); 8978c2ecf20Sopenharmony_ci if (unlikely(!skb)) 8988c2ecf20Sopenharmony_ci return; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci can_change_state(dev, cf, tx_state, rx_state); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci if (unlikely(new_state == CAN_STATE_BUS_OFF)) 9038c2ecf20Sopenharmony_ci can_bus_off(dev); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp); 9068c2ecf20Sopenharmony_ci if (err) 9078c2ecf20Sopenharmony_ci dev->stats.rx_fifo_errors++; 9088c2ecf20Sopenharmony_ci} 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_cistatic inline u64 flexcan_read64_mask(struct flexcan_priv *priv, void __iomem *addr, u64 mask) 9118c2ecf20Sopenharmony_ci{ 9128c2ecf20Sopenharmony_ci u64 reg = 0; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci if (upper_32_bits(mask)) 9158c2ecf20Sopenharmony_ci reg = (u64)priv->read(addr - 4) << 32; 9168c2ecf20Sopenharmony_ci if (lower_32_bits(mask)) 9178c2ecf20Sopenharmony_ci reg |= priv->read(addr); 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci return reg & mask; 9208c2ecf20Sopenharmony_ci} 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_cistatic inline void flexcan_write64(struct flexcan_priv *priv, u64 val, void __iomem *addr) 9238c2ecf20Sopenharmony_ci{ 9248c2ecf20Sopenharmony_ci if (upper_32_bits(val)) 9258c2ecf20Sopenharmony_ci priv->write(upper_32_bits(val), addr - 4); 9268c2ecf20Sopenharmony_ci if (lower_32_bits(val)) 9278c2ecf20Sopenharmony_ci priv->write(lower_32_bits(val), addr); 9288c2ecf20Sopenharmony_ci} 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_cistatic inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv) 9318c2ecf20Sopenharmony_ci{ 9328c2ecf20Sopenharmony_ci return flexcan_read64_mask(priv, &priv->regs->iflag1, priv->rx_mask); 9338c2ecf20Sopenharmony_ci} 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_cistatic inline u64 flexcan_read_reg_iflag_tx(struct flexcan_priv *priv) 9368c2ecf20Sopenharmony_ci{ 9378c2ecf20Sopenharmony_ci return flexcan_read64_mask(priv, &priv->regs->iflag1, priv->tx_mask); 9388c2ecf20Sopenharmony_ci} 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_cistatic inline struct flexcan_priv *rx_offload_to_priv(struct can_rx_offload *offload) 9418c2ecf20Sopenharmony_ci{ 9428c2ecf20Sopenharmony_ci return container_of(offload, struct flexcan_priv, offload); 9438c2ecf20Sopenharmony_ci} 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_cistatic struct sk_buff *flexcan_mailbox_read(struct can_rx_offload *offload, 9468c2ecf20Sopenharmony_ci unsigned int n, u32 *timestamp, 9478c2ecf20Sopenharmony_ci bool drop) 9488c2ecf20Sopenharmony_ci{ 9498c2ecf20Sopenharmony_ci struct flexcan_priv *priv = rx_offload_to_priv(offload); 9508c2ecf20Sopenharmony_ci struct flexcan_regs __iomem *regs = priv->regs; 9518c2ecf20Sopenharmony_ci struct flexcan_mb __iomem *mb; 9528c2ecf20Sopenharmony_ci struct sk_buff *skb; 9538c2ecf20Sopenharmony_ci struct canfd_frame *cfd; 9548c2ecf20Sopenharmony_ci u32 reg_ctrl, reg_id, reg_iflag1; 9558c2ecf20Sopenharmony_ci int i; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci mb = flexcan_get_mb(priv, n); 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { 9608c2ecf20Sopenharmony_ci u32 code; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci do { 9638c2ecf20Sopenharmony_ci reg_ctrl = priv->read(&mb->can_ctrl); 9648c2ecf20Sopenharmony_ci } while (reg_ctrl & FLEXCAN_MB_CODE_RX_BUSY_BIT); 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci /* is this MB empty? */ 9678c2ecf20Sopenharmony_ci code = reg_ctrl & FLEXCAN_MB_CODE_MASK; 9688c2ecf20Sopenharmony_ci if ((code != FLEXCAN_MB_CODE_RX_FULL) && 9698c2ecf20Sopenharmony_ci (code != FLEXCAN_MB_CODE_RX_OVERRUN)) 9708c2ecf20Sopenharmony_ci return NULL; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci if (code == FLEXCAN_MB_CODE_RX_OVERRUN) { 9738c2ecf20Sopenharmony_ci /* This MB was overrun, we lost data */ 9748c2ecf20Sopenharmony_ci offload->dev->stats.rx_over_errors++; 9758c2ecf20Sopenharmony_ci offload->dev->stats.rx_errors++; 9768c2ecf20Sopenharmony_ci } 9778c2ecf20Sopenharmony_ci } else { 9788c2ecf20Sopenharmony_ci reg_iflag1 = priv->read(®s->iflag1); 9798c2ecf20Sopenharmony_ci if (!(reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE)) 9808c2ecf20Sopenharmony_ci return NULL; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci reg_ctrl = priv->read(&mb->can_ctrl); 9838c2ecf20Sopenharmony_ci } 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci if (unlikely(drop)) { 9868c2ecf20Sopenharmony_ci skb = ERR_PTR(-ENOBUFS); 9878c2ecf20Sopenharmony_ci goto mark_as_read; 9888c2ecf20Sopenharmony_ci } 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci if (reg_ctrl & FLEXCAN_MB_CNT_EDL) 9918c2ecf20Sopenharmony_ci skb = alloc_canfd_skb(offload->dev, &cfd); 9928c2ecf20Sopenharmony_ci else 9938c2ecf20Sopenharmony_ci skb = alloc_can_skb(offload->dev, (struct can_frame **)&cfd); 9948c2ecf20Sopenharmony_ci if (unlikely(!skb)) { 9958c2ecf20Sopenharmony_ci skb = ERR_PTR(-ENOMEM); 9968c2ecf20Sopenharmony_ci goto mark_as_read; 9978c2ecf20Sopenharmony_ci } 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci /* increase timstamp to full 32 bit */ 10008c2ecf20Sopenharmony_ci *timestamp = reg_ctrl << 16; 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci reg_id = priv->read(&mb->can_id); 10038c2ecf20Sopenharmony_ci if (reg_ctrl & FLEXCAN_MB_CNT_IDE) 10048c2ecf20Sopenharmony_ci cfd->can_id = ((reg_id >> 0) & CAN_EFF_MASK) | CAN_EFF_FLAG; 10058c2ecf20Sopenharmony_ci else 10068c2ecf20Sopenharmony_ci cfd->can_id = (reg_id >> 18) & CAN_SFF_MASK; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci if (reg_ctrl & FLEXCAN_MB_CNT_EDL) { 10098c2ecf20Sopenharmony_ci cfd->len = can_dlc2len(get_canfd_dlc((reg_ctrl >> 16) & 0xf)); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci if (reg_ctrl & FLEXCAN_MB_CNT_BRS) 10128c2ecf20Sopenharmony_ci cfd->flags |= CANFD_BRS; 10138c2ecf20Sopenharmony_ci } else { 10148c2ecf20Sopenharmony_ci cfd->len = get_can_dlc((reg_ctrl >> 16) & 0xf); 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci if (reg_ctrl & FLEXCAN_MB_CNT_RTR) 10178c2ecf20Sopenharmony_ci cfd->can_id |= CAN_RTR_FLAG; 10188c2ecf20Sopenharmony_ci } 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci if (reg_ctrl & FLEXCAN_MB_CNT_ESI) 10218c2ecf20Sopenharmony_ci cfd->flags |= CANFD_ESI; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci for (i = 0; i < cfd->len; i += sizeof(u32)) { 10248c2ecf20Sopenharmony_ci __be32 data = cpu_to_be32(priv->read(&mb->data[i / sizeof(u32)])); 10258c2ecf20Sopenharmony_ci *(__be32 *)(cfd->data + i) = data; 10268c2ecf20Sopenharmony_ci } 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci mark_as_read: 10298c2ecf20Sopenharmony_ci if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) 10308c2ecf20Sopenharmony_ci flexcan_write64(priv, FLEXCAN_IFLAG_MB(n), ®s->iflag1); 10318c2ecf20Sopenharmony_ci else 10328c2ecf20Sopenharmony_ci priv->write(FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, ®s->iflag1); 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci /* Read the Free Running Timer. It is optional but recommended 10358c2ecf20Sopenharmony_ci * to unlock Mailbox as soon as possible and make it available 10368c2ecf20Sopenharmony_ci * for reception. 10378c2ecf20Sopenharmony_ci */ 10388c2ecf20Sopenharmony_ci priv->read(®s->timer); 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci return skb; 10418c2ecf20Sopenharmony_ci} 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_cistatic irqreturn_t flexcan_irq(int irq, void *dev_id) 10448c2ecf20Sopenharmony_ci{ 10458c2ecf20Sopenharmony_ci struct net_device *dev = dev_id; 10468c2ecf20Sopenharmony_ci struct net_device_stats *stats = &dev->stats; 10478c2ecf20Sopenharmony_ci struct flexcan_priv *priv = netdev_priv(dev); 10488c2ecf20Sopenharmony_ci struct flexcan_regs __iomem *regs = priv->regs; 10498c2ecf20Sopenharmony_ci irqreturn_t handled = IRQ_NONE; 10508c2ecf20Sopenharmony_ci u64 reg_iflag_tx; 10518c2ecf20Sopenharmony_ci u32 reg_esr; 10528c2ecf20Sopenharmony_ci enum can_state last_state = priv->can.state; 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci /* reception interrupt */ 10558c2ecf20Sopenharmony_ci if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { 10568c2ecf20Sopenharmony_ci u64 reg_iflag_rx; 10578c2ecf20Sopenharmony_ci int ret; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci while ((reg_iflag_rx = flexcan_read_reg_iflag_rx(priv))) { 10608c2ecf20Sopenharmony_ci handled = IRQ_HANDLED; 10618c2ecf20Sopenharmony_ci ret = can_rx_offload_irq_offload_timestamp(&priv->offload, 10628c2ecf20Sopenharmony_ci reg_iflag_rx); 10638c2ecf20Sopenharmony_ci if (!ret) 10648c2ecf20Sopenharmony_ci break; 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci } else { 10678c2ecf20Sopenharmony_ci u32 reg_iflag1; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci reg_iflag1 = priv->read(®s->iflag1); 10708c2ecf20Sopenharmony_ci if (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE) { 10718c2ecf20Sopenharmony_ci handled = IRQ_HANDLED; 10728c2ecf20Sopenharmony_ci can_rx_offload_irq_offload_fifo(&priv->offload); 10738c2ecf20Sopenharmony_ci } 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci /* FIFO overflow interrupt */ 10768c2ecf20Sopenharmony_ci if (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_OVERFLOW) { 10778c2ecf20Sopenharmony_ci handled = IRQ_HANDLED; 10788c2ecf20Sopenharmony_ci priv->write(FLEXCAN_IFLAG_RX_FIFO_OVERFLOW, 10798c2ecf20Sopenharmony_ci ®s->iflag1); 10808c2ecf20Sopenharmony_ci dev->stats.rx_over_errors++; 10818c2ecf20Sopenharmony_ci dev->stats.rx_errors++; 10828c2ecf20Sopenharmony_ci } 10838c2ecf20Sopenharmony_ci } 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci reg_iflag_tx = flexcan_read_reg_iflag_tx(priv); 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci /* transmission complete interrupt */ 10888c2ecf20Sopenharmony_ci if (reg_iflag_tx & priv->tx_mask) { 10898c2ecf20Sopenharmony_ci u32 reg_ctrl = priv->read(&priv->tx_mb->can_ctrl); 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci handled = IRQ_HANDLED; 10928c2ecf20Sopenharmony_ci stats->tx_bytes += can_rx_offload_get_echo_skb(&priv->offload, 10938c2ecf20Sopenharmony_ci 0, reg_ctrl << 16); 10948c2ecf20Sopenharmony_ci stats->tx_packets++; 10958c2ecf20Sopenharmony_ci can_led_event(dev, CAN_LED_EVENT_TX); 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci /* after sending a RTR frame MB is in RX mode */ 10988c2ecf20Sopenharmony_ci priv->write(FLEXCAN_MB_CODE_TX_INACTIVE, 10998c2ecf20Sopenharmony_ci &priv->tx_mb->can_ctrl); 11008c2ecf20Sopenharmony_ci flexcan_write64(priv, priv->tx_mask, ®s->iflag1); 11018c2ecf20Sopenharmony_ci netif_wake_queue(dev); 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci reg_esr = priv->read(®s->esr); 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci /* ACK all bus error, state change and wake IRQ sources */ 11078c2ecf20Sopenharmony_ci if (reg_esr & (FLEXCAN_ESR_ALL_INT | FLEXCAN_ESR_WAK_INT)) { 11088c2ecf20Sopenharmony_ci handled = IRQ_HANDLED; 11098c2ecf20Sopenharmony_ci priv->write(reg_esr & (FLEXCAN_ESR_ALL_INT | FLEXCAN_ESR_WAK_INT), ®s->esr); 11108c2ecf20Sopenharmony_ci } 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci /* state change interrupt or broken error state quirk fix is enabled */ 11138c2ecf20Sopenharmony_ci if ((reg_esr & FLEXCAN_ESR_ERR_STATE) || 11148c2ecf20Sopenharmony_ci (priv->devtype_data->quirks & (FLEXCAN_QUIRK_BROKEN_WERR_STATE | 11158c2ecf20Sopenharmony_ci FLEXCAN_QUIRK_BROKEN_PERR_STATE))) 11168c2ecf20Sopenharmony_ci flexcan_irq_state(dev, reg_esr); 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci /* bus error IRQ - handle if bus error reporting is activated */ 11198c2ecf20Sopenharmony_ci if ((reg_esr & FLEXCAN_ESR_ERR_BUS) && 11208c2ecf20Sopenharmony_ci (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)) 11218c2ecf20Sopenharmony_ci flexcan_irq_bus_err(dev, reg_esr); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci /* availability of error interrupt among state transitions in case 11248c2ecf20Sopenharmony_ci * bus error reporting is de-activated and 11258c2ecf20Sopenharmony_ci * FLEXCAN_QUIRK_BROKEN_PERR_STATE is enabled: 11268c2ecf20Sopenharmony_ci * +--------------------------------------------------------------+ 11278c2ecf20Sopenharmony_ci * | +----------------------------------------------+ [stopped / | 11288c2ecf20Sopenharmony_ci * | | | sleeping] -+ 11298c2ecf20Sopenharmony_ci * +-+-> active <-> warning <-> passive -> bus off -+ 11308c2ecf20Sopenharmony_ci * ___________^^^^^^^^^^^^_______________________________ 11318c2ecf20Sopenharmony_ci * disabled(1) enabled disabled 11328c2ecf20Sopenharmony_ci * 11338c2ecf20Sopenharmony_ci * (1): enabled if FLEXCAN_QUIRK_BROKEN_WERR_STATE is enabled 11348c2ecf20Sopenharmony_ci */ 11358c2ecf20Sopenharmony_ci if ((last_state != priv->can.state) && 11368c2ecf20Sopenharmony_ci (priv->devtype_data->quirks & FLEXCAN_QUIRK_BROKEN_PERR_STATE) && 11378c2ecf20Sopenharmony_ci !(priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)) { 11388c2ecf20Sopenharmony_ci switch (priv->can.state) { 11398c2ecf20Sopenharmony_ci case CAN_STATE_ERROR_ACTIVE: 11408c2ecf20Sopenharmony_ci if (priv->devtype_data->quirks & 11418c2ecf20Sopenharmony_ci FLEXCAN_QUIRK_BROKEN_WERR_STATE) 11428c2ecf20Sopenharmony_ci flexcan_error_irq_enable(priv); 11438c2ecf20Sopenharmony_ci else 11448c2ecf20Sopenharmony_ci flexcan_error_irq_disable(priv); 11458c2ecf20Sopenharmony_ci break; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci case CAN_STATE_ERROR_WARNING: 11488c2ecf20Sopenharmony_ci flexcan_error_irq_enable(priv); 11498c2ecf20Sopenharmony_ci break; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci case CAN_STATE_ERROR_PASSIVE: 11528c2ecf20Sopenharmony_ci case CAN_STATE_BUS_OFF: 11538c2ecf20Sopenharmony_ci flexcan_error_irq_disable(priv); 11548c2ecf20Sopenharmony_ci break; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci default: 11578c2ecf20Sopenharmony_ci break; 11588c2ecf20Sopenharmony_ci } 11598c2ecf20Sopenharmony_ci } 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci return handled; 11628c2ecf20Sopenharmony_ci} 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_cistatic void flexcan_set_bittiming_ctrl(const struct net_device *dev) 11658c2ecf20Sopenharmony_ci{ 11668c2ecf20Sopenharmony_ci const struct flexcan_priv *priv = netdev_priv(dev); 11678c2ecf20Sopenharmony_ci const struct can_bittiming *bt = &priv->can.bittiming; 11688c2ecf20Sopenharmony_ci struct flexcan_regs __iomem *regs = priv->regs; 11698c2ecf20Sopenharmony_ci u32 reg; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci reg = priv->read(®s->ctrl); 11728c2ecf20Sopenharmony_ci reg &= ~(FLEXCAN_CTRL_PRESDIV(0xff) | 11738c2ecf20Sopenharmony_ci FLEXCAN_CTRL_RJW(0x3) | 11748c2ecf20Sopenharmony_ci FLEXCAN_CTRL_PSEG1(0x7) | 11758c2ecf20Sopenharmony_ci FLEXCAN_CTRL_PSEG2(0x7) | 11768c2ecf20Sopenharmony_ci FLEXCAN_CTRL_PROPSEG(0x7)); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci reg |= FLEXCAN_CTRL_PRESDIV(bt->brp - 1) | 11798c2ecf20Sopenharmony_ci FLEXCAN_CTRL_PSEG1(bt->phase_seg1 - 1) | 11808c2ecf20Sopenharmony_ci FLEXCAN_CTRL_PSEG2(bt->phase_seg2 - 1) | 11818c2ecf20Sopenharmony_ci FLEXCAN_CTRL_RJW(bt->sjw - 1) | 11828c2ecf20Sopenharmony_ci FLEXCAN_CTRL_PROPSEG(bt->prop_seg - 1); 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci netdev_dbg(dev, "writing ctrl=0x%08x\n", reg); 11858c2ecf20Sopenharmony_ci priv->write(reg, ®s->ctrl); 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci /* print chip status */ 11888c2ecf20Sopenharmony_ci netdev_dbg(dev, "%s: mcr=0x%08x ctrl=0x%08x\n", __func__, 11898c2ecf20Sopenharmony_ci priv->read(®s->mcr), priv->read(®s->ctrl)); 11908c2ecf20Sopenharmony_ci} 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_cistatic void flexcan_set_bittiming_cbt(const struct net_device *dev) 11938c2ecf20Sopenharmony_ci{ 11948c2ecf20Sopenharmony_ci struct flexcan_priv *priv = netdev_priv(dev); 11958c2ecf20Sopenharmony_ci struct can_bittiming *bt = &priv->can.bittiming; 11968c2ecf20Sopenharmony_ci struct can_bittiming *dbt = &priv->can.data_bittiming; 11978c2ecf20Sopenharmony_ci struct flexcan_regs __iomem *regs = priv->regs; 11988c2ecf20Sopenharmony_ci u32 reg_cbt, reg_fdctrl; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci /* CBT */ 12018c2ecf20Sopenharmony_ci /* CBT[EPSEG1] is 5 bit long and CBT[EPROPSEG] is 6 bit 12028c2ecf20Sopenharmony_ci * long. The can_calc_bittiming() tries to divide the tseg1 12038c2ecf20Sopenharmony_ci * equally between phase_seg1 and prop_seg, which may not fit 12048c2ecf20Sopenharmony_ci * in CBT register. Therefore, if phase_seg1 is more than 12058c2ecf20Sopenharmony_ci * possible value, increase prop_seg and decrease phase_seg1. 12068c2ecf20Sopenharmony_ci */ 12078c2ecf20Sopenharmony_ci if (bt->phase_seg1 > 0x20) { 12088c2ecf20Sopenharmony_ci bt->prop_seg += (bt->phase_seg1 - 0x20); 12098c2ecf20Sopenharmony_ci bt->phase_seg1 = 0x20; 12108c2ecf20Sopenharmony_ci } 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci reg_cbt = FLEXCAN_CBT_BTF | 12138c2ecf20Sopenharmony_ci FIELD_PREP(FLEXCAN_CBT_EPRESDIV_MASK, bt->brp - 1) | 12148c2ecf20Sopenharmony_ci FIELD_PREP(FLEXCAN_CBT_ERJW_MASK, bt->sjw - 1) | 12158c2ecf20Sopenharmony_ci FIELD_PREP(FLEXCAN_CBT_EPROPSEG_MASK, bt->prop_seg - 1) | 12168c2ecf20Sopenharmony_ci FIELD_PREP(FLEXCAN_CBT_EPSEG1_MASK, bt->phase_seg1 - 1) | 12178c2ecf20Sopenharmony_ci FIELD_PREP(FLEXCAN_CBT_EPSEG2_MASK, bt->phase_seg2 - 1); 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci netdev_dbg(dev, "writing cbt=0x%08x\n", reg_cbt); 12208c2ecf20Sopenharmony_ci priv->write(reg_cbt, ®s->cbt); 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci if (priv->can.ctrlmode & CAN_CTRLMODE_FD) { 12238c2ecf20Sopenharmony_ci u32 reg_fdcbt, reg_ctrl2; 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci if (bt->brp != dbt->brp) 12268c2ecf20Sopenharmony_ci netdev_warn(dev, "Data brp=%d and brp=%d don't match, this may result in a phase error. Consider using different bitrate and/or data bitrate.\n", 12278c2ecf20Sopenharmony_ci dbt->brp, bt->brp); 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci /* FDCBT */ 12308c2ecf20Sopenharmony_ci /* FDCBT[FPSEG1] is 3 bit long and FDCBT[FPROPSEG] is 12318c2ecf20Sopenharmony_ci * 5 bit long. The can_calc_bittiming tries to divide 12328c2ecf20Sopenharmony_ci * the tseg1 equally between phase_seg1 and prop_seg, 12338c2ecf20Sopenharmony_ci * which may not fit in FDCBT register. Therefore, if 12348c2ecf20Sopenharmony_ci * phase_seg1 is more than possible value, increase 12358c2ecf20Sopenharmony_ci * prop_seg and decrease phase_seg1 12368c2ecf20Sopenharmony_ci */ 12378c2ecf20Sopenharmony_ci if (dbt->phase_seg1 > 0x8) { 12388c2ecf20Sopenharmony_ci dbt->prop_seg += (dbt->phase_seg1 - 0x8); 12398c2ecf20Sopenharmony_ci dbt->phase_seg1 = 0x8; 12408c2ecf20Sopenharmony_ci } 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci reg_fdcbt = priv->read(®s->fdcbt); 12438c2ecf20Sopenharmony_ci reg_fdcbt &= ~(FIELD_PREP(FLEXCAN_FDCBT_FPRESDIV_MASK, 0x3ff) | 12448c2ecf20Sopenharmony_ci FIELD_PREP(FLEXCAN_FDCBT_FRJW_MASK, 0x7) | 12458c2ecf20Sopenharmony_ci FIELD_PREP(FLEXCAN_FDCBT_FPROPSEG_MASK, 0x1f) | 12468c2ecf20Sopenharmony_ci FIELD_PREP(FLEXCAN_FDCBT_FPSEG1_MASK, 0x7) | 12478c2ecf20Sopenharmony_ci FIELD_PREP(FLEXCAN_FDCBT_FPSEG2_MASK, 0x7)); 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci reg_fdcbt |= FIELD_PREP(FLEXCAN_FDCBT_FPRESDIV_MASK, dbt->brp - 1) | 12508c2ecf20Sopenharmony_ci FIELD_PREP(FLEXCAN_FDCBT_FRJW_MASK, dbt->sjw - 1) | 12518c2ecf20Sopenharmony_ci FIELD_PREP(FLEXCAN_FDCBT_FPROPSEG_MASK, dbt->prop_seg) | 12528c2ecf20Sopenharmony_ci FIELD_PREP(FLEXCAN_FDCBT_FPSEG1_MASK, dbt->phase_seg1 - 1) | 12538c2ecf20Sopenharmony_ci FIELD_PREP(FLEXCAN_FDCBT_FPSEG2_MASK, dbt->phase_seg2 - 1); 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci netdev_dbg(dev, "writing fdcbt=0x%08x\n", reg_fdcbt); 12568c2ecf20Sopenharmony_ci priv->write(reg_fdcbt, ®s->fdcbt); 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci /* CTRL2 */ 12598c2ecf20Sopenharmony_ci reg_ctrl2 = priv->read(®s->ctrl2); 12608c2ecf20Sopenharmony_ci reg_ctrl2 &= ~FLEXCAN_CTRL2_ISOCANFDEN; 12618c2ecf20Sopenharmony_ci if (!(priv->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO)) 12628c2ecf20Sopenharmony_ci reg_ctrl2 |= FLEXCAN_CTRL2_ISOCANFDEN; 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci netdev_dbg(dev, "writing ctrl2=0x%08x\n", reg_ctrl2); 12658c2ecf20Sopenharmony_ci priv->write(reg_ctrl2, ®s->ctrl2); 12668c2ecf20Sopenharmony_ci } 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci /* FDCTRL */ 12698c2ecf20Sopenharmony_ci reg_fdctrl = priv->read(®s->fdctrl); 12708c2ecf20Sopenharmony_ci reg_fdctrl &= ~(FLEXCAN_FDCTRL_FDRATE | 12718c2ecf20Sopenharmony_ci FIELD_PREP(FLEXCAN_FDCTRL_TDCOFF, 0x1f)); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci if (priv->can.ctrlmode & CAN_CTRLMODE_FD) { 12748c2ecf20Sopenharmony_ci reg_fdctrl |= FLEXCAN_FDCTRL_FDRATE; 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) { 12778c2ecf20Sopenharmony_ci /* TDC must be disabled for Loop Back mode */ 12788c2ecf20Sopenharmony_ci reg_fdctrl &= ~FLEXCAN_FDCTRL_TDCEN; 12798c2ecf20Sopenharmony_ci } else { 12808c2ecf20Sopenharmony_ci reg_fdctrl |= FLEXCAN_FDCTRL_TDCEN | 12818c2ecf20Sopenharmony_ci FIELD_PREP(FLEXCAN_FDCTRL_TDCOFF, 12828c2ecf20Sopenharmony_ci ((dbt->phase_seg1 - 1) + 12838c2ecf20Sopenharmony_ci dbt->prop_seg + 2) * 12848c2ecf20Sopenharmony_ci ((dbt->brp - 1 ) + 1)); 12858c2ecf20Sopenharmony_ci } 12868c2ecf20Sopenharmony_ci } 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci netdev_dbg(dev, "writing fdctrl=0x%08x\n", reg_fdctrl); 12898c2ecf20Sopenharmony_ci priv->write(reg_fdctrl, ®s->fdctrl); 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci netdev_dbg(dev, "%s: mcr=0x%08x ctrl=0x%08x ctrl2=0x%08x fdctrl=0x%08x cbt=0x%08x fdcbt=0x%08x\n", 12928c2ecf20Sopenharmony_ci __func__, 12938c2ecf20Sopenharmony_ci priv->read(®s->mcr), priv->read(®s->ctrl), 12948c2ecf20Sopenharmony_ci priv->read(®s->ctrl2), priv->read(®s->fdctrl), 12958c2ecf20Sopenharmony_ci priv->read(®s->cbt), priv->read(®s->fdcbt)); 12968c2ecf20Sopenharmony_ci} 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_cistatic void flexcan_set_bittiming(struct net_device *dev) 12998c2ecf20Sopenharmony_ci{ 13008c2ecf20Sopenharmony_ci const struct flexcan_priv *priv = netdev_priv(dev); 13018c2ecf20Sopenharmony_ci struct flexcan_regs __iomem *regs = priv->regs; 13028c2ecf20Sopenharmony_ci u32 reg; 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci reg = priv->read(®s->ctrl); 13058c2ecf20Sopenharmony_ci reg &= ~(FLEXCAN_CTRL_LPB | FLEXCAN_CTRL_SMP | 13068c2ecf20Sopenharmony_ci FLEXCAN_CTRL_LOM); 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) 13098c2ecf20Sopenharmony_ci reg |= FLEXCAN_CTRL_LPB; 13108c2ecf20Sopenharmony_ci if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) 13118c2ecf20Sopenharmony_ci reg |= FLEXCAN_CTRL_LOM; 13128c2ecf20Sopenharmony_ci if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) 13138c2ecf20Sopenharmony_ci reg |= FLEXCAN_CTRL_SMP; 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci netdev_dbg(dev, "writing ctrl=0x%08x\n", reg); 13168c2ecf20Sopenharmony_ci priv->write(reg, ®s->ctrl); 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) 13198c2ecf20Sopenharmony_ci return flexcan_set_bittiming_cbt(dev); 13208c2ecf20Sopenharmony_ci else 13218c2ecf20Sopenharmony_ci return flexcan_set_bittiming_ctrl(dev); 13228c2ecf20Sopenharmony_ci} 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_cistatic void flexcan_ram_init(struct net_device *dev) 13258c2ecf20Sopenharmony_ci{ 13268c2ecf20Sopenharmony_ci struct flexcan_priv *priv = netdev_priv(dev); 13278c2ecf20Sopenharmony_ci struct flexcan_regs __iomem *regs = priv->regs; 13288c2ecf20Sopenharmony_ci u32 reg_ctrl2; 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci /* 11.8.3.13 Detection and correction of memory errors: 13318c2ecf20Sopenharmony_ci * CTRL2[WRMFRZ] grants write access to all memory positions 13328c2ecf20Sopenharmony_ci * that require initialization, ranging from 0x080 to 0xADF 13338c2ecf20Sopenharmony_ci * and from 0xF28 to 0xFFF when the CAN FD feature is enabled. 13348c2ecf20Sopenharmony_ci * The RXMGMASK, RX14MASK, RX15MASK, and RXFGMASK registers 13358c2ecf20Sopenharmony_ci * need to be initialized as well. MCR[RFEN] must not be set 13368c2ecf20Sopenharmony_ci * during memory initialization. 13378c2ecf20Sopenharmony_ci */ 13388c2ecf20Sopenharmony_ci reg_ctrl2 = priv->read(®s->ctrl2); 13398c2ecf20Sopenharmony_ci reg_ctrl2 |= FLEXCAN_CTRL2_WRMFRZ; 13408c2ecf20Sopenharmony_ci priv->write(reg_ctrl2, ®s->ctrl2); 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci memset_io(®s->mb[0][0], 0, 13438c2ecf20Sopenharmony_ci offsetof(struct flexcan_regs, rx_smb1[3]) - 13448c2ecf20Sopenharmony_ci offsetof(struct flexcan_regs, mb[0][0]) + 0x4); 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci if (priv->can.ctrlmode & CAN_CTRLMODE_FD) 13478c2ecf20Sopenharmony_ci memset_io(®s->tx_smb_fd[0], 0, 13488c2ecf20Sopenharmony_ci offsetof(struct flexcan_regs, rx_smb1_fd[17]) - 13498c2ecf20Sopenharmony_ci offsetof(struct flexcan_regs, tx_smb_fd[0]) + 0x4); 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci reg_ctrl2 &= ~FLEXCAN_CTRL2_WRMFRZ; 13528c2ecf20Sopenharmony_ci priv->write(reg_ctrl2, ®s->ctrl2); 13538c2ecf20Sopenharmony_ci} 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci/* flexcan_chip_start 13568c2ecf20Sopenharmony_ci * 13578c2ecf20Sopenharmony_ci * this functions is entered with clocks enabled 13588c2ecf20Sopenharmony_ci * 13598c2ecf20Sopenharmony_ci */ 13608c2ecf20Sopenharmony_cistatic int flexcan_chip_start(struct net_device *dev) 13618c2ecf20Sopenharmony_ci{ 13628c2ecf20Sopenharmony_ci struct flexcan_priv *priv = netdev_priv(dev); 13638c2ecf20Sopenharmony_ci struct flexcan_regs __iomem *regs = priv->regs; 13648c2ecf20Sopenharmony_ci u32 reg_mcr, reg_ctrl, reg_ctrl2, reg_mecr; 13658c2ecf20Sopenharmony_ci u64 reg_imask; 13668c2ecf20Sopenharmony_ci int err, i; 13678c2ecf20Sopenharmony_ci struct flexcan_mb __iomem *mb; 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci /* enable module */ 13708c2ecf20Sopenharmony_ci err = flexcan_chip_enable(priv); 13718c2ecf20Sopenharmony_ci if (err) 13728c2ecf20Sopenharmony_ci return err; 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci /* soft reset */ 13758c2ecf20Sopenharmony_ci err = flexcan_chip_softreset(priv); 13768c2ecf20Sopenharmony_ci if (err) 13778c2ecf20Sopenharmony_ci goto out_chip_disable; 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SUPPORT_ECC) 13808c2ecf20Sopenharmony_ci flexcan_ram_init(dev); 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci flexcan_set_bittiming(dev); 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci /* set freeze, halt */ 13858c2ecf20Sopenharmony_ci err = flexcan_chip_freeze(priv); 13868c2ecf20Sopenharmony_ci if (err) 13878c2ecf20Sopenharmony_ci goto out_chip_disable; 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci /* MCR 13908c2ecf20Sopenharmony_ci * 13918c2ecf20Sopenharmony_ci * only supervisor access 13928c2ecf20Sopenharmony_ci * enable warning int 13938c2ecf20Sopenharmony_ci * enable individual RX masking 13948c2ecf20Sopenharmony_ci * choose format C 13958c2ecf20Sopenharmony_ci * set max mailbox number 13968c2ecf20Sopenharmony_ci */ 13978c2ecf20Sopenharmony_ci reg_mcr = priv->read(®s->mcr); 13988c2ecf20Sopenharmony_ci reg_mcr &= ~FLEXCAN_MCR_MAXMB(0xff); 13998c2ecf20Sopenharmony_ci reg_mcr |= FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN | FLEXCAN_MCR_IRMQ | 14008c2ecf20Sopenharmony_ci FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_MAXMB(priv->tx_mb_idx); 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci /* MCR 14038c2ecf20Sopenharmony_ci * 14048c2ecf20Sopenharmony_ci * FIFO: 14058c2ecf20Sopenharmony_ci * - disable for timestamp mode 14068c2ecf20Sopenharmony_ci * - enable for FIFO mode 14078c2ecf20Sopenharmony_ci */ 14088c2ecf20Sopenharmony_ci if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) 14098c2ecf20Sopenharmony_ci reg_mcr &= ~FLEXCAN_MCR_FEN; 14108c2ecf20Sopenharmony_ci else 14118c2ecf20Sopenharmony_ci reg_mcr |= FLEXCAN_MCR_FEN; 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci /* MCR 14148c2ecf20Sopenharmony_ci * 14158c2ecf20Sopenharmony_ci * NOTE: In loopback mode, the CAN_MCR[SRXDIS] cannot be 14168c2ecf20Sopenharmony_ci * asserted because this will impede the self reception 14178c2ecf20Sopenharmony_ci * of a transmitted message. This is not documented in 14188c2ecf20Sopenharmony_ci * earlier versions of flexcan block guide. 14198c2ecf20Sopenharmony_ci * 14208c2ecf20Sopenharmony_ci * Self Reception: 14218c2ecf20Sopenharmony_ci * - enable Self Reception for loopback mode 14228c2ecf20Sopenharmony_ci * (by clearing "Self Reception Disable" bit) 14238c2ecf20Sopenharmony_ci * - disable for normal operation 14248c2ecf20Sopenharmony_ci */ 14258c2ecf20Sopenharmony_ci if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) 14268c2ecf20Sopenharmony_ci reg_mcr &= ~FLEXCAN_MCR_SRX_DIS; 14278c2ecf20Sopenharmony_ci else 14288c2ecf20Sopenharmony_ci reg_mcr |= FLEXCAN_MCR_SRX_DIS; 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci /* MCR - CAN-FD */ 14318c2ecf20Sopenharmony_ci if (priv->can.ctrlmode & CAN_CTRLMODE_FD) 14328c2ecf20Sopenharmony_ci reg_mcr |= FLEXCAN_MCR_FDEN; 14338c2ecf20Sopenharmony_ci else 14348c2ecf20Sopenharmony_ci reg_mcr &= ~FLEXCAN_MCR_FDEN; 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci netdev_dbg(dev, "%s: writing mcr=0x%08x", __func__, reg_mcr); 14378c2ecf20Sopenharmony_ci priv->write(reg_mcr, ®s->mcr); 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci /* CTRL 14408c2ecf20Sopenharmony_ci * 14418c2ecf20Sopenharmony_ci * disable timer sync feature 14428c2ecf20Sopenharmony_ci * 14438c2ecf20Sopenharmony_ci * disable auto busoff recovery 14448c2ecf20Sopenharmony_ci * transmit lowest buffer first 14458c2ecf20Sopenharmony_ci * 14468c2ecf20Sopenharmony_ci * enable tx and rx warning interrupt 14478c2ecf20Sopenharmony_ci * enable bus off interrupt 14488c2ecf20Sopenharmony_ci * (== FLEXCAN_CTRL_ERR_STATE) 14498c2ecf20Sopenharmony_ci */ 14508c2ecf20Sopenharmony_ci reg_ctrl = priv->read(®s->ctrl); 14518c2ecf20Sopenharmony_ci reg_ctrl &= ~FLEXCAN_CTRL_TSYN; 14528c2ecf20Sopenharmony_ci reg_ctrl |= FLEXCAN_CTRL_BOFF_REC | FLEXCAN_CTRL_LBUF | 14538c2ecf20Sopenharmony_ci FLEXCAN_CTRL_ERR_STATE; 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci /* enable the "error interrupt" (FLEXCAN_CTRL_ERR_MSK), 14568c2ecf20Sopenharmony_ci * on most Flexcan cores, too. Otherwise we don't get 14578c2ecf20Sopenharmony_ci * any error warning or passive interrupts. 14588c2ecf20Sopenharmony_ci */ 14598c2ecf20Sopenharmony_ci if (priv->devtype_data->quirks & FLEXCAN_QUIRK_BROKEN_WERR_STATE || 14608c2ecf20Sopenharmony_ci priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) 14618c2ecf20Sopenharmony_ci reg_ctrl |= FLEXCAN_CTRL_ERR_MSK; 14628c2ecf20Sopenharmony_ci else 14638c2ecf20Sopenharmony_ci reg_ctrl &= ~FLEXCAN_CTRL_ERR_MSK; 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci /* save for later use */ 14668c2ecf20Sopenharmony_ci priv->reg_ctrl_default = reg_ctrl; 14678c2ecf20Sopenharmony_ci /* leave interrupts disabled for now */ 14688c2ecf20Sopenharmony_ci reg_ctrl &= ~FLEXCAN_CTRL_ERR_ALL; 14698c2ecf20Sopenharmony_ci netdev_dbg(dev, "%s: writing ctrl=0x%08x", __func__, reg_ctrl); 14708c2ecf20Sopenharmony_ci priv->write(reg_ctrl, ®s->ctrl); 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci if ((priv->devtype_data->quirks & FLEXCAN_QUIRK_ENABLE_EACEN_RRS)) { 14738c2ecf20Sopenharmony_ci reg_ctrl2 = priv->read(®s->ctrl2); 14748c2ecf20Sopenharmony_ci reg_ctrl2 |= FLEXCAN_CTRL2_EACEN | FLEXCAN_CTRL2_RRS; 14758c2ecf20Sopenharmony_ci priv->write(reg_ctrl2, ®s->ctrl2); 14768c2ecf20Sopenharmony_ci } 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) { 14798c2ecf20Sopenharmony_ci u32 reg_fdctrl; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci reg_fdctrl = priv->read(®s->fdctrl); 14828c2ecf20Sopenharmony_ci reg_fdctrl &= ~(FIELD_PREP(FLEXCAN_FDCTRL_MBDSR1, 0x3) | 14838c2ecf20Sopenharmony_ci FIELD_PREP(FLEXCAN_FDCTRL_MBDSR0, 0x3)); 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci if (priv->can.ctrlmode & CAN_CTRLMODE_FD) { 14868c2ecf20Sopenharmony_ci reg_fdctrl |= 14878c2ecf20Sopenharmony_ci FIELD_PREP(FLEXCAN_FDCTRL_MBDSR1, 14888c2ecf20Sopenharmony_ci FLEXCAN_FDCTRL_MBDSR_64) | 14898c2ecf20Sopenharmony_ci FIELD_PREP(FLEXCAN_FDCTRL_MBDSR0, 14908c2ecf20Sopenharmony_ci FLEXCAN_FDCTRL_MBDSR_64); 14918c2ecf20Sopenharmony_ci } else { 14928c2ecf20Sopenharmony_ci reg_fdctrl |= 14938c2ecf20Sopenharmony_ci FIELD_PREP(FLEXCAN_FDCTRL_MBDSR1, 14948c2ecf20Sopenharmony_ci FLEXCAN_FDCTRL_MBDSR_8) | 14958c2ecf20Sopenharmony_ci FIELD_PREP(FLEXCAN_FDCTRL_MBDSR0, 14968c2ecf20Sopenharmony_ci FLEXCAN_FDCTRL_MBDSR_8); 14978c2ecf20Sopenharmony_ci } 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci netdev_dbg(dev, "%s: writing fdctrl=0x%08x", 15008c2ecf20Sopenharmony_ci __func__, reg_fdctrl); 15018c2ecf20Sopenharmony_ci priv->write(reg_fdctrl, ®s->fdctrl); 15028c2ecf20Sopenharmony_ci } 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { 15058c2ecf20Sopenharmony_ci for (i = priv->offload.mb_first; i <= priv->offload.mb_last; i++) { 15068c2ecf20Sopenharmony_ci mb = flexcan_get_mb(priv, i); 15078c2ecf20Sopenharmony_ci priv->write(FLEXCAN_MB_CODE_RX_EMPTY, 15088c2ecf20Sopenharmony_ci &mb->can_ctrl); 15098c2ecf20Sopenharmony_ci } 15108c2ecf20Sopenharmony_ci } else { 15118c2ecf20Sopenharmony_ci /* clear and invalidate unused mailboxes first */ 15128c2ecf20Sopenharmony_ci for (i = FLEXCAN_TX_MB_RESERVED_OFF_FIFO; i < priv->mb_count; i++) { 15138c2ecf20Sopenharmony_ci mb = flexcan_get_mb(priv, i); 15148c2ecf20Sopenharmony_ci priv->write(FLEXCAN_MB_CODE_RX_INACTIVE, 15158c2ecf20Sopenharmony_ci &mb->can_ctrl); 15168c2ecf20Sopenharmony_ci } 15178c2ecf20Sopenharmony_ci } 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci /* Errata ERR005829: mark first TX mailbox as INACTIVE */ 15208c2ecf20Sopenharmony_ci priv->write(FLEXCAN_MB_CODE_TX_INACTIVE, 15218c2ecf20Sopenharmony_ci &priv->tx_mb_reserved->can_ctrl); 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci /* mark TX mailbox as INACTIVE */ 15248c2ecf20Sopenharmony_ci priv->write(FLEXCAN_MB_CODE_TX_INACTIVE, 15258c2ecf20Sopenharmony_ci &priv->tx_mb->can_ctrl); 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci /* acceptance mask/acceptance code (accept everything) */ 15288c2ecf20Sopenharmony_ci priv->write(0x0, ®s->rxgmask); 15298c2ecf20Sopenharmony_ci priv->write(0x0, ®s->rx14mask); 15308c2ecf20Sopenharmony_ci priv->write(0x0, ®s->rx15mask); 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_RXFG) 15338c2ecf20Sopenharmony_ci priv->write(0x0, ®s->rxfgmask); 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci /* clear acceptance filters */ 15368c2ecf20Sopenharmony_ci for (i = 0; i < priv->mb_count; i++) 15378c2ecf20Sopenharmony_ci priv->write(0, ®s->rximr[i]); 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci /* On Vybrid, disable non-correctable errors interrupt and 15408c2ecf20Sopenharmony_ci * freeze mode. It still can correct the correctable errors 15418c2ecf20Sopenharmony_ci * when HW supports ECC. 15428c2ecf20Sopenharmony_ci * 15438c2ecf20Sopenharmony_ci * This also works around errata e5295 which generates false 15448c2ecf20Sopenharmony_ci * positive memory errors and put the device in freeze mode. 15458c2ecf20Sopenharmony_ci */ 15468c2ecf20Sopenharmony_ci if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_MECR) { 15478c2ecf20Sopenharmony_ci /* Follow the protocol as described in "Detection 15488c2ecf20Sopenharmony_ci * and Correction of Memory Errors" to write to 15498c2ecf20Sopenharmony_ci * MECR register (step 1 - 5) 15508c2ecf20Sopenharmony_ci * 15518c2ecf20Sopenharmony_ci * 1. By default, CTRL2[ECRWRE] = 0, MECR[ECRWRDIS] = 1 15528c2ecf20Sopenharmony_ci * 2. set CTRL2[ECRWRE] 15538c2ecf20Sopenharmony_ci */ 15548c2ecf20Sopenharmony_ci reg_ctrl2 = priv->read(®s->ctrl2); 15558c2ecf20Sopenharmony_ci reg_ctrl2 |= FLEXCAN_CTRL2_ECRWRE; 15568c2ecf20Sopenharmony_ci priv->write(reg_ctrl2, ®s->ctrl2); 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci /* 3. clear MECR[ECRWRDIS] */ 15598c2ecf20Sopenharmony_ci reg_mecr = priv->read(®s->mecr); 15608c2ecf20Sopenharmony_ci reg_mecr &= ~FLEXCAN_MECR_ECRWRDIS; 15618c2ecf20Sopenharmony_ci priv->write(reg_mecr, ®s->mecr); 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci /* 4. all writes to MECR must keep MECR[ECRWRDIS] cleared */ 15648c2ecf20Sopenharmony_ci reg_mecr &= ~(FLEXCAN_MECR_NCEFAFRZ | FLEXCAN_MECR_HANCEI_MSK | 15658c2ecf20Sopenharmony_ci FLEXCAN_MECR_FANCEI_MSK); 15668c2ecf20Sopenharmony_ci priv->write(reg_mecr, ®s->mecr); 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci /* 5. after configuration done, lock MECR by either 15698c2ecf20Sopenharmony_ci * setting MECR[ECRWRDIS] or clearing CTRL2[ECRWRE] 15708c2ecf20Sopenharmony_ci */ 15718c2ecf20Sopenharmony_ci reg_mecr |= FLEXCAN_MECR_ECRWRDIS; 15728c2ecf20Sopenharmony_ci priv->write(reg_mecr, ®s->mecr); 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci reg_ctrl2 &= ~FLEXCAN_CTRL2_ECRWRE; 15758c2ecf20Sopenharmony_ci priv->write(reg_ctrl2, ®s->ctrl2); 15768c2ecf20Sopenharmony_ci } 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci /* synchronize with the can bus */ 15798c2ecf20Sopenharmony_ci err = flexcan_chip_unfreeze(priv); 15808c2ecf20Sopenharmony_ci if (err) 15818c2ecf20Sopenharmony_ci goto out_chip_disable; 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci priv->can.state = CAN_STATE_ERROR_ACTIVE; 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci /* enable interrupts atomically */ 15868c2ecf20Sopenharmony_ci disable_irq(dev->irq); 15878c2ecf20Sopenharmony_ci priv->write(priv->reg_ctrl_default, ®s->ctrl); 15888c2ecf20Sopenharmony_ci reg_imask = priv->rx_mask | priv->tx_mask; 15898c2ecf20Sopenharmony_ci priv->write(upper_32_bits(reg_imask), ®s->imask2); 15908c2ecf20Sopenharmony_ci priv->write(lower_32_bits(reg_imask), ®s->imask1); 15918c2ecf20Sopenharmony_ci enable_irq(dev->irq); 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci /* print chip status */ 15948c2ecf20Sopenharmony_ci netdev_dbg(dev, "%s: reading mcr=0x%08x ctrl=0x%08x\n", __func__, 15958c2ecf20Sopenharmony_ci priv->read(®s->mcr), priv->read(®s->ctrl)); 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci return 0; 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci out_chip_disable: 16008c2ecf20Sopenharmony_ci flexcan_chip_disable(priv); 16018c2ecf20Sopenharmony_ci return err; 16028c2ecf20Sopenharmony_ci} 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci/* __flexcan_chip_stop 16058c2ecf20Sopenharmony_ci * 16068c2ecf20Sopenharmony_ci * this function is entered with clocks enabled 16078c2ecf20Sopenharmony_ci */ 16088c2ecf20Sopenharmony_cistatic int __flexcan_chip_stop(struct net_device *dev, bool disable_on_error) 16098c2ecf20Sopenharmony_ci{ 16108c2ecf20Sopenharmony_ci struct flexcan_priv *priv = netdev_priv(dev); 16118c2ecf20Sopenharmony_ci struct flexcan_regs __iomem *regs = priv->regs; 16128c2ecf20Sopenharmony_ci int err; 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci /* freeze + disable module */ 16158c2ecf20Sopenharmony_ci err = flexcan_chip_freeze(priv); 16168c2ecf20Sopenharmony_ci if (err && !disable_on_error) 16178c2ecf20Sopenharmony_ci return err; 16188c2ecf20Sopenharmony_ci err = flexcan_chip_disable(priv); 16198c2ecf20Sopenharmony_ci if (err && !disable_on_error) 16208c2ecf20Sopenharmony_ci goto out_chip_unfreeze; 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci /* Disable all interrupts */ 16238c2ecf20Sopenharmony_ci priv->write(0, ®s->imask2); 16248c2ecf20Sopenharmony_ci priv->write(0, ®s->imask1); 16258c2ecf20Sopenharmony_ci priv->write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL, 16268c2ecf20Sopenharmony_ci ®s->ctrl); 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci priv->can.state = CAN_STATE_STOPPED; 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci return 0; 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci out_chip_unfreeze: 16338c2ecf20Sopenharmony_ci flexcan_chip_unfreeze(priv); 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci return err; 16368c2ecf20Sopenharmony_ci} 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_cistatic inline int flexcan_chip_stop_disable_on_error(struct net_device *dev) 16398c2ecf20Sopenharmony_ci{ 16408c2ecf20Sopenharmony_ci return __flexcan_chip_stop(dev, true); 16418c2ecf20Sopenharmony_ci} 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_cistatic inline int flexcan_chip_stop(struct net_device *dev) 16448c2ecf20Sopenharmony_ci{ 16458c2ecf20Sopenharmony_ci return __flexcan_chip_stop(dev, false); 16468c2ecf20Sopenharmony_ci} 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_cistatic int flexcan_open(struct net_device *dev) 16498c2ecf20Sopenharmony_ci{ 16508c2ecf20Sopenharmony_ci struct flexcan_priv *priv = netdev_priv(dev); 16518c2ecf20Sopenharmony_ci int err; 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci if ((priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) && 16548c2ecf20Sopenharmony_ci (priv->can.ctrlmode & CAN_CTRLMODE_FD)) { 16558c2ecf20Sopenharmony_ci netdev_err(dev, "Three Samples mode and CAN-FD mode can't be used together\n"); 16568c2ecf20Sopenharmony_ci return -EINVAL; 16578c2ecf20Sopenharmony_ci } 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci err = pm_runtime_get_sync(priv->dev); 16608c2ecf20Sopenharmony_ci if (err < 0) { 16618c2ecf20Sopenharmony_ci pm_runtime_put_noidle(priv->dev); 16628c2ecf20Sopenharmony_ci return err; 16638c2ecf20Sopenharmony_ci } 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci err = open_candev(dev); 16668c2ecf20Sopenharmony_ci if (err) 16678c2ecf20Sopenharmony_ci goto out_runtime_put; 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci err = flexcan_transceiver_enable(priv); 16708c2ecf20Sopenharmony_ci if (err) 16718c2ecf20Sopenharmony_ci goto out_close; 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci err = request_irq(dev->irq, flexcan_irq, IRQF_SHARED, dev->name, dev); 16748c2ecf20Sopenharmony_ci if (err) 16758c2ecf20Sopenharmony_ci goto out_transceiver_disable; 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci if (priv->can.ctrlmode & CAN_CTRLMODE_FD) 16788c2ecf20Sopenharmony_ci priv->mb_size = sizeof(struct flexcan_mb) + CANFD_MAX_DLEN; 16798c2ecf20Sopenharmony_ci else 16808c2ecf20Sopenharmony_ci priv->mb_size = sizeof(struct flexcan_mb) + CAN_MAX_DLEN; 16818c2ecf20Sopenharmony_ci priv->mb_count = (sizeof(priv->regs->mb[0]) / priv->mb_size) + 16828c2ecf20Sopenharmony_ci (sizeof(priv->regs->mb[1]) / priv->mb_size); 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_ci if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) 16858c2ecf20Sopenharmony_ci priv->tx_mb_reserved = 16868c2ecf20Sopenharmony_ci flexcan_get_mb(priv, FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP); 16878c2ecf20Sopenharmony_ci else 16888c2ecf20Sopenharmony_ci priv->tx_mb_reserved = 16898c2ecf20Sopenharmony_ci flexcan_get_mb(priv, FLEXCAN_TX_MB_RESERVED_OFF_FIFO); 16908c2ecf20Sopenharmony_ci priv->tx_mb_idx = priv->mb_count - 1; 16918c2ecf20Sopenharmony_ci priv->tx_mb = flexcan_get_mb(priv, priv->tx_mb_idx); 16928c2ecf20Sopenharmony_ci priv->tx_mask = FLEXCAN_IFLAG_MB(priv->tx_mb_idx); 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci priv->offload.mailbox_read = flexcan_mailbox_read; 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { 16978c2ecf20Sopenharmony_ci priv->offload.mb_first = FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST; 16988c2ecf20Sopenharmony_ci priv->offload.mb_last = priv->mb_count - 2; 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci priv->rx_mask = GENMASK_ULL(priv->offload.mb_last, 17018c2ecf20Sopenharmony_ci priv->offload.mb_first); 17028c2ecf20Sopenharmony_ci err = can_rx_offload_add_timestamp(dev, &priv->offload); 17038c2ecf20Sopenharmony_ci } else { 17048c2ecf20Sopenharmony_ci priv->rx_mask = FLEXCAN_IFLAG_RX_FIFO_OVERFLOW | 17058c2ecf20Sopenharmony_ci FLEXCAN_IFLAG_RX_FIFO_AVAILABLE; 17068c2ecf20Sopenharmony_ci err = can_rx_offload_add_fifo(dev, &priv->offload, 17078c2ecf20Sopenharmony_ci FLEXCAN_NAPI_WEIGHT); 17088c2ecf20Sopenharmony_ci } 17098c2ecf20Sopenharmony_ci if (err) 17108c2ecf20Sopenharmony_ci goto out_free_irq; 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci /* start chip and queuing */ 17138c2ecf20Sopenharmony_ci err = flexcan_chip_start(dev); 17148c2ecf20Sopenharmony_ci if (err) 17158c2ecf20Sopenharmony_ci goto out_offload_del; 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci can_led_event(dev, CAN_LED_EVENT_OPEN); 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci can_rx_offload_enable(&priv->offload); 17208c2ecf20Sopenharmony_ci netif_start_queue(dev); 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci return 0; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci out_offload_del: 17258c2ecf20Sopenharmony_ci can_rx_offload_del(&priv->offload); 17268c2ecf20Sopenharmony_ci out_free_irq: 17278c2ecf20Sopenharmony_ci free_irq(dev->irq, dev); 17288c2ecf20Sopenharmony_ci out_transceiver_disable: 17298c2ecf20Sopenharmony_ci flexcan_transceiver_disable(priv); 17308c2ecf20Sopenharmony_ci out_close: 17318c2ecf20Sopenharmony_ci close_candev(dev); 17328c2ecf20Sopenharmony_ci out_runtime_put: 17338c2ecf20Sopenharmony_ci pm_runtime_put(priv->dev); 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci return err; 17368c2ecf20Sopenharmony_ci} 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_cistatic int flexcan_close(struct net_device *dev) 17398c2ecf20Sopenharmony_ci{ 17408c2ecf20Sopenharmony_ci struct flexcan_priv *priv = netdev_priv(dev); 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci netif_stop_queue(dev); 17438c2ecf20Sopenharmony_ci can_rx_offload_disable(&priv->offload); 17448c2ecf20Sopenharmony_ci flexcan_chip_stop_disable_on_error(dev); 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci can_rx_offload_del(&priv->offload); 17478c2ecf20Sopenharmony_ci free_irq(dev->irq, dev); 17488c2ecf20Sopenharmony_ci flexcan_transceiver_disable(priv); 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci close_candev(dev); 17518c2ecf20Sopenharmony_ci pm_runtime_put(priv->dev); 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci can_led_event(dev, CAN_LED_EVENT_STOP); 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci return 0; 17568c2ecf20Sopenharmony_ci} 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_cistatic int flexcan_set_mode(struct net_device *dev, enum can_mode mode) 17598c2ecf20Sopenharmony_ci{ 17608c2ecf20Sopenharmony_ci int err; 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci switch (mode) { 17638c2ecf20Sopenharmony_ci case CAN_MODE_START: 17648c2ecf20Sopenharmony_ci err = flexcan_chip_start(dev); 17658c2ecf20Sopenharmony_ci if (err) 17668c2ecf20Sopenharmony_ci return err; 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci netif_wake_queue(dev); 17698c2ecf20Sopenharmony_ci break; 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci default: 17728c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 17738c2ecf20Sopenharmony_ci } 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci return 0; 17768c2ecf20Sopenharmony_ci} 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_cistatic const struct net_device_ops flexcan_netdev_ops = { 17798c2ecf20Sopenharmony_ci .ndo_open = flexcan_open, 17808c2ecf20Sopenharmony_ci .ndo_stop = flexcan_close, 17818c2ecf20Sopenharmony_ci .ndo_start_xmit = flexcan_start_xmit, 17828c2ecf20Sopenharmony_ci .ndo_change_mtu = can_change_mtu, 17838c2ecf20Sopenharmony_ci}; 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_cistatic int register_flexcandev(struct net_device *dev) 17868c2ecf20Sopenharmony_ci{ 17878c2ecf20Sopenharmony_ci struct flexcan_priv *priv = netdev_priv(dev); 17888c2ecf20Sopenharmony_ci struct flexcan_regs __iomem *regs = priv->regs; 17898c2ecf20Sopenharmony_ci u32 reg, err; 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci err = flexcan_clks_enable(priv); 17928c2ecf20Sopenharmony_ci if (err) 17938c2ecf20Sopenharmony_ci return err; 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci /* select "bus clock", chip must be disabled */ 17968c2ecf20Sopenharmony_ci err = flexcan_chip_disable(priv); 17978c2ecf20Sopenharmony_ci if (err) 17988c2ecf20Sopenharmony_ci goto out_clks_disable; 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci reg = priv->read(®s->ctrl); 18018c2ecf20Sopenharmony_ci if (priv->clk_src) 18028c2ecf20Sopenharmony_ci reg |= FLEXCAN_CTRL_CLK_SRC; 18038c2ecf20Sopenharmony_ci else 18048c2ecf20Sopenharmony_ci reg &= ~FLEXCAN_CTRL_CLK_SRC; 18058c2ecf20Sopenharmony_ci priv->write(reg, ®s->ctrl); 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci err = flexcan_chip_enable(priv); 18088c2ecf20Sopenharmony_ci if (err) 18098c2ecf20Sopenharmony_ci goto out_chip_disable; 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci /* set freeze, halt */ 18128c2ecf20Sopenharmony_ci err = flexcan_chip_freeze(priv); 18138c2ecf20Sopenharmony_ci if (err) 18148c2ecf20Sopenharmony_ci goto out_chip_disable; 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci /* activate FIFO, restrict register access */ 18178c2ecf20Sopenharmony_ci reg = priv->read(®s->mcr); 18188c2ecf20Sopenharmony_ci reg |= FLEXCAN_MCR_FEN | FLEXCAN_MCR_SUPV; 18198c2ecf20Sopenharmony_ci priv->write(reg, ®s->mcr); 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci /* Currently we only support newer versions of this core 18228c2ecf20Sopenharmony_ci * featuring a RX hardware FIFO (although this driver doesn't 18238c2ecf20Sopenharmony_ci * make use of it on some cores). Older cores, found on some 18248c2ecf20Sopenharmony_ci * Coldfire derivates are not tested. 18258c2ecf20Sopenharmony_ci */ 18268c2ecf20Sopenharmony_ci reg = priv->read(®s->mcr); 18278c2ecf20Sopenharmony_ci if (!(reg & FLEXCAN_MCR_FEN)) { 18288c2ecf20Sopenharmony_ci netdev_err(dev, "Could not enable RX FIFO, unsupported core\n"); 18298c2ecf20Sopenharmony_ci err = -ENODEV; 18308c2ecf20Sopenharmony_ci goto out_chip_disable; 18318c2ecf20Sopenharmony_ci } 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci err = register_candev(dev); 18348c2ecf20Sopenharmony_ci if (err) 18358c2ecf20Sopenharmony_ci goto out_chip_disable; 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci /* Disable core and let pm_runtime_put() disable the clocks. 18388c2ecf20Sopenharmony_ci * If CONFIG_PM is not enabled, the clocks will stay powered. 18398c2ecf20Sopenharmony_ci */ 18408c2ecf20Sopenharmony_ci flexcan_chip_disable(priv); 18418c2ecf20Sopenharmony_ci pm_runtime_put(priv->dev); 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci return 0; 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci out_chip_disable: 18468c2ecf20Sopenharmony_ci flexcan_chip_disable(priv); 18478c2ecf20Sopenharmony_ci out_clks_disable: 18488c2ecf20Sopenharmony_ci flexcan_clks_disable(priv); 18498c2ecf20Sopenharmony_ci return err; 18508c2ecf20Sopenharmony_ci} 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_cistatic void unregister_flexcandev(struct net_device *dev) 18538c2ecf20Sopenharmony_ci{ 18548c2ecf20Sopenharmony_ci unregister_candev(dev); 18558c2ecf20Sopenharmony_ci} 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_cistatic int flexcan_setup_stop_mode(struct platform_device *pdev) 18588c2ecf20Sopenharmony_ci{ 18598c2ecf20Sopenharmony_ci struct net_device *dev = platform_get_drvdata(pdev); 18608c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 18618c2ecf20Sopenharmony_ci struct device_node *gpr_np; 18628c2ecf20Sopenharmony_ci struct flexcan_priv *priv; 18638c2ecf20Sopenharmony_ci phandle phandle; 18648c2ecf20Sopenharmony_ci u32 out_val[3]; 18658c2ecf20Sopenharmony_ci int ret; 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci if (!np) 18688c2ecf20Sopenharmony_ci return -EINVAL; 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci /* stop mode property format is: 18718c2ecf20Sopenharmony_ci * <&gpr req_gpr req_bit>. 18728c2ecf20Sopenharmony_ci */ 18738c2ecf20Sopenharmony_ci ret = of_property_read_u32_array(np, "fsl,stop-mode", out_val, 18748c2ecf20Sopenharmony_ci ARRAY_SIZE(out_val)); 18758c2ecf20Sopenharmony_ci if (ret) { 18768c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "no stop-mode property\n"); 18778c2ecf20Sopenharmony_ci return ret; 18788c2ecf20Sopenharmony_ci } 18798c2ecf20Sopenharmony_ci phandle = *out_val; 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci gpr_np = of_find_node_by_phandle(phandle); 18828c2ecf20Sopenharmony_ci if (!gpr_np) { 18838c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "could not find gpr node by phandle\n"); 18848c2ecf20Sopenharmony_ci return -ENODEV; 18858c2ecf20Sopenharmony_ci } 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci priv = netdev_priv(dev); 18888c2ecf20Sopenharmony_ci priv->stm.gpr = syscon_node_to_regmap(gpr_np); 18898c2ecf20Sopenharmony_ci if (IS_ERR(priv->stm.gpr)) { 18908c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "could not find gpr regmap\n"); 18918c2ecf20Sopenharmony_ci ret = PTR_ERR(priv->stm.gpr); 18928c2ecf20Sopenharmony_ci goto out_put_node; 18938c2ecf20Sopenharmony_ci } 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci priv->stm.req_gpr = out_val[1]; 18968c2ecf20Sopenharmony_ci priv->stm.req_bit = out_val[2]; 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, 18998c2ecf20Sopenharmony_ci "gpr %s req_gpr=0x02%x req_bit=%u\n", 19008c2ecf20Sopenharmony_ci gpr_np->full_name, priv->stm.req_gpr, priv->stm.req_bit); 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci device_set_wakeup_capable(&pdev->dev, true); 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci if (of_property_read_bool(np, "wakeup-source")) 19058c2ecf20Sopenharmony_ci device_set_wakeup_enable(&pdev->dev, true); 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci return 0; 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ciout_put_node: 19108c2ecf20Sopenharmony_ci of_node_put(gpr_np); 19118c2ecf20Sopenharmony_ci return ret; 19128c2ecf20Sopenharmony_ci} 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_cistatic const struct of_device_id flexcan_of_match[] = { 19158c2ecf20Sopenharmony_ci { .compatible = "fsl,imx8qm-flexcan", .data = &fsl_imx8qm_devtype_data, }, 19168c2ecf20Sopenharmony_ci { .compatible = "fsl,imx8mp-flexcan", .data = &fsl_imx8mp_devtype_data, }, 19178c2ecf20Sopenharmony_ci { .compatible = "fsl,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, }, 19188c2ecf20Sopenharmony_ci { .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, }, 19198c2ecf20Sopenharmony_ci { .compatible = "fsl,imx53-flexcan", .data = &fsl_imx25_devtype_data, }, 19208c2ecf20Sopenharmony_ci { .compatible = "fsl,imx35-flexcan", .data = &fsl_imx25_devtype_data, }, 19218c2ecf20Sopenharmony_ci { .compatible = "fsl,imx25-flexcan", .data = &fsl_imx25_devtype_data, }, 19228c2ecf20Sopenharmony_ci { .compatible = "fsl,p1010-flexcan", .data = &fsl_p1010_devtype_data, }, 19238c2ecf20Sopenharmony_ci { .compatible = "fsl,vf610-flexcan", .data = &fsl_vf610_devtype_data, }, 19248c2ecf20Sopenharmony_ci { .compatible = "fsl,ls1021ar2-flexcan", .data = &fsl_ls1021a_r2_devtype_data, }, 19258c2ecf20Sopenharmony_ci { .compatible = "fsl,lx2160ar1-flexcan", .data = &fsl_lx2160a_r1_devtype_data, }, 19268c2ecf20Sopenharmony_ci { /* sentinel */ }, 19278c2ecf20Sopenharmony_ci}; 19288c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, flexcan_of_match); 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_cistatic const struct platform_device_id flexcan_id_table[] = { 19318c2ecf20Sopenharmony_ci { .name = "flexcan", .driver_data = (kernel_ulong_t)&fsl_p1010_devtype_data, }, 19328c2ecf20Sopenharmony_ci { /* sentinel */ }, 19338c2ecf20Sopenharmony_ci}; 19348c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(platform, flexcan_id_table); 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_cistatic int flexcan_probe(struct platform_device *pdev) 19378c2ecf20Sopenharmony_ci{ 19388c2ecf20Sopenharmony_ci const struct of_device_id *of_id; 19398c2ecf20Sopenharmony_ci const struct flexcan_devtype_data *devtype_data; 19408c2ecf20Sopenharmony_ci struct net_device *dev; 19418c2ecf20Sopenharmony_ci struct flexcan_priv *priv; 19428c2ecf20Sopenharmony_ci struct regulator *reg_xceiver; 19438c2ecf20Sopenharmony_ci struct clk *clk_ipg = NULL, *clk_per = NULL; 19448c2ecf20Sopenharmony_ci struct flexcan_regs __iomem *regs; 19458c2ecf20Sopenharmony_ci int err, irq; 19468c2ecf20Sopenharmony_ci u8 clk_src = 1; 19478c2ecf20Sopenharmony_ci u32 clock_freq = 0; 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci reg_xceiver = devm_regulator_get_optional(&pdev->dev, "xceiver"); 19508c2ecf20Sopenharmony_ci if (PTR_ERR(reg_xceiver) == -EPROBE_DEFER) 19518c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 19528c2ecf20Sopenharmony_ci else if (PTR_ERR(reg_xceiver) == -ENODEV) 19538c2ecf20Sopenharmony_ci reg_xceiver = NULL; 19548c2ecf20Sopenharmony_ci else if (IS_ERR(reg_xceiver)) 19558c2ecf20Sopenharmony_ci return PTR_ERR(reg_xceiver); 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci if (pdev->dev.of_node) { 19588c2ecf20Sopenharmony_ci of_property_read_u32(pdev->dev.of_node, 19598c2ecf20Sopenharmony_ci "clock-frequency", &clock_freq); 19608c2ecf20Sopenharmony_ci of_property_read_u8(pdev->dev.of_node, 19618c2ecf20Sopenharmony_ci "fsl,clk-source", &clk_src); 19628c2ecf20Sopenharmony_ci } 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_ci if (!clock_freq) { 19658c2ecf20Sopenharmony_ci clk_ipg = devm_clk_get(&pdev->dev, "ipg"); 19668c2ecf20Sopenharmony_ci if (IS_ERR(clk_ipg)) { 19678c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "no ipg clock defined\n"); 19688c2ecf20Sopenharmony_ci return PTR_ERR(clk_ipg); 19698c2ecf20Sopenharmony_ci } 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci clk_per = devm_clk_get(&pdev->dev, "per"); 19728c2ecf20Sopenharmony_ci if (IS_ERR(clk_per)) { 19738c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "no per clock defined\n"); 19748c2ecf20Sopenharmony_ci return PTR_ERR(clk_per); 19758c2ecf20Sopenharmony_ci } 19768c2ecf20Sopenharmony_ci clock_freq = clk_get_rate(clk_per); 19778c2ecf20Sopenharmony_ci } 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 19808c2ecf20Sopenharmony_ci if (irq <= 0) 19818c2ecf20Sopenharmony_ci return -ENODEV; 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_ci regs = devm_platform_ioremap_resource(pdev, 0); 19848c2ecf20Sopenharmony_ci if (IS_ERR(regs)) 19858c2ecf20Sopenharmony_ci return PTR_ERR(regs); 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci of_id = of_match_device(flexcan_of_match, &pdev->dev); 19888c2ecf20Sopenharmony_ci if (of_id) { 19898c2ecf20Sopenharmony_ci devtype_data = of_id->data; 19908c2ecf20Sopenharmony_ci } else if (platform_get_device_id(pdev)->driver_data) { 19918c2ecf20Sopenharmony_ci devtype_data = (struct flexcan_devtype_data *) 19928c2ecf20Sopenharmony_ci platform_get_device_id(pdev)->driver_data; 19938c2ecf20Sopenharmony_ci } else { 19948c2ecf20Sopenharmony_ci return -ENODEV; 19958c2ecf20Sopenharmony_ci } 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci if ((devtype_data->quirks & FLEXCAN_QUIRK_SUPPORT_FD) && 19988c2ecf20Sopenharmony_ci !(devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP)) { 19998c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "CAN-FD mode doesn't work with FIFO mode!\n"); 20008c2ecf20Sopenharmony_ci return -EINVAL; 20018c2ecf20Sopenharmony_ci } 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_ci dev = alloc_candev(sizeof(struct flexcan_priv), 1); 20048c2ecf20Sopenharmony_ci if (!dev) 20058c2ecf20Sopenharmony_ci return -ENOMEM; 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, dev); 20088c2ecf20Sopenharmony_ci SET_NETDEV_DEV(dev, &pdev->dev); 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ci dev->netdev_ops = &flexcan_netdev_ops; 20118c2ecf20Sopenharmony_ci dev->irq = irq; 20128c2ecf20Sopenharmony_ci dev->flags |= IFF_ECHO; 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci priv = netdev_priv(dev); 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci if (of_property_read_bool(pdev->dev.of_node, "big-endian") || 20178c2ecf20Sopenharmony_ci devtype_data->quirks & FLEXCAN_QUIRK_DEFAULT_BIG_ENDIAN) { 20188c2ecf20Sopenharmony_ci priv->read = flexcan_read_be; 20198c2ecf20Sopenharmony_ci priv->write = flexcan_write_be; 20208c2ecf20Sopenharmony_ci } else { 20218c2ecf20Sopenharmony_ci priv->read = flexcan_read_le; 20228c2ecf20Sopenharmony_ci priv->write = flexcan_write_le; 20238c2ecf20Sopenharmony_ci } 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci priv->dev = &pdev->dev; 20268c2ecf20Sopenharmony_ci priv->can.clock.freq = clock_freq; 20278c2ecf20Sopenharmony_ci priv->can.do_set_mode = flexcan_set_mode; 20288c2ecf20Sopenharmony_ci priv->can.do_get_berr_counter = flexcan_get_berr_counter; 20298c2ecf20Sopenharmony_ci priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | 20308c2ecf20Sopenharmony_ci CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_3_SAMPLES | 20318c2ecf20Sopenharmony_ci CAN_CTRLMODE_BERR_REPORTING; 20328c2ecf20Sopenharmony_ci priv->regs = regs; 20338c2ecf20Sopenharmony_ci priv->clk_ipg = clk_ipg; 20348c2ecf20Sopenharmony_ci priv->clk_per = clk_per; 20358c2ecf20Sopenharmony_ci priv->clk_src = clk_src; 20368c2ecf20Sopenharmony_ci priv->devtype_data = devtype_data; 20378c2ecf20Sopenharmony_ci priv->reg_xceiver = reg_xceiver; 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_ci if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SUPPORT_FD) { 20408c2ecf20Sopenharmony_ci priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD | 20418c2ecf20Sopenharmony_ci CAN_CTRLMODE_FD_NON_ISO; 20428c2ecf20Sopenharmony_ci priv->can.bittiming_const = &flexcan_fd_bittiming_const; 20438c2ecf20Sopenharmony_ci priv->can.data_bittiming_const = 20448c2ecf20Sopenharmony_ci &flexcan_fd_data_bittiming_const; 20458c2ecf20Sopenharmony_ci } else { 20468c2ecf20Sopenharmony_ci priv->can.bittiming_const = &flexcan_bittiming_const; 20478c2ecf20Sopenharmony_ci } 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci pm_runtime_get_noresume(&pdev->dev); 20508c2ecf20Sopenharmony_ci pm_runtime_set_active(&pdev->dev); 20518c2ecf20Sopenharmony_ci pm_runtime_enable(&pdev->dev); 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci err = register_flexcandev(dev); 20548c2ecf20Sopenharmony_ci if (err) { 20558c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "registering netdev failed\n"); 20568c2ecf20Sopenharmony_ci goto failed_register; 20578c2ecf20Sopenharmony_ci } 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci of_can_transceiver(dev); 20608c2ecf20Sopenharmony_ci devm_can_led_init(dev); 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE) { 20638c2ecf20Sopenharmony_ci err = flexcan_setup_stop_mode(pdev); 20648c2ecf20Sopenharmony_ci if (err) 20658c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "failed to setup stop-mode\n"); 20668c2ecf20Sopenharmony_ci } 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ci return 0; 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci failed_register: 20718c2ecf20Sopenharmony_ci pm_runtime_put_noidle(&pdev->dev); 20728c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 20738c2ecf20Sopenharmony_ci free_candev(dev); 20748c2ecf20Sopenharmony_ci return err; 20758c2ecf20Sopenharmony_ci} 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_cistatic int flexcan_remove(struct platform_device *pdev) 20788c2ecf20Sopenharmony_ci{ 20798c2ecf20Sopenharmony_ci struct net_device *dev = platform_get_drvdata(pdev); 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci device_set_wakeup_enable(&pdev->dev, false); 20828c2ecf20Sopenharmony_ci device_set_wakeup_capable(&pdev->dev, false); 20838c2ecf20Sopenharmony_ci unregister_flexcandev(dev); 20848c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 20858c2ecf20Sopenharmony_ci free_candev(dev); 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci return 0; 20888c2ecf20Sopenharmony_ci} 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_cistatic int __maybe_unused flexcan_suspend(struct device *device) 20918c2ecf20Sopenharmony_ci{ 20928c2ecf20Sopenharmony_ci struct net_device *dev = dev_get_drvdata(device); 20938c2ecf20Sopenharmony_ci struct flexcan_priv *priv = netdev_priv(dev); 20948c2ecf20Sopenharmony_ci int err; 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_ci if (netif_running(dev)) { 20978c2ecf20Sopenharmony_ci /* if wakeup is enabled, enter stop mode 20988c2ecf20Sopenharmony_ci * else enter disabled mode. 20998c2ecf20Sopenharmony_ci */ 21008c2ecf20Sopenharmony_ci if (device_may_wakeup(device)) { 21018c2ecf20Sopenharmony_ci enable_irq_wake(dev->irq); 21028c2ecf20Sopenharmony_ci err = flexcan_enter_stop_mode(priv); 21038c2ecf20Sopenharmony_ci if (err) 21048c2ecf20Sopenharmony_ci return err; 21058c2ecf20Sopenharmony_ci } else { 21068c2ecf20Sopenharmony_ci err = flexcan_chip_stop(dev); 21078c2ecf20Sopenharmony_ci if (err) 21088c2ecf20Sopenharmony_ci return err; 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ci err = pinctrl_pm_select_sleep_state(device); 21118c2ecf20Sopenharmony_ci if (err) 21128c2ecf20Sopenharmony_ci return err; 21138c2ecf20Sopenharmony_ci } 21148c2ecf20Sopenharmony_ci netif_stop_queue(dev); 21158c2ecf20Sopenharmony_ci netif_device_detach(dev); 21168c2ecf20Sopenharmony_ci } 21178c2ecf20Sopenharmony_ci priv->can.state = CAN_STATE_SLEEPING; 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci return 0; 21208c2ecf20Sopenharmony_ci} 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_cistatic int __maybe_unused flexcan_resume(struct device *device) 21238c2ecf20Sopenharmony_ci{ 21248c2ecf20Sopenharmony_ci struct net_device *dev = dev_get_drvdata(device); 21258c2ecf20Sopenharmony_ci struct flexcan_priv *priv = netdev_priv(dev); 21268c2ecf20Sopenharmony_ci int err; 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ci priv->can.state = CAN_STATE_ERROR_ACTIVE; 21298c2ecf20Sopenharmony_ci if (netif_running(dev)) { 21308c2ecf20Sopenharmony_ci netif_device_attach(dev); 21318c2ecf20Sopenharmony_ci netif_start_queue(dev); 21328c2ecf20Sopenharmony_ci if (device_may_wakeup(device)) { 21338c2ecf20Sopenharmony_ci disable_irq_wake(dev->irq); 21348c2ecf20Sopenharmony_ci err = flexcan_exit_stop_mode(priv); 21358c2ecf20Sopenharmony_ci if (err) 21368c2ecf20Sopenharmony_ci return err; 21378c2ecf20Sopenharmony_ci } else { 21388c2ecf20Sopenharmony_ci err = pinctrl_pm_select_default_state(device); 21398c2ecf20Sopenharmony_ci if (err) 21408c2ecf20Sopenharmony_ci return err; 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ci err = flexcan_chip_start(dev); 21438c2ecf20Sopenharmony_ci if (err) 21448c2ecf20Sopenharmony_ci return err; 21458c2ecf20Sopenharmony_ci } 21468c2ecf20Sopenharmony_ci } 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci return 0; 21498c2ecf20Sopenharmony_ci} 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_cistatic int __maybe_unused flexcan_runtime_suspend(struct device *device) 21528c2ecf20Sopenharmony_ci{ 21538c2ecf20Sopenharmony_ci struct net_device *dev = dev_get_drvdata(device); 21548c2ecf20Sopenharmony_ci struct flexcan_priv *priv = netdev_priv(dev); 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci flexcan_clks_disable(priv); 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci return 0; 21598c2ecf20Sopenharmony_ci} 21608c2ecf20Sopenharmony_ci 21618c2ecf20Sopenharmony_cistatic int __maybe_unused flexcan_runtime_resume(struct device *device) 21628c2ecf20Sopenharmony_ci{ 21638c2ecf20Sopenharmony_ci struct net_device *dev = dev_get_drvdata(device); 21648c2ecf20Sopenharmony_ci struct flexcan_priv *priv = netdev_priv(dev); 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_ci return flexcan_clks_enable(priv); 21678c2ecf20Sopenharmony_ci} 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_cistatic int __maybe_unused flexcan_noirq_suspend(struct device *device) 21708c2ecf20Sopenharmony_ci{ 21718c2ecf20Sopenharmony_ci struct net_device *dev = dev_get_drvdata(device); 21728c2ecf20Sopenharmony_ci struct flexcan_priv *priv = netdev_priv(dev); 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci if (netif_running(dev)) { 21758c2ecf20Sopenharmony_ci int err; 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_ci if (device_may_wakeup(device)) 21788c2ecf20Sopenharmony_ci flexcan_enable_wakeup_irq(priv, true); 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_ci err = pm_runtime_force_suspend(device); 21818c2ecf20Sopenharmony_ci if (err) 21828c2ecf20Sopenharmony_ci return err; 21838c2ecf20Sopenharmony_ci } 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci return 0; 21868c2ecf20Sopenharmony_ci} 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_cistatic int __maybe_unused flexcan_noirq_resume(struct device *device) 21898c2ecf20Sopenharmony_ci{ 21908c2ecf20Sopenharmony_ci struct net_device *dev = dev_get_drvdata(device); 21918c2ecf20Sopenharmony_ci struct flexcan_priv *priv = netdev_priv(dev); 21928c2ecf20Sopenharmony_ci 21938c2ecf20Sopenharmony_ci if (netif_running(dev)) { 21948c2ecf20Sopenharmony_ci int err; 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci err = pm_runtime_force_resume(device); 21978c2ecf20Sopenharmony_ci if (err) 21988c2ecf20Sopenharmony_ci return err; 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_ci if (device_may_wakeup(device)) 22018c2ecf20Sopenharmony_ci flexcan_enable_wakeup_irq(priv, false); 22028c2ecf20Sopenharmony_ci } 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci return 0; 22058c2ecf20Sopenharmony_ci} 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_cistatic const struct dev_pm_ops flexcan_pm_ops = { 22088c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(flexcan_suspend, flexcan_resume) 22098c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(flexcan_runtime_suspend, flexcan_runtime_resume, NULL) 22108c2ecf20Sopenharmony_ci SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(flexcan_noirq_suspend, flexcan_noirq_resume) 22118c2ecf20Sopenharmony_ci}; 22128c2ecf20Sopenharmony_ci 22138c2ecf20Sopenharmony_cistatic struct platform_driver flexcan_driver = { 22148c2ecf20Sopenharmony_ci .driver = { 22158c2ecf20Sopenharmony_ci .name = DRV_NAME, 22168c2ecf20Sopenharmony_ci .pm = &flexcan_pm_ops, 22178c2ecf20Sopenharmony_ci .of_match_table = flexcan_of_match, 22188c2ecf20Sopenharmony_ci }, 22198c2ecf20Sopenharmony_ci .probe = flexcan_probe, 22208c2ecf20Sopenharmony_ci .remove = flexcan_remove, 22218c2ecf20Sopenharmony_ci .id_table = flexcan_id_table, 22228c2ecf20Sopenharmony_ci}; 22238c2ecf20Sopenharmony_ci 22248c2ecf20Sopenharmony_cimodule_platform_driver(flexcan_driver); 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ciMODULE_AUTHOR("Sascha Hauer <kernel@pengutronix.de>, " 22278c2ecf20Sopenharmony_ci "Marc Kleine-Budde <kernel@pengutronix.de>"); 22288c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 22298c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("CAN port driver for flexcan based chip"); 2230