Browse Source

更加sc2210相关资料。重点更新set gain函数

alex 11 months ago
parent
commit
69a6482c52
6 changed files with 4035 additions and 20 deletions
  1. BIN
      SC2210_数据手册_V0.8.pdf
  2. 137 20
      sc2210.c
  3. 1751 0
      sc2210.c.bak
  4. 372 0
      sc2210_0x8.7.json
  5. 649 0
      sc2210_mipi.c
  6. 1126 0
      sc2210_mipi.h

BIN
SC2210_数据手册_V0.8.pdf


+ 137 - 20
sc2210.c

@@ -5,6 +5,7 @@
  * Copyright (C) 2022 Rockchip Electronics Co., Ltd.
  * Copyright (C) 2022 Rockchip Electronics Co., Ltd.
  *
  *
  * V0.0X01.0X01 first version
  * V0.0X01.0X01 first version
+ * 20240810 : 根据SC2210数据手册修改了增益设置函数
  */
  */
 
 
 //#define DEBUG
 //#define DEBUG
@@ -56,17 +57,22 @@
 #define sc2210_REG_EXPOSURE_H		0x3e00
 #define sc2210_REG_EXPOSURE_H		0x3e00
 #define sc2210_REG_EXPOSURE_M		0x3e01
 #define sc2210_REG_EXPOSURE_M		0x3e01
 #define sc2210_REG_EXPOSURE_L		0x3e02
 #define sc2210_REG_EXPOSURE_L		0x3e02
+//1
 #define	sc2210_EXPOSURE_MIN		1
 #define	sc2210_EXPOSURE_MIN		1
 #define	sc2210_EXPOSURE_STEP		1
 #define	sc2210_EXPOSURE_STEP		1
 #define sc2210_VTS_MAX			0x7fff
 #define sc2210_VTS_MAX			0x7fff
 
 
 #define sc2210_REG_DIG_GAIN		0x3e06
 #define sc2210_REG_DIG_GAIN		0x3e06
 #define sc2210_REG_DIG_FINE_GAIN	0x3e07
 #define sc2210_REG_DIG_FINE_GAIN	0x3e07
-#define sc2210_REG_ANA_GAIN		0x3e09
-#define sc2210_GAIN_MIN			0x0020
-#define sc2210_GAIN_MAX			(4096)	//32*4*32
+#define sc2210_REG_ANA_GAIN		0x3e08
+#define sc2210_REG_ANA_FINE_GAIN   0x3e09
+
+//agian  0x3F 0x7F  54.07
+//dgain  0x0F  0xFC  31.5 
+#define sc2210_GAIN_MIN			(1000) //1x*1000
+#define sc2210_GAIN_MAX			(1703205)	// 54.07*31.5 *1000
 #define sc2210_GAIN_STEP		1
 #define sc2210_GAIN_STEP		1
-#define sc2210_GAIN_DEFAULT		0x80
+#define sc2210_GAIN_DEFAULT		(32000) // 32x*1000
 
 
 
 
 //#define sc2210_REG_GROUP_HOLD		0x3812
 //#define sc2210_REG_GROUP_HOLD		0x3812
@@ -208,9 +214,9 @@ static const struct regval sc2210_linear_10_1920x1080_30fps_regs[] = {
 {0x3205,0x8b},
 {0x3205,0x8b},
 {0x3206,0x04},
 {0x3206,0x04},
 {0x3207,0x43},
 {0x3207,0x43},
-{0x320c,0x04},
+{0x320c,0x04}, //0x44c=1100 应该为 1920/2=960?
 {0x320d,0x4c},
 {0x320d,0x4c},
-{0x320e,0x05},    //sc2210_REG_VTS_H
+{0x320e,0x05},//sc2210_REG_VTS_H
 {0x320f,0x46},//25fps  sc2210_REG_VTS_L
 {0x320f,0x46},//25fps  sc2210_REG_VTS_L
 {0x3211,0x04}, //输出窗口列起始位置
 {0x3211,0x04}, //输出窗口列起始位置
 {0x3213,0x04}, //输出窗口行起始位置
 {0x3213,0x04}, //输出窗口行起始位置
@@ -418,8 +424,8 @@ static const struct regval sc2210_linear_10_1920x1080_30fps_regs[] = {
 {0x39eb,0x4f},
 {0x39eb,0x4f},
 {0x39ec,0x08},
 {0x39ec,0x08},
 {0x39ed,0x00},
 {0x39ed,0x00},
-{0x3e01,0x46},
-{0x3e02,0x10},
+{0x3e01,0x05},
+{0x3e02,0x43},
 {0x3e09,0x40},
 {0x3e09,0x40},
 {0x3e14,0x31},
 {0x3e14,0x31},
 {0x3e1b,0x3a},
 {0x3e1b,0x3a},
@@ -447,13 +453,14 @@ static const struct sc2210_mode supported_modes[] = {
 		.width = 1920,
 		.width = 1920,
 		.height = 1080,
 		.height = 1080,
 		.max_fps = {
 		.max_fps = {
-			.numerator = 10000,
-			.denominator = 250000,
+			.numerator = 1,
+			.denominator = 25,
 		},
 		},
 		.exp_def = 0x80,  //0x080
 		.exp_def = 0x80,  //0x080
 		.hts_def = (1100),
 		.hts_def = (1100),
 		.vts_def = (0x546), //0x546
 		.vts_def = (0x546), //0x546
 		.bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10,  //MEDIA_BUS_FMT_SBGGR10_1X10
 		.bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10,  //MEDIA_BUS_FMT_SBGGR10_1X10
+	//	.bus_fmt = MEDIA_BUS_FMT_Y10_1X10,
 		.reg_list = sc2210_linear_10_1920x1080_30fps_regs,
 		.reg_list = sc2210_linear_10_1920x1080_30fps_regs,
 		.hdr_mode = NO_HDR,
 		.hdr_mode = NO_HDR,
 		.xvclk_freq = 27000000,
 		.xvclk_freq = 27000000,
@@ -468,7 +475,6 @@ static const s64 link_freq_menu_items[] = {
 
 
 static const char * const sc2210_test_pattern_menu[] = {
 static const char * const sc2210_test_pattern_menu[] = {
 	"Disabled",
 	"Disabled",
-	"Vertical Color Bar Type 1",
 	"Vertical Color Bar Type 2",
 	"Vertical Color Bar Type 2",
 	"Vertical Color Bar Type 3",
 	"Vertical Color Bar Type 3",
 	"Vertical Color Bar Type 4",
 	"Vertical Color Bar Type 4",
@@ -485,6 +491,8 @@ static int sc2210_write_reg(struct i2c_client *client, u16 reg,
 
 
 	if (len > 4)
 	if (len > 4)
 		return -EINVAL;
 		return -EINVAL;
+		
+	udelay(10*1000); //debug add
 
 
 
 
 	buf[0] = reg >> 8;
 	buf[0] = reg >> 8;
@@ -500,7 +508,7 @@ static int sc2210_write_reg(struct i2c_client *client, u16 reg,
 
 
 	if (i2c_master_send(client, buf, len + 2) != len + 2)
 	if (i2c_master_send(client, buf, len + 2) != len + 2)
 	{
 	{
-		printk("i2c_master_send error\n");
+		printk("isc2210_write_reg i2c_master_send error addr=0x%X val=0x%X len=%d \n",reg,val,len);
 		return -EIO;
 		return -EIO;
 	}
 	}
 	
 	
@@ -519,6 +527,8 @@ static int isc2210_write_reg(struct i2c_client *client, u16 reg,
 
 
 	if (len > 4)
 	if (len > 4)
 		return -EINVAL;
 		return -EINVAL;
+		
+	udelay(10*1000); //debug add
 
 
 
 
 	buf[0] = reg >> 8;
 	buf[0] = reg >> 8;
@@ -534,7 +544,7 @@ static int isc2210_write_reg(struct i2c_client *client, u16 reg,
 
 
 	if (i2c_master_send(client, buf, len + 2) != len + 2)
 	if (i2c_master_send(client, buf, len + 2) != len + 2)
 	{
 	{
-		printk("i2c_master_send error\n");
+		printk("isc2210_write_reg i2c_master_send error addr=0x%X val=0x%X len=%d \n",reg,val,len);
 		return -EIO;
 		return -EIO;
 	}
 	}
 	
 	
@@ -547,14 +557,19 @@ static int isc2210_write_reg(struct i2c_client *client, u16 reg,
 static int sc2210_write_array(struct i2c_client *client,
 static int sc2210_write_array(struct i2c_client *client,
 			       const struct regval *regs)
 			       const struct regval *regs)
 {
 {
-	u32 i;
+	u32 i,j;
 	int ret = 0;
 	int ret = 0;
 
 
-	for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++)
-		ret = isc2210_write_reg(client, regs[i].addr,
+	for(j=0;j<10;j++)
+	{
+		for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++)
+			ret = isc2210_write_reg(client, regs[i].addr,
 					sc2210_REG_VALUE_08BIT, regs[i].val);
 					sc2210_REG_VALUE_08BIT, regs[i].val);
 
 
-	printk("sc2210_write_array! i=%d \n",i);
+		printk("sc2210_write_array! i=%d \n",i);
+		if(i==257)
+			break;
+	}
 
 
 	return ret;
 	return ret;
 }
 }
@@ -593,6 +608,103 @@ static int sc2210_read_reg(struct i2c_client *client, u16 reg, unsigned int len,
 
 
 	return 0;
 	return 0;
 }
 }
+#if 1
+//static int sc4238_get_gain_reg(struct sc4238 *sc4238, u32 total_gain,
+//			       u32 *again_coarse_reg, u32 *again_fine_reg,
+//			       u32 *dgain_coarse_reg, u32 *dgain_fine_reg)
+static int sc2210_set_gain_reg(struct sc2210 *sc2210, u32 gain)				   
+{
+	u32 again_coarse_reg, u32 again_fine_reg;
+	u32 dgain_coarse_reg, u32 dgain_fine_reg;
+	float fgain,again, dgain;
+
+
+	//agian  0x3F 0x7F  54.07
+	//dgain  0x0F  0xFC  31.5 
+//	if (total_gain > 32004) {
+//		dev_err(&sc4238->client->dev,
+//			"total_gain max is 15.875*31.5*64, current total_gain is %d\n",
+	//		total_gain);
+//		return -EINVAL;
+//	}
+	fgain = (float)gain/1000.0;
+
+
+	if (fgain > 54.07) {
+		again = 54.07;
+		dgain = fgain /54.07;
+	} else {
+		again = fgain;
+		dgain = 1.0;
+	}
+
+	//数值比数据手册大一点0.0001,为了解决浮点数不能相等的问题
+	if (again < 1.9841) {
+		again_fine_reg = 0x40 + (u32)((again-1.0)*(1/64.0));
+		again_coarse_reg = 0x03;
+	} else if (again < 3.3751) {
+		again_fine_reg = 0x40 + (u32)((again-2.0)*(1/32.0));
+		again_coarse_reg = 0x07;
+	} else if (again < 6.7591) { 
+		again_fine_reg = 0x40 + (u32)((again-3.406)*(0.053));
+		again_coarse_reg = 0x23;
+	} else if (again < 13.5181) {
+		again_fine_reg = 0x40 + (u32)((again-6.812)*(0.106));
+		again_coarse_reg = 0x27;
+	} else if (again < 27.0351) { 
+		again_fine_reg = 0x40 + (u32)((again-13.624)*(0.213));
+		again_coarse_reg = 0x2F;
+	} else if (again < (54.0701)) { 
+		again_fine_reg = 0x40 + (u32)((again-27.248)*(0.426));
+		again_coarse_reg = 0x3F;
+	} 
+	
+
+	if (dgain < 1.9691) { 
+		dgain_fine_reg = 0x80 + (u32)((dgain-1.0)*(0.125/4/4));
+		dgain_coarse_reg = 0x00;
+	} else if (dgain < 3.9381) { 
+		dgain_fine_reg = 0x80 + (u32)((dgain-2.0)*(0.125/2/4));
+		dgain_coarse_reg = 0x01;
+	} else if (dgain < 7.8751) { 
+		dgain_fine_reg = 0x80 + (u32)((dgain-4.0)*(0.125/4));
+		dgain_coarse_reg = 0x03;
+	} else if (dgain < 15.7501) { 
+		dgain_fine_reg =  0x80 + (u32)((dgain-8.0)*(0.25/4));
+		dgain_coarse_reg = 0x07;
+	} else if (dgain < 31.5001) { 
+		dgain_fine_reg =  0x80 + (u32)((dgain-16.0)*(0.5/4));
+		dgain_coarse_reg = 0x0F;
+	} 
+
+	dev_dbg(&sc2210->client->dev,
+		"total_gain 0x%x again_coarse 0x%x, again_fine 0x%x, dgain_coarse 0x%x, dgain_fine 0x%x\n",
+		gain, again_coarse_reg, again_fine_reg, dgain_coarse_reg, dgain_fine_reg);
+
+	printk("sc2210_set_gain_reg total_gain 0x%x again_coarse 0x%x, again_fine 0x%x, dgain_coarse 0x%x, dgain_fine 0x%x\n",
+		gain, again_coarse_reg, again_fine_reg, dgain_coarse_reg, dgain_fine_reg);
+
+	ret = sc2210_write_reg(sc2210->client,
+				sc2210_REG_DIG_GAIN,
+				sc2210_REG_VALUE_08BIT,
+				dgain_coarse_reg);
+	ret |= sc2210_write_reg(sc2210->client,
+				 sc2210_REG_DIG_FINE_GAIN,
+				 sc2210_REG_VALUE_08BIT,
+				 dgain_fine_reg);
+	ret |= sc2210_write_reg(sc2210->client,
+				 sc2210_REG_ANA_GAIN,
+				 sc2210_REG_VALUE_08BIT,
+				 again_coarse_reg);
+	ret |= sc2210_write_reg(sc2210->client,
+				 sc2210_REG_ANA_FINE_GAIN,
+				 sc2210_REG_VALUE_08BIT,
+				 again_fine_reg);
+
+	return ret;
+}
+
+#else
 
 
 static int sc2210_set_gain_reg(struct sc2210 *sc2210, u32 gain)
 static int sc2210_set_gain_reg(struct sc2210 *sc2210, u32 gain)
 {
 {
@@ -600,7 +712,7 @@ static int sc2210_set_gain_reg(struct sc2210 *sc2210, u32 gain)
 	u32 gain_factor;
 	u32 gain_factor;
 	int ret = 0;
 	int ret = 0;
 
 
-	return ret; //debug ws
+//	return ret; //debug ws
 
 
 	gain_factor = gain * 1000 / 32;
 	gain_factor = gain * 1000 / 32;
 	if (gain_factor < 1000) {
 	if (gain_factor < 1000) {
@@ -644,6 +756,9 @@ static int sc2210_set_gain_reg(struct sc2210 *sc2210, u32 gain)
 	dev_dbg(&sc2210->client->dev,
 	dev_dbg(&sc2210->client->dev,
 		"total_gain: 0x%x, d_gain: 0x%x, d_fine_gain: 0x%x, c_gain: 0x%x\n",
 		"total_gain: 0x%x, d_gain: 0x%x, d_fine_gain: 0x%x, c_gain: 0x%x\n",
 		gain, coarse_dgain, fine_dgain, coarse_again);
 		gain, coarse_dgain, fine_dgain, coarse_again);
+		
+	printk("sc2210_set_gain_reg total_gain: 0x%x, d_gain: 0x%x, d_fine_gain: 0x%x, c_gain: 0x%x\n",
+		gain, coarse_dgain, fine_dgain, coarse_again);
 
 
 	ret = sc2210_write_reg(sc2210->client,
 	ret = sc2210_write_reg(sc2210->client,
 				sc2210_REG_DIG_GAIN,
 				sc2210_REG_DIG_GAIN,
@@ -660,7 +775,7 @@ static int sc2210_set_gain_reg(struct sc2210 *sc2210, u32 gain)
 
 
 	return ret;
 	return ret;
 }
 }
-
+#endif
 static int sc2210_get_reso_dist(const struct sc2210_mode *mode,
 static int sc2210_get_reso_dist(const struct sc2210_mode *mode,
 				 struct v4l2_mbus_framefmt *framefmt)
 				 struct v4l2_mbus_framefmt *framefmt)
 {
 {
@@ -1347,7 +1462,9 @@ static int sc2210_set_ctrl(struct v4l2_ctrl *ctrl)
 	switch (ctrl->id) {
 	switch (ctrl->id) {
 	case V4L2_CID_EXPOSURE:
 	case V4L2_CID_EXPOSURE:
 		dev_dbg(&client->dev, "set exposure 0x%x\n", ctrl->val);
 		dev_dbg(&client->dev, "set exposure 0x%x\n", ctrl->val);
+		printk("set exposure 0x%x\n", ctrl->val);
 		if (sc2210->cur_mode->hdr_mode == NO_HDR) {
 		if (sc2210->cur_mode->hdr_mode == NO_HDR) {
+	//	if (0) {
 			val = ctrl->val;
 			val = ctrl->val;
 // 			// /* 4 least significant bits of expsoure are fractional part */
 // 			// /* 4 least significant bits of expsoure are fractional part */
  			ret = sc2210_write_reg(sc2210->client,
  			ret = sc2210_write_reg(sc2210->client,
@@ -1412,7 +1529,7 @@ static int sc2210_set_ctrl(struct v4l2_ctrl *ctrl)
 }
 }
 
 
 static const struct v4l2_ctrl_ops sc2210_ctrl_ops = {
 static const struct v4l2_ctrl_ops sc2210_ctrl_ops = {
-	.s_ctrl = sc2210_set_ctrl,
+	.s_ctrl = sc2210_set_ctrl
 };
 };
 
 
 static int sc2210_initialize_controls(struct sc2210 *sc2210)
 static int sc2210_initialize_controls(struct sc2210 *sc2210)

+ 1751 - 0
sc2210.c.bak

@@ -0,0 +1,1751 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * sc2210 driver
+ *
+ * Copyright (C) 2022 Rockchip Electronics Co., Ltd.
+ *
+ * V0.0X01.0X01 first version
+ */
+
+//#define DEBUG
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/sysfs.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/rk-camera-module.h>
+#include <linux/rk-preisp.h>
+#include <media/media-entity.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+#include <linux/pinctrl/consumer.h>
+#include "../platform/rockchip/isp/rkisp_tb_helper.h"
+
+#define DRIVER_VERSION			KERNEL_VERSION(0, 0x01, 0x01)
+
+#ifndef V4L2_CID_DIGITAL_GAIN
+#define V4L2_CID_DIGITAL_GAIN		V4L2_CID_GAIN
+#endif
+
+#define sc2210_LANES			(2LL)   
+#define sc2210_BITS_PER_SAMPLE		(10LL)
+//#define sc2210_LINK_FREQ_405		432000000LL  
+//186000000
+//202500000LL
+//#define sc2210_LINK_FREQ_405		(200000000LL) 
+// 798M : can not get any video
+// 250M : 
+#define sc2210_LINK_FREQ_405		(200000000LL) 
+
+#define PIXEL_RATE_WITH_405M_10BIT	(sc2210_LINK_FREQ_405 * 2LL * sc2210_LANES / sc2210_BITS_PER_SAMPLE)
+
+#define CHIP_ID				0x2210
+#define sc2210_REG_CHIP_ID		0x3107
+
+#define sc2210_REG_CTRL_MODE		0x0100
+#define sc2210_MODE_SW_STANDBY		0x0
+#define sc2210_MODE_STREAMING		BIT(0)
+
+#define sc2210_REG_EXPOSURE_H		0x3e00
+#define sc2210_REG_EXPOSURE_M		0x3e01
+#define sc2210_REG_EXPOSURE_L		0x3e02
+#define	sc2210_EXPOSURE_MIN		1
+#define	sc2210_EXPOSURE_STEP		1
+#define sc2210_VTS_MAX			0x7fff
+
+#define sc2210_REG_DIG_GAIN		0x3e06
+#define sc2210_REG_DIG_FINE_GAIN	0x3e07
+#define sc2210_REG_ANA_GAIN		0x3e09
+#define sc2210_GAIN_MIN			0x0020
+#define sc2210_GAIN_MAX			(4096)	//32*4*32
+#define sc2210_GAIN_STEP		1
+#define sc2210_GAIN_DEFAULT		0x80
+
+
+//#define sc2210_REG_GROUP_HOLD		0x3812
+//#define sc2210_GROUP_HOLD_START		0x00
+//#define sc2210_GROUP_HOLD_END		0x30
+
+#define sc2210_REG_TEST_PATTERN		0x4501
+#define sc2210_TEST_PATTERN_BIT_MASK	BIT(3)
+
+#define sc2210_REG_VTS_H		0x320e
+#define sc2210_REG_VTS_L		0x320f
+
+#define sc2210_FLIP_MIRROR_REG		0x3221
+
+#define sc2210_FETCH_EXP_H(VAL)		(((VAL) >> 12) & 0xF)
+#define sc2210_FETCH_EXP_M(VAL)		(((VAL) >> 4) & 0xFF)
+#define sc2210_FETCH_EXP_L(VAL)		(((VAL) & 0xF) << 4)
+
+#define sc2210_FETCH_AGAIN_H(VAL)	(((VAL) >> 8) & 0x03)
+#define sc2210_FETCH_AGAIN_L(VAL)	((VAL) & 0xFF)
+
+#define sc2210_FETCH_MIRROR(VAL, ENABLE)	(ENABLE ? VAL | 0x06 : VAL & 0xf9)
+#define sc2210_FETCH_FLIP(VAL, ENABLE)		(ENABLE ? VAL | 0x60 : VAL & 0x9f)
+
+#define REG_DELAY			0xFFFE
+#define REG_NULL			0xFFFF
+
+#define sc2210_REG_VALUE_08BIT		1
+#define sc2210_REG_VALUE_16BIT		2
+#define sc2210_REG_VALUE_24BIT		3
+
+#define OF_CAMERA_PINCTRL_STATE_DEFAULT	"rockchip,camera_default"
+#define OF_CAMERA_PINCTRL_STATE_SLEEP	"rockchip,camera_sleep"
+#define sc2210_NAME			"sc2210"
+
+static const char * const sc2210_supply_names[] = {
+	"avdd",		/* Analog power */
+	"dovdd",	/* Digital I/O power */
+	"dvdd",		/* Digital core power */
+};
+
+#define sc2210_NUM_SUPPLIES ARRAY_SIZE(sc2210_supply_names)
+
+struct regval {
+	u16 addr;
+	u8 val;
+};
+
+struct sc2210_mode {
+	u32 bus_fmt;
+	u32 width;
+	u32 height;
+	struct v4l2_fract max_fps;
+	u32 hts_def;
+	u32 vts_def;
+	u32 exp_def;
+	const struct regval *reg_list;
+	u32 hdr_mode;
+	u32 xvclk_freq;
+	u32 link_freq_idx;
+	u32 vc[PAD_MAX];
+};
+
+struct sc2210 {
+	struct i2c_client	*client;
+	struct clk		*xvclk;
+	struct gpio_desc	*reset_gpio;
+	struct regulator_bulk_data supplies[sc2210_NUM_SUPPLIES];
+
+	struct pinctrl		*pinctrl;
+	struct pinctrl_state	*pins_default;
+	struct pinctrl_state	*pins_sleep;
+
+	struct v4l2_subdev	subdev;
+	struct media_pad	pad;
+	struct v4l2_ctrl_handler ctrl_handler;
+	struct v4l2_ctrl	*exposure;
+	struct v4l2_ctrl	*anal_gain;
+	struct v4l2_ctrl	*digi_gain;
+	struct v4l2_ctrl	*hblank;
+	struct v4l2_ctrl	*vblank;
+	struct v4l2_ctrl	*pixel_rate;
+	struct v4l2_ctrl	*link_freq;
+	struct v4l2_ctrl	*test_pattern;
+	struct mutex		mutex;
+	bool			streaming;
+	bool			power_on;
+	const struct sc2210_mode *cur_mode;
+	u32			module_index;
+	const char		*module_facing;
+	const char		*module_name;
+	const char		*len_name;
+	u32			cur_vts;
+	bool			has_init_exp;
+	bool			is_thunderboot;
+	bool			is_first_streamoff;
+	struct preisp_hdrae_exp_s init_hdrae_exp;
+};
+
+#define to_sc2210(sd) container_of(sd, struct sc2210, subdev)
+
+/*
+ * Xclk 24Mhz
+ */
+static const struct regval sc2210_global_regs[] = {
+	{REG_NULL, 0x00},
+};
+
+/*
+
+1080p_25p
+ */
+static const struct regval sc2210_linear_10_1920x1080_30fps_regs[] = {
+{0x0100,0x00},
+{0x0100,0x00},
+{0x0100,0x00},
+{0x0103,0x01}, //reset
+{0x0100,0x00},
+{0x0100,0x00},
+{0x0100,0x00},
+{0x0100,0x00},
+{0x0100,0x00},
+{0x36e9,0x80},
+{0x36f9,0x80},
+{0x3001,0x07},
+{0x3002,0xc0},
+{0x300a,0x2c},
+{0x300f,0x00},
+{0x3018,0x33},
+{0x3019,0x0c},
+{0x301f,0x47},
+{0x3031,0x0a},
+{0x3033,0x20},
+{0x3038,0x22},
+{0x3106,0x81},
+{0x3201,0x04},
+{0x3203,0x04},
+{0x3204,0x07},
+{0x3205,0x8b},
+{0x3206,0x04},
+{0x3207,0x43},
+{0x320c,0x04},
+{0x320d,0x4c},
+{0x320e,0x05},    //sc2210_REG_VTS_H
+{0x320f,0x46},//25fps  sc2210_REG_VTS_L
+{0x3211,0x04}, //输出窗口列起始位置
+{0x3213,0x04}, //输出窗口行起始位置
+{0x3231,0x02},
+{0x3253,0x04},
+{0x3301,0x0a},
+{0x3302,0x10},
+{0x3304,0x48},
+{0x3305,0x00},
+{0x3306,0x68},
+{0x3308,0x20},
+{0x3309,0x98},
+{0x330a,0x00},
+{0x330b,0xe8},
+{0x330e,0x68},
+{0x3314,0x92},
+{0x3000,0xc0},
+{0x331e,0x41},
+{0x331f,0x91},
+{0x334c,0x10},
+{0x335d,0x60},
+{0x335e,0x02},
+{0x335f,0x06},
+{0x3364,0x16},
+{0x3366,0x92},
+{0x3367,0x10},
+{0x3368,0x04},
+{0x3369,0x00},
+{0x336a,0x00},
+{0x336b,0x00},
+{0x336d,0x03},
+{0x337c,0x08},
+{0x337d,0x0e},
+{0x337f,0x33},
+{0x3390,0x10},
+{0x3391,0x30},
+{0x3392,0x40},
+{0x3393,0x0a},
+{0x3394,0x0a},
+{0x3395,0x0a},
+{0x3396,0x08},
+{0x3397,0x30},
+{0x3398,0x3f},
+{0x3399,0x50},
+{0x339a,0x50},
+{0x339b,0x50},
+{0x339c,0x50},
+{0x33a2,0x0a},
+{0x33b9,0x0e},
+{0x33e1,0x08},
+{0x33e2,0x18},
+{0x33e3,0x18},
+{0x33e4,0x18},
+{0x33e5,0x10},
+{0x33e6,0x06},
+{0x33e7,0x02},
+{0x33e8,0x18},
+{0x33e9,0x10},
+{0x33ea,0x0c},
+{0x33eb,0x10},
+{0x33ec,0x04},
+{0x33ed,0x02},
+{0x33ee,0xa0},
+{0x33ef,0x08},
+{0x33f4,0x18},
+{0x33f5,0x10},
+{0x33f6,0x0c},
+{0x33f7,0x10},
+{0x33f8,0x06},
+{0x33f9,0x02},
+{0x33fa,0x18},
+{0x33fb,0x10},
+{0x33fc,0x0c},
+{0x33fd,0x10},
+{0x33fe,0x04},
+{0x33ff,0x02},
+{0x360f,0x01},
+{0x3622,0xf7},
+{0x3625,0x0a},
+{0x3627,0x02},
+{0x3630,0xa2},
+{0x3631,0x00},
+{0x3632,0xd8},
+{0x3633,0x33},
+{0x3635,0x20},
+{0x3638,0x24},
+{0x363a,0x80},
+{0x363b,0x02},
+{0x363e,0x22},
+{0x3670,0x40},
+{0x3671,0xf7},
+{0x3672,0xf7},
+{0x3673,0x07},
+{0x367a,0x40},
+{0x367b,0x7f},
+{0x36b5,0x40},
+{0x36b6,0x7f},
+{0x36c0,0x80},
+{0x36c1,0x9f},
+{0x36c2,0x9f},
+{0x36cc,0x22},
+{0x36cd,0x23},
+{0x36ce,0x30},
+{0x36d0,0x20},
+{0x36d1,0x40},
+{0x36d2,0x7f},
+{0x36ea,0x75},
+{0x36eb,0x0d},
+{0x36ec,0x13},
+{0x36ed,0x24},
+{0x36fa,0x5f},
+{0x36fb,0x1b},
+{0x36fc,0x10},
+{0x36fd,0x07},
+{0x3905,0xd8},
+{0x3907,0x01},
+{0x3908,0x11},
+{0x391b,0x83},
+{0x391d,0x2c},
+{0x391f,0x00},
+{0x3933,0x28},
+{0x3934,0xa6},
+{0x3940,0x70},
+{0x3942,0x08},
+{0x3943,0xbc},
+{0x3958,0x02},
+{0x3959,0x04},
+{0x3980,0x61},
+{0x3987,0x0b},
+{0x3990,0x00},
+{0x3991,0x00},
+{0x3992,0x00},
+{0x3993,0x00},
+{0x3994,0x00},
+{0x3995,0x00},
+{0x3996,0x00},
+{0x3997,0x00},
+{0x3998,0x00},
+{0x3999,0x00},
+{0x399a,0x00},
+{0x399b,0x00},
+{0x399c,0x00},
+{0x399d,0x00},
+{0x399e,0x00},
+{0x399f,0x00},
+{0x39a0,0x00},
+{0x39a1,0x00},
+{0x39a2,0x03},
+{0x39a3,0x30},
+{0x39a4,0x03},
+{0x39a5,0x60},
+{0x39a6,0x03},
+{0x39a7,0xa0},
+{0x39a8,0x03},
+{0x39a9,0xb0},
+{0x39aa,0x00},
+{0x39ab,0x00},
+{0x39ac,0x00},
+{0x39ad,0x20},
+{0x39ae,0x00},
+{0x39af,0x40},
+{0x39b0,0x00},
+{0x39b1,0x60},
+{0x39b2,0x00},
+{0x39b3,0x00},
+{0x39b4,0x08},
+{0x39b5,0x14},
+{0x39b6,0x20},
+{0x39b7,0x38},
+{0x39b8,0x38},
+{0x39b9,0x20},
+{0x39ba,0x14},
+{0x39bb,0x08},
+{0x39bc,0x08},
+{0x39bd,0x10},
+{0x39be,0x20},
+{0x39bf,0x30},
+{0x39c0,0x30},
+{0x39c1,0x20},
+{0x39c2,0x10},
+{0x39c3,0x08},
+{0x39c4,0x00},
+{0x39c5,0x80},
+{0x39c6,0x00},
+{0x39c7,0x80},
+{0x39c8,0x00},
+{0x39c9,0x00},
+{0x39ca,0x80},
+{0x39cb,0x00},
+{0x39cc,0x00},
+{0x39cd,0x00},
+{0x39ce,0x00},
+{0x39cf,0x00},
+{0x39d0,0x00},
+{0x39d1,0x00},
+{0x39e2,0x05},
+{0x39e3,0xeb},
+{0x39e4,0x07},
+{0x39e5,0xb6},
+{0x39e6,0x00},
+{0x39e7,0x3a},
+{0x39e8,0x3f},
+{0x39e9,0xb7},
+{0x39ea,0x02},
+{0x39eb,0x4f},
+{0x39ec,0x08},
+{0x39ed,0x00},
+{0x3e01,0x46},
+{0x3e02,0x10},
+{0x3e09,0x40},
+{0x3e14,0x31},
+{0x3e1b,0x3a},
+{0x3e26,0x40},
+{0x4401,0x1a},
+{0x4407,0xc0},
+{0x4418,0x34},
+{0x4500,0x18},
+{0x4501,0xb4},  //test patten 0xb4
+{0x4509,0x20},
+{0x4603,0x00},
+{0x4800,0x24},
+{0x4837,0x2b},
+{0x5000,0x0e},
+{0x550f,0x20},
+{0x36e9,0x51},
+{0x36f9,0x53},
+//{0x0100,0x01},
+{REG_NULL, 0x00},
+};
+
+
+static const struct sc2210_mode supported_modes[] = {
+	{
+		.width = 1920,
+		.height = 1080,
+		.max_fps = {
+			.numerator = 10000,
+			.denominator = 250000,
+		},
+		.exp_def = 0x80,  //0x080
+		.hts_def = (1100),
+		.vts_def = (0x546), //0x546
+		.bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10,  //MEDIA_BUS_FMT_SBGGR10_1X10
+		.reg_list = sc2210_linear_10_1920x1080_30fps_regs,
+		.hdr_mode = NO_HDR,
+		.xvclk_freq = 27000000,
+		.link_freq_idx = 0,
+		.vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0,
+	},
+};
+
+static const s64 link_freq_menu_items[] = {
+	sc2210_LINK_FREQ_405,
+};
+
+static const char * const sc2210_test_pattern_menu[] = {
+	"Disabled",
+	"Vertical Color Bar Type 1",
+	"Vertical Color Bar Type 2",
+	"Vertical Color Bar Type 3",
+	"Vertical Color Bar Type 4",
+};
+
+/* Write registers up to 4 at a time */
+static int sc2210_write_reg(struct i2c_client *client, u16 reg,
+			    u32 len, u32 val)
+{
+	u32 buf_i, val_i;
+	u8 buf[6];
+	u8 *val_p;
+	__be32 val_be;
+
+	if (len > 4)
+		return -EINVAL;
+
+
+	buf[0] = reg >> 8;
+	buf[1] = reg & 0xff;
+
+	val_be = cpu_to_be32(val);
+	val_p = (u8 *)&val_be;
+	buf_i = 2;
+	val_i = 4 - len;
+
+	while (val_i < 4)
+		buf[buf_i++] = val_p[val_i++];
+
+	if (i2c_master_send(client, buf, len + 2) != len + 2)
+	{
+		printk("i2c_master_send error\n");
+		return -EIO;
+	}
+	
+	printk("sc2210_write_reg! addr=0x%X val=0x%X len=%d \n",reg,val,len);
+
+	return 0;
+}
+
+static int isc2210_write_reg(struct i2c_client *client, u16 reg,
+			    u32 len, u32 val)
+{
+	u32 buf_i, val_i;
+	u8 buf[6];
+	u8 *val_p;
+	__be32 val_be;
+
+	if (len > 4)
+		return -EINVAL;
+
+
+	buf[0] = reg >> 8;
+	buf[1] = reg & 0xff;
+
+	val_be = cpu_to_be32(val);
+	val_p = (u8 *)&val_be;
+	buf_i = 2;
+	val_i = 4 - len;
+
+	while (val_i < 4)
+		buf[buf_i++] = val_p[val_i++];
+
+	if (i2c_master_send(client, buf, len + 2) != len + 2)
+	{
+		printk("i2c_master_send error\n");
+		return -EIO;
+	}
+	
+//	printk("sc2210_write_reg! addr=0x%X val=0x%X len=%d \n",reg,val,len);
+
+	return 0;
+}
+
+
+static int sc2210_write_array(struct i2c_client *client,
+			       const struct regval *regs)
+{
+	u32 i;
+	int ret = 0;
+
+	for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++)
+		ret = isc2210_write_reg(client, regs[i].addr,
+					sc2210_REG_VALUE_08BIT, regs[i].val);
+
+	printk("sc2210_write_array! i=%d \n",i);
+
+	return ret;
+}
+
+/* Read registers up to 4 at a time */
+static int sc2210_read_reg(struct i2c_client *client, u16 reg, unsigned int len,
+			    u32 *val)
+{
+	struct i2c_msg msgs[2];
+	u8 *data_be_p;
+	__be32 data_be = 0;
+	__be16 reg_addr_be = cpu_to_be16(reg);
+	int ret;
+
+	if (len > 4 || !len)
+		return -EINVAL;
+
+	data_be_p = (u8 *)&data_be;
+	/* Write register address */
+	msgs[0].addr = client->addr;
+	msgs[0].flags = 0;
+	msgs[0].len = 2;
+	msgs[0].buf = (u8 *)&reg_addr_be;
+
+	/* Read data from register */
+	msgs[1].addr = client->addr;
+	msgs[1].flags = I2C_M_RD;
+	msgs[1].len = len;
+	msgs[1].buf = &data_be_p[4 - len];
+
+	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (ret != ARRAY_SIZE(msgs))
+		return -EIO;
+
+	*val = be32_to_cpu(data_be);
+
+	return 0;
+}
+
+static int sc2210_set_gain_reg(struct sc2210 *sc2210, u32 gain)
+{
+	u32 coarse_again = 0, coarse_dgain = 0, fine_dgain = 0;
+	u32 gain_factor;
+	int ret = 0;
+
+	return ret; //debug ws
+
+	gain_factor = gain * 1000 / 32;
+	if (gain_factor < 1000) {
+		coarse_again = 0x00;
+		coarse_dgain = 0x00;
+		fine_dgain = 0x80;
+	} else if (gain_factor < 1000 * 2) {			/*1x ~ 2x gain*/
+		coarse_again = 0x00;
+		coarse_dgain = 0x00;
+		fine_dgain = gain_factor * 128 / 1000;
+	} else if (gain_factor < 1000 * 4) {			/*2x ~ 4x gain*/
+		coarse_again = 0x01;
+		coarse_dgain = 0x00;
+		fine_dgain = gain_factor * 128 / 1000 / 2;
+	} else if (gain_factor < 1000 * 8) {			/*4x ~ 8x gain*/
+		coarse_again = 0x03;
+		coarse_dgain = 0x00;
+		fine_dgain = gain_factor * 128 / 1000 / 4;
+	} else if (gain_factor < 1000 * 16) {			/*8x ~ 16x gain*/
+		coarse_again = 0x07;
+		coarse_dgain = 0x00;
+		fine_dgain = gain_factor * 128 / 1000 / 8;
+	} else if (gain_factor < 1000 * 32) {			/*16x ~ 32x gain*/
+		coarse_again = 0x0f;
+		coarse_dgain = 0x00;
+		fine_dgain = gain_factor * 128 / 1000 / 16;
+	//open dgain begin  max digital gain 4X
+	} else if (gain_factor < 1000 * 64) {			/*32x ~ 64x gain*/
+		coarse_again = 0x1f;
+		coarse_dgain = 0x00;
+		fine_dgain = gain_factor * 128 / 1000 / 32;
+	} else if (gain_factor < 1000 * 128) {			/*64x ~ 128x gain*/
+		coarse_again = 0x1f;
+		coarse_dgain = 0x01;
+		fine_dgain = gain_factor * 128 / 1000 / 64;
+	} else {						/*max 128x gain*/
+		coarse_again = 0x1f;
+		coarse_dgain = 0x03;
+		fine_dgain = 0x80;
+	}
+	dev_dbg(&sc2210->client->dev,
+		"total_gain: 0x%x, d_gain: 0x%x, d_fine_gain: 0x%x, c_gain: 0x%x\n",
+		gain, coarse_dgain, fine_dgain, coarse_again);
+
+	ret = sc2210_write_reg(sc2210->client,
+				sc2210_REG_DIG_GAIN,
+				sc2210_REG_VALUE_08BIT,
+				coarse_dgain);
+	ret |= sc2210_write_reg(sc2210->client,
+				 sc2210_REG_DIG_FINE_GAIN,
+				 sc2210_REG_VALUE_08BIT,
+				 fine_dgain);
+	ret |= sc2210_write_reg(sc2210->client,
+				 sc2210_REG_ANA_GAIN,
+				 sc2210_REG_VALUE_08BIT,
+				 coarse_again);
+
+	return ret;
+}
+
+static int sc2210_get_reso_dist(const struct sc2210_mode *mode,
+				 struct v4l2_mbus_framefmt *framefmt)
+{
+	return abs(mode->width - framefmt->width) +
+	       abs(mode->height - framefmt->height);
+}
+
+static const struct sc2210_mode *
+sc2210_find_best_fit(struct v4l2_subdev_format *fmt)
+{
+	struct v4l2_mbus_framefmt *framefmt = &fmt->format;
+	int dist;
+	int cur_best_fit = 0;
+	int cur_best_fit_dist = -1;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {
+		dist = sc2210_get_reso_dist(&supported_modes[i], framefmt);
+		if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) {
+			cur_best_fit_dist = dist;
+			cur_best_fit = i;
+		}
+	}
+
+	return &supported_modes[cur_best_fit];
+}
+
+static int sc2210_set_fmt(struct v4l2_subdev *sd,
+			   struct v4l2_subdev_pad_config *cfg,
+			   struct v4l2_subdev_format *fmt)
+{
+	struct sc2210 *sc2210 = to_sc2210(sd);
+	const struct sc2210_mode *mode;
+	struct device *dev = &sc2210->client->dev;
+	s64 h_blank, vblank_def;
+	u64 dst_link_freq = 0;
+	u64 dst_pixel_rate = 0;
+
+	dev_info(dev,"enter sc2210_set_fmt\n");
+
+	mutex_lock(&sc2210->mutex);
+
+	mode = sc2210_find_best_fit(fmt);
+	fmt->format.code = mode->bus_fmt;
+	fmt->format.width = mode->width;
+	fmt->format.height = mode->height;
+	fmt->format.field = V4L2_FIELD_NONE;
+
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+		dev_info(dev,"enter v4l2_subdev_get_try_format\n");
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+		*v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
+#else
+		mutex_unlock(&sc2210->mutex);
+		return -ENOTTY;
+#endif
+	} else {
+		sc2210->cur_mode = mode;
+		h_blank = mode->hts_def - mode->width;
+		
+		__v4l2_ctrl_modify_range(sc2210->hblank, h_blank,
+					 h_blank, 1, h_blank);
+		vblank_def = mode->vts_def - mode->height;
+		__v4l2_ctrl_modify_range(sc2210->vblank, vblank_def,
+					 sc2210_VTS_MAX - mode->height,
+					 1, vblank_def);
+		dst_link_freq = mode->link_freq_idx;
+		dst_pixel_rate = (u32)link_freq_menu_items[mode->link_freq_idx] /
+						 sc2210_BITS_PER_SAMPLE * 2 * sc2210_LANES;
+		__v4l2_ctrl_s_ctrl_int64(sc2210->pixel_rate,
+					 dst_pixel_rate);
+		__v4l2_ctrl_s_ctrl(sc2210->link_freq,
+				   dst_link_freq);
+		dev_info(dev,"h_blank=%lld vblank_def=%lld dst_link_freq=%lld dst_pixel_rate=%lld\n",h_blank,vblank_def,dst_link_freq,dst_pixel_rate);
+	}
+
+	mutex_unlock(&sc2210->mutex);
+
+	return 0;
+}
+
+static int sc2210_get_fmt(struct v4l2_subdev *sd,
+			   struct v4l2_subdev_pad_config *cfg,
+			   struct v4l2_subdev_format *fmt)
+{
+	struct sc2210 *sc2210 = to_sc2210(sd);
+	const struct sc2210_mode *mode = sc2210->cur_mode;
+
+	mutex_lock(&sc2210->mutex);
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+		fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+#else
+		mutex_unlock(&sc2210->mutex);
+		return -ENOTTY;
+#endif
+	} else {
+		fmt->format.width = mode->width;
+		fmt->format.height = mode->height;
+		fmt->format.code = mode->bus_fmt;
+		fmt->format.field = V4L2_FIELD_NONE;
+		/* format info: width/height/data type/virctual channel */
+		if (fmt->pad < PAD_MAX && mode->hdr_mode != NO_HDR)
+			fmt->reserved[0] = mode->vc[fmt->pad];
+		else
+			fmt->reserved[0] = mode->vc[PAD0];
+	}
+	mutex_unlock(&sc2210->mutex);
+
+	return 0;
+}
+
+static int sc2210_enum_mbus_code(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_pad_config *cfg,
+				  struct v4l2_subdev_mbus_code_enum *code)
+{
+	struct sc2210 *sc2210 = to_sc2210(sd);
+
+	if (code->index != 0)
+		return -EINVAL;
+	code->code = sc2210->cur_mode->bus_fmt;
+
+	return 0;
+}
+
+static int sc2210_enum_frame_sizes(struct v4l2_subdev *sd,
+				    struct v4l2_subdev_pad_config *cfg,
+				    struct v4l2_subdev_frame_size_enum *fse)
+{
+	if (fse->index >= ARRAY_SIZE(supported_modes))
+		return -EINVAL;
+
+	if (fse->code != supported_modes[0].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;
+
+	return 0;
+}
+
+static int sc2210_enable_test_pattern(struct sc2210 *sc2210, u32 pattern)
+{
+	u32 val = 0;
+	int ret = 0;
+
+	ret = sc2210_read_reg(sc2210->client, sc2210_REG_TEST_PATTERN,
+			       sc2210_REG_VALUE_08BIT, &val);
+	if (pattern)
+		val |= sc2210_TEST_PATTERN_BIT_MASK;
+	else
+		val &= ~sc2210_TEST_PATTERN_BIT_MASK;
+
+	ret |= sc2210_write_reg(sc2210->client, sc2210_REG_TEST_PATTERN,
+				 sc2210_REG_VALUE_08BIT, val);
+	return ret;
+}
+
+static int sc2210_g_frame_interval(struct v4l2_subdev *sd,
+				    struct v4l2_subdev_frame_interval *fi)
+{
+	struct sc2210 *sc2210 = to_sc2210(sd);
+	const struct sc2210_mode *mode = sc2210->cur_mode;
+
+	fi->interval = mode->max_fps;
+
+	return 0;
+}
+
+static int sc2210_g_mbus_config(struct v4l2_subdev *sd,
+				unsigned int pad_id,
+				struct v4l2_mbus_config *config)
+{
+	struct sc2210 *sc2210 = to_sc2210(sd);
+	const struct sc2210_mode *mode = sc2210->cur_mode;
+
+	u32 val = (1 << (sc2210_LANES - 1)) |
+		V4L2_MBUS_CSI2_CHANNEL_0 |
+		V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;  //  V4L2_MBUS_CSI2_CONTINUOUS_CLOCK
+
+//	if (mode->hdr_mode != NO_HDR)
+//		val |= V4L2_MBUS_CSI2_CHANNEL_1;
+//	if (mode->hdr_mode == HDR_X3)
+	//	val |= V4L2_MBUS_CSI2_CHANNEL_2;
+
+	config->type = V4L2_MBUS_CSI2_DPHY;
+	config->flags = val;
+
+	printk("sc2210_g_mbus_config val=0x%X hdr_mode=%d\n",val,mode->hdr_mode );
+
+	return 0;
+}
+
+static void sc2210_get_module_inf(struct sc2210 *sc2210,
+				   struct rkmodule_inf *inf)
+{
+	memset(inf, 0, sizeof(*inf));
+	strscpy(inf->base.sensor, sc2210_NAME, sizeof(inf->base.sensor));
+	strscpy(inf->base.module, sc2210->module_name,
+		sizeof(inf->base.module));
+	strscpy(inf->base.lens, sc2210->len_name, sizeof(inf->base.lens));
+}
+
+static long sc2210_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+	struct sc2210 *sc2210 = to_sc2210(sd);
+	struct rkmodule_hdr_cfg *hdr;
+	u32 i, h, w;
+	long ret = 0;
+	u32 stream = 0;
+
+	switch (cmd) {
+	case RKMODULE_GET_MODULE_INFO:
+		sc2210_get_module_inf(sc2210, (struct rkmodule_inf *)arg);
+		break;
+	case RKMODULE_GET_HDR_CFG:
+		hdr = (struct rkmodule_hdr_cfg *)arg;
+		hdr->esp.mode = HDR_NORMAL_VC;
+		hdr->hdr_mode = sc2210->cur_mode->hdr_mode;
+		break;
+	case RKMODULE_SET_HDR_CFG:
+		hdr = (struct rkmodule_hdr_cfg *)arg;
+		w = sc2210->cur_mode->width;
+		h = sc2210->cur_mode->height;
+		for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {
+			if (w == supported_modes[i].width &&
+			    h == supported_modes[i].height &&
+			    supported_modes[i].hdr_mode == hdr->hdr_mode) {
+				sc2210->cur_mode = &supported_modes[i];
+				break;
+			}
+		}
+		if (i == ARRAY_SIZE(supported_modes)) {
+			dev_err(&sc2210->client->dev,
+				"not find hdr mode:%d %dx%d config\n",
+				hdr->hdr_mode, w, h);
+			ret = -EINVAL;
+		} else {
+			w = sc2210->cur_mode->hts_def - sc2210->cur_mode->width;
+			h = sc2210->cur_mode->vts_def - sc2210->cur_mode->height;
+			__v4l2_ctrl_modify_range(sc2210->hblank, w, w, 1, w);
+			__v4l2_ctrl_modify_range(sc2210->vblank, h,
+						 sc2210_VTS_MAX - sc2210->cur_mode->height, 1, h);
+		}
+		break;
+	case PREISP_CMD_SET_HDRAE_EXP:
+		break;
+	case RKMODULE_SET_QUICK_STREAM:
+
+		stream = *((u32 *)arg);
+
+		if (stream)
+			ret = sc2210_write_reg(sc2210->client, sc2210_REG_CTRL_MODE,
+				 sc2210_REG_VALUE_08BIT, sc2210_MODE_STREAMING);
+		else
+			ret = sc2210_write_reg(sc2210->client, sc2210_REG_CTRL_MODE,
+				 sc2210_REG_VALUE_08BIT, sc2210_MODE_SW_STANDBY);
+		break;
+	default:
+		ret = -ENOIOCTLCMD;
+		break;
+	}
+
+	return ret;
+}
+
+#ifdef CONFIG_COMPAT
+static long sc2210_compat_ioctl32(struct v4l2_subdev *sd,
+				   unsigned int cmd, unsigned long arg)
+{
+	void __user *up = compat_ptr(arg);
+	struct rkmodule_inf *inf;
+	struct rkmodule_hdr_cfg *hdr;
+	struct preisp_hdrae_exp_s *hdrae;
+	long ret;
+	u32 stream = 0;
+
+	switch (cmd) {
+	case RKMODULE_GET_MODULE_INFO:
+		inf = kzalloc(sizeof(*inf), GFP_KERNEL);
+		if (!inf) {
+			ret = -ENOMEM;
+			return ret;
+		}
+
+		ret = sc2210_ioctl(sd, cmd, inf);
+		if (!ret) {
+			if (copy_to_user(up, inf, sizeof(*inf)))
+				ret = -EFAULT;
+		}
+		kfree(inf);
+		break;
+	case RKMODULE_GET_HDR_CFG:
+		hdr = kzalloc(sizeof(*hdr), GFP_KERNEL);
+		if (!hdr) {
+			ret = -ENOMEM;
+			return ret;
+		}
+
+		ret = sc2210_ioctl(sd, cmd, hdr);
+		if (!ret) {
+			if (copy_to_user(up, hdr, sizeof(*hdr)))
+				ret = -EFAULT;
+		}
+		kfree(hdr);
+		break;
+	case RKMODULE_SET_HDR_CFG:
+		hdr = kzalloc(sizeof(*hdr), GFP_KERNEL);
+		if (!hdr) {
+			ret = -ENOMEM;
+			return ret;
+		}
+
+		ret = copy_from_user(hdr, up, sizeof(*hdr));
+		if (!ret)
+			ret = sc2210_ioctl(sd, cmd, hdr);
+		else
+			ret = -EFAULT;
+		kfree(hdr);
+		break;
+	case PREISP_CMD_SET_HDRAE_EXP:
+		hdrae = kzalloc(sizeof(*hdrae), GFP_KERNEL);
+		if (!hdrae) {
+			ret = -ENOMEM;
+			return ret;
+		}
+
+		ret = copy_from_user(hdrae, up, sizeof(*hdrae));
+		if (!ret)
+			ret = sc2210_ioctl(sd, cmd, hdrae);
+		else
+			ret = -EFAULT;
+		kfree(hdrae);
+		break;
+	case RKMODULE_SET_QUICK_STREAM:
+		ret = copy_from_user(&stream, up, sizeof(u32));
+		if (!ret)
+			ret = sc2210_ioctl(sd, cmd, &stream);
+		else
+			ret = -EFAULT;
+		break;
+	default:
+		ret = -ENOIOCTLCMD;
+		break;
+	}
+
+	return ret;
+}
+#endif
+
+static int __sc2210_start_stream(struct sc2210 *sc2210)
+{
+	int ret;
+
+	if (!sc2210->is_thunderboot) {
+		ret = sc2210_write_array(sc2210->client, sc2210->cur_mode->reg_list);
+		if (ret)
+			return ret;
+		/* In case these controls are set before streaming */
+		ret = __v4l2_ctrl_handler_setup(&sc2210->ctrl_handler);
+		if (ret)
+			return ret;
+		if (sc2210->has_init_exp && sc2210->cur_mode->hdr_mode != NO_HDR) {
+			ret = sc2210_ioctl(&sc2210->subdev, PREISP_CMD_SET_HDRAE_EXP,
+				&sc2210->init_hdrae_exp);
+			if (ret) {
+				dev_err(&sc2210->client->dev,
+					"init exp fail in hdr mode\n");
+				return ret;
+			}
+		}
+	}
+	ret = sc2210_write_reg(sc2210->client, sc2210_REG_CTRL_MODE,
+				 sc2210_REG_VALUE_08BIT, sc2210_MODE_STREAMING);
+	return ret;
+}
+
+static int __sc2210_stop_stream(struct sc2210 *sc2210)
+{
+	sc2210->has_init_exp = false;
+	if (sc2210->is_thunderboot) {
+		sc2210->is_first_streamoff = true;
+		pm_runtime_put(&sc2210->client->dev);
+	}
+	return sc2210_write_reg(sc2210->client, sc2210_REG_CTRL_MODE,
+				 sc2210_REG_VALUE_08BIT, sc2210_MODE_SW_STANDBY);
+}
+
+static int __sc2210_power_on(struct sc2210 *sc2210);
+static int sc2210_s_stream(struct v4l2_subdev *sd, int on)
+{
+	struct sc2210 *sc2210 = to_sc2210(sd);
+	struct i2c_client *client = sc2210->client;
+	int ret = 0;
+
+	mutex_lock(&sc2210->mutex);
+	on = !!on;
+	if (on == sc2210->streaming)
+		goto unlock_and_return;
+	if (on) {
+		if (sc2210->is_thunderboot && rkisp_tb_get_state() == RKISP_TB_NG) {
+			sc2210->is_thunderboot = false;
+			__sc2210_power_on(sc2210);
+		}
+		ret = pm_runtime_get_sync(&client->dev);
+		if (ret < 0) {
+			pm_runtime_put_noidle(&client->dev);
+			goto unlock_and_return;
+		}
+		ret = __sc2210_start_stream(sc2210);
+		if (ret) {
+			v4l2_err(sd, "start stream failed while write regs\n");
+			pm_runtime_put(&client->dev);
+			goto unlock_and_return;
+		}
+	} else {
+		__sc2210_stop_stream(sc2210);
+		pm_runtime_put(&client->dev);
+	}
+
+	sc2210->streaming = on;
+unlock_and_return:
+	mutex_unlock(&sc2210->mutex);
+	return ret;
+}
+
+static int sc2210_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct sc2210 *sc2210 = to_sc2210(sd);
+	struct i2c_client *client = sc2210->client;
+	int ret = 0;
+
+	mutex_lock(&sc2210->mutex);
+
+	/* If the power state is not modified - no work to do. */
+	if (sc2210->power_on == !!on)
+		goto unlock_and_return;
+
+	if (on) {
+		ret = pm_runtime_get_sync(&client->dev);
+		if (ret < 0) {
+			pm_runtime_put_noidle(&client->dev);
+			goto unlock_and_return;
+		}
+
+		if (!sc2210->is_thunderboot) {
+			printk("sc2210_write_array sc2210_linear_10_1920x1080_30fps_regs\n");
+			ret = sc2210_write_array(sc2210->client, sc2210_linear_10_1920x1080_30fps_regs);
+			if (ret) {
+				v4l2_err(sd, "could not set init registers\n");
+				pm_runtime_put_noidle(&client->dev);
+				goto unlock_and_return;
+			}
+		}
+
+		sc2210->power_on = true;
+	} else {
+		pm_runtime_put(&client->dev);
+		sc2210->power_on = false;
+	}
+
+unlock_and_return:
+	mutex_unlock(&sc2210->mutex);
+
+	return ret;
+}
+
+/* Calculate the delay in us by clock rate and clock cycles */
+static inline u32 sc2210_cal_delay(u32 cycles, struct sc2210 *sc2210)
+{
+	return DIV_ROUND_UP(cycles, sc2210->cur_mode->xvclk_freq / 1000 / 1000);
+}
+
+static int __sc2210_power_on(struct sc2210 *sc2210)
+{
+	int ret;
+	u32 delay_us;
+	struct device *dev = &sc2210->client->dev;
+
+	if (!IS_ERR_OR_NULL(sc2210->pins_default)) {
+		ret = pinctrl_select_state(sc2210->pinctrl,
+					   sc2210->pins_default);
+		if (ret < 0)
+			dev_err(dev, "could not set pins\n");
+	}
+	ret = clk_set_rate(sc2210->xvclk, sc2210->cur_mode->xvclk_freq);
+	if (ret < 0)
+		dev_warn(dev, "Failed to set xvclk rate (%dHz)\n", sc2210->cur_mode->xvclk_freq);
+	if (clk_get_rate(sc2210->xvclk) != sc2210->cur_mode->xvclk_freq)
+		dev_warn(dev, "xvclk mismatched, modes are based on %dHz\n",
+			 sc2210->cur_mode->xvclk_freq);
+	ret = clk_prepare_enable(sc2210->xvclk);
+	if (ret < 0) {
+		dev_err(dev, "Failed to enable xvclk\n");
+		return ret;
+	}
+
+	if (sc2210->is_thunderboot)
+		return 0;
+
+	if (!IS_ERR(sc2210->reset_gpio))
+		gpiod_set_value_cansleep(sc2210->reset_gpio, 0);
+
+	ret = regulator_bulk_enable(sc2210_NUM_SUPPLIES, sc2210->supplies);
+	if (ret < 0) {
+		dev_err(dev, "Failed to enable regulators\n");
+		goto disable_clk;
+	}
+
+	if (!IS_ERR(sc2210->reset_gpio))
+		gpiod_set_value_cansleep(sc2210->reset_gpio, 1);
+
+	usleep_range(500, 1000);
+
+	if (!IS_ERR(sc2210->reset_gpio))
+		usleep_range(6000, 8000);
+	else
+		usleep_range(12000, 16000);
+
+	/* 8192 cycles prior to first SCCB transaction */
+	delay_us = sc2210_cal_delay(8192, sc2210);
+	usleep_range(delay_us, delay_us * 2);
+
+	return 0;
+
+disable_clk:
+	clk_disable_unprepare(sc2210->xvclk);
+
+	return ret;
+}
+
+static void __sc2210_power_off(struct sc2210 *sc2210)
+{
+	int ret;
+	struct device *dev = &sc2210->client->dev;
+
+	clk_disable_unprepare(sc2210->xvclk);
+	if (sc2210->is_thunderboot) {
+		if (sc2210->is_first_streamoff) {
+			sc2210->is_thunderboot = false;
+			sc2210->is_first_streamoff = false;
+		} else {
+			return;
+		}
+	}
+
+	if (!IS_ERR(sc2210->reset_gpio))
+		gpiod_set_value_cansleep(sc2210->reset_gpio, 0);
+	if (!IS_ERR_OR_NULL(sc2210->pins_sleep)) {
+		ret = pinctrl_select_state(sc2210->pinctrl,
+					   sc2210->pins_sleep);
+		if (ret < 0)
+			dev_dbg(dev, "could not set pins\n");
+	}
+	regulator_bulk_disable(sc2210_NUM_SUPPLIES, sc2210->supplies);
+}
+
+static int sc2210_runtime_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct sc2210 *sc2210 = to_sc2210(sd);
+
+	return __sc2210_power_on(sc2210);
+}
+
+static int sc2210_runtime_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct sc2210 *sc2210 = to_sc2210(sd);
+
+	__sc2210_power_off(sc2210);
+
+	return 0;
+}
+
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+static int sc2210_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	struct sc2210 *sc2210 = to_sc2210(sd);
+	struct v4l2_mbus_framefmt *try_fmt =
+				v4l2_subdev_get_try_format(sd, fh->pad, 0);
+	const struct sc2210_mode *def_mode = &supported_modes[0];
+
+	mutex_lock(&sc2210->mutex);
+	/* Initialize try_fmt */
+	try_fmt->width = def_mode->width;
+	try_fmt->height = def_mode->height;
+	try_fmt->code = def_mode->bus_fmt;
+	try_fmt->field = V4L2_FIELD_NONE;
+
+	mutex_unlock(&sc2210->mutex);
+	/* No crop or compose */
+
+	return 0;
+}
+#endif
+
+static int sc2210_enum_frame_interval(struct v4l2_subdev *sd,
+				       struct v4l2_subdev_pad_config *cfg,
+				       struct v4l2_subdev_frame_interval_enum *fie)
+{
+	if (fie->index >= ARRAY_SIZE(supported_modes))
+		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;
+	return 0;
+}
+
+static const struct dev_pm_ops sc2210_pm_ops = {
+	SET_RUNTIME_PM_OPS(sc2210_runtime_suspend,
+			   sc2210_runtime_resume, NULL)
+};
+
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+static const struct v4l2_subdev_internal_ops sc2210_internal_ops = {
+	.open = sc2210_open,
+};
+#endif
+
+static const struct v4l2_subdev_core_ops sc2210_core_ops = {
+	.s_power = sc2210_s_power,
+	.ioctl = sc2210_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl32 = sc2210_compat_ioctl32,
+#endif
+};
+
+static const struct v4l2_subdev_video_ops sc2210_video_ops = {
+	.s_stream = sc2210_s_stream,
+	.g_frame_interval = sc2210_g_frame_interval,
+};
+
+static const struct v4l2_subdev_pad_ops sc2210_pad_ops = {
+	.enum_mbus_code = sc2210_enum_mbus_code,
+	.enum_frame_size = sc2210_enum_frame_sizes,
+	.enum_frame_interval = sc2210_enum_frame_interval,
+	.get_fmt = sc2210_get_fmt,
+	.set_fmt = sc2210_set_fmt,
+	.get_mbus_config = sc2210_g_mbus_config,
+};
+
+static const struct v4l2_subdev_ops sc2210_subdev_ops = {
+	.core	= &sc2210_core_ops,
+	.video	= &sc2210_video_ops,
+	.pad	= &sc2210_pad_ops,
+};
+
+/// @brief 
+/// @param ctrl 
+/// @return 
+static int sc2210_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct sc2210 *sc2210 = container_of(ctrl->handler,
+					       struct sc2210, ctrl_handler);
+	struct i2c_client *client = sc2210->client;
+	s64 max;
+	int ret = 0;
+	u32 val = 0;
+
+	/* Propagate change of current control to all related controls */
+	switch (ctrl->id) {
+	case V4L2_CID_VBLANK:
+		/* Update max exposure while meeting expected vblanking */
+		 max = sc2210->cur_mode->height + ctrl->val - 8;
+		 __v4l2_ctrl_modify_range(sc2210->exposure,
+		 			 sc2210->exposure->minimum, max,
+		 			 sc2210->exposure->step,
+		 			 sc2210->exposure->default_value);
+		break;
+	}
+
+	if (!pm_runtime_get_if_in_use(&client->dev))
+		return 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_EXPOSURE:
+		dev_dbg(&client->dev, "set exposure 0x%x\n", ctrl->val);
+		if (sc2210->cur_mode->hdr_mode == NO_HDR) {
+			val = ctrl->val;
+// 			// /* 4 least significant bits of expsoure are fractional part */
+ 			ret = sc2210_write_reg(sc2210->client,
+						sc2210_REG_EXPOSURE_H,
+						sc2210_REG_VALUE_08BIT,
+						sc2210_FETCH_EXP_H(val));
+			ret |= sc2210_write_reg(sc2210->client,
+						 sc2210_REG_EXPOSURE_M,
+						 sc2210_REG_VALUE_08BIT,
+						 sc2210_FETCH_EXP_M(val));
+			ret |= sc2210_write_reg(sc2210->client,
+						 sc2210_REG_EXPOSURE_L,
+						 sc2210_REG_VALUE_08BIT,
+						 sc2210_FETCH_EXP_L(val)); 
+		}
+		break;
+	case V4L2_CID_ANALOGUE_GAIN:
+		dev_dbg(&client->dev, "set gain 0x%x\n", ctrl->val);
+		 if (sc2210->cur_mode->hdr_mode == NO_HDR)
+		 	ret = sc2210_set_gain_reg(sc2210, ctrl->val);
+		break;
+	case V4L2_CID_VBLANK:
+		dev_dbg(&client->dev, "set vblank 0x%x\n", ctrl->val);
+		ret = sc2210_write_reg(sc2210->client,
+					sc2210_REG_VTS_H,
+					sc2210_REG_VALUE_08BIT,
+					(ctrl->val + sc2210->cur_mode->height)
+					>> 8);
+		ret |= sc2210_write_reg(sc2210->client,
+					 sc2210_REG_VTS_L,
+					 sc2210_REG_VALUE_08BIT,
+					 (ctrl->val + sc2210->cur_mode->height)
+					 & 0xff);
+		sc2210->cur_vts = ctrl->val + sc2210->cur_mode->height;
+		break;
+	case V4L2_CID_TEST_PATTERN:
+		 ret = sc2210_enable_test_pattern(sc2210, ctrl->val);
+		break;
+	case V4L2_CID_HFLIP:
+		ret = sc2210_read_reg(sc2210->client, sc2210_FLIP_MIRROR_REG,
+				       sc2210_REG_VALUE_08BIT, &val);
+		ret |= sc2210_write_reg(sc2210->client, sc2210_FLIP_MIRROR_REG,
+					 sc2210_REG_VALUE_08BIT,
+					 sc2210_FETCH_MIRROR(val, ctrl->val));
+		break;
+	case V4L2_CID_VFLIP:
+		ret = sc2210_read_reg(sc2210->client, sc2210_FLIP_MIRROR_REG,
+				       sc2210_REG_VALUE_08BIT, &val);
+		ret |= sc2210_write_reg(sc2210->client, sc2210_FLIP_MIRROR_REG,
+					 sc2210_REG_VALUE_08BIT,
+					 sc2210_FETCH_FLIP(val, ctrl->val));
+		break;
+	default:
+		dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n",
+			 __func__, ctrl->id, ctrl->val);
+		break;
+	}
+
+	pm_runtime_put(&client->dev);
+
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops sc2210_ctrl_ops = {
+	.s_ctrl = sc2210_set_ctrl,
+};
+
+static int sc2210_initialize_controls(struct sc2210 *sc2210)
+{
+	const struct sc2210_mode *mode;
+	struct v4l2_ctrl_handler *handler;
+	struct device *dev = &sc2210->client->dev;
+	s64 exposure_max, vblank_def;
+	u32 h_blank;
+	int ret;
+	u64 dst_link_freq = 0;
+	u64 dst_pixel_rate = 0;
+
+	handler = &sc2210->ctrl_handler;
+	mode = sc2210->cur_mode;
+	ret = v4l2_ctrl_handler_init(handler, 9);
+	if (ret)
+		return ret;
+	handler->lock = &sc2210->mutex;
+
+	sc2210->link_freq = v4l2_ctrl_new_int_menu(handler, NULL,
+			V4L2_CID_LINK_FREQ,
+			ARRAY_SIZE(link_freq_menu_items) - 1, 0, link_freq_menu_items);
+	if (sc2210->link_freq)
+		sc2210->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+	dst_link_freq = mode->link_freq_idx;
+	dst_pixel_rate = (u32)link_freq_menu_items[mode->link_freq_idx] /
+					 sc2210_BITS_PER_SAMPLE * 2 * sc2210_LANES;
+	sc2210->pixel_rate = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE,
+			  0, PIXEL_RATE_WITH_405M_10BIT, 1, dst_pixel_rate);
+
+	__v4l2_ctrl_s_ctrl(sc2210->link_freq, dst_link_freq);
+
+	h_blank = mode->hts_def - mode->width;
+	sc2210->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK,
+					    h_blank, h_blank, 1, h_blank);
+	if (sc2210->hblank)
+		sc2210->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+	vblank_def = mode->vts_def - mode->height;
+	sc2210->vblank = v4l2_ctrl_new_std(handler, &sc2210_ctrl_ops,
+					    V4L2_CID_VBLANK, vblank_def,
+					    sc2210_VTS_MAX - mode->height,
+					    1, vblank_def);
+	exposure_max = mode->vts_def - 8;
+	sc2210->exposure = v4l2_ctrl_new_std(handler, &sc2210_ctrl_ops,
+					      V4L2_CID_EXPOSURE, sc2210_EXPOSURE_MIN,
+					      exposure_max, sc2210_EXPOSURE_STEP,
+					      mode->exp_def);
+	sc2210->anal_gain = v4l2_ctrl_new_std(handler, &sc2210_ctrl_ops,
+					       V4L2_CID_ANALOGUE_GAIN, sc2210_GAIN_MIN,
+					       sc2210_GAIN_MAX, sc2210_GAIN_STEP,
+					       sc2210_GAIN_DEFAULT);
+	sc2210->test_pattern = v4l2_ctrl_new_std_menu_items(handler,
+							    &sc2210_ctrl_ops,
+					V4L2_CID_TEST_PATTERN,
+					ARRAY_SIZE(sc2210_test_pattern_menu) - 1,
+					0, 0, sc2210_test_pattern_menu);
+	v4l2_ctrl_new_std(handler, &sc2210_ctrl_ops,
+				V4L2_CID_HFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(handler, &sc2210_ctrl_ops,
+				V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+	
+
+
+	if (handler->error) {
+		ret = handler->error;
+		dev_err(&sc2210->client->dev,
+			"Failed to init controls(%d)\n", ret);
+		goto err_free_handler;
+	}
+
+	sc2210->subdev.ctrl_handler = handler;
+	sc2210->has_init_exp = false;
+
+	dev_info(dev,"sc2210_initialize_controls \n");
+
+	return 0;
+
+err_free_handler:
+	v4l2_ctrl_handler_free(handler);
+
+	return ret;
+}
+
+static int sc2210_check_sensor_id(struct sc2210 *sc2210,
+				   struct i2c_client *client)
+{
+	struct device *dev = &sc2210->client->dev;
+	u32 id = 0;
+	int ret;
+
+	if (sc2210->is_thunderboot) {
+		dev_info(dev, "Enable thunderboot mode, skip sensor id check\n");
+		return 0;
+	}
+
+	ret = sc2210_read_reg(client, sc2210_REG_CHIP_ID,
+			       sc2210_REG_VALUE_16BIT, &id);
+	if (id != CHIP_ID) {
+		dev_err(dev, "Unexpected sensor id(%06x), ret(%d)\n", id, ret);
+		return -ENODEV;
+	}
+
+	dev_info(dev, "Detected SC%06x sensor\n", CHIP_ID);
+
+	return 0;
+}
+
+static int sc2210_configure_regulators(struct sc2210 *sc2210)
+{
+	unsigned int i;
+
+	for (i = 0; i < sc2210_NUM_SUPPLIES; i++)
+		sc2210->supplies[i].supply = sc2210_supply_names[i];
+
+	return devm_regulator_bulk_get(&sc2210->client->dev,
+				       sc2210_NUM_SUPPLIES,
+				       sc2210->supplies);
+}
+
+static int sc2210_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device_node *node = dev->of_node;
+	struct sc2210 *sc2210;
+	struct v4l2_subdev *sd;
+	char facing[2];
+	int ret;
+	int i, hdr_mode = 0;
+
+	dev_info(dev, "driver version: %02x.%02x.%02x",
+		 DRIVER_VERSION >> 16,
+		 (DRIVER_VERSION & 0xff00) >> 8,
+		 DRIVER_VERSION & 0x00ff);
+
+	sc2210 = devm_kzalloc(dev, sizeof(*sc2210), GFP_KERNEL);
+	if (!sc2210)
+		return -ENOMEM;
+
+	ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
+				   &sc2210->module_index);
+	ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING,
+				       &sc2210->module_facing);
+	ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME,
+				       &sc2210->module_name);
+	ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME,
+				       &sc2210->len_name);
+	if (ret) {
+		dev_err(dev, "could not get module information!\n");
+		return -EINVAL;
+	}
+
+	sc2210->is_thunderboot = IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP);
+
+	sc2210->client = client;
+	for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {
+		if (hdr_mode == supported_modes[i].hdr_mode) {
+			sc2210->cur_mode = &supported_modes[i];
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(supported_modes))
+		sc2210->cur_mode = &supported_modes[0];
+
+	sc2210->xvclk = devm_clk_get(dev, "xvclk");
+	if (IS_ERR(sc2210->xvclk)) {
+		dev_err(dev, "Failed to get xvclk\n");
+		return -EINVAL;
+	}
+
+	if (sc2210->is_thunderboot) {
+		sc2210->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS);
+		if (IS_ERR(sc2210->reset_gpio))
+			dev_warn(dev, "Failed to get reset-gpios\n");
+	} else {
+		sc2210->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+		if (IS_ERR(sc2210->reset_gpio))
+			dev_warn(dev, "Failed to get reset-gpios\n");
+	}
+
+	sc2210->pinctrl = devm_pinctrl_get(dev);
+	if (!IS_ERR(sc2210->pinctrl)) {
+		sc2210->pins_default =
+			pinctrl_lookup_state(sc2210->pinctrl,
+					     OF_CAMERA_PINCTRL_STATE_DEFAULT);
+		if (IS_ERR(sc2210->pins_default))
+			dev_err(dev, "could not get default pinstate\n");
+
+		sc2210->pins_sleep =
+			pinctrl_lookup_state(sc2210->pinctrl,
+					     OF_CAMERA_PINCTRL_STATE_SLEEP);
+		if (IS_ERR(sc2210->pins_sleep))
+			dev_err(dev, "could not get sleep pinstate\n");
+	} else {
+		dev_err(dev, "no pinctrl\n");
+	}
+
+	ret = sc2210_configure_regulators(sc2210);
+	if (ret) {
+		dev_err(dev, "Failed to get power regulators\n");
+		return ret;
+	}
+
+	mutex_init(&sc2210->mutex);
+
+	sd = &sc2210->subdev;
+	v4l2_i2c_subdev_init(sd, client, &sc2210_subdev_ops);
+	ret = sc2210_initialize_controls(sc2210);
+	if (ret)
+		goto err_destroy_mutex;
+
+	ret = __sc2210_power_on(sc2210);
+	if (ret)
+		goto err_free_handler;
+
+	ret = sc2210_check_sensor_id(sc2210, client);
+	if (ret)
+		goto err_power_off;
+
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+	sd->internal_ops = &sc2210_internal_ops;
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+		     V4L2_SUBDEV_FL_HAS_EVENTS;
+#endif
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	sc2210->pad.flags = MEDIA_PAD_FL_SOURCE;
+	sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
+	ret = media_entity_pads_init(&sd->entity, 1, &sc2210->pad);
+	if (ret < 0)
+		goto err_power_off;
+#endif
+
+	memset(facing, 0, sizeof(facing));
+	if (strcmp(sc2210->module_facing, "back") == 0)
+		facing[0] = 'b';
+	else
+		facing[0] = 'f';
+
+	snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s",
+		 sc2210->module_index, facing,
+		 sc2210_NAME, dev_name(sd->dev));
+	ret = v4l2_async_register_subdev_sensor_common(sd);
+	if (ret) {
+		dev_err(dev, "v4l2 async register subdev failed\n");
+		goto err_clean_entity;
+	}
+
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+	if (sc2210->is_thunderboot)
+		pm_runtime_get_sync(dev);
+	else
+		pm_runtime_idle(dev);
+
+	return 0;
+
+err_clean_entity:
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	media_entity_cleanup(&sd->entity);
+#endif
+err_power_off:
+	__sc2210_power_off(sc2210);
+err_free_handler:
+	v4l2_ctrl_handler_free(&sc2210->ctrl_handler);
+err_destroy_mutex:
+	mutex_destroy(&sc2210->mutex);
+
+	return ret;
+}
+
+static int sc2210_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct sc2210 *sc2210 = to_sc2210(sd);
+
+	v4l2_async_unregister_subdev(sd);
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	media_entity_cleanup(&sd->entity);
+#endif
+	v4l2_ctrl_handler_free(&sc2210->ctrl_handler);
+	mutex_destroy(&sc2210->mutex);
+
+	pm_runtime_disable(&client->dev);
+	if (!pm_runtime_status_suspended(&client->dev))
+		__sc2210_power_off(sc2210);
+	pm_runtime_set_suspended(&client->dev);
+
+	return 0;
+}
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id sc2210_of_match[] = {
+	{ .compatible = "smartsens,sc2210" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, sc2210_of_match);
+#endif
+
+static const struct i2c_device_id sc2210_match_id[] = {
+	{ "smartsens,sc2210", 0 },
+	{ },
+};
+
+static struct i2c_driver sc2210_i2c_driver = {
+	.driver = {
+		.name = sc2210_NAME,
+		.pm = &sc2210_pm_ops,
+		.of_match_table = of_match_ptr(sc2210_of_match),
+	},
+	.probe		= &sc2210_probe,
+	.remove		= &sc2210_remove,
+	.id_table	= sc2210_match_id,
+};
+
+static int __init sensor_mod_init(void)
+{
+	return i2c_add_driver(&sc2210_i2c_driver);
+}
+
+static void __exit sensor_mod_exit(void)
+{
+	i2c_del_driver(&sc2210_i2c_driver);
+}
+
+#if defined(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP) && !defined(CONFIG_INITCALL_ASYNC)
+subsys_initcall(sensor_mod_init);
+#else
+device_initcall_sync(sensor_mod_init);
+#endif
+module_exit(sensor_mod_exit);
+
+MODULE_DESCRIPTION("smartsens sc2210 sensor driver");
+MODULE_LICENSE("GPL");

File diff suppressed because it is too large
+ 372 - 0
sc2210_0x8.7.json


+ 649 - 0
sc2210_mipi.c

@@ -0,0 +1,649 @@
+/*
+ * sc2210_mipi.c
+ *
+*/
+
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#include "isp_func_def.h"
+#include "isp_sensor_if.h"
+
+
+#include "sensor_ops.h"
+#include "clock_ops.h"
+#include "isp_enum.h"
+#include "mipi_api.h"
+#include "sc2210_mipi.h"
+#include "sensor.h"
+
+
+#ifndef OS_LINUX
+#include <rtthread.h>
+#endif
+
+static struct sns_cfg_s sns_cfg = {
+    .inited = 0,
+    .curr_exposure_ratio = 256,  // 默认初始化为16倍
+    .MinRstLine = 5,
+    .minAGain = 0x40,
+};
+
+static int SetIntt(FH_UINT32 intt, FH_UINT8 fNo);
+static int GetIntt();
+static int SetGain(FH_UINT32 again, FH_UINT8 fNo);
+static int GetGain();
+static int SetExposureRatio(FH_UINT32 exposure_ratio);
+static int GetExposureRatio(FH_UINT32 *exposure_ratio);
+
+static int GetSensorViAttr(ISP_VI_ATTR_S *vi_attr)
+{
+
+    if(vi_attr == NULL)
+        return FH_ERR_NULL_POINTER;
+
+    switch (sns_cfg.sensor_fmt)
+    {
+    case FORMAT_1080P25:
+        vi_attr->u16WndWidth = FRAM_W_1080P25;
+        vi_attr->u16WndHeight = FRAM_H_1080P25;
+        vi_attr->u16InputWidth = ACTIVE_W_1080P25;
+        vi_attr->u16InputHeight = ACTIVE_H_1080P25;
+        vi_attr->u16PicWidth = PIC_IN_W_1080P25;
+        vi_attr->u16PicHeight = PIC_IN_H_1080P25;
+        vi_attr->u16OffsetX = OFFSET_X_1080P25;
+        vi_attr->u16OffsetY = OFFSET_Y_1080P25;
+        vi_attr->enBayerType = BAYER_BGGR;
+        sns_cfg.curr_hsf = 25 * vi_attr->u16WndHeight;
+        break;
+    case FORMAT_1080P30:
+        vi_attr->u16WndWidth = FRAM_W_1080P30;
+        vi_attr->u16WndHeight = FRAM_H_1080P30;
+        vi_attr->u16InputWidth = ACTIVE_W_1080P30;
+        vi_attr->u16InputHeight = ACTIVE_H_1080P30;
+        vi_attr->u16PicWidth = PIC_IN_W_1080P30;
+        vi_attr->u16PicHeight = PIC_IN_H_1080P30;
+        vi_attr->u16OffsetX = OFFSET_X_1080P30;
+        vi_attr->u16OffsetY = OFFSET_Y_1080P30;
+        vi_attr->enBayerType = BAYER_BGGR;
+        
+        sns_cfg.curr_hsf = 30 * vi_attr->u16WndHeight;
+        break;
+    case FORMAT_WDR_1080P25:
+        vi_attr->u16WndWidth = FRAM_W_1080P25_WDR;
+        vi_attr->u16WndHeight = FRAM_H_1080P25_WDR;
+        vi_attr->u16InputWidth = ACTIVE_W_1080P25_WDR;
+        vi_attr->u16InputHeight = ACTIVE_H_1080P25_WDR;
+        vi_attr->u16PicWidth = PIC_IN_W_1080P25_WDR;
+        vi_attr->u16PicHeight = PIC_IN_H_1080P25_WDR;
+        vi_attr->u16OffsetX = OFFSET_X_1080P25_WDR;
+        vi_attr->u16OffsetY = OFFSET_Y_1080P25_WDR;
+        vi_attr->enBayerType = BAYER_BGGR;
+        
+        sns_cfg.curr_hsf = 25 * vi_attr->u16WndHeight;
+        break;     
+    case FORMAT_WDR_1080P30:
+        vi_attr->u16WndWidth = FRAM_W_1080P30_WDR;
+        vi_attr->u16WndHeight = FRAM_H_1080P30_WDR;
+        vi_attr->u16InputWidth = ACTIVE_W_1080P30_WDR;
+        vi_attr->u16InputHeight = ACTIVE_H_1080P30_WDR;
+        vi_attr->u16PicWidth = PIC_IN_W_1080P30_WDR;
+        vi_attr->u16PicHeight = PIC_IN_H_1080P30_WDR;
+        vi_attr->u16OffsetX = OFFSET_X_1080P30_WDR;
+        vi_attr->u16OffsetY = OFFSET_Y_1080P30_WDR;
+        vi_attr->enBayerType = BAYER_BGGR;
+        
+        sns_cfg.curr_hsf = 30 * vi_attr->u16WndHeight;
+        break;
+    default:
+        break;
+    }
+    return 0;
+}
+
+static void SensorReset(void)
+{
+	return;
+}
+
+static unsigned short sc2210_i2c_addr = 0x60;
+static int Sensor_Isconnect(void)
+{
+    unsigned short pid1, pid2;
+    unsigned short i2c_addr[4] = {0x60,0x62, 0x64,0x66};
+    int i;
+    for(i = 0; i < 4; i ++)
+    {
+        SensorDevice_Init((i2c_addr[i] >> 1), 2);
+
+        pid1 = Sensor_Read(0x3107);
+        if(pid1!=0x22)
+        {
+            SensorDevice_Close();
+            continue;
+        }
+        pid2 = Sensor_Read(0x3108);
+        SensorDevice_Close();
+        if (pid1 == 0x22 && pid2 == 0x10) 
+        {
+            sc2210_i2c_addr = i2c_addr[i];
+            return 1;
+        }   
+        else
+        {
+            continue;
+        }
+    } 
+	return 0;
+}
+
+static int Sensor_Init(void)
+{
+    Sensor_Isconnect();
+
+    SensorDevice_Init((sc2210_i2c_addr>>1), 2); 
+
+    SensorReset();
+
+    sns_cfg.inited = 1;
+    return 0;
+}
+
+static int Sensor_DeInit(void)
+{
+    SensorReset();
+    return SensorDevice_Close();
+}
+
+
+// GetGain仅在ae refresh时会重新获取,所以尽量直接从sensor端获取,保证intt的正确性
+static int GetGain()
+{
+    return sns_cfg.curr_sensor_gain;
+
+}
+// GetIntt仅在ae refresh时会重新获取,所以尽量直接从sensor端获取,保证intt的正确性
+static int GetIntt(void)
+{
+    return sns_cfg.curr_sensor_intt;
+
+}
+
+static int SetLaneNumMax(FH_UINT32 lane_num)
+{
+    sns_cfg.maxLaneNum = lane_num;
+    return 0;
+}
+
+static void SetSensorMipiCfg(void)
+{
+
+    struct mipi_conf config;
+    config.frq_range = R_750_799;
+    config.sensor_mode = NOT_SONY_WDR_USE_WDR;
+    config.raw_type = RAW10;
+   // config.lf_vc_id = 0;
+   // config.sf_vc_id = 1;
+   // config.lane_num =2;
+    if(!sns_cfg.wdr_flag)
+    {
+
+        config.lf_vc_id = 0xff;//0xff
+        config.sf_vc_id = 0xff;//0xff
+        config.lane_num =2;
+    }
+    else
+    {
+
+        config.lf_vc_id = 0;
+        config.sf_vc_id = 2;
+        config.lane_num =2;
+    }
+    
+    mipi_init(&config);
+
+}
+
+static int SetSensorFmt(int format)
+{
+    sns_cfg.sensor_fmt = format;
+    sns_cfg.wdr_flag = (format >> 16)&1;
+
+    SetSensorMipiCfg();
+
+
+    if(sns_cfg.inited)
+    {
+        int i;
+
+       
+        printf("sc2210 ver20210701\n");
+        switch(format)
+        {
+        case FORMAT_1080P25:
+            printf("1080p25\n");
+            for(i=0; i<sizeof(Sensor_Cfg_SC2210_MIPI_1080P25)/4; i++)
+            {
+                Sensor_Write(Sensor_Cfg_SC2210_MIPI_1080P25[2*i], Sensor_Cfg_SC2210_MIPI_1080P25[2*i+1]);
+            }
+            break;
+        case FORMAT_1080P30:
+            printf("1080p30\n");
+            for(i=0; i<sizeof(Sensor_Cfg_SC2210_MIPI_1080P30)/4; i++)
+            {
+                Sensor_Write(Sensor_Cfg_SC2210_MIPI_1080P30[2*i], Sensor_Cfg_SC2210_MIPI_1080P30[2*i+1]);
+            }
+            break;
+        case FORMAT_WDR_1080P25:
+            printf("1080p25wdr\n");
+            for(i=0; i<sizeof(Sensor_Cfg_SC2210_MIPI_1080P25_WDR)/4; i++)
+            {
+                Sensor_Write(Sensor_Cfg_SC2210_MIPI_1080P25_WDR[2*i], Sensor_Cfg_SC2210_MIPI_1080P25_WDR[2*i+1]);
+            }
+            break;
+        case FORMAT_WDR_1080P30:
+            printf("1080p30wdr\n");
+            for(i=0; i<sizeof(Sensor_Cfg_SC2210_MIPI_1080P30_WDR)/4; i++)
+            {
+                Sensor_Write(Sensor_Cfg_SC2210_MIPI_1080P30_WDR[2*i], Sensor_Cfg_SC2210_MIPI_1080P30_WDR[2*i+1]);
+            }
+            break;
+        default:
+            printf("Format error!");
+            return -1;
+            break;
+        }
+         usleep(20000);
+    }
+    else
+    {
+        return -1;
+    }
+
+    sns_cfg.v_cycle = (Sensor_Read(0x320e) << 8) | (Sensor_Read(0x320f));
+    sns_cfg.fullLineStd = sns_cfg.v_cycle;
+    if (sns_cfg.wdr_flag == 0)
+    {
+        sns_cfg.MinRstLine = 5;
+    }
+    else
+    {
+        sns_cfg.MinRstLine = sns_cfg.v_cycle / 7 + 5;
+    }
+
+    sns_cfg.max_intt = sns_cfg.v_cycle - sns_cfg.MinRstLine;
+    SetIntt(sns_cfg.max_intt, 0);
+    SetExposureRatio(sns_cfg.curr_exposure_ratio);
+    SetGain(sns_cfg.minAGain, 0);
+    sns_cfg.curr_sensor_gain = sns_cfg.minAGain;
+    return 0;
+}
+
+static int GetAEInfo(Sensor_AE_INFO_S *sensAEInfo)
+{
+    sensAEInfo->currIntt = GetIntt();
+    sensAEInfo->currAGain = GetGain();
+    sensAEInfo->currHsf = sns_cfg.curr_hsf;
+    sensAEInfo->currFrameH = sns_cfg.v_cycle;
+    return 0;
+
+}
+
+static int GetAEDefault(Sensor_AE_Default_S *sensAEDefault)
+{
+    sensAEDefault->minIntt = 1;
+    sensAEDefault->maxIntt = sns_cfg.max_intt;
+    sensAEDefault->minAGain = sns_cfg.minAGain;
+    sensAEDefault->maxAGain = 0x7fff;
+    sensAEDefault->fullLineStd = sns_cfg.fullLineStd;
+    sensAEDefault->MinRstLine = sns_cfg.MinRstLine;
+    return 0;
+
+}
+static int CalcSnsValidGain(FH_UINT32 *u32Gain)
+{
+    return 0;
+}
+
+static int SetGain(FH_UINT32 again, FH_UINT8 fNo)
+{
+	sns_cfg.curr_sensor_gain = again;
+
+	unsigned char gain_0x3e06 = 0x00;
+	unsigned char gain_0x3e07 = 0x80;
+	unsigned char gain_0x3e08 = 0x03;
+	unsigned char gain_0x3e09 = 0x40;
+    //UINT32 gainShift = 0;
+
+	//printf("again: 0x%x, ", again);
+	
+	
+	if (again < 64 * 2) 	  //again 1x-2x
+	{
+		gain_0x3e08 = 0x03;
+		gain_0x3e09 = again;
+		gain_0x3e06 = 0x0; 
+		gain_0x3e07 = 0x80;
+	}
+	else if (again <= 64 * 3.375) //again 2x-3.375x
+	{
+		gain_0x3e08 = 0x07;
+		gain_0x3e09 = again / 2;
+		gain_0x3e06 = 0x0; 
+		gain_0x3e07 = 0x80;
+	}
+	else if (again <= 64 * 3.375 * 2) //again 3.375x-6.812x
+	{
+		gain_0x3e08 = 0x23;
+		gain_0x3e09 = again / 3.375;
+		gain_0x3e06 = 0x0; 
+		gain_0x3e07 = 0x80;
+	}
+	else if (again <= 64 * 3.375 * 4) //again 6.812x-13.624x
+	{
+		gain_0x3e08 = 0x27;
+		gain_0x3e09 = again / 3.375 / 2;
+		gain_0x3e06 = 0x0; 
+		gain_0x3e07 = 0x80;
+	}
+	else if (again <= 64 * 3.375 * 8) //again 13.624x-27.248x
+	{
+		gain_0x3e08 = 0x2f;
+		gain_0x3e09 = again / 3.375 / 4;
+		gain_0x3e06 = 0x0; 
+		gain_0x3e07 = 0x80;
+	}
+	else if (again <= 64 * 3.375 * 16) //again 27.248x-54.07x
+	{
+		gain_0x3e08 = 0x3f;
+		gain_0x3e09 = again / 3.375 / 8;
+		gain_0x3e06 = 0x0; 
+		gain_0x3e07 = 0x80;
+	}
+#if 1
+	else if (again <= 64 * 3.375 * 16 * 2) //again 54.07x dgain 2x
+	{
+		gain_0x3e08 = 0x3f;
+		gain_0x3e09 = 0x7f;
+		gain_0x3e06 = 0x0; 
+		gain_0x3e07 = again / 3.375 / 8;
+	}
+	else if (again <= 64 * 3.375 * 16 * 4) //again 54.07x dgain 4x
+	{
+		gain_0x3e08 = 0x3f;
+		gain_0x3e09 = 0x7f;
+		gain_0x3e06 = 0x1; 
+		gain_0x3e07 = again / 3.375 / 16;
+	}
+	else if (again <= 64 * 3.375 * 16 * 8) //again 54.07x dgain 8x 
+	{
+		gain_0x3e08 = 0x3f;
+		gain_0x3e09 = 0x7f;		
+		gain_0x3e06 = 0x3; 
+		gain_0x3e07 = again / 3.375 / 32;
+	}
+	else if (again <= 64 * 3.375 * 16 * 16) //again 54.07x dgain 16x 
+	{
+		gain_0x3e08 = 0x3f;
+		gain_0x3e09 = 0x7f;
+		gain_0x3e06 = 0x7; 
+		gain_0x3e07 = again / 3.375 / 64;
+	}
+	else if (again <= 64 * 3.375 * 16 * 32) //again 54.07x dgain 32x
+	{
+		gain_0x3e08 = 0x3f;
+		gain_0x3e09 = 0x7f;
+		gain_0x3e06 = 0xf; 
+		gain_0x3e07 = again / 3.375 / 128;
+	}
+#endif
+    // high frm GAIN
+	Sensor_Write(0x3e06, gain_0x3e06);
+    Sensor_Write(0x3e07, gain_0x3e07);
+    Sensor_Write(0x3e08, gain_0x3e08);
+    Sensor_Write(0x3e09, gain_0x3e09);
+
+	// low frm GAIN
+	Sensor_Write(0x3e10, gain_0x3e06);
+    Sensor_Write(0x3e11, gain_0x3e07);
+    Sensor_Write(0x3e12, gain_0x3e08);
+    Sensor_Write(0x3e13, gain_0x3e09);
+    return 0;
+}
+
+static int CalcSnsValidIntt(FH_UINT32 *u32Intt)
+{
+    return 0;
+
+}
+
+static int SetIntt(FH_UINT32 intt, FH_UINT8 fNo)
+{
+    //printf("intt=%d----",intt);
+    if(intt<2)
+        intt=2;
+    sns_cfg.curr_sensor_intt = intt;
+    //printf("curr_sensor_intt=%d\n",curr_sensor_intt);
+    /*
+    FH_SINT32 height1L,height1H,height1,height2L,height2H,height2;
+    height1H = Sensor_Read(0x320e);
+	height1L = Sensor_Read(0x320f);
+    height1 = (height1H << 8) | height1L;
+    height2H = Sensor_Read(0x3e23);
+	height2L = Sensor_Read(0x3e24);
+    height2 = (height2H << 8) | height2L;
+    */
+    FH_UINT8 exposure_3e00 = 0x00;
+    FH_UINT8 exposure_3e01 = 0x00;
+    FH_UINT8 exposure_3e02 = 0x00;
+    /*
+    if(wdr_flag==0)
+    {
+        if(intt > height1-4 )
+            intt = height1-4;
+    }
+    else
+    {
+        if(intt > height1-height2-8 )
+            intt = height1-height2-8 ;
+    }
+    */
+    exposure_3e00 = (intt>>12) & 0x0f;
+    exposure_3e01 = (intt &0xfff)>>4;
+    exposure_3e02 = (intt&0xf)<<4;  
+    Sensor_Write(0x3e00, exposure_3e00);
+    Sensor_Write(0x3e01, exposure_3e01);
+    Sensor_Write(0x3e02, exposure_3e02);
+    sns_cfg.curr_sensor_intt = intt;
+    return 0;
+}
+
+static int SetSnsFrameH(FH_UINT32 frameH)
+{
+    //if(sns_cfg.wdr_flag)    
+    //    frame_height = (vi_attr.u16WndHeight )* multiple;
+   // else
+    //    frame_height = (vi_attr.u16WndHeight/2 )* multiple;
+
+    Sensor_Write(0x320e, (frameH>>8)&0xff);
+    Sensor_Write(0x320f, frameH&0xff);
+    sns_cfg.v_cycle = frameH;
+    return 0;
+
+}
+
+
+static int SetExposureRatio(FH_UINT32 exposure_ratio)
+{
+    FH_UINT32 s_intt;
+    //FH_SINT32 s_3e23,s_3e24,sf_exp_limit;
+    if(exposure_ratio == 0) 
+        return 0;
+    //s_3e23=Sensor_Read(0x3e23);
+    //s_3e24=Sensor_Read(0x3e24);
+    //sf_exp_limit=(s_3e23<<8)|s_3e24;
+  
+    s_intt =  MAX((((sns_cfg.curr_sensor_intt<<6)+(exposure_ratio>>1)) / exposure_ratio), 1);
+    
+    //printf("the s_intt =%d, %d\n",s_intt,s_intt%4);
+    if(s_intt < 1)
+        s_intt = 1;
+        /*
+    if(s_intt > (2 * sf_exp_limit -8))
+        s_intt = 2 * sf_exp_limit -8;
+        */
+
+    Sensor_Write(0x3e04, (s_intt&0xfff)>>4);
+    Sensor_Write(0x3e05, (s_intt&0xf)<<4);
+
+    sns_cfg.curr_exposure_ratio = (sns_cfg.curr_sensor_intt<<4)/s_intt;
+    return 0;
+}
+static int GetExposureRatio(FH_UINT32 *exposure_ratio)
+{
+    *exposure_ratio = sns_cfg.curr_exposure_ratio;
+    return 0;
+}
+/*
+static int Sensor_Kick()
+{
+    if (sns_cfg.inited)
+    {
+        SensorDevice_Init((sc2210_i2c_addr>>1), 2); //0x64
+
+        SensorReset();
+
+        sns_cfg.inited = 1;
+    }
+    return 0;
+
+}
+*/
+
+static int SetSensorReg(unsigned short addr,unsigned short data)
+{
+    Sensor_Write(addr,data);
+    return 0;
+}
+static int GetSensorReg(unsigned short addr, unsigned short *data)
+{
+    *data = Sensor_Read(addr);
+    return 0;
+}
+static int SetSensorFlipMirror(FH_UINT32 sensor_en_stat)
+{
+    FH_UINT32 mirror,flip;
+    mirror = (sensor_en_stat >>1)&0x1;
+    flip = sensor_en_stat & 0x1;
+    Sensor_Write(0x3221,    ((flip?0x3:0x00)<<5) | ((mirror?0x3:0x00) <<1) );
+    return 0;
+}
+static int GetSensorFlipMirror(FH_UINT32 *sensor_en_stat)
+{
+    FH_UINT32 mirror,flip,tmp;
+    tmp = Sensor_Read(0x3221);
+    mirror = (tmp>>1) & 0x1;
+    flip =  (tmp>>5) &0x01 ;
+    *sensor_en_stat = (mirror<<1)|flip;
+    return 0;
+}
+
+static int GetSensorAttribute(char *name, FH_UINT32 *value)
+{
+#ifdef OS_LINUX
+    if (strcmp(name, "WDR") == 0) {
+#else
+    if (rt_strcmp(name, "WDR") == 0) {
+#endif
+        *value = sns_cfg.wdr_flag;
+        return 0;
+    }
+
+    return -1;
+}
+
+static int SensorCommonIf(FH_UINT32 cmd, ISP_SENSOR_COMMON_CMD_DATA0* data0, ISP_SENSOR_COMMON_CMD_DATA1* data1)
+{
+     int ret = -1;
+
+
+     return ret;
+
+}
+
+static FH_UINT32* GetMirrorFlipBayerFormat(void) {
+     return NAME(MirrorFlipBayerFormat);
+}
+
+static FH_UINT32* GetUserSensorAwbGain(FH_UINT32 idx) {return 0;}
+
+static FH_UINT32* GetSensorLtmCurve(FH_UINT32 idx) {
+    return 0;
+}
+
+
+
+/***********************adv api related end*************************************/
+
+        /***********************not used for now start**********************************/
+static int SetSensorAwbGain(FH_UINT32 *awb_gain){return 0;}
+static int GetSensorAwbGain(FH_UINT32 *awb_gain){return 0;}
+static int SetSensorIris(FH_UINT32 iris){return 0;}
+
+#define SENSOR_SC2210_MIPI	"sc2210_mipi"
+struct isp_sensor_if sc2210_mipi_sensor_if;
+
+/***********************not used for now end************************************/
+#ifdef OS_RTT
+struct isp_sensor_if sc2210_mipi_sensor_if __attribute__((section(".sensor_drv"))) = {
+#else
+struct isp_sensor_if sc2210_mipi_sensor_if = {
+#endif
+
+    .name = SENSOR_SC2210_MIPI,
+    .get_vi_attr = GetSensorViAttr,
+    .set_flipmirror = SetSensorFlipMirror,
+    .get_flipmirror = GetSensorFlipMirror,
+    .set_iris = SetSensorIris,
+    .init = Sensor_Init,
+    .reset = SensorReset,
+    .deinit = Sensor_DeInit,
+    .set_sns_fmt = SetSensorFmt,
+    //.kick = Sensor_Kick,
+    .set_sns_reg = SetSensorReg,
+    .set_exposure_ratio = SetExposureRatio,
+    .get_exposure_ratio = GetExposureRatio,
+    .get_sensor_attribute = GetSensorAttribute,
+    .set_lane_num_max = SetLaneNumMax,
+    .get_sns_reg = GetSensorReg,
+    .get_awb_gain = GetSensorAwbGain,
+    .set_awb_gain = SetSensorAwbGain,
+    .data = 0,
+    .common_if = SensorCommonIf,
+    .get_sns_ae_default = GetAEDefault,
+    .get_sns_ae_info = GetAEInfo,
+    .set_sns_intt = SetIntt,
+    .calc_sns_valid_intt = CalcSnsValidIntt,
+    .set_sns_gain =  SetGain,
+    .calc_sns_valid_gain = CalcSnsValidGain,
+    .set_sns_frame_height = SetSnsFrameH,
+    .get_sensor_mirror_flip_bayer_format = GetMirrorFlipBayerFormat,
+    .get_user_awb_gain = GetUserSensorAwbGain,
+    .get_user_ltm_curve = GetSensorLtmCurve,
+    .is_sensor_connect = Sensor_Isconnect,
+};
+#ifdef OS_RTT
+#else
+struct isp_sensor_if* NAME(Sensor_Create)() {
+    return &sc2210_mipi_sensor_if;
+}
+
+void NAME(Sensor_Destroy)(struct isp_sensor_if* s_if){
+    memset(&sc2210_mipi_sensor_if, 0, sizeof(struct isp_sensor_if));
+}
+#endif
+

+ 1126 - 0
sc2210_mipi.h

@@ -0,0 +1,1126 @@
+#ifndef SC2210_MIPI_H_
+#define SC2210_MIPI_H_
+
+#define _NAME(n, s) n##_##s
+#if MULTI_SENSOR
+#define NAME(n) _NAME(n, SC2210_MIPI)
+#else
+#define NAME(n) n
+#endif
+//---------------------------1080P25-------------------------------------------------------
+#define FRAM_W_1080P25				1100//2200
+#define FRAM_H_1080P25				1350
+#define ACTIVE_W_1080P25			1920
+#define ACTIVE_H_1080P25			1080
+#define PIC_IN_W_1080P25			1920
+#define PIC_IN_H_1080P25			1080
+#define OFFSET_X_1080P25			0
+#define OFFSET_Y_1080P25			0
+//---------------------------1080P30-------------------------------------------------------
+#define FRAM_W_1080P30				1100//2200
+#define FRAM_H_1080P30				1125//1100
+#define ACTIVE_W_1080P30			1920
+#define ACTIVE_H_1080P30			1080//1088
+#define PIC_IN_W_1080P30			1920
+#define PIC_IN_H_1080P30			1080
+#define OFFSET_X_1080P30			0
+#define OFFSET_Y_1080P30			0
+
+//---------------------------1080P25 wdr-------------------------------------------------------
+#define FRAM_W_1080P25_WDR				1100//2200//2640//2529//2200
+#define FRAM_H_1080P25_WDR				1440//2880//2250//2700
+#define ACTIVE_W_1080P25_WDR			1920
+#define ACTIVE_H_1080P25_WDR			1080
+#define PIC_IN_W_1080P25_WDR			1920
+#define PIC_IN_H_1080P25_WDR			1080
+#define OFFSET_X_1080P25_WDR			0
+#define OFFSET_Y_1080P25_WDR			0
+
+
+//---------------------------1080P30 wdr-------------------------------------------------------
+#define FRAM_W_1080P30_WDR				1100//2200//2200
+#define FRAM_H_1080P30_WDR				1200//2400//2250//1250//2400//1250//2250//1125
+#define ACTIVE_W_1080P30_WDR			1920
+#define ACTIVE_H_1080P30_WDR			1080
+#define PIC_IN_W_1080P30_WDR			1920
+#define PIC_IN_H_1080P30_WDR			1080
+#define OFFSET_X_1080P30_WDR			0
+#define OFFSET_Y_1080P30_WDR			0
+
+const unsigned short Sensor_Cfg_SC2210_MIPI_1080P30_WDR[]=
+{
+
+0x0103,0x01,
+0x0100,0x00,
+0x36e9,0x80,
+0x36f9,0x80,
+0x3001,0x07,
+0x3002,0xc0,
+0x300a,0x2c,
+0x300f,0x00,
+0x3018,0x33,
+0x3019,0x0c,
+0x301f,0x48,
+0x3031,0x0a,
+0x3033,0x20,
+0x3038,0x22,
+0x3106,0x81,
+0x3201,0x04,
+0x3203,0x04,
+0x3204,0x07,
+0x3205,0x8b,
+0x3206,0x04,
+0x3207,0x43,
+0x320c,0x04,
+0x320d,0x4c,
+0x320e,0x09,
+0x320f,0x60,
+0x3211,0x04,
+0x3213,0x04,
+0x3220,0x53,
+0x3231,0x02,
+0x3250,0x3f,
+0x3253,0x04,
+0x3301,0x0c,
+0x3302,0x10,
+0x3304,0x58,
+0x3305,0x00,
+0x3306,0xb0,
+0x3308,0x20,
+0x3309,0x98,
+0x330a,0x01,
+0x330b,0x68,
+0x3000,0xc0,
+0x330e,0x48,
+0x3314,0x92,
+0x331e,0x49,
+0x331f,0x89,
+0x334c,0x10,
+0x335d,0x60,
+0x335e,0x02,
+0x335f,0x06,
+0x3364,0x16,
+0x3366,0x92,
+0x3367,0x10,
+0x3368,0x04,
+0x3369,0x00,
+0x336a,0x00,
+0x336b,0x00,
+0x336d,0x03,
+0x337c,0x08,
+0x337d,0x0e,
+0x337f,0x33,
+0x3390,0x10,
+0x3391,0x30,
+0x3392,0x40,
+0x3393,0x0c,
+0x3394,0x0c,
+0x3395,0x0c,
+0x3396,0x0c,
+0x3397,0x30,
+0x3398,0x3f,
+0x3399,0x30,
+0x339a,0x30,
+0x339b,0x30,
+0x339c,0x30,
+0x33a2,0x0a,
+0x33b9,0x0e,
+0x33e1,0x08,
+0x33e2,0x18,
+0x33e3,0x18,
+0x33e4,0x18,
+0x33e5,0x10,
+0x33e6,0x06,
+0x33e7,0x02,
+0x33e8,0x18,
+0x33e9,0x10,
+0x33ea,0x0c,
+0x33eb,0x10,
+0x33ec,0x04,
+0x33ed,0x02,
+0x33ee,0xa0,
+0x33ef,0x08,
+0x33f4,0x18,
+0x33f5,0x10,
+0x33f6,0x0c,
+0x33f7,0x10,
+0x33f8,0x06,
+0x33f9,0x02,
+0x33fa,0x18,
+0x33fb,0x10,
+0x33fc,0x0c,
+0x33fd,0x10,
+0x33fe,0x04,
+0x33ff,0x02,
+0x360f,0x01,
+0x3622,0xf7,
+0x3625,0x0a,
+0x3627,0x02,
+0x3630,0xa2,
+0x3631,0x00,
+0x3632,0xd8,
+0x3633,0x43,
+0x3635,0x20,
+0x3638,0x24,
+0x363a,0x80,
+0x363b,0x02,
+0x363e,0x22,
+0x3670,0x48,
+0x3671,0xf7,
+0x3672,0xf7,
+0x3673,0x07,
+0x367a,0x40,
+0x367b,0x7f,
+0x3690,0x42,
+0x3691,0x43,
+0x3692,0x54,
+0x369c,0x40,
+0x369d,0x7f,
+0x36b5,0x40,
+0x36b6,0x7f,
+0x36c0,0x80,
+0x36c1,0x9f,
+0x36c2,0x9f,
+0x36cc,0x20,
+0x36cd,0x20,
+0x36ce,0x30,
+0x36d0,0x20,
+0x36d1,0x40,
+0x36d2,0x7f,
+0x36ea,0x35,
+0x36eb,0x05,
+0x36ec,0x03,
+0x36ed,0x04,
+0x36fa,0xf5,
+0x36fb,0x15,
+0x36fc,0x10,
+0x36fd,0x07,
+0x3905,0xd8,
+0x3907,0x01,
+0x3908,0x11,
+0x391b,0x83,
+0x391f,0x00,
+0x3933,0x28,
+0x3934,0xa6,
+0x3940,0x70,
+0x3942,0x08,
+0x3943,0xbc,
+0x3958,0x02,
+0x3959,0x04,
+0x3980,0x61,
+0x3987,0x0b,
+0x3990,0x00,
+0x3991,0x00,
+0x3992,0x00,
+0x3993,0x00,
+0x3994,0x00,
+0x3995,0x00,
+0x3996,0x00,
+0x3997,0x00,
+0x3998,0x00,
+0x3999,0x00,
+0x399a,0x00,
+0x399b,0x00,
+0x399c,0x00,
+0x399d,0x00,
+0x399e,0x00,
+0x399f,0x00,
+0x39a0,0x00,
+0x39a1,0x00,
+0x39a2,0x03,
+0x39a3,0x30,
+0x39a4,0x03,
+0x39a5,0x60,
+0x39a6,0x03,
+0x39a7,0xa0,
+0x39a8,0x03,
+0x39a9,0xb0,
+0x39aa,0x00,
+0x39ab,0x00,
+0x39ac,0x00,
+0x39ad,0x20,
+0x39ae,0x00,
+0x39af,0x40,
+0x39b0,0x00,
+0x39b1,0x60,
+0x39b2,0x00,
+0x39b3,0x00,
+0x39b4,0x08,
+0x39b5,0x14,
+0x39b6,0x20,
+0x39b7,0x38,
+0x39b8,0x38,
+0x39b9,0x20,
+0x39ba,0x14,
+0x39bb,0x08,
+0x39bc,0x08,
+0x39bd,0x10,
+0x39be,0x20,
+0x39bf,0x30,
+0x39c0,0x30,
+0x39c1,0x20,
+0x39c2,0x10,
+0x39c3,0x08,
+0x39c4,0x00,
+0x39c5,0x80,
+0x39c6,0x00,
+0x39c7,0x80,
+0x39c8,0x00,
+0x39c9,0x00,
+0x39ca,0x80,
+0x39cb,0x00,
+0x39cc,0x00,
+0x39cd,0x00,
+0x39ce,0x00,
+0x39cf,0x00,
+0x39d0,0x00,
+0x39d1,0x00,
+0x39e2,0x05,
+0x39e3,0xeb,
+0x39e4,0x07,
+0x39e5,0xb6,
+0x39e6,0x00,
+0x39e7,0x3a,
+0x39e8,0x3f,
+0x39e9,0xb7,
+0x39ea,0x02,
+0x39eb,0x4f,
+0x39ec,0x08,
+0x39ed,0x00,
+0x3e00,0x00,
+0x3e01,0x8c,
+0x3e02,0x00,
+0x3e03,0x0b,
+0x3e04,0x08,
+0x3e05,0xc0,
+0x3e06,0x00,
+0x3e07,0x80,
+0x3e08,0x03,
+0x3e09,0x40,
+0x3e10,0x00,
+0x3e11,0x80,
+0x3e12,0x03,
+0x3e13,0x40,
+0x3e14,0x31,
+0x3e1b,0x3a,
+0x3e22,0x00,
+0x3e23,0x00,
+0x3e24,0x92,
+0x3e26,0x40,
+0x3f08,0x08,
+0x4401,0x1a,
+0x4407,0xc0,
+0x4418,0x34,
+0x4500,0x18,
+0x4501,0xb4,
+0x4503,0xc0,
+0x4509,0x20,
+0x4603,0x00,
+0x4800,0x24,
+0x4814,0x2a,
+0x4837,0x14,
+0x4851,0xab,
+0x4853,0xf8,
+0x5000,0x0e,
+0x550f,0x20,
+0x36e9,0x27,
+0x36f9,0x33,
+0x0100,0x01,
+
+};
+const unsigned short Sensor_Cfg_SC2210_MIPI_1080P25_WDR[]= //haven't change 
+{
+0x0103,0x01,
+0x0100,0x00,
+0x36e9,0x80,
+0x36f9,0x80,
+0x3001,0x07,
+0x3002,0xc0,
+0x300a,0x2c,
+0x300f,0x00,
+0x3018,0x33,
+0x3019,0x0c,
+0x301f,0x48,
+0x3031,0x0a,
+0x3033,0x20,
+0x3038,0x22,
+0x3106,0x81,
+0x3201,0x04,
+0x3203,0x04,
+0x3204,0x07,
+0x3205,0x8b,
+0x3206,0x04,
+0x3207,0x43,
+0x320c,0x04,
+0x320d,0x4c,
+0x320e,0x0b,
+0x320f,0x40,
+0x3211,0x04,
+0x3213,0x04,
+0x3220,0x53,
+0x3231,0x02,
+0x3250,0x3f,
+0x3253,0x04,
+0x3301,0x0c,
+0x3302,0x10,
+0x3304,0x58,
+0x3305,0x00,
+0x3306,0xb0,
+0x3308,0x20,
+0x3309,0x98,
+0x330a,0x01,
+0x330b,0x68,
+0x3000,0xc0,
+0x330e,0x48,
+0x3314,0x92,
+0x331e,0x49,
+0x331f,0x89,
+0x334c,0x10,
+0x335d,0x60,
+0x335e,0x02,
+0x335f,0x06,
+0x3364,0x16,
+0x3366,0x92,
+0x3367,0x10,
+0x3368,0x04,
+0x3369,0x00,
+0x336a,0x00,
+0x336b,0x00,
+0x336d,0x03,
+0x337c,0x08,
+0x337d,0x0e,
+0x337f,0x33,
+0x3390,0x10,
+0x3391,0x30,
+0x3392,0x40,
+0x3393,0x0c,
+0x3394,0x0c,
+0x3395,0x0c,
+0x3396,0x0c,
+0x3397,0x30,
+0x3398,0x3f,
+0x3399,0x30,
+0x339a,0x30,
+0x339b,0x30,
+0x339c,0x30,
+0x33a2,0x0a,
+0x33b9,0x0e,
+0x33e1,0x08,
+0x33e2,0x18,
+0x33e3,0x18,
+0x33e4,0x18,
+0x33e5,0x10,
+0x33e6,0x06,
+0x33e7,0x02,
+0x33e8,0x18,
+0x33e9,0x10,
+0x33ea,0x0c,
+0x33eb,0x10,
+0x33ec,0x04,
+0x33ed,0x02,
+0x33ee,0xa0,
+0x33ef,0x08,
+0x33f4,0x18,
+0x33f5,0x10,
+0x33f6,0x0c,
+0x33f7,0x10,
+0x33f8,0x06,
+0x33f9,0x02,
+0x33fa,0x18,
+0x33fb,0x10,
+0x33fc,0x0c,
+0x33fd,0x10,
+0x33fe,0x04,
+0x33ff,0x02,
+0x360f,0x01,
+0x3622,0xf7,
+0x3625,0x0a,
+0x3627,0x02,
+0x3630,0xa2,
+0x3631,0x00,
+0x3632,0xd8,
+0x3633,0x43,
+0x3635,0x20,
+0x3638,0x24,
+0x363a,0x80,
+0x363b,0x02,
+0x363e,0x22,
+0x3670,0x48,
+0x3671,0xf7,
+0x3672,0xf7,
+0x3673,0x07,
+0x367a,0x40,
+0x367b,0x7f,
+0x3690,0x42,
+0x3691,0x43,
+0x3692,0x54,
+0x369c,0x40,
+0x369d,0x7f,
+0x36b5,0x40,
+0x36b6,0x7f,
+0x36c0,0x80,
+0x36c1,0x9f,
+0x36c2,0x9f,
+0x36cc,0x20,
+0x36cd,0x20,
+0x36ce,0x30,
+0x36d0,0x20,
+0x36d1,0x40,
+0x36d2,0x7f,
+0x36ea,0x35,
+0x36eb,0x05,
+0x36ec,0x03,
+0x36ed,0x04,
+0x36fa,0xf5,
+0x36fb,0x15,
+0x36fc,0x10,
+0x36fd,0x07,
+0x3905,0xd8,
+0x3907,0x01,
+0x3908,0x11,
+0x391b,0x83,
+0x391f,0x00,
+0x3933,0x28,
+0x3934,0xa6,
+0x3940,0x70,
+0x3942,0x08,
+0x3943,0xbc,
+0x3958,0x02,
+0x3959,0x04,
+0x3980,0x61,
+0x3987,0x0b,
+0x3990,0x00,
+0x3991,0x00,
+0x3992,0x00,
+0x3993,0x00,
+0x3994,0x00,
+0x3995,0x00,
+0x3996,0x00,
+0x3997,0x00,
+0x3998,0x00,
+0x3999,0x00,
+0x399a,0x00,
+0x399b,0x00,
+0x399c,0x00,
+0x399d,0x00,
+0x399e,0x00,
+0x399f,0x00,
+0x39a0,0x00,
+0x39a1,0x00,
+0x39a2,0x03,
+0x39a3,0x30,
+0x39a4,0x03,
+0x39a5,0x60,
+0x39a6,0x03,
+0x39a7,0xa0,
+0x39a8,0x03,
+0x39a9,0xb0,
+0x39aa,0x00,
+0x39ab,0x00,
+0x39ac,0x00,
+0x39ad,0x20,
+0x39ae,0x00,
+0x39af,0x40,
+0x39b0,0x00,
+0x39b1,0x60,
+0x39b2,0x00,
+0x39b3,0x00,
+0x39b4,0x08,
+0x39b5,0x14,
+0x39b6,0x20,
+0x39b7,0x38,
+0x39b8,0x38,
+0x39b9,0x20,
+0x39ba,0x14,
+0x39bb,0x08,
+0x39bc,0x08,
+0x39bd,0x10,
+0x39be,0x20,
+0x39bf,0x30,
+0x39c0,0x30,
+0x39c1,0x20,
+0x39c2,0x10,
+0x39c3,0x08,
+0x39c4,0x00,
+0x39c5,0x80,
+0x39c6,0x00,
+0x39c7,0x80,
+0x39c8,0x00,
+0x39c9,0x00,
+0x39ca,0x80,
+0x39cb,0x00,
+0x39cc,0x00,
+0x39cd,0x00,
+0x39ce,0x00,
+0x39cf,0x00,
+0x39d0,0x00,
+0x39d1,0x00,
+0x39e2,0x05,
+0x39e3,0xeb,
+0x39e4,0x07,
+0x39e5,0xb6,
+0x39e6,0x00,
+0x39e7,0x3a,
+0x39e8,0x3f,
+0x39e9,0xb7,
+0x39ea,0x02,
+0x39eb,0x4f,
+0x39ec,0x08,
+0x39ed,0x00,
+0x3e00,0x00,
+0x3e01,0x8c,
+0x3e02,0x00,
+0x3e03,0x0b,
+0x3e04,0x08,
+0x3e05,0xc0,
+0x3e06,0x00,
+0x3e07,0x80,
+0x3e08,0x03,
+0x3e09,0x40,
+0x3e10,0x00,
+0x3e11,0x80,
+0x3e12,0x03,
+0x3e13,0x40,
+0x3e14,0x31,
+0x3e1b,0x3a,
+0x3e22,0x00,
+0x3e23,0x00,
+0x3e24,0x92,
+0x3e26,0x40,
+0x3f08,0x08,
+0x4401,0x1a,
+0x4407,0xc0,
+0x4418,0x34,
+0x4500,0x18,
+0x4501,0xb4,
+0x4503,0xc0,
+0x4509,0x20,
+0x4603,0x00,
+0x4800,0x24,
+0x4814,0x2a,
+0x4837,0x14,
+0x4851,0xab,
+0x4853,0xf8,
+0x5000,0x0e,
+0x550f,0x20,
+0x36e9,0x27,
+0x36f9,0x33,
+0x0100,0x01,
+
+};
+const unsigned short Sensor_Cfg_SC2210_MIPI_1080P30[]=
+{
+
+0x0103,0x01,
+0x0100,0x00,
+0x36e9,0x80,
+0x36f9,0x80,
+0x3001,0x07,
+0x3002,0xc0,
+0x300a,0x2c,
+0x300f,0x00,
+0x3018,0x33,
+0x3019,0x0c,
+0x301f,0x47,
+0x3031,0x0a,
+0x3033,0x20,
+0x3038,0x22,
+0x3106,0x81,
+0x3201,0x04,
+0x3203,0x04,
+0x3204,0x07,
+0x3205,0x8b,
+0x3206,0x04,
+0x3207,0x43,
+0x320c,0x04,
+0x320d,0x4c,
+0x320e,0x04,
+0x320f,0x65,
+0x3211,0x04,
+0x3213,0x04,
+0x3231,0x02,
+0x3253,0x04,
+0x3301,0x0a,
+0x3302,0x10,
+0x3304,0x48,
+0x3305,0x00,
+0x3306,0x68,
+0x3308,0x20,
+0x3309,0x98,
+0x330a,0x00,
+0x330b,0xe8,
+0x330e,0x68,
+0x3314,0x92,
+0x3000,0xc0,
+0x331e,0x41,
+0x331f,0x91,
+0x334c,0x10,
+0x335d,0x60,
+0x335e,0x02,
+0x335f,0x06,
+0x3364,0x16,
+0x3366,0x92,
+0x3367,0x10,
+0x3368,0x04,
+0x3369,0x00,
+0x336a,0x00,
+0x336b,0x00,
+0x336d,0x03,
+0x337c,0x08,
+0x337d,0x0e,
+0x337f,0x33,
+0x3390,0x10,
+0x3391,0x30,
+0x3392,0x40,
+0x3393,0x0a,
+0x3394,0x0a,
+0x3395,0x0a,
+0x3396,0x08,
+0x3397,0x30,
+0x3398,0x3f,
+0x3399,0x50,
+0x339a,0x50,
+0x339b,0x50,
+0x339c,0x50,
+0x33a2,0x0a,
+0x33b9,0x0e,
+0x33e1,0x08,
+0x33e2,0x18,
+0x33e3,0x18,
+0x33e4,0x18,
+0x33e5,0x10,
+0x33e6,0x06,
+0x33e7,0x02,
+0x33e8,0x18,
+0x33e9,0x10,
+0x33ea,0x0c,
+0x33eb,0x10,
+0x33ec,0x04,
+0x33ed,0x02,
+0x33ee,0xa0,
+0x33ef,0x08,
+0x33f4,0x18,
+0x33f5,0x10,
+0x33f6,0x0c,
+0x33f7,0x10,
+0x33f8,0x06,
+0x33f9,0x02,
+0x33fa,0x18,
+0x33fb,0x10,
+0x33fc,0x0c,
+0x33fd,0x10,
+0x33fe,0x04,
+0x33ff,0x02,
+0x360f,0x01,
+0x3622,0xf7,
+0x3625,0x0a,
+0x3627,0x02,
+0x3630,0xa2,
+0x3631,0x00,
+0x3632,0xd8,
+0x3633,0x33,
+0x3635,0x20,
+0x3638,0x24,
+0x363a,0x80,
+0x363b,0x02,
+0x363e,0x22,
+0x3670,0x40,
+0x3671,0xf7,
+0x3672,0xf7,
+0x3673,0x07,
+0x367a,0x40,
+0x367b,0x7f,
+0x36b5,0x40,
+0x36b6,0x7f,
+0x36c0,0x80,
+0x36c1,0x9f,
+0x36c2,0x9f,
+0x36cc,0x22,
+0x36cd,0x23,
+0x36ce,0x30,
+0x36d0,0x20,
+0x36d1,0x40,
+0x36d2,0x7f,
+0x36ea,0x75,
+0x36eb,0x0d,
+0x36ec,0x13,
+0x36ed,0x24,
+0x36fa,0x5f,
+0x36fb,0x1b,
+0x36fc,0x10,
+0x36fd,0x07,
+0x3905,0xd8,
+0x3907,0x01,
+0x3908,0x11,
+0x391b,0x83,
+0x391d,0x2c,
+0x391f,0x00,
+0x3933,0x28,
+0x3934,0xa6,
+0x3940,0x70,
+0x3942,0x08,
+0x3943,0xbc,
+0x3958,0x02,
+0x3959,0x04,
+0x3980,0x61,
+0x3987,0x0b,
+0x3990,0x00,
+0x3991,0x00,
+0x3992,0x00,
+0x3993,0x00,
+0x3994,0x00,
+0x3995,0x00,
+0x3996,0x00,
+0x3997,0x00,
+0x3998,0x00,
+0x3999,0x00,
+0x399a,0x00,
+0x399b,0x00,
+0x399c,0x00,
+0x399d,0x00,
+0x399e,0x00,
+0x399f,0x00,
+0x39a0,0x00,
+0x39a1,0x00,
+0x39a2,0x03,
+0x39a3,0x30,
+0x39a4,0x03,
+0x39a5,0x60,
+0x39a6,0x03,
+0x39a7,0xa0,
+0x39a8,0x03,
+0x39a9,0xb0,
+0x39aa,0x00,
+0x39ab,0x00,
+0x39ac,0x00,
+0x39ad,0x20,
+0x39ae,0x00,
+0x39af,0x40,
+0x39b0,0x00,
+0x39b1,0x60,
+0x39b2,0x00,
+0x39b3,0x00,
+0x39b4,0x08,
+0x39b5,0x14,
+0x39b6,0x20,
+0x39b7,0x38,
+0x39b8,0x38,
+0x39b9,0x20,
+0x39ba,0x14,
+0x39bb,0x08,
+0x39bc,0x08,
+0x39bd,0x10,
+0x39be,0x20,
+0x39bf,0x30,
+0x39c0,0x30,
+0x39c1,0x20,
+0x39c2,0x10,
+0x39c3,0x08,
+0x39c4,0x00,
+0x39c5,0x80,
+0x39c6,0x00,
+0x39c7,0x80,
+0x39c8,0x00,
+0x39c9,0x00,
+0x39ca,0x80,
+0x39cb,0x00,
+0x39cc,0x00,
+0x39cd,0x00,
+0x39ce,0x00,
+0x39cf,0x00,
+0x39d0,0x00,
+0x39d1,0x00,
+0x39e2,0x05,
+0x39e3,0xeb,
+0x39e4,0x07,
+0x39e5,0xb6,
+0x39e6,0x00,
+0x39e7,0x3a,
+0x39e8,0x3f,
+0x39e9,0xb7,
+0x39ea,0x02,
+0x39eb,0x4f,
+0x39ec,0x08,
+0x39ed,0x00,
+0x3e01,0x46,
+0x3e02,0x10,
+0x3e09,0x40,
+0x3e14,0x31,
+0x3e1b,0x3a,
+0x3e26,0x40,
+0x4401,0x1a,
+0x4407,0xc0,
+0x4418,0x34,
+0x4500,0x18,
+0x4501,0xb4,
+0x4509,0x20,
+0x4603,0x00,
+0x4800,0x24,
+0x4837,0x2b,
+0x5000,0x0e,
+0x550f,0x20,
+0x36e9,0x51,
+0x36f9,0x53,
+0x0100,0x01,
+
+};
+const unsigned short Sensor_Cfg_SC2210_MIPI_1080P25[]=
+{
+0x0103,0x01,
+0x0100,0x00,
+0x36e9,0x80,
+0x36f9,0x80,
+0x3001,0x07,
+0x3002,0xc0,
+0x300a,0x2c,
+0x300f,0x00,
+0x3018,0x33,
+0x3019,0x0c,
+0x301f,0x47,
+0x3031,0x0a,
+0x3033,0x20,
+0x3038,0x22,
+0x3106,0x81,
+0x3201,0x04,
+0x3203,0x04,
+0x3204,0x07,
+0x3205,0x8b,
+0x3206,0x04,
+0x3207,0x43,
+0x320c,0x04,
+0x320d,0x4c,
+0x320e,0x05,
+0x320f,0x46,//25fps
+0x3211,0x04,
+0x3213,0x04,
+0x3231,0x02,
+0x3253,0x04,
+0x3301,0x0a,
+0x3302,0x10,
+0x3304,0x48,
+0x3305,0x00,
+0x3306,0x68,
+0x3308,0x20,
+0x3309,0x98,
+0x330a,0x00,
+0x330b,0xe8,
+0x330e,0x68,
+0x3314,0x92,
+0x3000,0xc0,
+0x331e,0x41,
+0x331f,0x91,
+0x334c,0x10,
+0x335d,0x60,
+0x335e,0x02,
+0x335f,0x06,
+0x3364,0x16,
+0x3366,0x92,
+0x3367,0x10,
+0x3368,0x04,
+0x3369,0x00,
+0x336a,0x00,
+0x336b,0x00,
+0x336d,0x03,
+0x337c,0x08,
+0x337d,0x0e,
+0x337f,0x33,
+0x3390,0x10,
+0x3391,0x30,
+0x3392,0x40,
+0x3393,0x0a,
+0x3394,0x0a,
+0x3395,0x0a,
+0x3396,0x08,
+0x3397,0x30,
+0x3398,0x3f,
+0x3399,0x50,
+0x339a,0x50,
+0x339b,0x50,
+0x339c,0x50,
+0x33a2,0x0a,
+0x33b9,0x0e,
+0x33e1,0x08,
+0x33e2,0x18,
+0x33e3,0x18,
+0x33e4,0x18,
+0x33e5,0x10,
+0x33e6,0x06,
+0x33e7,0x02,
+0x33e8,0x18,
+0x33e9,0x10,
+0x33ea,0x0c,
+0x33eb,0x10,
+0x33ec,0x04,
+0x33ed,0x02,
+0x33ee,0xa0,
+0x33ef,0x08,
+0x33f4,0x18,
+0x33f5,0x10,
+0x33f6,0x0c,
+0x33f7,0x10,
+0x33f8,0x06,
+0x33f9,0x02,
+0x33fa,0x18,
+0x33fb,0x10,
+0x33fc,0x0c,
+0x33fd,0x10,
+0x33fe,0x04,
+0x33ff,0x02,
+0x360f,0x01,
+0x3622,0xf7,
+0x3625,0x0a,
+0x3627,0x02,
+0x3630,0xa2,
+0x3631,0x00,
+0x3632,0xd8,
+0x3633,0x33,
+0x3635,0x20,
+0x3638,0x24,
+0x363a,0x80,
+0x363b,0x02,
+0x363e,0x22,
+0x3670,0x40,
+0x3671,0xf7,
+0x3672,0xf7,
+0x3673,0x07,
+0x367a,0x40,
+0x367b,0x7f,
+0x36b5,0x40,
+0x36b6,0x7f,
+0x36c0,0x80,
+0x36c1,0x9f,
+0x36c2,0x9f,
+0x36cc,0x22,
+0x36cd,0x23,
+0x36ce,0x30,
+0x36d0,0x20,
+0x36d1,0x40,
+0x36d2,0x7f,
+0x36ea,0x75,
+0x36eb,0x0d,
+0x36ec,0x13,
+0x36ed,0x24,
+0x36fa,0x5f,
+0x36fb,0x1b,
+0x36fc,0x10,
+0x36fd,0x07,
+0x3905,0xd8,
+0x3907,0x01,
+0x3908,0x11,
+0x391b,0x83,
+0x391d,0x2c,
+0x391f,0x00,
+0x3933,0x28,
+0x3934,0xa6,
+0x3940,0x70,
+0x3942,0x08,
+0x3943,0xbc,
+0x3958,0x02,
+0x3959,0x04,
+0x3980,0x61,
+0x3987,0x0b,
+0x3990,0x00,
+0x3991,0x00,
+0x3992,0x00,
+0x3993,0x00,
+0x3994,0x00,
+0x3995,0x00,
+0x3996,0x00,
+0x3997,0x00,
+0x3998,0x00,
+0x3999,0x00,
+0x399a,0x00,
+0x399b,0x00,
+0x399c,0x00,
+0x399d,0x00,
+0x399e,0x00,
+0x399f,0x00,
+0x39a0,0x00,
+0x39a1,0x00,
+0x39a2,0x03,
+0x39a3,0x30,
+0x39a4,0x03,
+0x39a5,0x60,
+0x39a6,0x03,
+0x39a7,0xa0,
+0x39a8,0x03,
+0x39a9,0xb0,
+0x39aa,0x00,
+0x39ab,0x00,
+0x39ac,0x00,
+0x39ad,0x20,
+0x39ae,0x00,
+0x39af,0x40,
+0x39b0,0x00,
+0x39b1,0x60,
+0x39b2,0x00,
+0x39b3,0x00,
+0x39b4,0x08,
+0x39b5,0x14,
+0x39b6,0x20,
+0x39b7,0x38,
+0x39b8,0x38,
+0x39b9,0x20,
+0x39ba,0x14,
+0x39bb,0x08,
+0x39bc,0x08,
+0x39bd,0x10,
+0x39be,0x20,
+0x39bf,0x30,
+0x39c0,0x30,
+0x39c1,0x20,
+0x39c2,0x10,
+0x39c3,0x08,
+0x39c4,0x00,
+0x39c5,0x80,
+0x39c6,0x00,
+0x39c7,0x80,
+0x39c8,0x00,
+0x39c9,0x00,
+0x39ca,0x80,
+0x39cb,0x00,
+0x39cc,0x00,
+0x39cd,0x00,
+0x39ce,0x00,
+0x39cf,0x00,
+0x39d0,0x00,
+0x39d1,0x00,
+0x39e2,0x05,
+0x39e3,0xeb,
+0x39e4,0x07,
+0x39e5,0xb6,
+0x39e6,0x00,
+0x39e7,0x3a,
+0x39e8,0x3f,
+0x39e9,0xb7,
+0x39ea,0x02,
+0x39eb,0x4f,
+0x39ec,0x08,
+0x39ed,0x00,
+0x3e01,0x46,
+0x3e02,0x10,
+0x3e09,0x40,
+0x3e14,0x31,
+0x3e1b,0x3a,
+0x3e26,0x40,
+0x4401,0x1a,
+0x4407,0xc0,
+0x4418,0x34,
+0x4500,0x18,
+0x4501,0xb4,
+0x4509,0x20,
+0x4603,0x00,
+0x4800,0x24,
+0x4837,0x2b,
+0x5000,0x0e,
+0x550f,0x20,
+0x36e9,0x51,
+0x36f9,0x53,
+0x0100,0x01,
+};
+unsigned int NAME(MirrorFlipBayerFormat)[4]=
+{
+    2,2,2,2
+};
+
+#endif /* SC2232_MIPI_H_ */

Some files were not shown because too many files changed in this diff