From e3e12f52b214121840b44c91de5b3e5af5d3eb84 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Mon, 06 Nov 2023 03:04:41 +0000
Subject: [PATCH] rk3568 rt init

---
 kernel/drivers/media/i2c/imx464.c | 1042 ++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 878 insertions(+), 164 deletions(-)

diff --git a/kernel/drivers/media/i2c/imx464.c b/kernel/drivers/media/i2c/imx464.c
index 3458ff9..8d6c04b 100644
--- a/kernel/drivers/media/i2c/imx464.c
+++ b/kernel/drivers/media/i2c/imx464.c
@@ -10,6 +10,7 @@
  * V0.0X01.0X03 support enum sensor fmt
  */
 
+//#define DEBUG
 #include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/delay.h>
@@ -26,8 +27,11 @@
 #include <media/v4l2-async.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-subdev.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mediabus.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/rk-preisp.h>
+#include <linux/of_graph.h>
 
 #define DRIVER_VERSION			KERNEL_VERSION(0, 0x01, 0x03)
 
@@ -42,15 +46,12 @@
 #define OF_CAMERA_HDR_MODE		"rockchip,camera-hdr-mode"
 
 /* pixel rate = link frequency * 2 * lanes / BITS_PER_SAMPLE */
-#define IMX464_10BIT_LINEAR_PIXEL_RATE	(MIPI_FREQ_445M * 2 / 10 * 4)
 #define IMX464_10BIT_HDR2_PIXEL_RATE	(MIPI_FREQ_594M * 2 / 10 * 4)
-#define IMX464_10BIT_HDR3_PIXEL_RATE	(MIPI_FREQ_594M * 2 / 10 * 4)
-#define IMX464_12BIT_PIXEL_RATE		(MIPI_FREQ_360M * 2 / 12 * 4)
 #define IMX464_XVCLK_FREQ_37M		37125000
 #define IMX464_XVCLK_FREQ_24M		24000000
 
-#define CHIP_ID				0x00
-#define IMX464_REG_CHIP_ID		0x0000
+#define CHIP_ID				0x06
+#define IMX464_REG_CHIP_ID		0x3057
 
 #define IMX464_REG_CTRL_MODE		0x3000
 #define IMX464_MODE_SW_STANDBY		BIT(0)
@@ -133,8 +134,6 @@
 #define IMX464_REG_VALUE_16BIT		2
 #define IMX464_REG_VALUE_24BIT		3
 
-#define IMX464_2LANES			2
-#define IMX464_4LANES			4
 #define IMX464_BITS_PER_SAMPLE		10
 
 #define IMX464_VREVERSE_REG	0x304f
@@ -150,12 +149,10 @@
 
 #define USED_SYS_DEBUG
 
-static bool g_isHCG;
-
 #define OF_CAMERA_PINCTRL_STATE_DEFAULT	"rockchip,camera_default"
 #define OF_CAMERA_PINCTRL_STATE_SLEEP	"rockchip,camera_sleep"
 
-#define IMX464_NAME			"IMX464"
+#define IMX464_NAME			"imx464"
 
 static const char * const IMX464_supply_names[] = {
 	"avdd",		/* Analog power */
@@ -165,17 +162,17 @@
 
 #define IMX464_NUM_SUPPLIES ARRAY_SIZE(IMX464_supply_names)
 
+struct regval {
+	u16 addr;
+	u8 val;
+};
+
 enum IMX464_max_pad {
 	PAD0, /* link to isp */
 	PAD1, /* link to csi wr0 | hdr x2:L x3:M */
 	PAD2, /* link to csi wr1 | hdr      x3:L */
 	PAD3, /* link to csi wr2 | hdr x2:M x3:S */
 	PAD_MAX,
-};
-
-struct regval {
-	u16 addr;
-	u8 val;
 };
 
 struct IMX464_mode {
@@ -186,6 +183,9 @@
 	u32 hts_def;
 	u32 vts_def;
 	u32 exp_def;
+	u32 mipi_freq_idx;
+	u32 mclk;
+	u32 bpp;
 	const struct regval *reg_list;
 	u32 hdr_mode;
 	u32 vc[PAD_MAX];
@@ -213,19 +213,22 @@
 	struct v4l2_ctrl	*pixel_rate;
 	struct v4l2_ctrl	*link_freq;
 	struct mutex		mutex;
+	struct v4l2_fwnode_endpoint bus_cfg;
 	bool			streaming;
 	bool			power_on;
+	bool			has_init_exp;
+	const struct IMX464_mode *support_modes;
 	const struct IMX464_mode *cur_mode;
 	u32			module_index;
 	u32			cfg_num;
-	u32			cur_pixel_rate;
-	u32			cur_link_freq;
+	u32			cur_vts;
+	u32			cur_mclk;
 	const char		*module_facing;
 	const char		*module_name;
 	const char		*len_name;
-	u32			cur_vts;
-	bool			has_init_exp;
+	enum rkmodule_sync_mode	sync_mode;
 	struct preisp_hdrae_exp_s init_hdrae_exp;
+	bool			isHCG;
 };
 
 #define to_IMX464(sd) container_of(sd, struct IMX464, subdev)
@@ -237,16 +240,16 @@
 	{REG_NULL, 0x00},
 };
 
-static const struct regval IMX464_linear_10bit_2688x1520_regs[] = {
+static __maybe_unused const struct regval IMX464_linear_10bit_2688x1520_2lane_37m_regs[] = {
 	{0x3000, 0x01},
 	{0x3002, 0x01},
 	{0x300C, 0x5B},
 	{0x300D, 0x40},
-	{0x3030, 0xE4},
-	{0x3031, 0x0C},
+	{0x3034, 0xDC},
+	{0x3035, 0x05},
 	{0x3050, 0x00},
-	{0x3058, 0x06},
-	{0x3059, 0x09},
+	{0x3058, 0x83},
+	{0x3059, 0x04},
 	{0x30BE, 0x5E},
 	{0x30E8, 0x14},
 	{0x3110, 0x02},
@@ -256,6 +259,488 @@
 	{0x319D, 0x00},
 	{0x319E, 0x02},
 	{0x31A1, 0x00},
+	{0x3288, 0x22},
+	{0x328A, 0x02},
+	{0x328C, 0xA2},
+	{0x328E, 0x22},
+	{0x3415, 0x27},
+	{0x3418, 0x27},
+	{0x3428, 0xFE},
+	{0x349E, 0x6A},
+	{0x34A2, 0x9A},
+	{0x34A4, 0x8A},
+	{0x34A6, 0x8E},
+	{0x34AA, 0xD8},
+	{0x35BC, 0x00},
+	{0x35BE, 0xFF},
+	{0x35CC, 0x1B},
+	{0x35CD, 0x00},
+	{0x35CE, 0x2A},
+	{0x35CF, 0x00},
+	{0x35DC, 0x07},
+	{0x35DE, 0x1A},
+	{0x35DF, 0x00},
+	{0x35E4, 0x2B},
+	{0x35E5, 0x00},
+	{0x35E6, 0x07},
+	{0x35E7, 0x01},
+	{0x3648, 0x01},
+	{0x3678, 0x01},
+	{0x367C, 0x69},
+	{0x367E, 0x69},
+	{0x3680, 0x69},
+	{0x3682, 0x69},
+	{0x3718, 0x1C},
+	{0x371D, 0x05},
+	{0x375D, 0x11},
+	{0x375E, 0x43},
+	{0x375F, 0x76},
+	{0x3760, 0x07},
+	{0x3768, 0x1B},
+	{0x3769, 0x1B},
+	{0x376A, 0x1A},
+	{0x376B, 0x19},
+	{0x376C, 0x17},
+	{0x376D, 0x0F},
+	{0x376E, 0x0B},
+	{0x376F, 0x0B},
+	{0x3770, 0x0B},
+	{0x3776, 0x89},
+	{0x3777, 0x00},
+	{0x3778, 0xCA},
+	{0x3779, 0x00},
+	{0x377A, 0x45},
+	{0x377B, 0x01},
+	{0x377C, 0x56},
+	{0x377D, 0x02},
+	{0x377E, 0xFE},
+	{0x377F, 0x03},
+	{0x3780, 0xFE},
+	{0x3781, 0x05},
+	{0x3782, 0xFE},
+	{0x3783, 0x06},
+	{0x3784, 0x7F},
+	{0x3788, 0x1F},
+	{0x378A, 0xCA},
+	{0x378B, 0x00},
+	{0x378C, 0x45},
+	{0x378D, 0x01},
+	{0x378E, 0x56},
+	{0x378F, 0x02},
+	{0x3790, 0xFE},
+	{0x3791, 0x03},
+	{0x3792, 0xFE},
+	{0x3793, 0x05},
+	{0x3794, 0xFE},
+	{0x3795, 0x06},
+	{0x3796, 0x7F},
+	{0x3798, 0xBF},
+	{0x3A01, 0x01},
+	{0x3A18, 0x7F},
+	{0x3A1A, 0x37},
+	{0x3A1C, 0x37},
+	{0x3A1E, 0xF7},
+	{0x3A1F, 0x00},
+	{0x3A20, 0x3F},
+	{0x3A22, 0x6F},
+	{0x3A24, 0x3F},
+	{0x3A26, 0x5F},
+	{0x3A28, 0x2F},
+	{REG_NULL, 0x00},
+};
+
+static __maybe_unused const struct regval IMX464_hdr_2x_10bit_2688x1520_2lane_37m_regs[] = {
+	{0x3000, 0x01},
+	{0x3002, 0x01},
+	{0x300C, 0x5B},
+	{0x300D, 0x40},
+	{0x3034, 0xDC},
+	{0x3035, 0x05},
+	{0x3048, 0x01},
+	{0x3049, 0x01},
+	{0x304A, 0x01},
+	{0x304B, 0x01},
+	{0x304C, 0x13},
+	{0x304D, 0x00},
+	{0x3050, 0x00},
+	{0x3058, 0xF4},
+	{0x3059, 0x0A},
+	{0x3068, 0x3D},
+	{0x30BE, 0x5E},
+	{0x30E8, 0x0A},
+	{0x3110, 0x02},
+	{0x314C, 0x80},//
+	{0x315A, 0x02},
+	{0x316A, 0x7E},
+	{0x319D, 0x00},
+	{0x319E, 0x01},//1188M
+	{0x31A1, 0x00},
+	{0x31D7, 0x01},
+	{0x3200, 0x10},
+	{0x3288, 0x22},
+	{0x328A, 0x02},
+	{0x328C, 0xA2},
+	{0x328E, 0x22},
+	{0x3415, 0x27},
+	{0x3418, 0x27},
+	{0x3428, 0xFE},
+	{0x349E, 0x6A},
+	{0x34A2, 0x9A},
+	{0x34A4, 0x8A},
+	{0x34A6, 0x8E},
+	{0x34AA, 0xD8},
+	{0x35BC, 0x00},
+	{0x35BE, 0xFF},
+	{0x35CC, 0x1B},
+	{0x35CD, 0x00},
+	{0x35CE, 0x2A},
+	{0x35CF, 0x00},
+	{0x35DC, 0x07},
+	{0x35DE, 0x1A},
+	{0x35DF, 0x00},
+	{0x35E4, 0x2B},
+	{0x35E5, 0x00},
+	{0x35E6, 0x07},
+	{0x35E7, 0x01},
+	{0x3648, 0x01},
+	{0x3678, 0x01},
+	{0x367C, 0x69},
+	{0x367E, 0x69},
+	{0x3680, 0x69},
+	{0x3682, 0x69},
+	{0x3718, 0x1C},
+	{0x371D, 0x05},
+	{0x375D, 0x11},
+	{0x375E, 0x43},
+	{0x375F, 0x76},
+	{0x3760, 0x07},
+	{0x3768, 0x1B},
+	{0x3769, 0x1B},
+	{0x376A, 0x1A},
+	{0x376B, 0x19},
+	{0x376C, 0x17},
+	{0x376D, 0x0F},
+	{0x376E, 0x0B},
+	{0x376F, 0x0B},
+	{0x3770, 0x0B},
+	{0x3776, 0x89},
+	{0x3777, 0x00},
+	{0x3778, 0xCA},
+	{0x3779, 0x00},
+	{0x377A, 0x45},
+	{0x377B, 0x01},
+	{0x377C, 0x56},
+	{0x377D, 0x02},
+	{0x377E, 0xFE},
+	{0x377F, 0x03},
+	{0x3780, 0xFE},
+	{0x3781, 0x05},
+	{0x3782, 0xFE},
+	{0x3783, 0x06},
+	{0x3784, 0x7F},
+	{0x3788, 0x1F},
+	{0x378A, 0xCA},
+	{0x378B, 0x00},
+	{0x378C, 0x45},
+	{0x378D, 0x01},
+	{0x378E, 0x56},
+	{0x378F, 0x02},
+	{0x3790, 0xFE},
+	{0x3791, 0x03},
+	{0x3792, 0xFE},
+	{0x3793, 0x05},
+	{0x3794, 0xFE},
+	{0x3795, 0x06},
+	{0x3796, 0x7F},
+	{0x3798, 0xBF},
+	{0x3A01, 0x01},
+	{0x3A18, 0x8F},
+	{0x3A1A, 0x4F},
+	{0x3A1C, 0x47},
+	{0x3A1E, 0x37},
+	{0x3A1F, 0x01},
+	{0x3A20, 0x4F},
+	{0x3A22, 0x87},
+	{0x3A24, 0x4F},
+	{0x3A26, 0x7F},
+	{0x3A28, 0x3F},
+	{REG_NULL, 0x00},
+};
+
+static const struct regval IMX464_linear_10bit_2688x1520_2lane_regs[] = {
+	{0x3000, 0x01},
+	{0x3002, 0x01},
+	{0x300C, 0x3b},
+	{0x300D, 0x2a},
+	{0x3034, 0xDC},
+	{0x3035, 0x05},
+	{0x3048, 0x00},
+	{0x3049, 0x00},
+	{0x304A, 0x03},
+	{0x304B, 0x02},
+	{0x304C, 0x14},
+	{0x304D, 0x03},
+	{0x3050, 0x00},
+	{0x3058, 0x83},
+	{0x3059, 0x04},
+	{0x3068, 0xc9},
+	{0x30BE, 0x5E},
+	{0x30E8, 0x14},
+	{0x3110, 0x02},
+	{0x314C, 0x29},
+	{0x314D, 0x01},
+	{0x315A, 0x06},
+	{0x3168, 0xA0},
+	{0x316A, 0x7E},
+	{0x319D, 0x00},
+	{0x319E, 0x02},
+	{0x31A1, 0x00},
+	{0x31D7, 0x00},
+	{0x3200, 0x11},
+	{0x3288, 0x22},
+	{0x328A, 0x02},
+	{0x328C, 0xA2},
+	{0x328E, 0x22},
+	{0x3415, 0x27},
+	{0x3418, 0x27},
+	{0x3428, 0xFE},
+	{0x349E, 0x6A},
+	{0x34A2, 0x9A},
+	{0x34A4, 0x8A},
+	{0x34A6, 0x8E},
+	{0x34AA, 0xD8},
+	{0x35BC, 0x00},
+	{0x35BE, 0xFF},
+	{0x35CC, 0x1B},
+	{0x35CD, 0x00},
+	{0x35CE, 0x2A},
+	{0x35CF, 0x00},
+	{0x35DC, 0x07},
+	{0x35DE, 0x1A},
+	{0x35DF, 0x00},
+	{0x35E4, 0x2B},
+	{0x35E5, 0x00},
+	{0x35E6, 0x07},
+	{0x35E7, 0x01},
+	{0x3648, 0x01},
+	{0x3678, 0x01},
+	{0x367C, 0x69},
+	{0x367E, 0x69},
+	{0x3680, 0x69},
+	{0x3682, 0x69},
+	{0x3718, 0x1C},
+	{0x371D, 0x05},
+	{0x375D, 0x11},
+	{0x375E, 0x43},
+	{0x375F, 0x76},
+	{0x3760, 0x07},
+	{0x3768, 0x1B},
+	{0x3769, 0x1B},
+	{0x376A, 0x1A},
+	{0x376B, 0x19},
+	{0x376C, 0x17},
+	{0x376D, 0x0F},
+	{0x376E, 0x0B},
+	{0x376F, 0x0B},
+	{0x3770, 0x0B},
+	{0x3776, 0x89},
+	{0x3777, 0x00},
+	{0x3778, 0xCA},
+	{0x3779, 0x00},
+	{0x377A, 0x45},
+	{0x377B, 0x01},
+	{0x377C, 0x56},
+	{0x377D, 0x02},
+	{0x377E, 0xFE},
+	{0x377F, 0x03},
+	{0x3780, 0xFE},
+	{0x3781, 0x05},
+	{0x3782, 0xFE},
+	{0x3783, 0x06},
+	{0x3784, 0x7F},
+	{0x3788, 0x1F},
+	{0x378A, 0xCA},
+	{0x378B, 0x00},
+	{0x378C, 0x45},
+	{0x378D, 0x01},
+	{0x378E, 0x56},
+	{0x378F, 0x02},
+	{0x3790, 0xFE},
+	{0x3791, 0x03},
+	{0x3792, 0xFE},
+	{0x3793, 0x05},
+	{0x3794, 0xFE},
+	{0x3795, 0x06},
+	{0x3796, 0x7F},
+	{0x3798, 0xBF},
+	{0x3A01, 0x01},
+	{0x3A18, 0x7F},
+	{0x3A1A, 0x37},
+	{0x3A1C, 0x37},
+	{0x3A1E, 0xF7},
+	{0x3A1F, 0x00},
+	{0x3A20, 0x3F},
+	{0x3A22, 0x6F},
+	{0x3A24, 0x3F},
+	{0x3A26, 0x5F},
+	{0x3A28, 0x2F},
+	{REG_NULL, 0x00},
+};
+
+static const struct regval IMX464_hdr_2x_10bit_2688x1520_2lane_regs[] = {
+	{0x3000, 0x01},
+	{0x3002, 0x01},
+	{0x300C, 0x3B},
+	{0x300D, 0x2A},
+	{0x3034, 0xDC},
+	{0x3035, 0x05},
+	{0x3048, 0x01},
+	{0x3049, 0x01},
+	{0x304A, 0x04},
+	{0x304B, 0x04},
+	{0x304C, 0x13},
+	{0x304D, 0x00},
+	{0x3050, 0x00},
+	{0x3058, 0xF4},
+	{0x3059, 0x0A},
+	{0x3068, 0x3D},
+	{0x30BE, 0x5E},
+	{0x30E8, 0x14},
+	{0x3110, 0x02},
+	{0x314C, 0x29},//
+	{0x314D, 0x01},//
+	{0x315A, 0x06},
+	{0x3168, 0xA0},
+	{0x316A, 0x7E},
+	{0x319D, 0x00},
+	{0x319E, 0x02},//1188M
+	{0x31A1, 0x00},
+	{0x31D7, 0x01},
+	{0x3200, 0x10},
+	{0x3288, 0x22},
+	{0x328A, 0x02},
+	{0x328C, 0xA2},
+	{0x328E, 0x22},
+	{0x3415, 0x27},
+	{0x3418, 0x27},
+	{0x3428, 0xFE},
+	{0x349E, 0x6A},
+	{0x34A2, 0x9A},
+	{0x34A4, 0x8A},
+	{0x34A6, 0x8E},
+	{0x34AA, 0xD8},
+	{0x35BC, 0x00},
+	{0x35BE, 0xFF},
+	{0x35CC, 0x1B},
+	{0x35CD, 0x00},
+	{0x35CE, 0x2A},
+	{0x35CF, 0x00},
+	{0x35DC, 0x07},
+	{0x35DE, 0x1A},
+	{0x35DF, 0x00},
+	{0x35E4, 0x2B},
+	{0x35E5, 0x00},
+	{0x35E6, 0x07},
+	{0x35E7, 0x01},
+	{0x3648, 0x01},
+	{0x3678, 0x01},
+	{0x367C, 0x69},
+	{0x367E, 0x69},
+	{0x3680, 0x69},
+	{0x3682, 0x69},
+	{0x3718, 0x1C},
+	{0x371D, 0x05},
+	{0x375D, 0x11},
+	{0x375E, 0x43},
+	{0x375F, 0x76},
+	{0x3760, 0x07},
+	{0x3768, 0x1B},
+	{0x3769, 0x1B},
+	{0x376A, 0x1A},
+	{0x376B, 0x19},
+	{0x376C, 0x17},
+	{0x376D, 0x0F},
+	{0x376E, 0x0B},
+	{0x376F, 0x0B},
+	{0x3770, 0x0B},
+	{0x3776, 0x89},
+	{0x3777, 0x00},
+	{0x3778, 0xCA},
+	{0x3779, 0x00},
+	{0x377A, 0x45},
+	{0x377B, 0x01},
+	{0x377C, 0x56},
+	{0x377D, 0x02},
+	{0x377E, 0xFE},
+	{0x377F, 0x03},
+	{0x3780, 0xFE},
+	{0x3781, 0x05},
+	{0x3782, 0xFE},
+	{0x3783, 0x06},
+	{0x3784, 0x7F},
+	{0x3788, 0x1F},
+	{0x378A, 0xCA},
+	{0x378B, 0x00},
+	{0x378C, 0x45},
+	{0x378D, 0x01},
+	{0x378E, 0x56},
+	{0x378F, 0x02},
+	{0x3790, 0xFE},
+	{0x3791, 0x03},
+	{0x3792, 0xFE},
+	{0x3793, 0x05},
+	{0x3794, 0xFE},
+	{0x3795, 0x06},
+	{0x3796, 0x7F},
+	{0x3798, 0xBF},
+	{0x3A01, 0x01},
+	{0x3A18, 0x7F},
+	{0x3A1A, 0x37},
+	{0x3A1C, 0x37},
+	{0x3A1E, 0xF7},
+	{0x3A1F, 0x00},
+	{0x3A20, 0x3F},
+	{0x3A22, 0x6F},
+	{0x3A24, 0x3F},
+	{0x3A26, 0x5F},
+	{0x3A28, 0x2F},
+	{REG_NULL, 0x00},
+};
+
+static const struct regval IMX464_linear_10bit_2688x1520_regs[] = {
+	{0x3000, 0x01},
+	{0x3002, 0x01},
+	{0x300C, 0x5B},
+	{0x300D, 0x40},
+	{0x3030, 0xE4},
+	{0x3031, 0x0C},
+	{0x3034, 0xee},
+	{0x3035, 0x02},
+	{0x3048, 0x00},
+	{0x3049, 0x00},
+	{0x304A, 0x03},
+	{0x304B, 0x02},
+	{0x304C, 0x14},
+	{0x3050, 0x00},
+	{0x3058, 0x06},
+	{0x3059, 0x09},
+	{0x305C, 0x09},
+	{0x3060, 0x21},
+	{0x3061, 0x01},
+	{0x3068, 0xc9},
+	{0x306C, 0x56},
+	{0x306D, 0x09},
+	{0x30BE, 0x5E},
+	{0x30E8, 0x14},
+	{0x3110, 0x02},
+	{0x314C, 0xC0},
+	{0x315A, 0x06},
+	{0x316A, 0x7E},
+	{0x319D, 0x00},
+	{0x319E, 0x02},
+	{0x31A1, 0x00},
+	{0x31D7, 0x00},
+	{0x3200, 0x11},
 	{0x3288, 0x22},
 	{0x328A, 0x02},
 	{0x328C, 0xA2},
@@ -350,6 +835,10 @@
 	{0x3002, 0x01},
 	{0x300C, 0x5B},
 	{0x300D, 0x40},
+	{0x3030, 0x72},
+	{0x3031, 0x06},
+	{0x3034, 0xee},
+	{0x3035, 0x02},
 	{0x3048, 0x01},
 	{0x3049, 0x01},
 	{0x304A, 0x04},
@@ -358,7 +847,12 @@
 	{0x3050, 0x00},
 	{0x3058, 0x06},
 	{0x3059, 0x09},
+	{0x305C, 0x09},
+	{0x3060, 0x21},
+	{0x3061, 0x01},
 	{0x3068, 0x6D},
+	{0x306C, 0x56},
+	{0x306D, 0x09},
 	{0x30BE, 0x5E},
 	{0x30E8, 0x14},
 	{0x3110, 0x02},
@@ -498,6 +992,7 @@
 	{0x319E, 0x01},
 	{0x31A1, 0x00},
 	{0x31D7, 0x03},
+	{0x3200, 0x10},
 	{0x3288, 0x22},
 	{0x328A, 0x02},
 	{0x328C, 0xA2},
@@ -584,7 +1079,6 @@
 	{0x3A24, 0x4F},
 	{0x3A26, 0x5F},
 	{0x3A28, 0x3F},
-	{0x3200, 0x10},
 	{REG_NULL, 0x00},
 };
 
@@ -824,6 +1318,33 @@
 	{REG_NULL, 0x00},
 };
 
+static __maybe_unused const struct regval IMX464_interal_sync_master_start_regs[] = {
+	{0x3010, 0x07},
+	{0x31a1, 0x00},
+	{REG_NULL, 0x00},
+};
+static __maybe_unused const struct regval IMX464_interal_sync_master_stop_regs[] = {
+	{0x31a1, 0x0f},
+	{REG_NULL, 0x00},
+};
+
+static __maybe_unused const struct regval IMX464_external_sync_master_start_regs[] = {
+	{0x3010, 0x05},
+	{0x31a1, 0x03},
+	{0x31d9, 0x01},
+	{REG_NULL, 0x00},
+};
+static __maybe_unused const struct regval IMX464_external_sync_master_stop_regs[] = {
+	{0x31a1, 0x0f},
+	{REG_NULL, 0x00},
+};
+
+static __maybe_unused const struct regval IMX464_slave_start_regs[] = {
+	{0x3010, 0x05},
+	{0x31a1, 0x0f},
+	{REG_NULL, 0x00},
+};
+
 /*
  * The width and height must be configured to be
  * the same as the current output resolution of the sensor.
@@ -848,6 +1369,9 @@
 		.exp_def = 0x0906,
 		.hts_def = 0x05dc * 2,
 		.vts_def = 0x0ce4,
+		.mipi_freq_idx = 0,
+		.bpp = 10,
+		.mclk = 37125000,
 		.reg_list = IMX464_linear_10bit_2688x1520_regs,
 		.hdr_mode = NO_HDR,
 		.vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0,
@@ -863,6 +1387,9 @@
 		.exp_def = 0x03de,
 		.hts_def = 0x02ee * 4,
 		.vts_def = 0x0672 * 2,
+		.mipi_freq_idx = 1,
+		.bpp = 10,
+		.mclk = 37125000,
 		.reg_list = IMX464_hdr_2x_10bit_2688x1520_regs,
 		.hdr_mode = HDR_X2,
 		.vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_1,
@@ -889,12 +1416,57 @@
 		#else
 		.vts_def = 0x04D1 * 4,
 		#endif
+		.mipi_freq_idx = 1,
+		.bpp = 10,
+		.mclk = 37125000,
 		.reg_list = IMX464_hdr_3x_10bit_2688x1520_regs,
 		.hdr_mode = HDR_X3,
 		.vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_2,
 		.vc[PAD1] = V4L2_MBUS_CSI2_CHANNEL_1,//M->csi wr0
 		.vc[PAD2] = V4L2_MBUS_CSI2_CHANNEL_0,//L->csi wr1
 		.vc[PAD3] = V4L2_MBUS_CSI2_CHANNEL_2,//S->csi wr2
+	},
+};
+
+static const struct IMX464_mode supported_modes_2lane[] = {
+	{
+		.bus_fmt = MEDIA_BUS_FMT_SRGGB10_1X10,
+		.width = 2712,
+		.height = 1538,
+		.max_fps = {
+			.numerator = 10000,
+			.denominator = 300000,
+		},
+		.exp_def = 0x0600,
+		.hts_def = 0x05dc * 2,
+		.vts_def = 0x672,
+		.mipi_freq_idx = 0,
+		.bpp = 10,
+		.mclk = 24000000,
+		.reg_list = IMX464_linear_10bit_2688x1520_2lane_regs,
+		.hdr_mode = NO_HDR,
+		.vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0,
+	},
+	{
+		.bus_fmt = MEDIA_BUS_FMT_SRGGB10_1X10,
+		.width = 2712,
+		.height = 1538,
+		.max_fps = {
+			.numerator = 10000,
+			.denominator = 150000,
+		},
+		.exp_def = 0x0600,
+		.hts_def = 0x05dc * 4,
+		.vts_def = 0x0672 * 2,
+		.mipi_freq_idx = 0,
+		.bpp = 10,
+		.mclk = 24000000,
+		.reg_list = IMX464_hdr_2x_10bit_2688x1520_2lane_regs,
+		.hdr_mode = HDR_X2,
+		.vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_1,
+		.vc[PAD1] = V4L2_MBUS_CSI2_CHANNEL_0,//L->csi wr0
+		.vc[PAD2] = V4L2_MBUS_CSI2_CHANNEL_1,
+		.vc[PAD3] = V4L2_MBUS_CSI2_CHANNEL_1,//M->csi wr2
 	},
 };
 
@@ -997,15 +1569,15 @@
 	unsigned int i;
 
 	for (i = 0; i < IMX464->cfg_num; i++) {
-		dist = IMX464_get_reso_dist(&supported_modes[i], framefmt);
+		dist = IMX464_get_reso_dist(&IMX464->support_modes[i], framefmt);
 		if ((cur_best_fit_dist == -1 || dist <= cur_best_fit_dist) &&
-			supported_modes[i].bus_fmt == framefmt->code) {
+			IMX464->support_modes[i].bus_fmt == framefmt->code) {
 			cur_best_fit_dist = dist;
 			cur_best_fit = i;
 		}
 	}
 
-	return &supported_modes[cur_best_fit];
+	return &IMX464->support_modes[cur_best_fit];
 }
 
 static int IMX464_set_fmt(struct v4l2_subdev *sd,
@@ -1015,8 +1587,7 @@
 	struct IMX464 *IMX464 = to_IMX464(sd);
 	const struct IMX464_mode *mode;
 	s64 h_blank, vblank_def;
-	struct device *dev = &IMX464->client->dev;
-	int ret = 0;
+	u64 pixel_rate = 0;
 
 	mutex_lock(&IMX464->mutex);
 
@@ -1042,42 +1613,12 @@
 					 IMX464_VTS_MAX - mode->height,
 					 1, vblank_def);
 		IMX464->cur_vts = IMX464->cur_mode->vts_def;
-		if (mode->bus_fmt == MEDIA_BUS_FMT_SRGGB10_1X10) {
-			IMX464->cur_link_freq = 1;
-			if (mode->hdr_mode == NO_HDR) {
-				IMX464->cur_pixel_rate = IMX464_10BIT_LINEAR_PIXEL_RATE;
-				IMX464->cur_link_freq = 0;
-			} else if (mode->hdr_mode == HDR_X2)
-				IMX464->cur_pixel_rate = IMX464_10BIT_HDR2_PIXEL_RATE;
-			else if (mode->hdr_mode == HDR_X3)
-				IMX464->cur_pixel_rate = IMX464_10BIT_HDR3_PIXEL_RATE;
-
-			clk_disable_unprepare(IMX464->xvclk);
-			ret = clk_set_rate(IMX464->xvclk, IMX464_XVCLK_FREQ_37M);
-			if (ret < 0)
-				dev_err(dev, "Failed to set xvclk rate\n");
-			if (clk_get_rate(IMX464->xvclk) != IMX464_XVCLK_FREQ_37M)
-				dev_err(dev, "xvclk mismatched\n");
-			ret = clk_prepare_enable(IMX464->xvclk);
-			if (ret < 0)
-				dev_err(dev, "Failed to enable xvclk\n");
-		} else {
-			IMX464->cur_pixel_rate = IMX464_12BIT_PIXEL_RATE;
-			IMX464->cur_link_freq = 0;
-			clk_disable_unprepare(IMX464->xvclk);
-			ret = clk_set_rate(IMX464->xvclk, IMX464_XVCLK_FREQ_24M);
-			if (ret < 0)
-				dev_err(dev, "Failed to set xvclk rate\n");
-			if (clk_get_rate(IMX464->xvclk) != IMX464_XVCLK_FREQ_24M)
-				dev_err(dev, "xvclk mismatched\n");
-			ret = clk_prepare_enable(IMX464->xvclk);
-			if (ret < 0)
-				dev_err(dev, "Failed to enable xvclk\n");
-		}
+		pixel_rate = (u32)link_freq_menu_items[mode->mipi_freq_idx] / mode->bpp * 2 *
+			     IMX464->bus_cfg.bus.mipi_csi2.num_data_lanes;
 		__v4l2_ctrl_s_ctrl_int64(IMX464->pixel_rate,
-					 IMX464->cur_pixel_rate);
+					 pixel_rate);
 		__v4l2_ctrl_s_ctrl(IMX464->link_freq,
-				   IMX464->cur_link_freq);
+				   mode->mipi_freq_idx);
 	}
 
 	mutex_unlock(&IMX464->mutex);
@@ -1137,13 +1678,13 @@
 	if (fse->index >= IMX464->cfg_num)
 		return -EINVAL;
 
-	if (fse->code != supported_modes[fse->index].bus_fmt)
+	if (fse->code != IMX464->support_modes[fse->index].bus_fmt)
 		return -EINVAL;
 
-	fse->min_width  = supported_modes[fse->index].width;
-	fse->max_width  = supported_modes[fse->index].width;
-	fse->max_height = supported_modes[fse->index].height;
-	fse->min_height = supported_modes[fse->index].height;
+	fse->min_width  = IMX464->support_modes[fse->index].width;
+	fse->max_width  = IMX464->support_modes[fse->index].width;
+	fse->max_height = IMX464->support_modes[fse->index].height;
+	fse->min_height = IMX464->support_modes[fse->index].height;
 
 	return 0;
 }
@@ -1167,19 +1708,20 @@
 	struct IMX464 *IMX464 = to_IMX464(sd);
 	const struct IMX464_mode *mode = IMX464->cur_mode;
 	u32 val = 0;
+	u32 lane_num = IMX464->bus_cfg.bus.mipi_csi2.num_data_lanes;
 
 	if (mode->hdr_mode == NO_HDR) {
-		val = 1 << (IMX464_4LANES - 1) |
+		val = 1 << (lane_num - 1) |
 		V4L2_MBUS_CSI2_CHANNEL_0 |
 		V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
 	}
 	if (mode->hdr_mode == HDR_X2)
-		val = 1 << (IMX464_4LANES - 1) |
+		val = 1 << (lane_num - 1) |
 		V4L2_MBUS_CSI2_CHANNEL_0 |
 		V4L2_MBUS_CSI2_CONTINUOUS_CLOCK |
 		V4L2_MBUS_CSI2_CHANNEL_1;
 	if (mode->hdr_mode == HDR_X3)
-		val = 1 << (IMX464_4LANES - 1) |
+		val = 1 << (lane_num - 1) |
 		V4L2_MBUS_CSI2_CHANNEL_0 |
 		V4L2_MBUS_CSI2_CONTINUOUS_CLOCK |
 		V4L2_MBUS_CSI2_CHANNEL_1 |
@@ -1241,12 +1783,12 @@
 		l_exp_time = m_exp_time;
 		cg_mode = ae->middle_cg_mode;
 	}
-	if (!g_isHCG && cg_mode == GAIN_MODE_HCG) {
+	if (!IMX464->isHCG && cg_mode == GAIN_MODE_HCG) {
 		gain_switch = 0x01 | 0x100;
-		g_isHCG = true;
-	} else if (g_isHCG && cg_mode == GAIN_MODE_LCG) {
+		IMX464->isHCG = true;
+	} else if (IMX464->isHCG && cg_mode == GAIN_MODE_LCG) {
 		gain_switch = 0x00 | 0x100;
-		g_isHCG = false;
+		IMX464->isHCG = false;
 	}
 	ret = imx464_write_reg(client,
 		IMX464_GROUP_HOLD_REG,
@@ -1428,12 +1970,12 @@
 		//3 stagger
 		cg_mode = ae->long_cg_mode;
 	}
-	if (!g_isHCG && cg_mode == GAIN_MODE_HCG) {
+	if (!IMX464->isHCG && cg_mode == GAIN_MODE_HCG) {
 		gain_switch = 0x01 | 0x100;
-		g_isHCG = true;
-	} else if (g_isHCG && cg_mode == GAIN_MODE_LCG) {
+		IMX464->isHCG = true;
+	} else if (IMX464->isHCG && cg_mode == GAIN_MODE_LCG) {
 		gain_switch = 0x00 | 0x100;
-		g_isHCG = false;
+		IMX464->isHCG = false;
 	}
 
 	dev_dbg(&client->dev,
@@ -1670,12 +2212,12 @@
 	int cur_cg = *cg;
 	u32 gain_switch = 0;
 
-	if (g_isHCG && cur_cg == GAIN_MODE_LCG) {
+	if (IMX464->isHCG && cur_cg == GAIN_MODE_LCG) {
 		gain_switch = 0x00 | 0x100;
-		g_isHCG = false;
-	} else if (!g_isHCG && cur_cg == GAIN_MODE_HCG) {
+		IMX464->isHCG = false;
+	} else if (!IMX464->isHCG && cur_cg == GAIN_MODE_HCG) {
 		gain_switch = 0x01 | 0x100;
-		g_isHCG = true;
+		IMX464->isHCG = true;
 	}
 	ret = imx464_write_reg(client,
 			IMX464_GROUP_HOLD_REG,
@@ -1743,12 +2285,26 @@
 }
 #endif
 
+static int IMX464_get_channel_info(struct IMX464 *IMX464, struct rkmodule_channel_info *ch_info)
+{
+	if (ch_info->index >= PAD_MAX)
+		return -EINVAL;
+	ch_info->vc = IMX464->cur_mode->vc[ch_info->index];
+	ch_info->width = IMX464->cur_mode->width;
+	ch_info->height = IMX464->cur_mode->height;
+	ch_info->bus_fmt = IMX464->cur_mode->bus_fmt;
+	return 0;
+}
+
 static long IMX464_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 {
 	struct IMX464 *IMX464 = to_IMX464(sd);
 	struct rkmodule_hdr_cfg *hdr;
+	struct rkmodule_channel_info *ch_info;
 	u32 i, h, w, stream;
 	long ret = 0;
+	u64 pixel_rate = 0;
+	u32 *sync_mode = NULL;
 
 	switch (cmd) {
 	case PREISP_CMD_SET_HDRAE_EXP:
@@ -1770,10 +2326,10 @@
 		w = IMX464->cur_mode->width;
 		h = IMX464->cur_mode->height;
 		for (i = 0; i < IMX464->cfg_num; i++) {
-			if (w == supported_modes[i].width &&
-			    h == supported_modes[i].height &&
-			    supported_modes[i].hdr_mode == hdr->hdr_mode) {
-				IMX464->cur_mode = &supported_modes[i];
+			if (w == IMX464->support_modes[i].width &&
+			    h == IMX464->support_modes[i].height &&
+			    IMX464->support_modes[i].hdr_mode == hdr->hdr_mode) {
+				IMX464->cur_mode = &IMX464->support_modes[i];
 				break;
 			}
 		}
@@ -1790,16 +2346,13 @@
 				IMX464_VTS_MAX - IMX464->cur_mode->height,
 				1, h);
 			IMX464->cur_vts = IMX464->cur_mode->vts_def;
-			if (IMX464->cur_mode->bus_fmt == MEDIA_BUS_FMT_SRGGB10_1X10) {
-				if (IMX464->cur_mode->hdr_mode == NO_HDR)
-					IMX464->cur_pixel_rate = IMX464_10BIT_LINEAR_PIXEL_RATE;
-				else if (IMX464->cur_mode->hdr_mode == HDR_X2)
-					IMX464->cur_pixel_rate = IMX464_10BIT_HDR2_PIXEL_RATE;
-				else if (IMX464->cur_mode->hdr_mode == HDR_X3)
-					IMX464->cur_pixel_rate = IMX464_10BIT_HDR3_PIXEL_RATE;
-				__v4l2_ctrl_s_ctrl_int64(IMX464->pixel_rate,
-							 IMX464->cur_pixel_rate);
-			}
+			pixel_rate = (u32)link_freq_menu_items[IMX464->cur_mode->mipi_freq_idx] /
+					 IMX464->cur_mode->bpp * 2 *
+				     IMX464->bus_cfg.bus.mipi_csi2.num_data_lanes;
+			__v4l2_ctrl_s_ctrl_int64(IMX464->pixel_rate,
+						 pixel_rate);
+			__v4l2_ctrl_s_ctrl(IMX464->link_freq,
+					   IMX464->cur_mode->mipi_freq_idx);
 		}
 		break;
 	case RKMODULE_SET_CONVERSION_GAIN:
@@ -1809,16 +2362,25 @@
 
 		stream = *((u32 *)arg);
 
-		if (stream) {
+		if (stream)
 			ret = imx464_write_reg(IMX464->client, IMX464_REG_CTRL_MODE,
 				IMX464_REG_VALUE_08BIT, IMX464_MODE_STREAMING);
-			usleep_range(30000, 40000);
-			imx464_write_reg(IMX464->client, IMX464_REG_MARSTER_MODE,
-				IMX464_REG_VALUE_08BIT, 0);
-		} else {
+		else
 			ret = imx464_write_reg(IMX464->client, IMX464_REG_CTRL_MODE,
 				IMX464_REG_VALUE_08BIT, IMX464_MODE_SW_STANDBY);
-		}
+
+		break;
+	case RKMODULE_GET_CHANNEL_INFO:
+		ch_info = (struct rkmodule_channel_info *)arg;
+		ret = IMX464_get_channel_info(IMX464, ch_info);
+		break;
+	case RKMODULE_GET_SYNC_MODE:
+		sync_mode = (u32 *)arg;
+		*sync_mode = IMX464->sync_mode;
+		break;
+	case RKMODULE_SET_SYNC_MODE:
+		sync_mode = (u32 *)arg;
+		IMX464->sync_mode = *sync_mode;
 		break;
 	default:
 		ret = -ENOIOCTLCMD;
@@ -1837,9 +2399,11 @@
 	struct rkmodule_awb_cfg *cfg;
 	struct rkmodule_hdr_cfg *hdr;
 	struct preisp_hdrae_exp_s *hdrae;
+	struct rkmodule_channel_info *ch_info;
 	long ret;
 	u32 cg = 0;
 	u32  stream;
+	u32 sync_mode;
 
 	switch (cmd) {
 	case RKMODULE_GET_MODULE_INFO:
@@ -1850,8 +2414,11 @@
 		}
 
 		ret = IMX464_ioctl(sd, cmd, inf);
-		if (!ret)
+		if (!ret) {
 			ret = copy_to_user(up, inf, sizeof(*inf));
+			if (ret)
+				ret = -EFAULT;
+		}
 		kfree(inf);
 		break;
 	case RKMODULE_AWB_CFG:
@@ -1864,6 +2431,8 @@
 		ret = copy_from_user(cfg, up, sizeof(*cfg));
 		if (!ret)
 			ret = IMX464_ioctl(sd, cmd, cfg);
+		else
+			ret = -EFAULT;
 		kfree(cfg);
 		break;
 	case RKMODULE_GET_HDR_CFG:
@@ -1874,8 +2443,11 @@
 		}
 
 		ret = IMX464_ioctl(sd, cmd, hdr);
-		if (!ret)
+		if (!ret) {
 			ret = copy_to_user(up, hdr, sizeof(*hdr));
+			if (ret)
+				ret = -EFAULT;
+		}
 		kfree(hdr);
 		break;
 	case RKMODULE_SET_HDR_CFG:
@@ -1888,6 +2460,8 @@
 		ret = copy_from_user(hdr, up, sizeof(*hdr));
 		if (!ret)
 			ret = IMX464_ioctl(sd, cmd, hdr);
+		else
+			ret = -EFAULT;
 		kfree(hdr);
 		break;
 	case PREISP_CMD_SET_HDRAE_EXP:
@@ -1900,18 +2474,54 @@
 		ret = copy_from_user(hdrae, up, sizeof(*hdrae));
 		if (!ret)
 			ret = IMX464_ioctl(sd, cmd, hdrae);
+		else
+			ret = -EFAULT;
 		kfree(hdrae);
 		break;
 	case RKMODULE_SET_CONVERSION_GAIN:
 		ret = copy_from_user(&cg, up, sizeof(cg));
 		if (!ret)
 			ret = IMX464_ioctl(sd, cmd, &cg);
+		else
+			ret = -EFAULT;
 		break;
 	case RKMODULE_SET_QUICK_STREAM:
 		ret = copy_from_user(&stream, up, sizeof(u32));
 		if (!ret)
 			ret = IMX464_ioctl(sd, cmd, &stream);
+		else
+			ret = -EFAULT;
 
+		break;
+	case RKMODULE_GET_CHANNEL_INFO:
+		ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL);
+		if (!ch_info) {
+			ret = -ENOMEM;
+			return ret;
+		}
+
+		ret = IMX464_ioctl(sd, cmd, ch_info);
+		if (!ret) {
+			ret = copy_to_user(up, ch_info, sizeof(*ch_info));
+			if (ret)
+				ret = -EFAULT;
+		}
+		kfree(ch_info);
+		break;
+	case RKMODULE_GET_SYNC_MODE:
+		ret = IMX464_ioctl(sd, cmd, &sync_mode);
+		if (!ret) {
+			ret = copy_to_user(up, &sync_mode, sizeof(u32));
+			if (ret)
+				ret = -EFAULT;
+		}
+		break;
+	case RKMODULE_SET_SYNC_MODE:
+		ret = copy_from_user(&sync_mode, up, sizeof(u32));
+		if (!ret)
+			ret = IMX464_ioctl(sd, cmd, &sync_mode);
+		else
+			ret = -EFAULT;
 		break;
 	default:
 		ret = -ENOIOCTLCMD;
@@ -1922,17 +2532,20 @@
 }
 #endif
 
-static int IMX464_init_conversion_gain(struct IMX464 *IMX464)
+static int IMX464_init_conversion_gain(struct IMX464 *IMX464, bool isHCG)
 {
-	int ret = 0;
 	struct i2c_client *client = IMX464->client;
+	int ret = 0;
+	u32 val = 0;
 
+	if (isHCG)
+		val = 0x01;
+	else
+		val = 0;
 	ret = imx464_write_reg(client,
 		IMX464_GAIN_SWITCH_REG,
 		IMX464_REG_VALUE_08BIT,
-		0X00);
-	if (!ret)
-		g_isHCG = false;
+		val);
 	return ret;
 }
 
@@ -1943,7 +2556,7 @@
 	ret = IMX464_write_array(IMX464->client, IMX464->cur_mode->reg_list);
 	if (ret)
 		return ret;
-	ret = IMX464_init_conversion_gain(IMX464);
+	ret = IMX464_init_conversion_gain(IMX464, IMX464->isHCG);
 	if (ret)
 		return ret;
 	/* In case these controls are set before streaming */
@@ -1959,18 +2572,43 @@
 			return ret;
 		}
 	}
-	imx464_write_reg(IMX464->client, IMX464_REG_CTRL_MODE,
-				IMX464_REG_VALUE_08BIT, IMX464_MODE_STREAMING);
-	usleep_range(30000, 40000);
-	return imx464_write_reg(IMX464->client, IMX464_REG_MARSTER_MODE,
-				IMX464_REG_VALUE_08BIT, 0);
+
+	if (IMX464->sync_mode == EXTERNAL_MASTER_MODE) {
+		ret |= IMX464_write_array(IMX464->client, IMX464_external_sync_master_start_regs);
+		v4l2_err(&IMX464->subdev, "cur externam master mode\n");
+	} else if (IMX464->sync_mode == INTERNAL_MASTER_MODE) {
+		ret |= IMX464_write_array(IMX464->client, IMX464_interal_sync_master_start_regs);
+		v4l2_err(&IMX464->subdev, "cur intertal master\n");
+	} else if (IMX464->sync_mode == SLAVE_MODE) {
+		ret |= IMX464_write_array(IMX464->client, IMX464_slave_start_regs);
+		v4l2_err(&IMX464->subdev, "cur slave mode\n");
+	}
+	if (IMX464->sync_mode == NO_SYNC_MODE) {
+		ret = imx464_write_reg(IMX464->client, IMX464_REG_CTRL_MODE,
+					IMX464_REG_VALUE_08BIT, IMX464_MODE_STREAMING);
+		usleep_range(30000, 40000);
+		ret |= imx464_write_reg(IMX464->client, IMX464_REG_MARSTER_MODE,
+					IMX464_REG_VALUE_08BIT, 0);
+	} else {
+		ret |= imx464_write_reg(IMX464->client, IMX464_REG_MARSTER_MODE,
+					IMX464_REG_VALUE_08BIT, 0);
+	}
+	return ret;
 }
 
 static int __IMX464_stop_stream(struct IMX464 *IMX464)
 {
+	int ret = 0;
+
 	IMX464->has_init_exp = false;
-	return imx464_write_reg(IMX464->client, IMX464_REG_CTRL_MODE,
-				IMX464_REG_VALUE_08BIT, IMX464_MODE_SW_STANDBY);
+	ret = imx464_write_reg(IMX464->client, IMX464_REG_CTRL_MODE,
+			IMX464_REG_VALUE_08BIT, IMX464_MODE_SW_STANDBY);
+
+	if (IMX464->sync_mode == EXTERNAL_MASTER_MODE)
+		ret |= IMX464_write_array(IMX464->client, IMX464_external_sync_master_stop_regs);
+	else if (IMX464->sync_mode == INTERNAL_MASTER_MODE)
+		ret |= IMX464_write_array(IMX464->client, IMX464_interal_sync_master_stop_regs);
+	return ret;
 }
 
 static int IMX464_s_stream(struct v4l2_subdev *sd, int on)
@@ -2059,7 +2697,6 @@
 	int ret;
 	u32 delay_us;
 	struct device *dev = &IMX464->client->dev;
-	unsigned long mclk = 0;
 
 	if (!IS_ERR_OR_NULL(IMX464->pins_default)) {
 		ret = pinctrl_select_state(IMX464->pinctrl,
@@ -2067,15 +2704,14 @@
 		if (ret < 0)
 			dev_err(dev, "could not set pins\n");
 	}
-	if (IMX464->cur_mode->bus_fmt == MEDIA_BUS_FMT_SRGGB10_1X10)
-		mclk = IMX464_XVCLK_FREQ_37M;
-	else
-		mclk = IMX464_XVCLK_FREQ_24M;
-	ret = clk_set_rate(IMX464->xvclk, mclk);
+
+	ret = clk_set_rate(IMX464->xvclk, IMX464->cur_mode->mclk);
 	if (ret < 0)
 		dev_warn(dev, "Failed to set xvclk rate\n");
-	if (clk_get_rate(IMX464->xvclk) != mclk)
-		dev_warn(dev, "xvclk mismatched\n");
+	if (clk_get_rate(IMX464->xvclk) != IMX464->cur_mode->mclk)
+		dev_warn(dev, "xvclk mismatched, %lu\n", clk_get_rate(IMX464->xvclk));
+	else
+		IMX464->cur_mclk = IMX464->cur_mode->mclk;
 	ret = clk_prepare_enable(IMX464->xvclk);
 	if (ret < 0) {
 		dev_err(dev, "Failed to enable xvclk\n");
@@ -2089,7 +2725,7 @@
 		dev_err(dev, "Failed to enable regulators\n");
 		goto disable_clk;
 	}
-
+	usleep_range(15000, 16000);
 	if (!IS_ERR(IMX464->reset_gpio))
 		gpiod_set_value_cansleep(IMX464->reset_gpio, 1);
 
@@ -2126,6 +2762,7 @@
 			dev_err(dev, "could not set pins\n");
 	}
 	regulator_bulk_disable(IMX464_NUM_SUPPLIES, IMX464->supplies);
+	usleep_range(15000, 16000);
 }
 
 static int IMX464_runtime_resume(struct device *dev)
@@ -2154,7 +2791,7 @@
 	struct IMX464 *IMX464 = to_IMX464(sd);
 	struct v4l2_mbus_framefmt *try_fmt =
 				v4l2_subdev_get_try_format(sd, fh->pad, 0);
-	const struct IMX464_mode *def_mode = &supported_modes[0];
+	const struct IMX464_mode *def_mode = &IMX464->support_modes[0];
 
 	mutex_lock(&IMX464->mutex);
 	/* Initialize try_fmt */
@@ -2179,16 +2816,16 @@
 	if (fie->index >= IMX464->cfg_num)
 		return -EINVAL;
 
-	fie->code = supported_modes[fie->index].bus_fmt;
-	fie->width = supported_modes[fie->index].width;
-	fie->height = supported_modes[fie->index].height;
-	fie->interval = supported_modes[fie->index].max_fps;
-	fie->reserved[0] = supported_modes[fie->index].hdr_mode;
+	fie->code = IMX464->support_modes[fie->index].bus_fmt;
+	fie->width = IMX464->support_modes[fie->index].width;
+	fie->height = IMX464->support_modes[fie->index].height;
+	fie->interval = IMX464->support_modes[fie->index].max_fps;
+	fie->reserved[0] = IMX464->support_modes[fie->index].hdr_mode;
 	return 0;
 }
 
 #define CROP_START(SRC, DST) (((SRC) - (DST)) / 2 / 4 * 4)
-#define DST_WIDTH 2688
+#define DST_WIDTH 2560
 #define DST_HEIGHT 1520
 
 /*
@@ -2266,7 +2903,7 @@
 	u32 vts = 0;
 	int ret = 0;
 	u32 shr0 = 0;
-	//u32 flip = 0;
+	u32 flip = 0;
 
 	/* Propagate change of current control to all related controls */
 	switch (ctrl->id) {
@@ -2298,7 +2935,7 @@
 			ret |= imx464_write_reg(IMX464->client, IMX464_LF_EXPO_REG_H,
 					IMX464_REG_VALUE_08BIT,
 					IMX464_FETCH_EXP_H(shr0));
-			dev_err(&client->dev, "set exposure 0x%x\n",
+			dev_dbg(&client->dev, "set exposure 0x%x\n",
 				ctrl->val);
 		}
 		break;
@@ -2310,7 +2947,7 @@
 			ret |= imx464_write_reg(IMX464->client, IMX464_LF_GAIN_REG_L,
 					IMX464_REG_VALUE_08BIT,
 					IMX464_FETCH_GAIN_L(ctrl->val));
-			dev_err(&client->dev, "set analog gain 0x%x\n",
+			dev_dbg(&client->dev, "set analog gain 0x%x\n",
 				ctrl->val);
 		}
 		break;
@@ -2338,12 +2975,67 @@
 				       IMX464_REG_VALUE_08BIT,
 				       IMX464_FETCH_VTS_H(vts));
 
-		dev_err(&client->dev, "set vts 0x%x\n",
-			vts);
+		dev_dbg(&client->dev, "set vts 0x%x\n", vts);
 		break;
 	case V4L2_CID_HFLIP:
+		ret = imx464_write_reg(client,
+				       IMX464_GROUP_HOLD_REG,
+				       IMX464_REG_VALUE_08BIT,
+				       IMX464_GROUP_HOLD_START);
+		ret |= imx464_write_reg(IMX464->client, IMX464_HREVERSE_REG,
+				       IMX464_REG_VALUE_08BIT, !!ctrl->val);
+		ret |= imx464_write_reg(client,
+					IMX464_GROUP_HOLD_REG,
+					IMX464_REG_VALUE_08BIT,
+					IMX464_GROUP_HOLD_END);
 		break;
 	case V4L2_CID_VFLIP:
+		flip = ctrl->val;
+		ret = imx464_write_reg(client,
+				       IMX464_GROUP_HOLD_REG,
+				       IMX464_REG_VALUE_08BIT,
+				       IMX464_GROUP_HOLD_START);
+		ret |= imx464_write_reg(IMX464->client, IMX464_VREVERSE_REG,
+				IMX464_REG_VALUE_08BIT, !!flip);
+		if (flip) {
+			ret |= imx464_write_reg(IMX464->client, 0x3074,
+				IMX464_REG_VALUE_08BIT, 0x40);
+			ret |= imx464_write_reg(IMX464->client, 0x3075,
+				IMX464_REG_VALUE_08BIT, 0x06);
+			ret |= imx464_write_reg(IMX464->client, 0x3080,
+				IMX464_REG_VALUE_08BIT, 0xff);
+			ret |= imx464_write_reg(IMX464->client, 0x30ad,
+				IMX464_REG_VALUE_08BIT, 0x7e);
+			ret |= imx464_write_reg(IMX464->client, 0x30b6,
+				IMX464_REG_VALUE_08BIT, 0xff);
+			ret |= imx464_write_reg(IMX464->client, 0x30b7,
+				IMX464_REG_VALUE_08BIT, 0x01);
+			ret |= imx464_write_reg(IMX464->client, 0x30d8,
+				IMX464_REG_VALUE_08BIT, 0x45);
+			ret |= imx464_write_reg(IMX464->client, 0x3114,
+				IMX464_REG_VALUE_08BIT, 0x01);
+		} else {
+			ret |= imx464_write_reg(IMX464->client, 0x3074,
+				IMX464_REG_VALUE_08BIT, 0x3c);
+			ret |= imx464_write_reg(IMX464->client, 0x3075,
+				IMX464_REG_VALUE_08BIT, 0x00);
+			ret |= imx464_write_reg(IMX464->client, 0x3080,
+				IMX464_REG_VALUE_08BIT, 0x01);
+			ret |= imx464_write_reg(IMX464->client, 0x30ad,
+				IMX464_REG_VALUE_08BIT, 0x02);
+			ret |= imx464_write_reg(IMX464->client, 0x30b6,
+				IMX464_REG_VALUE_08BIT, 0x00);
+			ret |= imx464_write_reg(IMX464->client, 0x30b7,
+				IMX464_REG_VALUE_08BIT, 0x00);
+			ret |= imx464_write_reg(IMX464->client, 0x30d8,
+				IMX464_REG_VALUE_08BIT, 0x44);
+			ret |= imx464_write_reg(IMX464->client, 0x3114,
+				IMX464_REG_VALUE_08BIT, 0x02);
+		}
+		ret |= imx464_write_reg(client,
+					IMX464_GROUP_HOLD_REG,
+					IMX464_REG_VALUE_08BIT,
+					IMX464_GROUP_HOLD_END);
 		break;
 	default:
 		dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n",
@@ -2366,6 +3058,7 @@
 	struct v4l2_ctrl_handler *handler;
 	s64 exposure_max, vblank_def;
 	u32 h_blank;
+	u64 pixel_rate = 0;
 	int ret;
 
 	handler = &IMX464->ctrl_handler;
@@ -2378,28 +3071,13 @@
 	IMX464->link_freq = v4l2_ctrl_new_int_menu(handler,
 				NULL, V4L2_CID_LINK_FREQ,
 				1, 0, link_freq_menu_items);
-	if (IMX464->cur_mode->bus_fmt == MEDIA_BUS_FMT_SRGGB10_1X10) {
-		IMX464->cur_link_freq = 1;
-		if (IMX464->cur_mode->hdr_mode == NO_HDR) {
-			IMX464->cur_pixel_rate =
-				IMX464_10BIT_LINEAR_PIXEL_RATE;
-			IMX464->cur_link_freq = 0;
-		} else if (IMX464->cur_mode->hdr_mode == HDR_X2)
-			IMX464->cur_pixel_rate =
-				IMX464_10BIT_HDR2_PIXEL_RATE;
-		else if (IMX464->cur_mode->hdr_mode == HDR_X3)
-			IMX464->cur_pixel_rate =
-				IMX464_10BIT_HDR3_PIXEL_RATE;
-	} else {
-		IMX464->cur_link_freq = 0;
-		IMX464->cur_pixel_rate =
-				IMX464_12BIT_PIXEL_RATE;
-	}
 	__v4l2_ctrl_s_ctrl(IMX464->link_freq,
-			 IMX464->cur_link_freq);
+			 IMX464->cur_mode->mipi_freq_idx);
+	pixel_rate = (u32)link_freq_menu_items[mode->mipi_freq_idx] / mode->bpp * 2 *
+		     IMX464->bus_cfg.bus.mipi_csi2.num_data_lanes;
 	IMX464->pixel_rate = v4l2_ctrl_new_std(handler, NULL,
 		V4L2_CID_PIXEL_RATE, 0, IMX464_10BIT_HDR2_PIXEL_RATE,
-		1, IMX464->cur_pixel_rate);
+		1, pixel_rate);
 
 	h_blank = mode->hts_def - mode->width;
 	IMX464->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK,
@@ -2436,6 +3114,7 @@
 
 	IMX464->subdev.ctrl_handler = handler;
 	IMX464->has_init_exp = false;
+	IMX464->isHCG = false;
 
 	return 0;
 
@@ -2483,9 +3162,12 @@
 	struct device_node *node = dev->of_node;
 	struct IMX464 *IMX464;
 	struct v4l2_subdev *sd;
+	struct device_node *endpoint;
 	char facing[2];
 	int ret;
 	u32 i, hdr_mode = 0;
+	const char *sync_mode_name = NULL;
+
 
 	dev_info(dev, "driver version: %02x.%02x.%02x",
 		DRIVER_VERSION >> 16,
@@ -2509,6 +3191,20 @@
 		return -EINVAL;
 	}
 
+	ret = of_property_read_string(node, RKMODULE_CAMERA_SYNC_MODE,
+				      &sync_mode_name);
+	if (ret) {
+		IMX464->sync_mode = NO_SYNC_MODE;
+		dev_err(dev, "could not get sync mode!\n");
+	} else {
+		if (strcmp(sync_mode_name, RKMODULE_EXTERNAL_MASTER_MODE) == 0)
+			IMX464->sync_mode = EXTERNAL_MASTER_MODE;
+		else if (strcmp(sync_mode_name, RKMODULE_INTERNAL_MASTER_MODE) == 0)
+			IMX464->sync_mode = INTERNAL_MASTER_MODE;
+		else if (strcmp(sync_mode_name, RKMODULE_SLAVE_MODE) == 0)
+			IMX464->sync_mode = SLAVE_MODE;
+	}
+
 	ret = of_property_read_u32(node, OF_CAMERA_HDR_MODE,
 			&hdr_mode);
 	if (ret) {
@@ -2516,15 +3212,32 @@
 		dev_warn(dev, " Get hdr mode failed! no hdr default\n");
 	}
 	IMX464->client = client;
+	endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+	if (!endpoint) {
+		dev_err(dev, "Failed to get endpoint\n");
+		return -EINVAL;
+	}
+	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(endpoint),
+		&IMX464->bus_cfg);
+	if (ret) {
+		dev_err(dev, "Failed to get bus cfg\n");
+		return ret;
+	}
+	if (IMX464->bus_cfg.bus.mipi_csi2.num_data_lanes == 4) {
+		IMX464->support_modes = supported_modes;
+		IMX464->cfg_num = ARRAY_SIZE(supported_modes);
+	} else {
+		IMX464->support_modes = supported_modes_2lane;
+		IMX464->cfg_num = ARRAY_SIZE(supported_modes_2lane);
+	}
 
-	IMX464->cfg_num = ARRAY_SIZE(supported_modes);
 	for (i = 0; i < IMX464->cfg_num; i++) {
-		if (hdr_mode == supported_modes[i].hdr_mode) {
-			IMX464->cur_mode = &supported_modes[i];
+		if (hdr_mode == IMX464->support_modes[i].hdr_mode) {
+			IMX464->cur_mode = &IMX464->support_modes[i];
 			break;
 		}
 	}
-	IMX464->cur_mode = &supported_modes[0];
+	IMX464->cur_mode = &IMX464->support_modes[0];
 	IMX464->xvclk = devm_clk_get(dev, "xvclk");
 	if (IS_ERR(IMX464->xvclk)) {
 		dev_err(dev, "Failed to get xvclk\n");
@@ -2610,7 +3323,6 @@
 	pm_runtime_enable(dev);
 	pm_runtime_idle(dev);
 
-	g_isHCG = false;
 #ifdef USED_SYS_DEBUG
 	add_sysfs_interfaces(dev);
 #endif
@@ -2655,6 +3367,7 @@
 #if IS_ENABLED(CONFIG_OF)
 static const struct of_device_id IMX464_of_match[] = {
 	{ .compatible = "sony,IMX464" },
+	{ .compatible = "sony,imx464" },
 	{},
 };
 MODULE_DEVICE_TABLE(of, IMX464_of_match);
@@ -2662,6 +3375,7 @@
 
 static const struct i2c_device_id IMX464_match_id[] = {
 	{ "sony,IMX464", 0 },
+	{ "sony,imx464", 0 },
 	{ },
 };
 

--
Gitblit v1.6.2