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