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(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
5128c2ecf20Sopenharmony_ci		udelay(10);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	if (!(priv->read(&regs->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(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
5268c2ecf20Sopenharmony_ci		udelay(10);
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	if (priv->read(&regs->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(&regs->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, &regs->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(&regs->mcr);
5558c2ecf20Sopenharmony_ci	reg_mcr |= FLEXCAN_MCR_SLF_WAK;
5568c2ecf20Sopenharmony_ci	priv->write(reg_mcr, &regs->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(&regs->mcr);
5758c2ecf20Sopenharmony_ci	reg_mcr &= ~FLEXCAN_MCR_SLF_WAK;
5768c2ecf20Sopenharmony_ci	priv->write(reg_mcr, &regs->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, &regs->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, &regs->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(&regs->mcr);
6408c2ecf20Sopenharmony_ci	reg &= ~FLEXCAN_MCR_MDIS;
6418c2ecf20Sopenharmony_ci	priv->write(reg, &regs->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(&regs->mcr);
6528c2ecf20Sopenharmony_ci	reg |= FLEXCAN_MCR_MDIS;
6538c2ecf20Sopenharmony_ci	priv->write(reg, &regs->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(&regs->mcr);
6718c2ecf20Sopenharmony_ci	reg |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT;
6728c2ecf20Sopenharmony_ci	priv->write(reg, &regs->mcr);
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	while (timeout-- && !(priv->read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
6758c2ecf20Sopenharmony_ci		udelay(100);
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	if (!(priv->read(&regs->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(&regs->mcr);
6908c2ecf20Sopenharmony_ci	reg &= ~FLEXCAN_MCR_HALT;
6918c2ecf20Sopenharmony_ci	priv->write(reg, &regs->mcr);
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	while (timeout-- && (priv->read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
6948c2ecf20Sopenharmony_ci		udelay(10);
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	if (priv->read(&regs->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, &regs->mcr);
7088c2ecf20Sopenharmony_ci	while (timeout-- && (priv->read(&regs->mcr) & FLEXCAN_MCR_SOFTRST))
7098c2ecf20Sopenharmony_ci		udelay(10);
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	if (priv->read(&regs->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(&regs->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(&regs->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(&regs->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(&regs->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), &regs->iflag1);
10318c2ecf20Sopenharmony_ci	else
10328c2ecf20Sopenharmony_ci		priv->write(FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, &regs->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(&regs->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(&regs->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				    &regs->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, &regs->iflag1);
11018c2ecf20Sopenharmony_ci		netif_wake_queue(dev);
11028c2ecf20Sopenharmony_ci	}
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	reg_esr = priv->read(&regs->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), &regs->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(&regs->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, &regs->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(&regs->mcr), priv->read(&regs->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, &regs->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(&regs->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, &regs->fdcbt);
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci		/* CTRL2 */
12598c2ecf20Sopenharmony_ci		reg_ctrl2 = priv->read(&regs->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, &regs->ctrl2);
12668c2ecf20Sopenharmony_ci	}
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_ci	/* FDCTRL */
12698c2ecf20Sopenharmony_ci	reg_fdctrl = priv->read(&regs->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, &regs->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(&regs->mcr), priv->read(&regs->ctrl),
12948c2ecf20Sopenharmony_ci		   priv->read(&regs->ctrl2), priv->read(&regs->fdctrl),
12958c2ecf20Sopenharmony_ci		   priv->read(&regs->cbt), priv->read(&regs->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(&regs->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, &regs->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(&regs->ctrl2);
13398c2ecf20Sopenharmony_ci	reg_ctrl2 |= FLEXCAN_CTRL2_WRMFRZ;
13408c2ecf20Sopenharmony_ci	priv->write(reg_ctrl2, &regs->ctrl2);
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci	memset_io(&regs->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(&regs->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, &regs->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(&regs->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, &regs->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(&regs->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, &regs->ctrl);
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci	if ((priv->devtype_data->quirks & FLEXCAN_QUIRK_ENABLE_EACEN_RRS)) {
14738c2ecf20Sopenharmony_ci		reg_ctrl2 = priv->read(&regs->ctrl2);
14748c2ecf20Sopenharmony_ci		reg_ctrl2 |= FLEXCAN_CTRL2_EACEN | FLEXCAN_CTRL2_RRS;
14758c2ecf20Sopenharmony_ci		priv->write(reg_ctrl2, &regs->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(&regs->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, &regs->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, &regs->rxgmask);
15298c2ecf20Sopenharmony_ci	priv->write(0x0, &regs->rx14mask);
15308c2ecf20Sopenharmony_ci	priv->write(0x0, &regs->rx15mask);
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_ci	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_DISABLE_RXFG)
15338c2ecf20Sopenharmony_ci		priv->write(0x0, &regs->rxfgmask);
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci	/* clear acceptance filters */
15368c2ecf20Sopenharmony_ci	for (i = 0; i < priv->mb_count; i++)
15378c2ecf20Sopenharmony_ci		priv->write(0, &regs->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(&regs->ctrl2);
15558c2ecf20Sopenharmony_ci		reg_ctrl2 |= FLEXCAN_CTRL2_ECRWRE;
15568c2ecf20Sopenharmony_ci		priv->write(reg_ctrl2, &regs->ctrl2);
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci		/* 3. clear MECR[ECRWRDIS] */
15598c2ecf20Sopenharmony_ci		reg_mecr = priv->read(&regs->mecr);
15608c2ecf20Sopenharmony_ci		reg_mecr &= ~FLEXCAN_MECR_ECRWRDIS;
15618c2ecf20Sopenharmony_ci		priv->write(reg_mecr, &regs->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, &regs->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, &regs->mecr);
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci		reg_ctrl2 &= ~FLEXCAN_CTRL2_ECRWRE;
15758c2ecf20Sopenharmony_ci		priv->write(reg_ctrl2, &regs->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, &regs->ctrl);
15888c2ecf20Sopenharmony_ci	reg_imask = priv->rx_mask | priv->tx_mask;
15898c2ecf20Sopenharmony_ci	priv->write(upper_32_bits(reg_imask), &regs->imask2);
15908c2ecf20Sopenharmony_ci	priv->write(lower_32_bits(reg_imask), &regs->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(&regs->mcr), priv->read(&regs->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, &regs->imask2);
16248c2ecf20Sopenharmony_ci	priv->write(0, &regs->imask1);
16258c2ecf20Sopenharmony_ci	priv->write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL,
16268c2ecf20Sopenharmony_ci		    &regs->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(&regs->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, &regs->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(&regs->mcr);
18188c2ecf20Sopenharmony_ci	reg |=  FLEXCAN_MCR_FEN | FLEXCAN_MCR_SUPV;
18198c2ecf20Sopenharmony_ci	priv->write(reg, &regs->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(&regs->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