162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Driver for Renesas R-Car MIPI CSI-2 Receiver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2018 Renesas Electronics Corp.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/delay.h>
962306a36Sopenharmony_ci#include <linux/interrupt.h>
1062306a36Sopenharmony_ci#include <linux/io.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/of.h>
1362306a36Sopenharmony_ci#include <linux/of_graph.h>
1462306a36Sopenharmony_ci#include <linux/platform_device.h>
1562306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1662306a36Sopenharmony_ci#include <linux/reset.h>
1762306a36Sopenharmony_ci#include <linux/sys_soc.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <media/mipi-csi2.h>
2062306a36Sopenharmony_ci#include <media/v4l2-ctrls.h>
2162306a36Sopenharmony_ci#include <media/v4l2-device.h>
2262306a36Sopenharmony_ci#include <media/v4l2-fwnode.h>
2362306a36Sopenharmony_ci#include <media/v4l2-mc.h>
2462306a36Sopenharmony_ci#include <media/v4l2-subdev.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistruct rcar_csi2;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/* Register offsets and bits */
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/* Control Timing Select */
3162306a36Sopenharmony_ci#define TREF_REG			0x00
3262306a36Sopenharmony_ci#define TREF_TREF			BIT(0)
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* Software Reset */
3562306a36Sopenharmony_ci#define SRST_REG			0x04
3662306a36Sopenharmony_ci#define SRST_SRST			BIT(0)
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci/* PHY Operation Control */
3962306a36Sopenharmony_ci#define PHYCNT_REG			0x08
4062306a36Sopenharmony_ci#define PHYCNT_SHUTDOWNZ		BIT(17)
4162306a36Sopenharmony_ci#define PHYCNT_RSTZ			BIT(16)
4262306a36Sopenharmony_ci#define PHYCNT_ENABLECLK		BIT(4)
4362306a36Sopenharmony_ci#define PHYCNT_ENABLE_3			BIT(3)
4462306a36Sopenharmony_ci#define PHYCNT_ENABLE_2			BIT(2)
4562306a36Sopenharmony_ci#define PHYCNT_ENABLE_1			BIT(1)
4662306a36Sopenharmony_ci#define PHYCNT_ENABLE_0			BIT(0)
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/* Checksum Control */
4962306a36Sopenharmony_ci#define CHKSUM_REG			0x0c
5062306a36Sopenharmony_ci#define CHKSUM_ECC_EN			BIT(1)
5162306a36Sopenharmony_ci#define CHKSUM_CRC_EN			BIT(0)
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/*
5462306a36Sopenharmony_ci * Channel Data Type Select
5562306a36Sopenharmony_ci * VCDT[0-15]:  Channel 0 VCDT[16-31]:  Channel 1
5662306a36Sopenharmony_ci * VCDT2[0-15]: Channel 2 VCDT2[16-31]: Channel 3
5762306a36Sopenharmony_ci */
5862306a36Sopenharmony_ci#define VCDT_REG			0x10
5962306a36Sopenharmony_ci#define VCDT2_REG			0x14
6062306a36Sopenharmony_ci#define VCDT_VCDTN_EN			BIT(15)
6162306a36Sopenharmony_ci#define VCDT_SEL_VC(n)			(((n) & 0x3) << 8)
6262306a36Sopenharmony_ci#define VCDT_SEL_DTN_ON			BIT(6)
6362306a36Sopenharmony_ci#define VCDT_SEL_DT(n)			(((n) & 0x3f) << 0)
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci/* Frame Data Type Select */
6662306a36Sopenharmony_ci#define FRDT_REG			0x18
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/* Field Detection Control */
6962306a36Sopenharmony_ci#define FLD_REG				0x1c
7062306a36Sopenharmony_ci#define FLD_FLD_NUM(n)			(((n) & 0xff) << 16)
7162306a36Sopenharmony_ci#define FLD_DET_SEL(n)			(((n) & 0x3) << 4)
7262306a36Sopenharmony_ci#define FLD_FLD_EN4			BIT(3)
7362306a36Sopenharmony_ci#define FLD_FLD_EN3			BIT(2)
7462306a36Sopenharmony_ci#define FLD_FLD_EN2			BIT(1)
7562306a36Sopenharmony_ci#define FLD_FLD_EN			BIT(0)
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/* Automatic Standby Control */
7862306a36Sopenharmony_ci#define ASTBY_REG			0x20
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci/* Long Data Type Setting 0 */
8162306a36Sopenharmony_ci#define LNGDT0_REG			0x28
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci/* Long Data Type Setting 1 */
8462306a36Sopenharmony_ci#define LNGDT1_REG			0x2c
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci/* Interrupt Enable */
8762306a36Sopenharmony_ci#define INTEN_REG			0x30
8862306a36Sopenharmony_ci#define INTEN_INT_AFIFO_OF		BIT(27)
8962306a36Sopenharmony_ci#define INTEN_INT_ERRSOTHS		BIT(4)
9062306a36Sopenharmony_ci#define INTEN_INT_ERRSOTSYNCHS		BIT(3)
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/* Interrupt Source Mask */
9362306a36Sopenharmony_ci#define INTCLOSE_REG			0x34
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci/* Interrupt Status Monitor */
9662306a36Sopenharmony_ci#define INTSTATE_REG			0x38
9762306a36Sopenharmony_ci#define INTSTATE_INT_ULPS_START		BIT(7)
9862306a36Sopenharmony_ci#define INTSTATE_INT_ULPS_END		BIT(6)
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci/* Interrupt Error Status Monitor */
10162306a36Sopenharmony_ci#define INTERRSTATE_REG			0x3c
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/* Short Packet Data */
10462306a36Sopenharmony_ci#define SHPDAT_REG			0x40
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci/* Short Packet Count */
10762306a36Sopenharmony_ci#define SHPCNT_REG			0x44
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci/* LINK Operation Control */
11062306a36Sopenharmony_ci#define LINKCNT_REG			0x48
11162306a36Sopenharmony_ci#define LINKCNT_MONITOR_EN		BIT(31)
11262306a36Sopenharmony_ci#define LINKCNT_REG_MONI_PACT_EN	BIT(25)
11362306a36Sopenharmony_ci#define LINKCNT_ICLK_NONSTOP		BIT(24)
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci/* Lane Swap */
11662306a36Sopenharmony_ci#define LSWAP_REG			0x4c
11762306a36Sopenharmony_ci#define LSWAP_L3SEL(n)			(((n) & 0x3) << 6)
11862306a36Sopenharmony_ci#define LSWAP_L2SEL(n)			(((n) & 0x3) << 4)
11962306a36Sopenharmony_ci#define LSWAP_L1SEL(n)			(((n) & 0x3) << 2)
12062306a36Sopenharmony_ci#define LSWAP_L0SEL(n)			(((n) & 0x3) << 0)
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci/* PHY Test Interface Write Register */
12362306a36Sopenharmony_ci#define PHTW_REG			0x50
12462306a36Sopenharmony_ci#define PHTW_DWEN			BIT(24)
12562306a36Sopenharmony_ci#define PHTW_TESTDIN_DATA(n)		(((n & 0xff)) << 16)
12662306a36Sopenharmony_ci#define PHTW_CWEN			BIT(8)
12762306a36Sopenharmony_ci#define PHTW_TESTDIN_CODE(n)		((n & 0xff))
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci#define PHYFRX_REG			0x64
13062306a36Sopenharmony_ci#define PHYFRX_FORCERX_MODE_3		BIT(3)
13162306a36Sopenharmony_ci#define PHYFRX_FORCERX_MODE_2		BIT(2)
13262306a36Sopenharmony_ci#define PHYFRX_FORCERX_MODE_1		BIT(1)
13362306a36Sopenharmony_ci#define PHYFRX_FORCERX_MODE_0		BIT(0)
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci/* V4H BASE registers */
13662306a36Sopenharmony_ci#define V4H_N_LANES_REG					0x0004
13762306a36Sopenharmony_ci#define V4H_CSI2_RESETN_REG				0x0008
13862306a36Sopenharmony_ci#define V4H_PHY_MODE_REG				0x001c
13962306a36Sopenharmony_ci#define V4H_PHY_SHUTDOWNZ_REG				0x0040
14062306a36Sopenharmony_ci#define V4H_DPHY_RSTZ_REG				0x0044
14162306a36Sopenharmony_ci#define V4H_FLDC_REG					0x0804
14262306a36Sopenharmony_ci#define V4H_FLDD_REG					0x0808
14362306a36Sopenharmony_ci#define V4H_IDIC_REG					0x0810
14462306a36Sopenharmony_ci#define V4H_PHY_EN_REG					0x2000
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci#define V4H_ST_PHYST_REG				0x2814
14762306a36Sopenharmony_ci#define V4H_ST_PHYST_ST_PHY_READY			BIT(31)
14862306a36Sopenharmony_ci#define V4H_ST_PHYST_ST_STOPSTATE_3			BIT(3)
14962306a36Sopenharmony_ci#define V4H_ST_PHYST_ST_STOPSTATE_2			BIT(2)
15062306a36Sopenharmony_ci#define V4H_ST_PHYST_ST_STOPSTATE_1			BIT(1)
15162306a36Sopenharmony_ci#define V4H_ST_PHYST_ST_STOPSTATE_0			BIT(0)
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci/* V4H PPI registers */
15462306a36Sopenharmony_ci#define V4H_PPI_STARTUP_RW_COMMON_DPHY_REG(n)		(0x21800 + ((n) * 2)) /* n = 0 - 9 */
15562306a36Sopenharmony_ci#define V4H_PPI_STARTUP_RW_COMMON_STARTUP_1_1_REG	0x21822
15662306a36Sopenharmony_ci#define V4H_PPI_CALIBCTRL_RW_COMMON_BG_0_REG		0x2184c
15762306a36Sopenharmony_ci#define V4H_PPI_RW_LPDCOCAL_TIMEBASE_REG		0x21c02
15862306a36Sopenharmony_ci#define V4H_PPI_RW_LPDCOCAL_NREF_REG			0x21c04
15962306a36Sopenharmony_ci#define V4H_PPI_RW_LPDCOCAL_NREF_RANGE_REG		0x21c06
16062306a36Sopenharmony_ci#define V4H_PPI_RW_LPDCOCAL_TWAIT_CONFIG_REG		0x21c0a
16162306a36Sopenharmony_ci#define V4H_PPI_RW_LPDCOCAL_VT_CONFIG_REG		0x21c0c
16262306a36Sopenharmony_ci#define V4H_PPI_RW_LPDCOCAL_COARSE_CFG_REG		0x21c10
16362306a36Sopenharmony_ci#define V4H_PPI_RW_COMMON_CFG_REG			0x21c6c
16462306a36Sopenharmony_ci#define V4H_PPI_RW_TERMCAL_CFG_0_REG			0x21c80
16562306a36Sopenharmony_ci#define V4H_PPI_RW_OFFSETCAL_CFG_0_REG			0x21ca0
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci/* V4H CORE registers */
16862306a36Sopenharmony_ci#define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(n)	(0x22040 + ((n) * 2)) /* n = 0 - 15 */
16962306a36Sopenharmony_ci#define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_REG(n)	(0x22440 + ((n) * 2)) /* n = 0 - 15 */
17062306a36Sopenharmony_ci#define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_REG(n)	(0x22840 + ((n) * 2)) /* n = 0 - 15 */
17162306a36Sopenharmony_ci#define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_REG(n)	(0x22c40 + ((n) * 2)) /* n = 0 - 15 */
17262306a36Sopenharmony_ci#define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_REG(n)	(0x23040 + ((n) * 2)) /* n = 0 - 15 */
17362306a36Sopenharmony_ci#define V4H_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_REG(n)	(0x23840 + ((n) * 2)) /* n = 0 - 11 */
17462306a36Sopenharmony_ci#define V4H_CORE_DIG_RW_COMMON_REG(n)			(0x23880 + ((n) * 2)) /* n = 0 - 15 */
17562306a36Sopenharmony_ci#define V4H_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_REG(n)	(0x239e0 + ((n) * 2)) /* n = 0 - 3 */
17662306a36Sopenharmony_ci#define V4H_CORE_DIG_CLANE_1_RW_CFG_0_REG		0x2a400
17762306a36Sopenharmony_ci#define V4H_CORE_DIG_CLANE_1_RW_HS_TX_6_REG		0x2a60c
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci/* V4H C-PHY */
18062306a36Sopenharmony_ci#define V4H_CORE_DIG_RW_TRIO0_REG(n)			(0x22100 + ((n) * 2)) /* n = 0 - 3 */
18162306a36Sopenharmony_ci#define V4H_CORE_DIG_RW_TRIO1_REG(n)			(0x22500 + ((n) * 2)) /* n = 0 - 3 */
18262306a36Sopenharmony_ci#define V4H_CORE_DIG_RW_TRIO2_REG(n)			(0x22900 + ((n) * 2)) /* n = 0 - 3 */
18362306a36Sopenharmony_ci#define V4H_CORE_DIG_CLANE_0_RW_LP_0_REG		0x2a080
18462306a36Sopenharmony_ci#define V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(n)		(0x2a100 + ((n) * 2)) /* n = 0 - 6 */
18562306a36Sopenharmony_ci#define V4H_CORE_DIG_CLANE_1_RW_LP_0_REG		0x2a480
18662306a36Sopenharmony_ci#define V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(n)		(0x2a500 + ((n) * 2)) /* n = 0 - 6 */
18762306a36Sopenharmony_ci#define V4H_CORE_DIG_CLANE_2_RW_LP_0_REG		0x2a880
18862306a36Sopenharmony_ci#define V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(n)		(0x2a900 + ((n) * 2)) /* n = 0 - 6 */
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistruct rcsi2_cphy_setting {
19162306a36Sopenharmony_ci	u16 msps;
19262306a36Sopenharmony_ci	u16 rx2;
19362306a36Sopenharmony_ci	u16 trio0;
19462306a36Sopenharmony_ci	u16 trio1;
19562306a36Sopenharmony_ci	u16 trio2;
19662306a36Sopenharmony_ci	u16 lane27;
19762306a36Sopenharmony_ci	u16 lane29;
19862306a36Sopenharmony_ci};
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic const struct rcsi2_cphy_setting cphy_setting_table_r8a779g0[] = {
20162306a36Sopenharmony_ci	{ .msps =   80, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x0134, .trio2 = 0x6a, .lane27 = 0x0000, .lane29 = 0x0a24 },
20262306a36Sopenharmony_ci	{ .msps =  100, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x00f5, .trio2 = 0x55, .lane27 = 0x0000, .lane29 = 0x0a24 },
20362306a36Sopenharmony_ci	{ .msps =  200, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x0077, .trio2 = 0x2b, .lane27 = 0x0000, .lane29 = 0x0a44 },
20462306a36Sopenharmony_ci	{ .msps =  300, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x004d, .trio2 = 0x1d, .lane27 = 0x0000, .lane29 = 0x0a44 },
20562306a36Sopenharmony_ci	{ .msps =  400, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x0038, .trio2 = 0x16, .lane27 = 0x0000, .lane29 = 0x0a64 },
20662306a36Sopenharmony_ci	{ .msps =  500, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x002b, .trio2 = 0x12, .lane27 = 0x0000, .lane29 = 0x0a64 },
20762306a36Sopenharmony_ci	{ .msps =  600, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x0023, .trio2 = 0x0f, .lane27 = 0x0000, .lane29 = 0x0a64 },
20862306a36Sopenharmony_ci	{ .msps =  700, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x001d, .trio2 = 0x0d, .lane27 = 0x0000, .lane29 = 0x0a84 },
20962306a36Sopenharmony_ci	{ .msps =  800, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x0018, .trio2 = 0x0c, .lane27 = 0x0000, .lane29 = 0x0a84 },
21062306a36Sopenharmony_ci	{ .msps =  900, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x0015, .trio2 = 0x0b, .lane27 = 0x0000, .lane29 = 0x0a84 },
21162306a36Sopenharmony_ci	{ .msps = 1000, .rx2 = 0x3e, .trio0 = 0x024a, .trio1 = 0x0012, .trio2 = 0x0a, .lane27 = 0x0400, .lane29 = 0x0a84 },
21262306a36Sopenharmony_ci	{ .msps = 1100, .rx2 = 0x44, .trio0 = 0x024a, .trio1 = 0x000f, .trio2 = 0x09, .lane27 = 0x0800, .lane29 = 0x0a84 },
21362306a36Sopenharmony_ci	{ .msps = 1200, .rx2 = 0x4a, .trio0 = 0x024a, .trio1 = 0x000e, .trio2 = 0x08, .lane27 = 0x0c00, .lane29 = 0x0a84 },
21462306a36Sopenharmony_ci	{ .msps = 1300, .rx2 = 0x51, .trio0 = 0x024a, .trio1 = 0x000c, .trio2 = 0x08, .lane27 = 0x0c00, .lane29 = 0x0aa4 },
21562306a36Sopenharmony_ci	{ .msps = 1400, .rx2 = 0x57, .trio0 = 0x024a, .trio1 = 0x000b, .trio2 = 0x07, .lane27 = 0x1000, .lane29 = 0x0aa4 },
21662306a36Sopenharmony_ci	{ .msps = 1500, .rx2 = 0x5d, .trio0 = 0x044a, .trio1 = 0x0009, .trio2 = 0x07, .lane27 = 0x1000, .lane29 = 0x0aa4 },
21762306a36Sopenharmony_ci	{ .msps = 1600, .rx2 = 0x63, .trio0 = 0x044a, .trio1 = 0x0008, .trio2 = 0x07, .lane27 = 0x1400, .lane29 = 0x0aa4 },
21862306a36Sopenharmony_ci	{ .msps = 1700, .rx2 = 0x6a, .trio0 = 0x044a, .trio1 = 0x0007, .trio2 = 0x06, .lane27 = 0x1400, .lane29 = 0x0aa4 },
21962306a36Sopenharmony_ci	{ .msps = 1800, .rx2 = 0x70, .trio0 = 0x044a, .trio1 = 0x0007, .trio2 = 0x06, .lane27 = 0x1400, .lane29 = 0x0aa4 },
22062306a36Sopenharmony_ci	{ .msps = 1900, .rx2 = 0x76, .trio0 = 0x044a, .trio1 = 0x0006, .trio2 = 0x06, .lane27 = 0x1400, .lane29 = 0x0aa4 },
22162306a36Sopenharmony_ci	{ .msps = 2000, .rx2 = 0x7c, .trio0 = 0x044a, .trio1 = 0x0005, .trio2 = 0x06, .lane27 = 0x1800, .lane29 = 0x0aa4 },
22262306a36Sopenharmony_ci	{ .msps = 2100, .rx2 = 0x83, .trio0 = 0x044a, .trio1 = 0x0005, .trio2 = 0x05, .lane27 = 0x1800, .lane29 = 0x0aa4 },
22362306a36Sopenharmony_ci	{ .msps = 2200, .rx2 = 0x89, .trio0 = 0x064a, .trio1 = 0x0004, .trio2 = 0x05, .lane27 = 0x1800, .lane29 = 0x0aa4 },
22462306a36Sopenharmony_ci	{ .msps = 2300, .rx2 = 0x8f, .trio0 = 0x064a, .trio1 = 0x0003, .trio2 = 0x05, .lane27 = 0x1800, .lane29 = 0x0aa4 },
22562306a36Sopenharmony_ci	{ .msps = 2400, .rx2 = 0x95, .trio0 = 0x064a, .trio1 = 0x0003, .trio2 = 0x05, .lane27 = 0x1800, .lane29 = 0x0aa4 },
22662306a36Sopenharmony_ci	{ .msps = 2500, .rx2 = 0x9c, .trio0 = 0x064a, .trio1 = 0x0003, .trio2 = 0x05, .lane27 = 0x1c00, .lane29 = 0x0aa4 },
22762306a36Sopenharmony_ci	{ .msps = 2600, .rx2 = 0xa2, .trio0 = 0x064a, .trio1 = 0x0002, .trio2 = 0x05, .lane27 = 0x1c00, .lane29 = 0x0ad4 },
22862306a36Sopenharmony_ci	{ .msps = 2700, .rx2 = 0xa8, .trio0 = 0x064a, .trio1 = 0x0002, .trio2 = 0x05, .lane27 = 0x1c00, .lane29 = 0x0ad4 },
22962306a36Sopenharmony_ci	{ .msps = 2800, .rx2 = 0xae, .trio0 = 0x064a, .trio1 = 0x0002, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 },
23062306a36Sopenharmony_ci	{ .msps = 2900, .rx2 = 0xb5, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 },
23162306a36Sopenharmony_ci	{ .msps = 3000, .rx2 = 0xbb, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 },
23262306a36Sopenharmony_ci	{ .msps = 3100, .rx2 = 0xc1, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 },
23362306a36Sopenharmony_ci	{ .msps = 3200, .rx2 = 0xc7, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 },
23462306a36Sopenharmony_ci	{ .msps = 3300, .rx2 = 0xce, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 },
23562306a36Sopenharmony_ci	{ .msps = 3400, .rx2 = 0xd4, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 },
23662306a36Sopenharmony_ci	{ .msps = 3500, .rx2 = 0xda, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 },
23762306a36Sopenharmony_ci	{ /* sentinel */ },
23862306a36Sopenharmony_ci};
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistruct phtw_value {
24162306a36Sopenharmony_ci	u16 data;
24262306a36Sopenharmony_ci	u16 code;
24362306a36Sopenharmony_ci};
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cistruct rcsi2_mbps_reg {
24662306a36Sopenharmony_ci	u16 mbps;
24762306a36Sopenharmony_ci	u16 reg;
24862306a36Sopenharmony_ci};
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_cistatic const struct rcsi2_mbps_reg phtw_mbps_v3u[] = {
25162306a36Sopenharmony_ci	{ .mbps = 1500, .reg = 0xcc },
25262306a36Sopenharmony_ci	{ .mbps = 1550, .reg = 0x1d },
25362306a36Sopenharmony_ci	{ .mbps = 1600, .reg = 0x27 },
25462306a36Sopenharmony_ci	{ .mbps = 1650, .reg = 0x30 },
25562306a36Sopenharmony_ci	{ .mbps = 1700, .reg = 0x39 },
25662306a36Sopenharmony_ci	{ .mbps = 1750, .reg = 0x42 },
25762306a36Sopenharmony_ci	{ .mbps = 1800, .reg = 0x4b },
25862306a36Sopenharmony_ci	{ .mbps = 1850, .reg = 0x55 },
25962306a36Sopenharmony_ci	{ .mbps = 1900, .reg = 0x5e },
26062306a36Sopenharmony_ci	{ .mbps = 1950, .reg = 0x67 },
26162306a36Sopenharmony_ci	{ .mbps = 2000, .reg = 0x71 },
26262306a36Sopenharmony_ci	{ .mbps = 2050, .reg = 0x79 },
26362306a36Sopenharmony_ci	{ .mbps = 2100, .reg = 0x83 },
26462306a36Sopenharmony_ci	{ .mbps = 2150, .reg = 0x8c },
26562306a36Sopenharmony_ci	{ .mbps = 2200, .reg = 0x95 },
26662306a36Sopenharmony_ci	{ .mbps = 2250, .reg = 0x9e },
26762306a36Sopenharmony_ci	{ .mbps = 2300, .reg = 0xa7 },
26862306a36Sopenharmony_ci	{ .mbps = 2350, .reg = 0xb0 },
26962306a36Sopenharmony_ci	{ .mbps = 2400, .reg = 0xba },
27062306a36Sopenharmony_ci	{ .mbps = 2450, .reg = 0xc3 },
27162306a36Sopenharmony_ci	{ .mbps = 2500, .reg = 0xcc },
27262306a36Sopenharmony_ci	{ /* sentinel */ },
27362306a36Sopenharmony_ci};
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_cistatic const struct rcsi2_mbps_reg phtw_mbps_h3_v3h_m3n[] = {
27662306a36Sopenharmony_ci	{ .mbps =   80, .reg = 0x86 },
27762306a36Sopenharmony_ci	{ .mbps =   90, .reg = 0x86 },
27862306a36Sopenharmony_ci	{ .mbps =  100, .reg = 0x87 },
27962306a36Sopenharmony_ci	{ .mbps =  110, .reg = 0x87 },
28062306a36Sopenharmony_ci	{ .mbps =  120, .reg = 0x88 },
28162306a36Sopenharmony_ci	{ .mbps =  130, .reg = 0x88 },
28262306a36Sopenharmony_ci	{ .mbps =  140, .reg = 0x89 },
28362306a36Sopenharmony_ci	{ .mbps =  150, .reg = 0x89 },
28462306a36Sopenharmony_ci	{ .mbps =  160, .reg = 0x8a },
28562306a36Sopenharmony_ci	{ .mbps =  170, .reg = 0x8a },
28662306a36Sopenharmony_ci	{ .mbps =  180, .reg = 0x8b },
28762306a36Sopenharmony_ci	{ .mbps =  190, .reg = 0x8b },
28862306a36Sopenharmony_ci	{ .mbps =  205, .reg = 0x8c },
28962306a36Sopenharmony_ci	{ .mbps =  220, .reg = 0x8d },
29062306a36Sopenharmony_ci	{ .mbps =  235, .reg = 0x8e },
29162306a36Sopenharmony_ci	{ .mbps =  250, .reg = 0x8e },
29262306a36Sopenharmony_ci	{ /* sentinel */ },
29362306a36Sopenharmony_ci};
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic const struct rcsi2_mbps_reg phtw_mbps_v3m_e3[] = {
29662306a36Sopenharmony_ci	{ .mbps =   80, .reg = 0x00 },
29762306a36Sopenharmony_ci	{ .mbps =   90, .reg = 0x20 },
29862306a36Sopenharmony_ci	{ .mbps =  100, .reg = 0x40 },
29962306a36Sopenharmony_ci	{ .mbps =  110, .reg = 0x02 },
30062306a36Sopenharmony_ci	{ .mbps =  130, .reg = 0x22 },
30162306a36Sopenharmony_ci	{ .mbps =  140, .reg = 0x42 },
30262306a36Sopenharmony_ci	{ .mbps =  150, .reg = 0x04 },
30362306a36Sopenharmony_ci	{ .mbps =  170, .reg = 0x24 },
30462306a36Sopenharmony_ci	{ .mbps =  180, .reg = 0x44 },
30562306a36Sopenharmony_ci	{ .mbps =  200, .reg = 0x06 },
30662306a36Sopenharmony_ci	{ .mbps =  220, .reg = 0x26 },
30762306a36Sopenharmony_ci	{ .mbps =  240, .reg = 0x46 },
30862306a36Sopenharmony_ci	{ .mbps =  250, .reg = 0x08 },
30962306a36Sopenharmony_ci	{ .mbps =  270, .reg = 0x28 },
31062306a36Sopenharmony_ci	{ .mbps =  300, .reg = 0x0a },
31162306a36Sopenharmony_ci	{ .mbps =  330, .reg = 0x2a },
31262306a36Sopenharmony_ci	{ .mbps =  360, .reg = 0x4a },
31362306a36Sopenharmony_ci	{ .mbps =  400, .reg = 0x0c },
31462306a36Sopenharmony_ci	{ .mbps =  450, .reg = 0x2c },
31562306a36Sopenharmony_ci	{ .mbps =  500, .reg = 0x0e },
31662306a36Sopenharmony_ci	{ .mbps =  550, .reg = 0x2e },
31762306a36Sopenharmony_ci	{ .mbps =  600, .reg = 0x10 },
31862306a36Sopenharmony_ci	{ .mbps =  650, .reg = 0x30 },
31962306a36Sopenharmony_ci	{ .mbps =  700, .reg = 0x12 },
32062306a36Sopenharmony_ci	{ .mbps =  750, .reg = 0x32 },
32162306a36Sopenharmony_ci	{ .mbps =  800, .reg = 0x52 },
32262306a36Sopenharmony_ci	{ .mbps =  850, .reg = 0x72 },
32362306a36Sopenharmony_ci	{ .mbps =  900, .reg = 0x14 },
32462306a36Sopenharmony_ci	{ .mbps =  950, .reg = 0x34 },
32562306a36Sopenharmony_ci	{ .mbps = 1000, .reg = 0x54 },
32662306a36Sopenharmony_ci	{ .mbps = 1050, .reg = 0x74 },
32762306a36Sopenharmony_ci	{ .mbps = 1125, .reg = 0x16 },
32862306a36Sopenharmony_ci	{ /* sentinel */ },
32962306a36Sopenharmony_ci};
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci/* PHY Test Interface Clear */
33262306a36Sopenharmony_ci#define PHTC_REG			0x58
33362306a36Sopenharmony_ci#define PHTC_TESTCLR			BIT(0)
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci/* PHY Frequency Control */
33662306a36Sopenharmony_ci#define PHYPLL_REG			0x68
33762306a36Sopenharmony_ci#define PHYPLL_HSFREQRANGE(n)		((n) << 16)
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cistatic const struct rcsi2_mbps_reg hsfreqrange_v3u[] = {
34062306a36Sopenharmony_ci	{ .mbps =   80, .reg = 0x00 },
34162306a36Sopenharmony_ci	{ .mbps =   90, .reg = 0x10 },
34262306a36Sopenharmony_ci	{ .mbps =  100, .reg = 0x20 },
34362306a36Sopenharmony_ci	{ .mbps =  110, .reg = 0x30 },
34462306a36Sopenharmony_ci	{ .mbps =  120, .reg = 0x01 },
34562306a36Sopenharmony_ci	{ .mbps =  130, .reg = 0x11 },
34662306a36Sopenharmony_ci	{ .mbps =  140, .reg = 0x21 },
34762306a36Sopenharmony_ci	{ .mbps =  150, .reg = 0x31 },
34862306a36Sopenharmony_ci	{ .mbps =  160, .reg = 0x02 },
34962306a36Sopenharmony_ci	{ .mbps =  170, .reg = 0x12 },
35062306a36Sopenharmony_ci	{ .mbps =  180, .reg = 0x22 },
35162306a36Sopenharmony_ci	{ .mbps =  190, .reg = 0x32 },
35262306a36Sopenharmony_ci	{ .mbps =  205, .reg = 0x03 },
35362306a36Sopenharmony_ci	{ .mbps =  220, .reg = 0x13 },
35462306a36Sopenharmony_ci	{ .mbps =  235, .reg = 0x23 },
35562306a36Sopenharmony_ci	{ .mbps =  250, .reg = 0x33 },
35662306a36Sopenharmony_ci	{ .mbps =  275, .reg = 0x04 },
35762306a36Sopenharmony_ci	{ .mbps =  300, .reg = 0x14 },
35862306a36Sopenharmony_ci	{ .mbps =  325, .reg = 0x25 },
35962306a36Sopenharmony_ci	{ .mbps =  350, .reg = 0x35 },
36062306a36Sopenharmony_ci	{ .mbps =  400, .reg = 0x05 },
36162306a36Sopenharmony_ci	{ .mbps =  450, .reg = 0x16 },
36262306a36Sopenharmony_ci	{ .mbps =  500, .reg = 0x26 },
36362306a36Sopenharmony_ci	{ .mbps =  550, .reg = 0x37 },
36462306a36Sopenharmony_ci	{ .mbps =  600, .reg = 0x07 },
36562306a36Sopenharmony_ci	{ .mbps =  650, .reg = 0x18 },
36662306a36Sopenharmony_ci	{ .mbps =  700, .reg = 0x28 },
36762306a36Sopenharmony_ci	{ .mbps =  750, .reg = 0x39 },
36862306a36Sopenharmony_ci	{ .mbps =  800, .reg = 0x09 },
36962306a36Sopenharmony_ci	{ .mbps =  850, .reg = 0x19 },
37062306a36Sopenharmony_ci	{ .mbps =  900, .reg = 0x29 },
37162306a36Sopenharmony_ci	{ .mbps =  950, .reg = 0x3a },
37262306a36Sopenharmony_ci	{ .mbps = 1000, .reg = 0x0a },
37362306a36Sopenharmony_ci	{ .mbps = 1050, .reg = 0x1a },
37462306a36Sopenharmony_ci	{ .mbps = 1100, .reg = 0x2a },
37562306a36Sopenharmony_ci	{ .mbps = 1150, .reg = 0x3b },
37662306a36Sopenharmony_ci	{ .mbps = 1200, .reg = 0x0b },
37762306a36Sopenharmony_ci	{ .mbps = 1250, .reg = 0x1b },
37862306a36Sopenharmony_ci	{ .mbps = 1300, .reg = 0x2b },
37962306a36Sopenharmony_ci	{ .mbps = 1350, .reg = 0x3c },
38062306a36Sopenharmony_ci	{ .mbps = 1400, .reg = 0x0c },
38162306a36Sopenharmony_ci	{ .mbps = 1450, .reg = 0x1c },
38262306a36Sopenharmony_ci	{ .mbps = 1500, .reg = 0x2c },
38362306a36Sopenharmony_ci	{ .mbps = 1550, .reg = 0x3d },
38462306a36Sopenharmony_ci	{ .mbps = 1600, .reg = 0x0d },
38562306a36Sopenharmony_ci	{ .mbps = 1650, .reg = 0x1d },
38662306a36Sopenharmony_ci	{ .mbps = 1700, .reg = 0x2e },
38762306a36Sopenharmony_ci	{ .mbps = 1750, .reg = 0x3e },
38862306a36Sopenharmony_ci	{ .mbps = 1800, .reg = 0x0e },
38962306a36Sopenharmony_ci	{ .mbps = 1850, .reg = 0x1e },
39062306a36Sopenharmony_ci	{ .mbps = 1900, .reg = 0x2f },
39162306a36Sopenharmony_ci	{ .mbps = 1950, .reg = 0x3f },
39262306a36Sopenharmony_ci	{ .mbps = 2000, .reg = 0x0f },
39362306a36Sopenharmony_ci	{ .mbps = 2050, .reg = 0x40 },
39462306a36Sopenharmony_ci	{ .mbps = 2100, .reg = 0x41 },
39562306a36Sopenharmony_ci	{ .mbps = 2150, .reg = 0x42 },
39662306a36Sopenharmony_ci	{ .mbps = 2200, .reg = 0x43 },
39762306a36Sopenharmony_ci	{ .mbps = 2300, .reg = 0x45 },
39862306a36Sopenharmony_ci	{ .mbps = 2350, .reg = 0x46 },
39962306a36Sopenharmony_ci	{ .mbps = 2400, .reg = 0x47 },
40062306a36Sopenharmony_ci	{ .mbps = 2450, .reg = 0x48 },
40162306a36Sopenharmony_ci	{ .mbps = 2500, .reg = 0x49 },
40262306a36Sopenharmony_ci	{ /* sentinel */ },
40362306a36Sopenharmony_ci};
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cistatic const struct rcsi2_mbps_reg hsfreqrange_h3_v3h_m3n[] = {
40662306a36Sopenharmony_ci	{ .mbps =   80, .reg = 0x00 },
40762306a36Sopenharmony_ci	{ .mbps =   90, .reg = 0x10 },
40862306a36Sopenharmony_ci	{ .mbps =  100, .reg = 0x20 },
40962306a36Sopenharmony_ci	{ .mbps =  110, .reg = 0x30 },
41062306a36Sopenharmony_ci	{ .mbps =  120, .reg = 0x01 },
41162306a36Sopenharmony_ci	{ .mbps =  130, .reg = 0x11 },
41262306a36Sopenharmony_ci	{ .mbps =  140, .reg = 0x21 },
41362306a36Sopenharmony_ci	{ .mbps =  150, .reg = 0x31 },
41462306a36Sopenharmony_ci	{ .mbps =  160, .reg = 0x02 },
41562306a36Sopenharmony_ci	{ .mbps =  170, .reg = 0x12 },
41662306a36Sopenharmony_ci	{ .mbps =  180, .reg = 0x22 },
41762306a36Sopenharmony_ci	{ .mbps =  190, .reg = 0x32 },
41862306a36Sopenharmony_ci	{ .mbps =  205, .reg = 0x03 },
41962306a36Sopenharmony_ci	{ .mbps =  220, .reg = 0x13 },
42062306a36Sopenharmony_ci	{ .mbps =  235, .reg = 0x23 },
42162306a36Sopenharmony_ci	{ .mbps =  250, .reg = 0x33 },
42262306a36Sopenharmony_ci	{ .mbps =  275, .reg = 0x04 },
42362306a36Sopenharmony_ci	{ .mbps =  300, .reg = 0x14 },
42462306a36Sopenharmony_ci	{ .mbps =  325, .reg = 0x25 },
42562306a36Sopenharmony_ci	{ .mbps =  350, .reg = 0x35 },
42662306a36Sopenharmony_ci	{ .mbps =  400, .reg = 0x05 },
42762306a36Sopenharmony_ci	{ .mbps =  450, .reg = 0x16 },
42862306a36Sopenharmony_ci	{ .mbps =  500, .reg = 0x26 },
42962306a36Sopenharmony_ci	{ .mbps =  550, .reg = 0x37 },
43062306a36Sopenharmony_ci	{ .mbps =  600, .reg = 0x07 },
43162306a36Sopenharmony_ci	{ .mbps =  650, .reg = 0x18 },
43262306a36Sopenharmony_ci	{ .mbps =  700, .reg = 0x28 },
43362306a36Sopenharmony_ci	{ .mbps =  750, .reg = 0x39 },
43462306a36Sopenharmony_ci	{ .mbps =  800, .reg = 0x09 },
43562306a36Sopenharmony_ci	{ .mbps =  850, .reg = 0x19 },
43662306a36Sopenharmony_ci	{ .mbps =  900, .reg = 0x29 },
43762306a36Sopenharmony_ci	{ .mbps =  950, .reg = 0x3a },
43862306a36Sopenharmony_ci	{ .mbps = 1000, .reg = 0x0a },
43962306a36Sopenharmony_ci	{ .mbps = 1050, .reg = 0x1a },
44062306a36Sopenharmony_ci	{ .mbps = 1100, .reg = 0x2a },
44162306a36Sopenharmony_ci	{ .mbps = 1150, .reg = 0x3b },
44262306a36Sopenharmony_ci	{ .mbps = 1200, .reg = 0x0b },
44362306a36Sopenharmony_ci	{ .mbps = 1250, .reg = 0x1b },
44462306a36Sopenharmony_ci	{ .mbps = 1300, .reg = 0x2b },
44562306a36Sopenharmony_ci	{ .mbps = 1350, .reg = 0x3c },
44662306a36Sopenharmony_ci	{ .mbps = 1400, .reg = 0x0c },
44762306a36Sopenharmony_ci	{ .mbps = 1450, .reg = 0x1c },
44862306a36Sopenharmony_ci	{ .mbps = 1500, .reg = 0x2c },
44962306a36Sopenharmony_ci	{ /* sentinel */ },
45062306a36Sopenharmony_ci};
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_cistatic const struct rcsi2_mbps_reg hsfreqrange_m3w[] = {
45362306a36Sopenharmony_ci	{ .mbps =   80,	.reg = 0x00 },
45462306a36Sopenharmony_ci	{ .mbps =   90,	.reg = 0x10 },
45562306a36Sopenharmony_ci	{ .mbps =  100,	.reg = 0x20 },
45662306a36Sopenharmony_ci	{ .mbps =  110,	.reg = 0x30 },
45762306a36Sopenharmony_ci	{ .mbps =  120,	.reg = 0x01 },
45862306a36Sopenharmony_ci	{ .mbps =  130,	.reg = 0x11 },
45962306a36Sopenharmony_ci	{ .mbps =  140,	.reg = 0x21 },
46062306a36Sopenharmony_ci	{ .mbps =  150,	.reg = 0x31 },
46162306a36Sopenharmony_ci	{ .mbps =  160,	.reg = 0x02 },
46262306a36Sopenharmony_ci	{ .mbps =  170,	.reg = 0x12 },
46362306a36Sopenharmony_ci	{ .mbps =  180,	.reg = 0x22 },
46462306a36Sopenharmony_ci	{ .mbps =  190,	.reg = 0x32 },
46562306a36Sopenharmony_ci	{ .mbps =  205,	.reg = 0x03 },
46662306a36Sopenharmony_ci	{ .mbps =  220,	.reg = 0x13 },
46762306a36Sopenharmony_ci	{ .mbps =  235,	.reg = 0x23 },
46862306a36Sopenharmony_ci	{ .mbps =  250,	.reg = 0x33 },
46962306a36Sopenharmony_ci	{ .mbps =  275,	.reg = 0x04 },
47062306a36Sopenharmony_ci	{ .mbps =  300,	.reg = 0x14 },
47162306a36Sopenharmony_ci	{ .mbps =  325,	.reg = 0x05 },
47262306a36Sopenharmony_ci	{ .mbps =  350,	.reg = 0x15 },
47362306a36Sopenharmony_ci	{ .mbps =  400,	.reg = 0x25 },
47462306a36Sopenharmony_ci	{ .mbps =  450,	.reg = 0x06 },
47562306a36Sopenharmony_ci	{ .mbps =  500,	.reg = 0x16 },
47662306a36Sopenharmony_ci	{ .mbps =  550,	.reg = 0x07 },
47762306a36Sopenharmony_ci	{ .mbps =  600,	.reg = 0x17 },
47862306a36Sopenharmony_ci	{ .mbps =  650,	.reg = 0x08 },
47962306a36Sopenharmony_ci	{ .mbps =  700,	.reg = 0x18 },
48062306a36Sopenharmony_ci	{ .mbps =  750,	.reg = 0x09 },
48162306a36Sopenharmony_ci	{ .mbps =  800,	.reg = 0x19 },
48262306a36Sopenharmony_ci	{ .mbps =  850,	.reg = 0x29 },
48362306a36Sopenharmony_ci	{ .mbps =  900,	.reg = 0x39 },
48462306a36Sopenharmony_ci	{ .mbps =  950,	.reg = 0x0a },
48562306a36Sopenharmony_ci	{ .mbps = 1000,	.reg = 0x1a },
48662306a36Sopenharmony_ci	{ .mbps = 1050,	.reg = 0x2a },
48762306a36Sopenharmony_ci	{ .mbps = 1100,	.reg = 0x3a },
48862306a36Sopenharmony_ci	{ .mbps = 1150,	.reg = 0x0b },
48962306a36Sopenharmony_ci	{ .mbps = 1200,	.reg = 0x1b },
49062306a36Sopenharmony_ci	{ .mbps = 1250,	.reg = 0x2b },
49162306a36Sopenharmony_ci	{ .mbps = 1300,	.reg = 0x3b },
49262306a36Sopenharmony_ci	{ .mbps = 1350,	.reg = 0x0c },
49362306a36Sopenharmony_ci	{ .mbps = 1400,	.reg = 0x1c },
49462306a36Sopenharmony_ci	{ .mbps = 1450,	.reg = 0x2c },
49562306a36Sopenharmony_ci	{ .mbps = 1500,	.reg = 0x3c },
49662306a36Sopenharmony_ci	{ /* sentinel */ },
49762306a36Sopenharmony_ci};
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci/* PHY ESC Error Monitor */
50062306a36Sopenharmony_ci#define PHEERM_REG			0x74
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci/* PHY Clock Lane Monitor */
50362306a36Sopenharmony_ci#define PHCLM_REG			0x78
50462306a36Sopenharmony_ci#define PHCLM_STOPSTATECKL		BIT(0)
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci/* PHY Data Lane Monitor */
50762306a36Sopenharmony_ci#define PHDLM_REG			0x7c
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci/* CSI0CLK Frequency Configuration Preset Register */
51062306a36Sopenharmony_ci#define CSI0CLKFCPR_REG			0x260
51162306a36Sopenharmony_ci#define CSI0CLKFREQRANGE(n)		((n & 0x3f) << 16)
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_cistruct rcar_csi2_format {
51462306a36Sopenharmony_ci	u32 code;
51562306a36Sopenharmony_ci	unsigned int datatype;
51662306a36Sopenharmony_ci	unsigned int bpp;
51762306a36Sopenharmony_ci};
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_cistatic const struct rcar_csi2_format rcar_csi2_formats[] = {
52062306a36Sopenharmony_ci	{
52162306a36Sopenharmony_ci		.code = MEDIA_BUS_FMT_RGB888_1X24,
52262306a36Sopenharmony_ci		.datatype = MIPI_CSI2_DT_RGB888,
52362306a36Sopenharmony_ci		.bpp = 24,
52462306a36Sopenharmony_ci	}, {
52562306a36Sopenharmony_ci		.code = MEDIA_BUS_FMT_UYVY8_1X16,
52662306a36Sopenharmony_ci		.datatype = MIPI_CSI2_DT_YUV422_8B,
52762306a36Sopenharmony_ci		.bpp = 16,
52862306a36Sopenharmony_ci	}, {
52962306a36Sopenharmony_ci		.code = MEDIA_BUS_FMT_YUYV8_1X16,
53062306a36Sopenharmony_ci		.datatype = MIPI_CSI2_DT_YUV422_8B,
53162306a36Sopenharmony_ci		.bpp = 16,
53262306a36Sopenharmony_ci	}, {
53362306a36Sopenharmony_ci		.code = MEDIA_BUS_FMT_UYVY8_2X8,
53462306a36Sopenharmony_ci		.datatype = MIPI_CSI2_DT_YUV422_8B,
53562306a36Sopenharmony_ci		.bpp = 16,
53662306a36Sopenharmony_ci	}, {
53762306a36Sopenharmony_ci		.code = MEDIA_BUS_FMT_YUYV10_2X10,
53862306a36Sopenharmony_ci		.datatype = MIPI_CSI2_DT_YUV422_8B,
53962306a36Sopenharmony_ci		.bpp = 20,
54062306a36Sopenharmony_ci	}, {
54162306a36Sopenharmony_ci		.code = MEDIA_BUS_FMT_Y10_1X10,
54262306a36Sopenharmony_ci		.datatype = MIPI_CSI2_DT_RAW10,
54362306a36Sopenharmony_ci		.bpp = 10,
54462306a36Sopenharmony_ci	}, {
54562306a36Sopenharmony_ci		.code = MEDIA_BUS_FMT_SBGGR8_1X8,
54662306a36Sopenharmony_ci		.datatype = MIPI_CSI2_DT_RAW8,
54762306a36Sopenharmony_ci		.bpp = 8,
54862306a36Sopenharmony_ci	}, {
54962306a36Sopenharmony_ci		.code = MEDIA_BUS_FMT_SGBRG8_1X8,
55062306a36Sopenharmony_ci		.datatype = MIPI_CSI2_DT_RAW8,
55162306a36Sopenharmony_ci		.bpp = 8,
55262306a36Sopenharmony_ci	}, {
55362306a36Sopenharmony_ci		.code = MEDIA_BUS_FMT_SGRBG8_1X8,
55462306a36Sopenharmony_ci		.datatype = MIPI_CSI2_DT_RAW8,
55562306a36Sopenharmony_ci		.bpp = 8,
55662306a36Sopenharmony_ci	}, {
55762306a36Sopenharmony_ci		.code = MEDIA_BUS_FMT_SRGGB8_1X8,
55862306a36Sopenharmony_ci		.datatype = MIPI_CSI2_DT_RAW8,
55962306a36Sopenharmony_ci		.bpp = 8,
56062306a36Sopenharmony_ci	}, {
56162306a36Sopenharmony_ci		.code = MEDIA_BUS_FMT_Y8_1X8,
56262306a36Sopenharmony_ci		.datatype = MIPI_CSI2_DT_RAW8,
56362306a36Sopenharmony_ci		.bpp = 8,
56462306a36Sopenharmony_ci	},
56562306a36Sopenharmony_ci};
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_cistatic const struct rcar_csi2_format *rcsi2_code_to_fmt(unsigned int code)
56862306a36Sopenharmony_ci{
56962306a36Sopenharmony_ci	unsigned int i;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(rcar_csi2_formats); i++)
57262306a36Sopenharmony_ci		if (rcar_csi2_formats[i].code == code)
57362306a36Sopenharmony_ci			return &rcar_csi2_formats[i];
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	return NULL;
57662306a36Sopenharmony_ci}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_cienum rcar_csi2_pads {
57962306a36Sopenharmony_ci	RCAR_CSI2_SINK,
58062306a36Sopenharmony_ci	RCAR_CSI2_SOURCE_VC0,
58162306a36Sopenharmony_ci	RCAR_CSI2_SOURCE_VC1,
58262306a36Sopenharmony_ci	RCAR_CSI2_SOURCE_VC2,
58362306a36Sopenharmony_ci	RCAR_CSI2_SOURCE_VC3,
58462306a36Sopenharmony_ci	NR_OF_RCAR_CSI2_PAD,
58562306a36Sopenharmony_ci};
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_cistruct rcar_csi2_info {
58862306a36Sopenharmony_ci	int (*init_phtw)(struct rcar_csi2 *priv, unsigned int mbps);
58962306a36Sopenharmony_ci	int (*phy_post_init)(struct rcar_csi2 *priv);
59062306a36Sopenharmony_ci	int (*start_receiver)(struct rcar_csi2 *priv);
59162306a36Sopenharmony_ci	void (*enter_standby)(struct rcar_csi2 *priv);
59262306a36Sopenharmony_ci	const struct rcsi2_mbps_reg *hsfreqrange;
59362306a36Sopenharmony_ci	unsigned int csi0clkfreqrange;
59462306a36Sopenharmony_ci	unsigned int num_channels;
59562306a36Sopenharmony_ci	bool clear_ulps;
59662306a36Sopenharmony_ci	bool use_isp;
59762306a36Sopenharmony_ci	bool support_dphy;
59862306a36Sopenharmony_ci	bool support_cphy;
59962306a36Sopenharmony_ci};
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_cistruct rcar_csi2 {
60262306a36Sopenharmony_ci	struct device *dev;
60362306a36Sopenharmony_ci	void __iomem *base;
60462306a36Sopenharmony_ci	const struct rcar_csi2_info *info;
60562306a36Sopenharmony_ci	struct reset_control *rstc;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	struct v4l2_subdev subdev;
60862306a36Sopenharmony_ci	struct media_pad pads[NR_OF_RCAR_CSI2_PAD];
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	struct v4l2_async_notifier notifier;
61162306a36Sopenharmony_ci	struct v4l2_subdev *remote;
61262306a36Sopenharmony_ci	unsigned int remote_pad;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	int channel_vc[4];
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	struct mutex lock; /* Protects mf and stream_count. */
61762306a36Sopenharmony_ci	struct v4l2_mbus_framefmt mf;
61862306a36Sopenharmony_ci	int stream_count;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	bool cphy;
62162306a36Sopenharmony_ci	unsigned short lanes;
62262306a36Sopenharmony_ci	unsigned char lane_swap[4];
62362306a36Sopenharmony_ci};
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_cistatic inline struct rcar_csi2 *sd_to_csi2(struct v4l2_subdev *sd)
62662306a36Sopenharmony_ci{
62762306a36Sopenharmony_ci	return container_of(sd, struct rcar_csi2, subdev);
62862306a36Sopenharmony_ci}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_cistatic inline struct rcar_csi2 *notifier_to_csi2(struct v4l2_async_notifier *n)
63162306a36Sopenharmony_ci{
63262306a36Sopenharmony_ci	return container_of(n, struct rcar_csi2, notifier);
63362306a36Sopenharmony_ci}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_cistatic u32 rcsi2_read(struct rcar_csi2 *priv, unsigned int reg)
63662306a36Sopenharmony_ci{
63762306a36Sopenharmony_ci	return ioread32(priv->base + reg);
63862306a36Sopenharmony_ci}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_cistatic void rcsi2_write(struct rcar_csi2 *priv, unsigned int reg, u32 data)
64162306a36Sopenharmony_ci{
64262306a36Sopenharmony_ci	iowrite32(data, priv->base + reg);
64362306a36Sopenharmony_ci}
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_cistatic void rcsi2_write16(struct rcar_csi2 *priv, unsigned int reg, u16 data)
64662306a36Sopenharmony_ci{
64762306a36Sopenharmony_ci	iowrite16(data, priv->base + reg);
64862306a36Sopenharmony_ci}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_cistatic void rcsi2_enter_standby_gen3(struct rcar_csi2 *priv)
65162306a36Sopenharmony_ci{
65262306a36Sopenharmony_ci	rcsi2_write(priv, PHYCNT_REG, 0);
65362306a36Sopenharmony_ci	rcsi2_write(priv, PHTC_REG, PHTC_TESTCLR);
65462306a36Sopenharmony_ci}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_cistatic void rcsi2_enter_standby(struct rcar_csi2 *priv)
65762306a36Sopenharmony_ci{
65862306a36Sopenharmony_ci	if (priv->info->enter_standby)
65962306a36Sopenharmony_ci		priv->info->enter_standby(priv);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	reset_control_assert(priv->rstc);
66262306a36Sopenharmony_ci	usleep_range(100, 150);
66362306a36Sopenharmony_ci	pm_runtime_put(priv->dev);
66462306a36Sopenharmony_ci}
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_cistatic int rcsi2_exit_standby(struct rcar_csi2 *priv)
66762306a36Sopenharmony_ci{
66862306a36Sopenharmony_ci	int ret;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	ret = pm_runtime_resume_and_get(priv->dev);
67162306a36Sopenharmony_ci	if (ret < 0)
67262306a36Sopenharmony_ci		return ret;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	reset_control_deassert(priv->rstc);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	return 0;
67762306a36Sopenharmony_ci}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_cistatic int rcsi2_wait_phy_start(struct rcar_csi2 *priv,
68062306a36Sopenharmony_ci				unsigned int lanes)
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci	unsigned int timeout;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	/* Wait for the clock and data lanes to enter LP-11 state. */
68562306a36Sopenharmony_ci	for (timeout = 0; timeout <= 20; timeout++) {
68662306a36Sopenharmony_ci		const u32 lane_mask = (1 << lanes) - 1;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci		if ((rcsi2_read(priv, PHCLM_REG) & PHCLM_STOPSTATECKL)  &&
68962306a36Sopenharmony_ci		    (rcsi2_read(priv, PHDLM_REG) & lane_mask) == lane_mask)
69062306a36Sopenharmony_ci			return 0;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci		usleep_range(1000, 2000);
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	dev_err(priv->dev, "Timeout waiting for LP-11 state\n");
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	return -ETIMEDOUT;
69862306a36Sopenharmony_ci}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_cistatic int rcsi2_set_phypll(struct rcar_csi2 *priv, unsigned int mbps)
70162306a36Sopenharmony_ci{
70262306a36Sopenharmony_ci	const struct rcsi2_mbps_reg *hsfreq;
70362306a36Sopenharmony_ci	const struct rcsi2_mbps_reg *hsfreq_prev = NULL;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	if (mbps < priv->info->hsfreqrange->mbps)
70662306a36Sopenharmony_ci		dev_warn(priv->dev, "%u Mbps less than min PHY speed %u Mbps",
70762306a36Sopenharmony_ci			 mbps, priv->info->hsfreqrange->mbps);
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	for (hsfreq = priv->info->hsfreqrange; hsfreq->mbps != 0; hsfreq++) {
71062306a36Sopenharmony_ci		if (hsfreq->mbps >= mbps)
71162306a36Sopenharmony_ci			break;
71262306a36Sopenharmony_ci		hsfreq_prev = hsfreq;
71362306a36Sopenharmony_ci	}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	if (!hsfreq->mbps) {
71662306a36Sopenharmony_ci		dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", mbps);
71762306a36Sopenharmony_ci		return -ERANGE;
71862306a36Sopenharmony_ci	}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	if (hsfreq_prev &&
72162306a36Sopenharmony_ci	    ((mbps - hsfreq_prev->mbps) <= (hsfreq->mbps - mbps)))
72262306a36Sopenharmony_ci		hsfreq = hsfreq_prev;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	rcsi2_write(priv, PHYPLL_REG, PHYPLL_HSFREQRANGE(hsfreq->reg));
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	return 0;
72762306a36Sopenharmony_ci}
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_cistatic int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp,
73062306a36Sopenharmony_ci			   unsigned int lanes)
73162306a36Sopenharmony_ci{
73262306a36Sopenharmony_ci	struct v4l2_subdev *source;
73362306a36Sopenharmony_ci	struct v4l2_ctrl *ctrl;
73462306a36Sopenharmony_ci	u64 mbps;
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	if (!priv->remote)
73762306a36Sopenharmony_ci		return -ENODEV;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	source = priv->remote;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	/* Read the pixel rate control from remote. */
74262306a36Sopenharmony_ci	ctrl = v4l2_ctrl_find(source->ctrl_handler, V4L2_CID_PIXEL_RATE);
74362306a36Sopenharmony_ci	if (!ctrl) {
74462306a36Sopenharmony_ci		dev_err(priv->dev, "no pixel rate control in subdev %s\n",
74562306a36Sopenharmony_ci			source->name);
74662306a36Sopenharmony_ci		return -EINVAL;
74762306a36Sopenharmony_ci	}
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	/*
75062306a36Sopenharmony_ci	 * Calculate the phypll in mbps.
75162306a36Sopenharmony_ci	 * link_freq = (pixel_rate * bits_per_sample) / (2 * nr_of_lanes)
75262306a36Sopenharmony_ci	 * bps = link_freq * 2
75362306a36Sopenharmony_ci	 */
75462306a36Sopenharmony_ci	mbps = v4l2_ctrl_g_ctrl_int64(ctrl) * bpp;
75562306a36Sopenharmony_ci	do_div(mbps, lanes * 1000000);
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	/* Adjust for C-PHY, divide by 2.8. */
75862306a36Sopenharmony_ci	if (priv->cphy)
75962306a36Sopenharmony_ci		mbps = div_u64(mbps * 5, 14);
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	return mbps;
76262306a36Sopenharmony_ci}
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_cistatic int rcsi2_get_active_lanes(struct rcar_csi2 *priv,
76562306a36Sopenharmony_ci				  unsigned int *lanes)
76662306a36Sopenharmony_ci{
76762306a36Sopenharmony_ci	struct v4l2_mbus_config mbus_config = { 0 };
76862306a36Sopenharmony_ci	int ret;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	*lanes = priv->lanes;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	ret = v4l2_subdev_call(priv->remote, pad, get_mbus_config,
77362306a36Sopenharmony_ci			       priv->remote_pad, &mbus_config);
77462306a36Sopenharmony_ci	if (ret == -ENOIOCTLCMD) {
77562306a36Sopenharmony_ci		dev_dbg(priv->dev, "No remote mbus configuration available\n");
77662306a36Sopenharmony_ci		return 0;
77762306a36Sopenharmony_ci	}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	if (ret) {
78062306a36Sopenharmony_ci		dev_err(priv->dev, "Failed to get remote mbus configuration\n");
78162306a36Sopenharmony_ci		return ret;
78262306a36Sopenharmony_ci	}
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	switch (mbus_config.type) {
78562306a36Sopenharmony_ci	case V4L2_MBUS_CSI2_CPHY:
78662306a36Sopenharmony_ci		if (!priv->cphy)
78762306a36Sopenharmony_ci			return -EINVAL;
78862306a36Sopenharmony_ci		break;
78962306a36Sopenharmony_ci	case V4L2_MBUS_CSI2_DPHY:
79062306a36Sopenharmony_ci		if (priv->cphy)
79162306a36Sopenharmony_ci			return -EINVAL;
79262306a36Sopenharmony_ci		break;
79362306a36Sopenharmony_ci	default:
79462306a36Sopenharmony_ci		dev_err(priv->dev, "Unsupported media bus type %u\n",
79562306a36Sopenharmony_ci			mbus_config.type);
79662306a36Sopenharmony_ci		return -EINVAL;
79762306a36Sopenharmony_ci	}
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	if (mbus_config.bus.mipi_csi2.num_data_lanes > priv->lanes) {
80062306a36Sopenharmony_ci		dev_err(priv->dev,
80162306a36Sopenharmony_ci			"Unsupported mbus config: too many data lanes %u\n",
80262306a36Sopenharmony_ci			mbus_config.bus.mipi_csi2.num_data_lanes);
80362306a36Sopenharmony_ci		return -EINVAL;
80462306a36Sopenharmony_ci	}
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	*lanes = mbus_config.bus.mipi_csi2.num_data_lanes;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	return 0;
80962306a36Sopenharmony_ci}
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_cistatic int rcsi2_start_receiver_gen3(struct rcar_csi2 *priv)
81262306a36Sopenharmony_ci{
81362306a36Sopenharmony_ci	const struct rcar_csi2_format *format;
81462306a36Sopenharmony_ci	u32 phycnt, vcdt = 0, vcdt2 = 0, fld = 0;
81562306a36Sopenharmony_ci	unsigned int lanes;
81662306a36Sopenharmony_ci	unsigned int i;
81762306a36Sopenharmony_ci	int mbps, ret;
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	dev_dbg(priv->dev, "Input size (%ux%u%c)\n",
82062306a36Sopenharmony_ci		priv->mf.width, priv->mf.height,
82162306a36Sopenharmony_ci		priv->mf.field == V4L2_FIELD_NONE ? 'p' : 'i');
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	/* Code is validated in set_fmt. */
82462306a36Sopenharmony_ci	format = rcsi2_code_to_fmt(priv->mf.code);
82562306a36Sopenharmony_ci	if (!format)
82662306a36Sopenharmony_ci		return -EINVAL;
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	/*
82962306a36Sopenharmony_ci	 * Enable all supported CSI-2 channels with virtual channel and
83062306a36Sopenharmony_ci	 * data type matching.
83162306a36Sopenharmony_ci	 *
83262306a36Sopenharmony_ci	 * NOTE: It's not possible to get individual datatype for each
83362306a36Sopenharmony_ci	 *       source virtual channel. Once this is possible in V4L2
83462306a36Sopenharmony_ci	 *       it should be used here.
83562306a36Sopenharmony_ci	 */
83662306a36Sopenharmony_ci	for (i = 0; i < priv->info->num_channels; i++) {
83762306a36Sopenharmony_ci		u32 vcdt_part;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci		if (priv->channel_vc[i] < 0)
84062306a36Sopenharmony_ci			continue;
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci		vcdt_part = VCDT_SEL_VC(priv->channel_vc[i]) | VCDT_VCDTN_EN |
84362306a36Sopenharmony_ci			VCDT_SEL_DTN_ON | VCDT_SEL_DT(format->datatype);
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci		/* Store in correct reg and offset. */
84662306a36Sopenharmony_ci		if (i < 2)
84762306a36Sopenharmony_ci			vcdt |= vcdt_part << ((i % 2) * 16);
84862306a36Sopenharmony_ci		else
84962306a36Sopenharmony_ci			vcdt2 |= vcdt_part << ((i % 2) * 16);
85062306a36Sopenharmony_ci	}
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	if (priv->mf.field == V4L2_FIELD_ALTERNATE) {
85362306a36Sopenharmony_ci		fld = FLD_DET_SEL(1) | FLD_FLD_EN4 | FLD_FLD_EN3 | FLD_FLD_EN2
85462306a36Sopenharmony_ci			| FLD_FLD_EN;
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci		if (priv->mf.height == 240)
85762306a36Sopenharmony_ci			fld |= FLD_FLD_NUM(0);
85862306a36Sopenharmony_ci		else
85962306a36Sopenharmony_ci			fld |= FLD_FLD_NUM(1);
86062306a36Sopenharmony_ci	}
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	/*
86362306a36Sopenharmony_ci	 * Get the number of active data lanes inspecting the remote mbus
86462306a36Sopenharmony_ci	 * configuration.
86562306a36Sopenharmony_ci	 */
86662306a36Sopenharmony_ci	ret = rcsi2_get_active_lanes(priv, &lanes);
86762306a36Sopenharmony_ci	if (ret)
86862306a36Sopenharmony_ci		return ret;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	phycnt = PHYCNT_ENABLECLK;
87162306a36Sopenharmony_ci	phycnt |= (1 << lanes) - 1;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	mbps = rcsi2_calc_mbps(priv, format->bpp, lanes);
87462306a36Sopenharmony_ci	if (mbps < 0)
87562306a36Sopenharmony_ci		return mbps;
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	/* Enable interrupts. */
87862306a36Sopenharmony_ci	rcsi2_write(priv, INTEN_REG, INTEN_INT_AFIFO_OF | INTEN_INT_ERRSOTHS
87962306a36Sopenharmony_ci		    | INTEN_INT_ERRSOTSYNCHS);
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	/* Init */
88262306a36Sopenharmony_ci	rcsi2_write(priv, TREF_REG, TREF_TREF);
88362306a36Sopenharmony_ci	rcsi2_write(priv, PHTC_REG, 0);
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	/* Configure */
88662306a36Sopenharmony_ci	if (!priv->info->use_isp) {
88762306a36Sopenharmony_ci		rcsi2_write(priv, VCDT_REG, vcdt);
88862306a36Sopenharmony_ci		if (vcdt2)
88962306a36Sopenharmony_ci			rcsi2_write(priv, VCDT2_REG, vcdt2);
89062306a36Sopenharmony_ci	}
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	/* Lanes are zero indexed. */
89362306a36Sopenharmony_ci	rcsi2_write(priv, LSWAP_REG,
89462306a36Sopenharmony_ci		    LSWAP_L0SEL(priv->lane_swap[0] - 1) |
89562306a36Sopenharmony_ci		    LSWAP_L1SEL(priv->lane_swap[1] - 1) |
89662306a36Sopenharmony_ci		    LSWAP_L2SEL(priv->lane_swap[2] - 1) |
89762306a36Sopenharmony_ci		    LSWAP_L3SEL(priv->lane_swap[3] - 1));
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	/* Start */
90062306a36Sopenharmony_ci	if (priv->info->init_phtw) {
90162306a36Sopenharmony_ci		ret = priv->info->init_phtw(priv, mbps);
90262306a36Sopenharmony_ci		if (ret)
90362306a36Sopenharmony_ci			return ret;
90462306a36Sopenharmony_ci	}
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	if (priv->info->hsfreqrange) {
90762306a36Sopenharmony_ci		ret = rcsi2_set_phypll(priv, mbps);
90862306a36Sopenharmony_ci		if (ret)
90962306a36Sopenharmony_ci			return ret;
91062306a36Sopenharmony_ci	}
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	if (priv->info->csi0clkfreqrange)
91362306a36Sopenharmony_ci		rcsi2_write(priv, CSI0CLKFCPR_REG,
91462306a36Sopenharmony_ci			    CSI0CLKFREQRANGE(priv->info->csi0clkfreqrange));
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	if (priv->info->use_isp)
91762306a36Sopenharmony_ci		rcsi2_write(priv, PHYFRX_REG,
91862306a36Sopenharmony_ci			    PHYFRX_FORCERX_MODE_3 | PHYFRX_FORCERX_MODE_2 |
91962306a36Sopenharmony_ci			    PHYFRX_FORCERX_MODE_1 | PHYFRX_FORCERX_MODE_0);
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	rcsi2_write(priv, PHYCNT_REG, phycnt);
92262306a36Sopenharmony_ci	rcsi2_write(priv, LINKCNT_REG, LINKCNT_MONITOR_EN |
92362306a36Sopenharmony_ci		    LINKCNT_REG_MONI_PACT_EN | LINKCNT_ICLK_NONSTOP);
92462306a36Sopenharmony_ci	rcsi2_write(priv, FLD_REG, fld);
92562306a36Sopenharmony_ci	rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ);
92662306a36Sopenharmony_ci	rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ | PHYCNT_RSTZ);
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	ret = rcsi2_wait_phy_start(priv, lanes);
92962306a36Sopenharmony_ci	if (ret)
93062306a36Sopenharmony_ci		return ret;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	if (priv->info->use_isp)
93362306a36Sopenharmony_ci		rcsi2_write(priv, PHYFRX_REG, 0);
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	/* Run post PHY start initialization, if needed. */
93662306a36Sopenharmony_ci	if (priv->info->phy_post_init) {
93762306a36Sopenharmony_ci		ret = priv->info->phy_post_init(priv);
93862306a36Sopenharmony_ci		if (ret)
93962306a36Sopenharmony_ci			return ret;
94062306a36Sopenharmony_ci	}
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	/* Clear Ultra Low Power interrupt. */
94362306a36Sopenharmony_ci	if (priv->info->clear_ulps)
94462306a36Sopenharmony_ci		rcsi2_write(priv, INTSTATE_REG,
94562306a36Sopenharmony_ci			    INTSTATE_INT_ULPS_START |
94662306a36Sopenharmony_ci			    INTSTATE_INT_ULPS_END);
94762306a36Sopenharmony_ci	return 0;
94862306a36Sopenharmony_ci}
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_cistatic int rcsi2_wait_phy_start_v4h(struct rcar_csi2 *priv, u32 match)
95162306a36Sopenharmony_ci{
95262306a36Sopenharmony_ci	unsigned int timeout;
95362306a36Sopenharmony_ci	u32 status;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	for (timeout = 0; timeout <= 10; timeout++) {
95662306a36Sopenharmony_ci		status = rcsi2_read(priv, V4H_ST_PHYST_REG);
95762306a36Sopenharmony_ci		if ((status & match) == match)
95862306a36Sopenharmony_ci			return 0;
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci		usleep_range(1000, 2000);
96162306a36Sopenharmony_ci	}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	return -ETIMEDOUT;
96462306a36Sopenharmony_ci}
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_cistatic int rcsi2_c_phy_setting_v4h(struct rcar_csi2 *priv, int msps)
96762306a36Sopenharmony_ci{
96862306a36Sopenharmony_ci	const struct rcsi2_cphy_setting *conf;
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	for (conf = cphy_setting_table_r8a779g0; conf->msps != 0; conf++) {
97162306a36Sopenharmony_ci		if (conf->msps > msps)
97262306a36Sopenharmony_ci			break;
97362306a36Sopenharmony_ci	}
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	if (!conf->msps) {
97662306a36Sopenharmony_ci		dev_err(priv->dev, "Unsupported PHY speed for msps setting (%u Msps)", msps);
97762306a36Sopenharmony_ci		return -ERANGE;
97862306a36Sopenharmony_ci	}
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	/* C-PHY specific */
98162306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_RW_COMMON_REG(7), 0x0155);
98262306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_PPI_STARTUP_RW_COMMON_DPHY_REG(7), 0x0068);
98362306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_PPI_STARTUP_RW_COMMON_DPHY_REG(8), 0x0010);
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_LP_0_REG, 0x463c);
98662306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_LP_0_REG, 0x463c);
98762306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_LP_0_REG, 0x463c);
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(0), 0x00d5);
99062306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(0), 0x00d5);
99162306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(0), 0x00d5);
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(1), 0x0013);
99462306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(1), 0x0013);
99562306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(1), 0x0013);
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(5), 0x0013);
99862306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(5), 0x0013);
99962306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(5), 0x0013);
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(6), 0x000a);
100262306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(6), 0x000a);
100362306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(6), 0x000a);
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(2), conf->rx2);
100662306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(2), conf->rx2);
100762306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(2), conf->rx2);
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(2), 0x0001);
101062306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_REG(2), 0);
101162306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_REG(2), 0x0001);
101262306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_REG(2), 0x0001);
101362306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_REG(2), 0);
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO0_REG(0), conf->trio0);
101662306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO1_REG(0), conf->trio0);
101762306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO2_REG(0), conf->trio0);
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO0_REG(2), conf->trio2);
102062306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO1_REG(2), conf->trio2);
102162306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO2_REG(2), conf->trio2);
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO0_REG(1), conf->trio1);
102462306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO1_REG(1), conf->trio1);
102562306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO2_REG(1), conf->trio1);
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	/*
102862306a36Sopenharmony_ci	 * Configure pin-swap.
102962306a36Sopenharmony_ci	 * TODO: This registers is not documented yet, the values should depend
103062306a36Sopenharmony_ci	 * on the 'clock-lanes' and 'data-lanes' devicetree properties.
103162306a36Sopenharmony_ci	 */
103262306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_CFG_0_REG, 0xf5);
103362306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_TX_6_REG, 0x5000);
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	/* Leave Shutdown mode */
103662306a36Sopenharmony_ci	rcsi2_write(priv, V4H_DPHY_RSTZ_REG, BIT(0));
103762306a36Sopenharmony_ci	rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, BIT(0));
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	/* Wait for calibration */
104062306a36Sopenharmony_ci	if (rcsi2_wait_phy_start_v4h(priv, V4H_ST_PHYST_ST_PHY_READY)) {
104162306a36Sopenharmony_ci		dev_err(priv->dev, "PHY calibration failed\n");
104262306a36Sopenharmony_ci		return -ETIMEDOUT;
104362306a36Sopenharmony_ci	}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	/* C-PHY setting - analog programing*/
104662306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(9), conf->lane29);
104762306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(7), conf->lane27);
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	return 0;
105062306a36Sopenharmony_ci}
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_cistatic int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv)
105362306a36Sopenharmony_ci{
105462306a36Sopenharmony_ci	const struct rcar_csi2_format *format;
105562306a36Sopenharmony_ci	unsigned int lanes;
105662306a36Sopenharmony_ci	int msps;
105762306a36Sopenharmony_ci	int ret;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	/* Calculate parameters */
106062306a36Sopenharmony_ci	format = rcsi2_code_to_fmt(priv->mf.code);
106162306a36Sopenharmony_ci	if (!format)
106262306a36Sopenharmony_ci		return -EINVAL;
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	ret = rcsi2_get_active_lanes(priv, &lanes);
106562306a36Sopenharmony_ci	if (ret)
106662306a36Sopenharmony_ci		return ret;
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	msps = rcsi2_calc_mbps(priv, format->bpp, lanes);
106962306a36Sopenharmony_ci	if (msps < 0)
107062306a36Sopenharmony_ci		return msps;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	/* Reset LINK and PHY*/
107362306a36Sopenharmony_ci	rcsi2_write(priv, V4H_CSI2_RESETN_REG, 0);
107462306a36Sopenharmony_ci	rcsi2_write(priv, V4H_DPHY_RSTZ_REG, 0);
107562306a36Sopenharmony_ci	rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, 0);
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	/* PHY static setting */
107862306a36Sopenharmony_ci	rcsi2_write(priv, V4H_PHY_EN_REG, BIT(0));
107962306a36Sopenharmony_ci	rcsi2_write(priv, V4H_FLDC_REG, 0);
108062306a36Sopenharmony_ci	rcsi2_write(priv, V4H_FLDD_REG, 0);
108162306a36Sopenharmony_ci	rcsi2_write(priv, V4H_IDIC_REG, 0);
108262306a36Sopenharmony_ci	rcsi2_write(priv, V4H_PHY_MODE_REG, BIT(0));
108362306a36Sopenharmony_ci	rcsi2_write(priv, V4H_N_LANES_REG, lanes - 1);
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	/* Reset CSI2 */
108662306a36Sopenharmony_ci	rcsi2_write(priv, V4H_CSI2_RESETN_REG, BIT(0));
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	/* Registers static setting through APB */
108962306a36Sopenharmony_ci	/* Common setting */
109062306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_REG(0), 0x1bfd);
109162306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_PPI_STARTUP_RW_COMMON_STARTUP_1_1_REG, 0x0233);
109262306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_PPI_STARTUP_RW_COMMON_DPHY_REG(6), 0x0027);
109362306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_PPI_CALIBCTRL_RW_COMMON_BG_0_REG, 0x01f4);
109462306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_PPI_RW_TERMCAL_CFG_0_REG, 0x0013);
109562306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_PPI_RW_OFFSETCAL_CFG_0_REG, 0x0003);
109662306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_TIMEBASE_REG, 0x004f);
109762306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_NREF_REG, 0x0320);
109862306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_NREF_RANGE_REG, 0x000f);
109962306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_TWAIT_CONFIG_REG, 0xfe18);
110062306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_VT_CONFIG_REG, 0x0c3c);
110162306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_COARSE_CFG_REG, 0x0105);
110262306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_REG(6), 0x1000);
110362306a36Sopenharmony_ci	rcsi2_write16(priv, V4H_PPI_RW_COMMON_CFG_REG, 0x0003);
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	/* C-PHY settings */
110662306a36Sopenharmony_ci	ret = rcsi2_c_phy_setting_v4h(priv, msps);
110762306a36Sopenharmony_ci	if (ret)
110862306a36Sopenharmony_ci		return ret;
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	rcsi2_wait_phy_start_v4h(priv, V4H_ST_PHYST_ST_STOPSTATE_0 |
111162306a36Sopenharmony_ci				 V4H_ST_PHYST_ST_STOPSTATE_1 |
111262306a36Sopenharmony_ci				 V4H_ST_PHYST_ST_STOPSTATE_2);
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	return 0;
111562306a36Sopenharmony_ci}
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_cistatic int rcsi2_start(struct rcar_csi2 *priv)
111862306a36Sopenharmony_ci{
111962306a36Sopenharmony_ci	int ret;
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	ret = rcsi2_exit_standby(priv);
112262306a36Sopenharmony_ci	if (ret < 0)
112362306a36Sopenharmony_ci		return ret;
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	ret = priv->info->start_receiver(priv);
112662306a36Sopenharmony_ci	if (ret) {
112762306a36Sopenharmony_ci		rcsi2_enter_standby(priv);
112862306a36Sopenharmony_ci		return ret;
112962306a36Sopenharmony_ci	}
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	ret = v4l2_subdev_call(priv->remote, video, s_stream, 1);
113262306a36Sopenharmony_ci	if (ret) {
113362306a36Sopenharmony_ci		rcsi2_enter_standby(priv);
113462306a36Sopenharmony_ci		return ret;
113562306a36Sopenharmony_ci	}
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	return 0;
113862306a36Sopenharmony_ci}
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_cistatic void rcsi2_stop(struct rcar_csi2 *priv)
114162306a36Sopenharmony_ci{
114262306a36Sopenharmony_ci	rcsi2_enter_standby(priv);
114362306a36Sopenharmony_ci	v4l2_subdev_call(priv->remote, video, s_stream, 0);
114462306a36Sopenharmony_ci}
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_cistatic int rcsi2_s_stream(struct v4l2_subdev *sd, int enable)
114762306a36Sopenharmony_ci{
114862306a36Sopenharmony_ci	struct rcar_csi2 *priv = sd_to_csi2(sd);
114962306a36Sopenharmony_ci	int ret = 0;
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci	mutex_lock(&priv->lock);
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	if (!priv->remote) {
115462306a36Sopenharmony_ci		ret = -ENODEV;
115562306a36Sopenharmony_ci		goto out;
115662306a36Sopenharmony_ci	}
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	if (enable && priv->stream_count == 0) {
115962306a36Sopenharmony_ci		ret = rcsi2_start(priv);
116062306a36Sopenharmony_ci		if (ret)
116162306a36Sopenharmony_ci			goto out;
116262306a36Sopenharmony_ci	} else if (!enable && priv->stream_count == 1) {
116362306a36Sopenharmony_ci		rcsi2_stop(priv);
116462306a36Sopenharmony_ci	}
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	priv->stream_count += enable ? 1 : -1;
116762306a36Sopenharmony_ciout:
116862306a36Sopenharmony_ci	mutex_unlock(&priv->lock);
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	return ret;
117162306a36Sopenharmony_ci}
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_cistatic int rcsi2_set_pad_format(struct v4l2_subdev *sd,
117462306a36Sopenharmony_ci				struct v4l2_subdev_state *sd_state,
117562306a36Sopenharmony_ci				struct v4l2_subdev_format *format)
117662306a36Sopenharmony_ci{
117762306a36Sopenharmony_ci	struct rcar_csi2 *priv = sd_to_csi2(sd);
117862306a36Sopenharmony_ci	struct v4l2_mbus_framefmt *framefmt;
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	mutex_lock(&priv->lock);
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	if (!rcsi2_code_to_fmt(format->format.code))
118362306a36Sopenharmony_ci		format->format.code = rcar_csi2_formats[0].code;
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
118662306a36Sopenharmony_ci		priv->mf = format->format;
118762306a36Sopenharmony_ci	} else {
118862306a36Sopenharmony_ci		framefmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
118962306a36Sopenharmony_ci		*framefmt = format->format;
119062306a36Sopenharmony_ci	}
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	mutex_unlock(&priv->lock);
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	return 0;
119562306a36Sopenharmony_ci}
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_cistatic int rcsi2_get_pad_format(struct v4l2_subdev *sd,
119862306a36Sopenharmony_ci				struct v4l2_subdev_state *sd_state,
119962306a36Sopenharmony_ci				struct v4l2_subdev_format *format)
120062306a36Sopenharmony_ci{
120162306a36Sopenharmony_ci	struct rcar_csi2 *priv = sd_to_csi2(sd);
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	mutex_lock(&priv->lock);
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
120662306a36Sopenharmony_ci		format->format = priv->mf;
120762306a36Sopenharmony_ci	else
120862306a36Sopenharmony_ci		format->format = *v4l2_subdev_get_try_format(sd, sd_state, 0);
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	mutex_unlock(&priv->lock);
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	return 0;
121362306a36Sopenharmony_ci}
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_cistatic const struct v4l2_subdev_video_ops rcar_csi2_video_ops = {
121662306a36Sopenharmony_ci	.s_stream = rcsi2_s_stream,
121762306a36Sopenharmony_ci};
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_cistatic const struct v4l2_subdev_pad_ops rcar_csi2_pad_ops = {
122062306a36Sopenharmony_ci	.set_fmt = rcsi2_set_pad_format,
122162306a36Sopenharmony_ci	.get_fmt = rcsi2_get_pad_format,
122262306a36Sopenharmony_ci};
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_cistatic const struct v4l2_subdev_ops rcar_csi2_subdev_ops = {
122562306a36Sopenharmony_ci	.video	= &rcar_csi2_video_ops,
122662306a36Sopenharmony_ci	.pad	= &rcar_csi2_pad_ops,
122762306a36Sopenharmony_ci};
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_cistatic irqreturn_t rcsi2_irq(int irq, void *data)
123062306a36Sopenharmony_ci{
123162306a36Sopenharmony_ci	struct rcar_csi2 *priv = data;
123262306a36Sopenharmony_ci	u32 status, err_status;
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	status = rcsi2_read(priv, INTSTATE_REG);
123562306a36Sopenharmony_ci	err_status = rcsi2_read(priv, INTERRSTATE_REG);
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	if (!status)
123862306a36Sopenharmony_ci		return IRQ_HANDLED;
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	rcsi2_write(priv, INTSTATE_REG, status);
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	if (!err_status)
124362306a36Sopenharmony_ci		return IRQ_HANDLED;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	rcsi2_write(priv, INTERRSTATE_REG, err_status);
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	dev_info(priv->dev, "Transfer error, restarting CSI-2 receiver\n");
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	return IRQ_WAKE_THREAD;
125062306a36Sopenharmony_ci}
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_cistatic irqreturn_t rcsi2_irq_thread(int irq, void *data)
125362306a36Sopenharmony_ci{
125462306a36Sopenharmony_ci	struct rcar_csi2 *priv = data;
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	mutex_lock(&priv->lock);
125762306a36Sopenharmony_ci	rcsi2_stop(priv);
125862306a36Sopenharmony_ci	usleep_range(1000, 2000);
125962306a36Sopenharmony_ci	if (rcsi2_start(priv))
126062306a36Sopenharmony_ci		dev_warn(priv->dev, "Failed to restart CSI-2 receiver\n");
126162306a36Sopenharmony_ci	mutex_unlock(&priv->lock);
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_ci	return IRQ_HANDLED;
126462306a36Sopenharmony_ci}
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
126762306a36Sopenharmony_ci * Async handling and registration of subdevices and links.
126862306a36Sopenharmony_ci */
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_cistatic int rcsi2_notify_bound(struct v4l2_async_notifier *notifier,
127162306a36Sopenharmony_ci			      struct v4l2_subdev *subdev,
127262306a36Sopenharmony_ci			      struct v4l2_async_connection *asc)
127362306a36Sopenharmony_ci{
127462306a36Sopenharmony_ci	struct rcar_csi2 *priv = notifier_to_csi2(notifier);
127562306a36Sopenharmony_ci	int pad;
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	pad = media_entity_get_fwnode_pad(&subdev->entity, asc->match.fwnode,
127862306a36Sopenharmony_ci					  MEDIA_PAD_FL_SOURCE);
127962306a36Sopenharmony_ci	if (pad < 0) {
128062306a36Sopenharmony_ci		dev_err(priv->dev, "Failed to find pad for %s\n", subdev->name);
128162306a36Sopenharmony_ci		return pad;
128262306a36Sopenharmony_ci	}
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	priv->remote = subdev;
128562306a36Sopenharmony_ci	priv->remote_pad = pad;
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	dev_dbg(priv->dev, "Bound %s pad: %d\n", subdev->name, pad);
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	return media_create_pad_link(&subdev->entity, pad,
129062306a36Sopenharmony_ci				     &priv->subdev.entity, 0,
129162306a36Sopenharmony_ci				     MEDIA_LNK_FL_ENABLED |
129262306a36Sopenharmony_ci				     MEDIA_LNK_FL_IMMUTABLE);
129362306a36Sopenharmony_ci}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_cistatic void rcsi2_notify_unbind(struct v4l2_async_notifier *notifier,
129662306a36Sopenharmony_ci				struct v4l2_subdev *subdev,
129762306a36Sopenharmony_ci				struct v4l2_async_connection *asc)
129862306a36Sopenharmony_ci{
129962306a36Sopenharmony_ci	struct rcar_csi2 *priv = notifier_to_csi2(notifier);
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	priv->remote = NULL;
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	dev_dbg(priv->dev, "Unbind %s\n", subdev->name);
130462306a36Sopenharmony_ci}
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_cistatic const struct v4l2_async_notifier_operations rcar_csi2_notify_ops = {
130762306a36Sopenharmony_ci	.bound = rcsi2_notify_bound,
130862306a36Sopenharmony_ci	.unbind = rcsi2_notify_unbind,
130962306a36Sopenharmony_ci};
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_cistatic int rcsi2_parse_v4l2(struct rcar_csi2 *priv,
131262306a36Sopenharmony_ci			    struct v4l2_fwnode_endpoint *vep)
131362306a36Sopenharmony_ci{
131462306a36Sopenharmony_ci	unsigned int i;
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	/* Only port 0 endpoint 0 is valid. */
131762306a36Sopenharmony_ci	if (vep->base.port || vep->base.id)
131862306a36Sopenharmony_ci		return -ENOTCONN;
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	priv->lanes = vep->bus.mipi_csi2.num_data_lanes;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	switch (vep->bus_type) {
132362306a36Sopenharmony_ci	case V4L2_MBUS_CSI2_DPHY:
132462306a36Sopenharmony_ci		if (!priv->info->support_dphy) {
132562306a36Sopenharmony_ci			dev_err(priv->dev, "D-PHY not supported\n");
132662306a36Sopenharmony_ci			return -EINVAL;
132762306a36Sopenharmony_ci		}
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci		if (priv->lanes != 1 && priv->lanes != 2 && priv->lanes != 4) {
133062306a36Sopenharmony_ci			dev_err(priv->dev,
133162306a36Sopenharmony_ci				"Unsupported number of data-lanes for D-PHY: %u\n",
133262306a36Sopenharmony_ci				priv->lanes);
133362306a36Sopenharmony_ci			return -EINVAL;
133462306a36Sopenharmony_ci		}
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci		priv->cphy = false;
133762306a36Sopenharmony_ci		break;
133862306a36Sopenharmony_ci	case V4L2_MBUS_CSI2_CPHY:
133962306a36Sopenharmony_ci		if (!priv->info->support_cphy) {
134062306a36Sopenharmony_ci			dev_err(priv->dev, "C-PHY not supported\n");
134162306a36Sopenharmony_ci			return -EINVAL;
134262306a36Sopenharmony_ci		}
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci		if (priv->lanes != 3) {
134562306a36Sopenharmony_ci			dev_err(priv->dev,
134662306a36Sopenharmony_ci				"Unsupported number of data-lanes for C-PHY: %u\n",
134762306a36Sopenharmony_ci				priv->lanes);
134862306a36Sopenharmony_ci			return -EINVAL;
134962306a36Sopenharmony_ci		}
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci		priv->cphy = true;
135262306a36Sopenharmony_ci		break;
135362306a36Sopenharmony_ci	default:
135462306a36Sopenharmony_ci		dev_err(priv->dev, "Unsupported bus: %u\n", vep->bus_type);
135562306a36Sopenharmony_ci		return -EINVAL;
135662306a36Sopenharmony_ci	}
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(priv->lane_swap); i++) {
135962306a36Sopenharmony_ci		priv->lane_swap[i] = i < priv->lanes ?
136062306a36Sopenharmony_ci			vep->bus.mipi_csi2.data_lanes[i] : i;
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci		/* Check for valid lane number. */
136362306a36Sopenharmony_ci		if (priv->lane_swap[i] < 1 || priv->lane_swap[i] > 4) {
136462306a36Sopenharmony_ci			dev_err(priv->dev, "data-lanes must be in 1-4 range\n");
136562306a36Sopenharmony_ci			return -EINVAL;
136662306a36Sopenharmony_ci		}
136762306a36Sopenharmony_ci	}
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	return 0;
137062306a36Sopenharmony_ci}
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_cistatic int rcsi2_parse_dt(struct rcar_csi2 *priv)
137362306a36Sopenharmony_ci{
137462306a36Sopenharmony_ci	struct v4l2_async_connection *asc;
137562306a36Sopenharmony_ci	struct fwnode_handle *fwnode;
137662306a36Sopenharmony_ci	struct fwnode_handle *ep;
137762306a36Sopenharmony_ci	struct v4l2_fwnode_endpoint v4l2_ep = {
137862306a36Sopenharmony_ci		.bus_type = V4L2_MBUS_UNKNOWN,
137962306a36Sopenharmony_ci	};
138062306a36Sopenharmony_ci	int ret;
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(priv->dev), 0, 0, 0);
138362306a36Sopenharmony_ci	if (!ep) {
138462306a36Sopenharmony_ci		dev_err(priv->dev, "Not connected to subdevice\n");
138562306a36Sopenharmony_ci		return -EINVAL;
138662306a36Sopenharmony_ci	}
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	ret = v4l2_fwnode_endpoint_parse(ep, &v4l2_ep);
138962306a36Sopenharmony_ci	if (ret) {
139062306a36Sopenharmony_ci		dev_err(priv->dev, "Could not parse v4l2 endpoint\n");
139162306a36Sopenharmony_ci		fwnode_handle_put(ep);
139262306a36Sopenharmony_ci		return -EINVAL;
139362306a36Sopenharmony_ci	}
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	ret = rcsi2_parse_v4l2(priv, &v4l2_ep);
139662306a36Sopenharmony_ci	if (ret) {
139762306a36Sopenharmony_ci		fwnode_handle_put(ep);
139862306a36Sopenharmony_ci		return ret;
139962306a36Sopenharmony_ci	}
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	fwnode = fwnode_graph_get_remote_endpoint(ep);
140262306a36Sopenharmony_ci	fwnode_handle_put(ep);
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	dev_dbg(priv->dev, "Found '%pOF'\n", to_of_node(fwnode));
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	v4l2_async_subdev_nf_init(&priv->notifier, &priv->subdev);
140762306a36Sopenharmony_ci	priv->notifier.ops = &rcar_csi2_notify_ops;
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	asc = v4l2_async_nf_add_fwnode(&priv->notifier, fwnode,
141062306a36Sopenharmony_ci				       struct v4l2_async_connection);
141162306a36Sopenharmony_ci	fwnode_handle_put(fwnode);
141262306a36Sopenharmony_ci	if (IS_ERR(asc))
141362306a36Sopenharmony_ci		return PTR_ERR(asc);
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	ret = v4l2_async_nf_register(&priv->notifier);
141662306a36Sopenharmony_ci	if (ret)
141762306a36Sopenharmony_ci		v4l2_async_nf_cleanup(&priv->notifier);
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci	return ret;
142062306a36Sopenharmony_ci}
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
142362306a36Sopenharmony_ci * PHTW initialization sequences.
142462306a36Sopenharmony_ci *
142562306a36Sopenharmony_ci * NOTE: Magic values are from the datasheet and lack documentation.
142662306a36Sopenharmony_ci */
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_cistatic int rcsi2_phtw_write(struct rcar_csi2 *priv, u16 data, u16 code)
142962306a36Sopenharmony_ci{
143062306a36Sopenharmony_ci	unsigned int timeout;
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	rcsi2_write(priv, PHTW_REG,
143362306a36Sopenharmony_ci		    PHTW_DWEN | PHTW_TESTDIN_DATA(data) |
143462306a36Sopenharmony_ci		    PHTW_CWEN | PHTW_TESTDIN_CODE(code));
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	/* Wait for DWEN and CWEN to be cleared by hardware. */
143762306a36Sopenharmony_ci	for (timeout = 0; timeout <= 20; timeout++) {
143862306a36Sopenharmony_ci		if (!(rcsi2_read(priv, PHTW_REG) & (PHTW_DWEN | PHTW_CWEN)))
143962306a36Sopenharmony_ci			return 0;
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci		usleep_range(1000, 2000);
144262306a36Sopenharmony_ci	}
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	dev_err(priv->dev, "Timeout waiting for PHTW_DWEN and/or PHTW_CWEN\n");
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	return -ETIMEDOUT;
144762306a36Sopenharmony_ci}
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_cistatic int rcsi2_phtw_write_array(struct rcar_csi2 *priv,
145062306a36Sopenharmony_ci				  const struct phtw_value *values)
145162306a36Sopenharmony_ci{
145262306a36Sopenharmony_ci	const struct phtw_value *value;
145362306a36Sopenharmony_ci	int ret;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	for (value = values; value->data || value->code; value++) {
145662306a36Sopenharmony_ci		ret = rcsi2_phtw_write(priv, value->data, value->code);
145762306a36Sopenharmony_ci		if (ret)
145862306a36Sopenharmony_ci			return ret;
145962306a36Sopenharmony_ci	}
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci	return 0;
146262306a36Sopenharmony_ci}
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_cistatic int rcsi2_phtw_write_mbps(struct rcar_csi2 *priv, unsigned int mbps,
146562306a36Sopenharmony_ci				 const struct rcsi2_mbps_reg *values, u16 code)
146662306a36Sopenharmony_ci{
146762306a36Sopenharmony_ci	const struct rcsi2_mbps_reg *value;
146862306a36Sopenharmony_ci	const struct rcsi2_mbps_reg *prev_value = NULL;
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	for (value = values; value->mbps; value++) {
147162306a36Sopenharmony_ci		if (value->mbps >= mbps)
147262306a36Sopenharmony_ci			break;
147362306a36Sopenharmony_ci		prev_value = value;
147462306a36Sopenharmony_ci	}
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci	if (prev_value &&
147762306a36Sopenharmony_ci	    ((mbps - prev_value->mbps) <= (value->mbps - mbps)))
147862306a36Sopenharmony_ci		value = prev_value;
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	if (!value->mbps) {
148162306a36Sopenharmony_ci		dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", mbps);
148262306a36Sopenharmony_ci		return -ERANGE;
148362306a36Sopenharmony_ci	}
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	return rcsi2_phtw_write(priv, value->reg, code);
148662306a36Sopenharmony_ci}
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_cistatic int __rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv,
148962306a36Sopenharmony_ci					unsigned int mbps)
149062306a36Sopenharmony_ci{
149162306a36Sopenharmony_ci	static const struct phtw_value step1[] = {
149262306a36Sopenharmony_ci		{ .data = 0xcc, .code = 0xe2 },
149362306a36Sopenharmony_ci		{ .data = 0x01, .code = 0xe3 },
149462306a36Sopenharmony_ci		{ .data = 0x11, .code = 0xe4 },
149562306a36Sopenharmony_ci		{ .data = 0x01, .code = 0xe5 },
149662306a36Sopenharmony_ci		{ .data = 0x10, .code = 0x04 },
149762306a36Sopenharmony_ci		{ /* sentinel */ },
149862306a36Sopenharmony_ci	};
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	static const struct phtw_value step2[] = {
150162306a36Sopenharmony_ci		{ .data = 0x38, .code = 0x08 },
150262306a36Sopenharmony_ci		{ .data = 0x01, .code = 0x00 },
150362306a36Sopenharmony_ci		{ .data = 0x4b, .code = 0xac },
150462306a36Sopenharmony_ci		{ .data = 0x03, .code = 0x00 },
150562306a36Sopenharmony_ci		{ .data = 0x80, .code = 0x07 },
150662306a36Sopenharmony_ci		{ /* sentinel */ },
150762306a36Sopenharmony_ci	};
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci	int ret;
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	ret = rcsi2_phtw_write_array(priv, step1);
151262306a36Sopenharmony_ci	if (ret)
151362306a36Sopenharmony_ci		return ret;
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci	if (mbps != 0 && mbps <= 250) {
151662306a36Sopenharmony_ci		ret = rcsi2_phtw_write(priv, 0x39, 0x05);
151762306a36Sopenharmony_ci		if (ret)
151862306a36Sopenharmony_ci			return ret;
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci		ret = rcsi2_phtw_write_mbps(priv, mbps, phtw_mbps_h3_v3h_m3n,
152162306a36Sopenharmony_ci					    0xf1);
152262306a36Sopenharmony_ci		if (ret)
152362306a36Sopenharmony_ci			return ret;
152462306a36Sopenharmony_ci	}
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	return rcsi2_phtw_write_array(priv, step2);
152762306a36Sopenharmony_ci}
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_cistatic int rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, unsigned int mbps)
153062306a36Sopenharmony_ci{
153162306a36Sopenharmony_ci	return __rcsi2_init_phtw_h3_v3h_m3n(priv, mbps);
153262306a36Sopenharmony_ci}
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_cistatic int rcsi2_init_phtw_h3es2(struct rcar_csi2 *priv, unsigned int mbps)
153562306a36Sopenharmony_ci{
153662306a36Sopenharmony_ci	return __rcsi2_init_phtw_h3_v3h_m3n(priv, 0);
153762306a36Sopenharmony_ci}
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_cistatic int rcsi2_init_phtw_v3m_e3(struct rcar_csi2 *priv, unsigned int mbps)
154062306a36Sopenharmony_ci{
154162306a36Sopenharmony_ci	return rcsi2_phtw_write_mbps(priv, mbps, phtw_mbps_v3m_e3, 0x44);
154262306a36Sopenharmony_ci}
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_cistatic int rcsi2_phy_post_init_v3m_e3(struct rcar_csi2 *priv)
154562306a36Sopenharmony_ci{
154662306a36Sopenharmony_ci	static const struct phtw_value step1[] = {
154762306a36Sopenharmony_ci		{ .data = 0xee, .code = 0x34 },
154862306a36Sopenharmony_ci		{ .data = 0xee, .code = 0x44 },
154962306a36Sopenharmony_ci		{ .data = 0xee, .code = 0x54 },
155062306a36Sopenharmony_ci		{ .data = 0xee, .code = 0x84 },
155162306a36Sopenharmony_ci		{ .data = 0xee, .code = 0x94 },
155262306a36Sopenharmony_ci		{ /* sentinel */ },
155362306a36Sopenharmony_ci	};
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_ci	return rcsi2_phtw_write_array(priv, step1);
155662306a36Sopenharmony_ci}
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_cistatic int rcsi2_init_phtw_v3u(struct rcar_csi2 *priv,
155962306a36Sopenharmony_ci			       unsigned int mbps)
156062306a36Sopenharmony_ci{
156162306a36Sopenharmony_ci	/* In case of 1500Mbps or less */
156262306a36Sopenharmony_ci	static const struct phtw_value step1[] = {
156362306a36Sopenharmony_ci		{ .data = 0xcc, .code = 0xe2 },
156462306a36Sopenharmony_ci		{ /* sentinel */ },
156562306a36Sopenharmony_ci	};
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	static const struct phtw_value step2[] = {
156862306a36Sopenharmony_ci		{ .data = 0x01, .code = 0xe3 },
156962306a36Sopenharmony_ci		{ .data = 0x11, .code = 0xe4 },
157062306a36Sopenharmony_ci		{ .data = 0x01, .code = 0xe5 },
157162306a36Sopenharmony_ci		{ /* sentinel */ },
157262306a36Sopenharmony_ci	};
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci	/* In case of 1500Mbps or less */
157562306a36Sopenharmony_ci	static const struct phtw_value step3[] = {
157662306a36Sopenharmony_ci		{ .data = 0x38, .code = 0x08 },
157762306a36Sopenharmony_ci		{ /* sentinel */ },
157862306a36Sopenharmony_ci	};
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci	static const struct phtw_value step4[] = {
158162306a36Sopenharmony_ci		{ .data = 0x01, .code = 0x00 },
158262306a36Sopenharmony_ci		{ .data = 0x4b, .code = 0xac },
158362306a36Sopenharmony_ci		{ .data = 0x03, .code = 0x00 },
158462306a36Sopenharmony_ci		{ .data = 0x80, .code = 0x07 },
158562306a36Sopenharmony_ci		{ /* sentinel */ },
158662306a36Sopenharmony_ci	};
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	int ret;
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	if (mbps != 0 && mbps <= 1500)
159162306a36Sopenharmony_ci		ret = rcsi2_phtw_write_array(priv, step1);
159262306a36Sopenharmony_ci	else
159362306a36Sopenharmony_ci		ret = rcsi2_phtw_write_mbps(priv, mbps, phtw_mbps_v3u, 0xe2);
159462306a36Sopenharmony_ci	if (ret)
159562306a36Sopenharmony_ci		return ret;
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci	ret = rcsi2_phtw_write_array(priv, step2);
159862306a36Sopenharmony_ci	if (ret)
159962306a36Sopenharmony_ci		return ret;
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci	if (mbps != 0 && mbps <= 1500) {
160262306a36Sopenharmony_ci		ret = rcsi2_phtw_write_array(priv, step3);
160362306a36Sopenharmony_ci		if (ret)
160462306a36Sopenharmony_ci			return ret;
160562306a36Sopenharmony_ci	}
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci	ret = rcsi2_phtw_write_array(priv, step4);
160862306a36Sopenharmony_ci	if (ret)
160962306a36Sopenharmony_ci		return ret;
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	return ret;
161262306a36Sopenharmony_ci}
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci/* -----------------------------------------------------------------------------
161562306a36Sopenharmony_ci * Platform Device Driver.
161662306a36Sopenharmony_ci */
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_cistatic int rcsi2_link_setup(struct media_entity *entity,
161962306a36Sopenharmony_ci			    const struct media_pad *local,
162062306a36Sopenharmony_ci			    const struct media_pad *remote, u32 flags)
162162306a36Sopenharmony_ci{
162262306a36Sopenharmony_ci	struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
162362306a36Sopenharmony_ci	struct rcar_csi2 *priv = sd_to_csi2(sd);
162462306a36Sopenharmony_ci	struct video_device *vdev;
162562306a36Sopenharmony_ci	int channel, vc;
162662306a36Sopenharmony_ci	u32 id;
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	if (!is_media_entity_v4l2_video_device(remote->entity)) {
162962306a36Sopenharmony_ci		dev_err(priv->dev, "Remote is not a video device\n");
163062306a36Sopenharmony_ci		return -EINVAL;
163162306a36Sopenharmony_ci	}
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci	vdev = media_entity_to_video_device(remote->entity);
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci	if (of_property_read_u32(vdev->dev_parent->of_node, "renesas,id", &id)) {
163662306a36Sopenharmony_ci		dev_err(priv->dev, "No renesas,id, can't configure routing\n");
163762306a36Sopenharmony_ci		return -EINVAL;
163862306a36Sopenharmony_ci	}
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_ci	channel = id % 4;
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	if (flags & MEDIA_LNK_FL_ENABLED) {
164362306a36Sopenharmony_ci		if (media_pad_remote_pad_first(local)) {
164462306a36Sopenharmony_ci			dev_dbg(priv->dev,
164562306a36Sopenharmony_ci				"Each VC can only be routed to one output channel\n");
164662306a36Sopenharmony_ci			return -EINVAL;
164762306a36Sopenharmony_ci		}
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci		vc = local->index - 1;
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci		dev_dbg(priv->dev, "Route VC%d to VIN%u on output channel %d\n",
165262306a36Sopenharmony_ci			vc, id, channel);
165362306a36Sopenharmony_ci	} else {
165462306a36Sopenharmony_ci		vc = -1;
165562306a36Sopenharmony_ci	}
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci	priv->channel_vc[channel] = vc;
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	return 0;
166062306a36Sopenharmony_ci}
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_cistatic const struct media_entity_operations rcar_csi2_entity_ops = {
166362306a36Sopenharmony_ci	.link_setup = rcsi2_link_setup,
166462306a36Sopenharmony_ci	.link_validate = v4l2_subdev_link_validate,
166562306a36Sopenharmony_ci};
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_cistatic int rcsi2_probe_resources(struct rcar_csi2 *priv,
166862306a36Sopenharmony_ci				 struct platform_device *pdev)
166962306a36Sopenharmony_ci{
167062306a36Sopenharmony_ci	int irq, ret;
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	priv->base = devm_platform_ioremap_resource(pdev, 0);
167362306a36Sopenharmony_ci	if (IS_ERR(priv->base))
167462306a36Sopenharmony_ci		return PTR_ERR(priv->base);
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
167762306a36Sopenharmony_ci	if (irq < 0)
167862306a36Sopenharmony_ci		return irq;
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci	ret = devm_request_threaded_irq(&pdev->dev, irq, rcsi2_irq,
168162306a36Sopenharmony_ci					rcsi2_irq_thread, IRQF_SHARED,
168262306a36Sopenharmony_ci					KBUILD_MODNAME, priv);
168362306a36Sopenharmony_ci	if (ret)
168462306a36Sopenharmony_ci		return ret;
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	priv->rstc = devm_reset_control_get(&pdev->dev, NULL);
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(priv->rstc);
168962306a36Sopenharmony_ci}
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_cistatic const struct rcar_csi2_info rcar_csi2_info_r8a7795 = {
169262306a36Sopenharmony_ci	.init_phtw = rcsi2_init_phtw_h3_v3h_m3n,
169362306a36Sopenharmony_ci	.start_receiver = rcsi2_start_receiver_gen3,
169462306a36Sopenharmony_ci	.enter_standby = rcsi2_enter_standby_gen3,
169562306a36Sopenharmony_ci	.hsfreqrange = hsfreqrange_h3_v3h_m3n,
169662306a36Sopenharmony_ci	.csi0clkfreqrange = 0x20,
169762306a36Sopenharmony_ci	.num_channels = 4,
169862306a36Sopenharmony_ci	.clear_ulps = true,
169962306a36Sopenharmony_ci	.support_dphy = true,
170062306a36Sopenharmony_ci};
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_cistatic const struct rcar_csi2_info rcar_csi2_info_r8a7795es2 = {
170362306a36Sopenharmony_ci	.init_phtw = rcsi2_init_phtw_h3es2,
170462306a36Sopenharmony_ci	.start_receiver = rcsi2_start_receiver_gen3,
170562306a36Sopenharmony_ci	.enter_standby = rcsi2_enter_standby_gen3,
170662306a36Sopenharmony_ci	.hsfreqrange = hsfreqrange_h3_v3h_m3n,
170762306a36Sopenharmony_ci	.csi0clkfreqrange = 0x20,
170862306a36Sopenharmony_ci	.num_channels = 4,
170962306a36Sopenharmony_ci	.clear_ulps = true,
171062306a36Sopenharmony_ci	.support_dphy = true,
171162306a36Sopenharmony_ci};
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_cistatic const struct rcar_csi2_info rcar_csi2_info_r8a7796 = {
171462306a36Sopenharmony_ci	.start_receiver = rcsi2_start_receiver_gen3,
171562306a36Sopenharmony_ci	.enter_standby = rcsi2_enter_standby_gen3,
171662306a36Sopenharmony_ci	.hsfreqrange = hsfreqrange_m3w,
171762306a36Sopenharmony_ci	.num_channels = 4,
171862306a36Sopenharmony_ci	.support_dphy = true,
171962306a36Sopenharmony_ci};
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_cistatic const struct rcar_csi2_info rcar_csi2_info_r8a77961 = {
172262306a36Sopenharmony_ci	.start_receiver = rcsi2_start_receiver_gen3,
172362306a36Sopenharmony_ci	.enter_standby = rcsi2_enter_standby_gen3,
172462306a36Sopenharmony_ci	.hsfreqrange = hsfreqrange_m3w,
172562306a36Sopenharmony_ci	.num_channels = 4,
172662306a36Sopenharmony_ci	.support_dphy = true,
172762306a36Sopenharmony_ci};
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_cistatic const struct rcar_csi2_info rcar_csi2_info_r8a77965 = {
173062306a36Sopenharmony_ci	.init_phtw = rcsi2_init_phtw_h3_v3h_m3n,
173162306a36Sopenharmony_ci	.start_receiver = rcsi2_start_receiver_gen3,
173262306a36Sopenharmony_ci	.enter_standby = rcsi2_enter_standby_gen3,
173362306a36Sopenharmony_ci	.hsfreqrange = hsfreqrange_h3_v3h_m3n,
173462306a36Sopenharmony_ci	.csi0clkfreqrange = 0x20,
173562306a36Sopenharmony_ci	.num_channels = 4,
173662306a36Sopenharmony_ci	.clear_ulps = true,
173762306a36Sopenharmony_ci	.support_dphy = true,
173862306a36Sopenharmony_ci};
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_cistatic const struct rcar_csi2_info rcar_csi2_info_r8a77970 = {
174162306a36Sopenharmony_ci	.init_phtw = rcsi2_init_phtw_v3m_e3,
174262306a36Sopenharmony_ci	.phy_post_init = rcsi2_phy_post_init_v3m_e3,
174362306a36Sopenharmony_ci	.start_receiver = rcsi2_start_receiver_gen3,
174462306a36Sopenharmony_ci	.enter_standby = rcsi2_enter_standby_gen3,
174562306a36Sopenharmony_ci	.num_channels = 4,
174662306a36Sopenharmony_ci	.support_dphy = true,
174762306a36Sopenharmony_ci};
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_cistatic const struct rcar_csi2_info rcar_csi2_info_r8a77980 = {
175062306a36Sopenharmony_ci	.init_phtw = rcsi2_init_phtw_h3_v3h_m3n,
175162306a36Sopenharmony_ci	.start_receiver = rcsi2_start_receiver_gen3,
175262306a36Sopenharmony_ci	.enter_standby = rcsi2_enter_standby_gen3,
175362306a36Sopenharmony_ci	.hsfreqrange = hsfreqrange_h3_v3h_m3n,
175462306a36Sopenharmony_ci	.csi0clkfreqrange = 0x20,
175562306a36Sopenharmony_ci	.clear_ulps = true,
175662306a36Sopenharmony_ci	.support_dphy = true,
175762306a36Sopenharmony_ci};
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_cistatic const struct rcar_csi2_info rcar_csi2_info_r8a77990 = {
176062306a36Sopenharmony_ci	.init_phtw = rcsi2_init_phtw_v3m_e3,
176162306a36Sopenharmony_ci	.phy_post_init = rcsi2_phy_post_init_v3m_e3,
176262306a36Sopenharmony_ci	.start_receiver = rcsi2_start_receiver_gen3,
176362306a36Sopenharmony_ci	.enter_standby = rcsi2_enter_standby_gen3,
176462306a36Sopenharmony_ci	.num_channels = 2,
176562306a36Sopenharmony_ci	.support_dphy = true,
176662306a36Sopenharmony_ci};
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_cistatic const struct rcar_csi2_info rcar_csi2_info_r8a779a0 = {
176962306a36Sopenharmony_ci	.init_phtw = rcsi2_init_phtw_v3u,
177062306a36Sopenharmony_ci	.start_receiver = rcsi2_start_receiver_gen3,
177162306a36Sopenharmony_ci	.enter_standby = rcsi2_enter_standby_gen3,
177262306a36Sopenharmony_ci	.hsfreqrange = hsfreqrange_v3u,
177362306a36Sopenharmony_ci	.csi0clkfreqrange = 0x20,
177462306a36Sopenharmony_ci	.clear_ulps = true,
177562306a36Sopenharmony_ci	.use_isp = true,
177662306a36Sopenharmony_ci	.support_dphy = true,
177762306a36Sopenharmony_ci};
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_cistatic const struct rcar_csi2_info rcar_csi2_info_r8a779g0 = {
178062306a36Sopenharmony_ci	.start_receiver = rcsi2_start_receiver_v4h,
178162306a36Sopenharmony_ci	.use_isp = true,
178262306a36Sopenharmony_ci	.support_cphy = true,
178362306a36Sopenharmony_ci};
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_cistatic const struct of_device_id rcar_csi2_of_table[] = {
178662306a36Sopenharmony_ci	{
178762306a36Sopenharmony_ci		.compatible = "renesas,r8a774a1-csi2",
178862306a36Sopenharmony_ci		.data = &rcar_csi2_info_r8a7796,
178962306a36Sopenharmony_ci	},
179062306a36Sopenharmony_ci	{
179162306a36Sopenharmony_ci		.compatible = "renesas,r8a774b1-csi2",
179262306a36Sopenharmony_ci		.data = &rcar_csi2_info_r8a77965,
179362306a36Sopenharmony_ci	},
179462306a36Sopenharmony_ci	{
179562306a36Sopenharmony_ci		.compatible = "renesas,r8a774c0-csi2",
179662306a36Sopenharmony_ci		.data = &rcar_csi2_info_r8a77990,
179762306a36Sopenharmony_ci	},
179862306a36Sopenharmony_ci	{
179962306a36Sopenharmony_ci		.compatible = "renesas,r8a774e1-csi2",
180062306a36Sopenharmony_ci		.data = &rcar_csi2_info_r8a7795,
180162306a36Sopenharmony_ci	},
180262306a36Sopenharmony_ci	{
180362306a36Sopenharmony_ci		.compatible = "renesas,r8a7795-csi2",
180462306a36Sopenharmony_ci		.data = &rcar_csi2_info_r8a7795,
180562306a36Sopenharmony_ci	},
180662306a36Sopenharmony_ci	{
180762306a36Sopenharmony_ci		.compatible = "renesas,r8a7796-csi2",
180862306a36Sopenharmony_ci		.data = &rcar_csi2_info_r8a7796,
180962306a36Sopenharmony_ci	},
181062306a36Sopenharmony_ci	{
181162306a36Sopenharmony_ci		.compatible = "renesas,r8a77961-csi2",
181262306a36Sopenharmony_ci		.data = &rcar_csi2_info_r8a77961,
181362306a36Sopenharmony_ci	},
181462306a36Sopenharmony_ci	{
181562306a36Sopenharmony_ci		.compatible = "renesas,r8a77965-csi2",
181662306a36Sopenharmony_ci		.data = &rcar_csi2_info_r8a77965,
181762306a36Sopenharmony_ci	},
181862306a36Sopenharmony_ci	{
181962306a36Sopenharmony_ci		.compatible = "renesas,r8a77970-csi2",
182062306a36Sopenharmony_ci		.data = &rcar_csi2_info_r8a77970,
182162306a36Sopenharmony_ci	},
182262306a36Sopenharmony_ci	{
182362306a36Sopenharmony_ci		.compatible = "renesas,r8a77980-csi2",
182462306a36Sopenharmony_ci		.data = &rcar_csi2_info_r8a77980,
182562306a36Sopenharmony_ci	},
182662306a36Sopenharmony_ci	{
182762306a36Sopenharmony_ci		.compatible = "renesas,r8a77990-csi2",
182862306a36Sopenharmony_ci		.data = &rcar_csi2_info_r8a77990,
182962306a36Sopenharmony_ci	},
183062306a36Sopenharmony_ci	{
183162306a36Sopenharmony_ci		.compatible = "renesas,r8a779a0-csi2",
183262306a36Sopenharmony_ci		.data = &rcar_csi2_info_r8a779a0,
183362306a36Sopenharmony_ci	},
183462306a36Sopenharmony_ci	{
183562306a36Sopenharmony_ci		.compatible = "renesas,r8a779g0-csi2",
183662306a36Sopenharmony_ci		.data = &rcar_csi2_info_r8a779g0,
183762306a36Sopenharmony_ci	},
183862306a36Sopenharmony_ci	{ /* sentinel */ },
183962306a36Sopenharmony_ci};
184062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, rcar_csi2_of_table);
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_cistatic const struct soc_device_attribute r8a7795[] = {
184362306a36Sopenharmony_ci	{
184462306a36Sopenharmony_ci		.soc_id = "r8a7795", .revision = "ES2.*",
184562306a36Sopenharmony_ci		.data = &rcar_csi2_info_r8a7795es2,
184662306a36Sopenharmony_ci	},
184762306a36Sopenharmony_ci	{ /* sentinel */ }
184862306a36Sopenharmony_ci};
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_cistatic int rcsi2_probe(struct platform_device *pdev)
185162306a36Sopenharmony_ci{
185262306a36Sopenharmony_ci	const struct soc_device_attribute *attr;
185362306a36Sopenharmony_ci	struct rcar_csi2 *priv;
185462306a36Sopenharmony_ci	unsigned int i, num_pads;
185562306a36Sopenharmony_ci	int ret;
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_ci	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
185862306a36Sopenharmony_ci	if (!priv)
185962306a36Sopenharmony_ci		return -ENOMEM;
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	priv->info = of_device_get_match_data(&pdev->dev);
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci	/*
186462306a36Sopenharmony_ci	 * The different ES versions of r8a7795 (H3) behave differently but
186562306a36Sopenharmony_ci	 * share the same compatible string.
186662306a36Sopenharmony_ci	 */
186762306a36Sopenharmony_ci	attr = soc_device_match(r8a7795);
186862306a36Sopenharmony_ci	if (attr)
186962306a36Sopenharmony_ci		priv->info = attr->data;
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	priv->dev = &pdev->dev;
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci	mutex_init(&priv->lock);
187462306a36Sopenharmony_ci	priv->stream_count = 0;
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci	ret = rcsi2_probe_resources(priv, pdev);
187762306a36Sopenharmony_ci	if (ret) {
187862306a36Sopenharmony_ci		dev_err(priv->dev, "Failed to get resources\n");
187962306a36Sopenharmony_ci		goto error_mutex;
188062306a36Sopenharmony_ci	}
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_ci	platform_set_drvdata(pdev, priv);
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_ci	ret = rcsi2_parse_dt(priv);
188562306a36Sopenharmony_ci	if (ret)
188662306a36Sopenharmony_ci		goto error_mutex;
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_ci	priv->subdev.owner = THIS_MODULE;
188962306a36Sopenharmony_ci	priv->subdev.dev = &pdev->dev;
189062306a36Sopenharmony_ci	v4l2_subdev_init(&priv->subdev, &rcar_csi2_subdev_ops);
189162306a36Sopenharmony_ci	v4l2_set_subdevdata(&priv->subdev, &pdev->dev);
189262306a36Sopenharmony_ci	snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s %s",
189362306a36Sopenharmony_ci		 KBUILD_MODNAME, dev_name(&pdev->dev));
189462306a36Sopenharmony_ci	priv->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci	priv->subdev.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
189762306a36Sopenharmony_ci	priv->subdev.entity.ops = &rcar_csi2_entity_ops;
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci	num_pads = priv->info->use_isp ? 2 : NR_OF_RCAR_CSI2_PAD;
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci	priv->pads[RCAR_CSI2_SINK].flags = MEDIA_PAD_FL_SINK;
190262306a36Sopenharmony_ci	for (i = RCAR_CSI2_SOURCE_VC0; i < num_pads; i++)
190362306a36Sopenharmony_ci		priv->pads[i].flags = MEDIA_PAD_FL_SOURCE;
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	ret = media_entity_pads_init(&priv->subdev.entity, num_pads,
190662306a36Sopenharmony_ci				     priv->pads);
190762306a36Sopenharmony_ci	if (ret)
190862306a36Sopenharmony_ci		goto error_async;
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(priv->channel_vc); i++)
191162306a36Sopenharmony_ci		priv->channel_vc[i] = -1;
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_ci	ret = v4l2_async_register_subdev(&priv->subdev);
191662306a36Sopenharmony_ci	if (ret < 0)
191762306a36Sopenharmony_ci		goto error_async;
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_ci	dev_info(priv->dev, "%d lanes found\n", priv->lanes);
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	return 0;
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_cierror_async:
192462306a36Sopenharmony_ci	v4l2_async_nf_unregister(&priv->notifier);
192562306a36Sopenharmony_ci	v4l2_async_nf_cleanup(&priv->notifier);
192662306a36Sopenharmony_cierror_mutex:
192762306a36Sopenharmony_ci	mutex_destroy(&priv->lock);
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci	return ret;
193062306a36Sopenharmony_ci}
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_cistatic void rcsi2_remove(struct platform_device *pdev)
193362306a36Sopenharmony_ci{
193462306a36Sopenharmony_ci	struct rcar_csi2 *priv = platform_get_drvdata(pdev);
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci	v4l2_async_nf_unregister(&priv->notifier);
193762306a36Sopenharmony_ci	v4l2_async_nf_cleanup(&priv->notifier);
193862306a36Sopenharmony_ci	v4l2_async_unregister_subdev(&priv->subdev);
193962306a36Sopenharmony_ci
194062306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci	mutex_destroy(&priv->lock);
194362306a36Sopenharmony_ci}
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_cistatic struct platform_driver rcar_csi2_pdrv = {
194662306a36Sopenharmony_ci	.remove_new = rcsi2_remove,
194762306a36Sopenharmony_ci	.probe	= rcsi2_probe,
194862306a36Sopenharmony_ci	.driver	= {
194962306a36Sopenharmony_ci		.name	= "rcar-csi2",
195062306a36Sopenharmony_ci		.suppress_bind_attrs = true,
195162306a36Sopenharmony_ci		.of_match_table	= rcar_csi2_of_table,
195262306a36Sopenharmony_ci	},
195362306a36Sopenharmony_ci};
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_cimodule_platform_driver(rcar_csi2_pdrv);
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ciMODULE_AUTHOR("Niklas Söderlund <niklas.soderlund@ragnatech.se>");
195862306a36Sopenharmony_ciMODULE_DESCRIPTION("Renesas R-Car MIPI CSI-2 receiver driver");
195962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1960