Extend two camera(tw9992) CSI-2 driver to multiple cameras

hello everyone;
I’m trying to support two cameras(tw9992) on L4T 24.2, one connect to CSI_A (i2c addr is 0x88,i2c bus is 3), the other connect to CSI_E (i2c addr is 0x7a,i2c bus is 3),I double copyed the arch/arm64/boot/dts/tegra210-platforms/tegra210-camera-e3326-a00.dtsi code, and add drivers refered to drivers/media/i2c/ov5693.c, how do i fixed the driver to support it?

and another question is: how can i show images of two cameras at the same time!

Thanks in advance!!

Hi, You can find information about how to create your own driver in the L4T Documentation (V4L2) section that yo can download from L4T Documentation. There are 3 parts on adding support to a new sensor

a) Create driver to initialize camera and modify device tree.
b) Integrate the driver with VI driver for the capture subsystem (VI) of tegra x1
c) Use an application to test the capture - You can use gstreamer or Yavta.

RidgeRun can help you with above steps. c) will help you to see if the image that you are capturing is correct.

Now, I haven’t tried to display both images at the same time so I am not sure if the nvidia gstreamer sink element supports dispaly two images at the same time. Otherwise you can give it a try to the element called videomixer and glvideomixer.

Hi DavidSoto;
Thanks for your reply!
I have already downloaded the L4T Documentation, and read in the last two weeks, but i still have a lot of questions about support two cameras;

  1. If the camera ov5693 is connected via i2c3 on the original development board,how to modify the device tree to adapt it?

  2. As described in the L4T Documentation(To register a device using main-platform device tree files)
    [b]"1. In kernel/arch/arm64/boot/dts/tegra210-plugin-manager/tegra210-jetson-cv-plugin-manager.dtsi, remove the following line:
    #include “tegra210-jetson-cv-camera-plugin-manager.dtsi”

  1. In kernel/arch/arm64/boot/dts/tegra210-jetson-cv-base-p2597-2180-a00.dts, replace the following line:
    #include “tegra210-platforms/tegra210-jetson-cv-camera-modules.dtsi”
    With an #include statement specifying your new device DTSI file."[/b]

I want to know how to write my new device DTSI file, whether by reference to the “arch/arm64/boot/dts/tegra210-platforms/tegra210-camera-e3326-a00.dtsi”

You could find a reference implementation in https://devtalk.nvidia.com/default/topic/970980/l4t-24-2-rasperry-pi-csi-camera-driver-debug/?offset=30#5011155

Hi David;
I have scanned the link you send,it looks very like the ov5693 driver,
but the extend board we disign now have some difference ,CVBS signal(NTSC) input from the front, and transformed to MIPI(1 lane)signals through two pieces TW9992, then one connect to CSI_A, and the other connect to CSI_E, I think I just need to configure tw9992 register table in the driver, do you have the reference driver about this?
and our supplier give me the register table is as follows:
{0x00, 0x92},
{0x01, 0x00},
{0x02, 0x40},
{0x03, 0x68},
{0x04, 0x00},
{0x05, 0x09},
{0x06, 0x00},
{0x07, 0x02},
{0x08, 0x15},
{0x09, 0xF0},
{0x0A, 0x14},
{0x0B, 0xD0},
{0x0C, 0xCC},
{0x0D, 0x00},
{0x10, 0x00},
{0x11, 0x64},
{0x12, 0x11},
{0x13, 0x80},
{0x14, 0x80},
{0x15, 0x00},
{0x17, 0x80},
{0x18, 0x44},
{0x19, 0x06},
{0x1A, 0x10},
{0x1B, 0x00},
{0x1C, 0x0F},
{0x1D, 0x7F},
{0x1F, 0x00},
{0x20, 0x50},
{0x21, 0x22},
{0x22, 0xF0},
{0x23, 0xD8},
{0x24, 0xBC},
{0x25, 0xB8},
{0x26, 0x44},
{0x27, 0x38},
{0x28, 0x00},
{0x29, 0x00},
{0x2A, 0x78},
{0x2B, 0x44},
{0x2C, 0x30},
{0x2D, 0x14},
{0x2E, 0xA5},
{0x2F, 0xE0},
{0x30, 0x00},
{0x31, 0x10},
{0x32, 0xFF},
{0x33, 0x05},
{0x34, 0x1A},
{0x35, 0x00},
{0x36, 0x5A},
{0x37, 0x18},
{0x38, 0xDD},
{0x39, 0x00},
{0x3A, 0x30},
{0x3B, 0x00},
{0x3C, 0x00},
{0x3D, 0x00},
{0x3F, 0x1A},
{0x40, 0x80},
{0x41, 0x00},
{0x42, 0x00},
{0x48, 0x02},
{0x49, 0x00},
{0x4A, 0x81},
{0x4B, 0x0A},
{0x4C, 0x00},
{0x4D, 0x01},
{0x4E, 0x01},
{0x50, 0x00},
{0x51, 0x17},
{0x52, 0x00},
{0x53, 0x00},
{0x54, 0x06},
{0x55, 0x00},
{0x56, 0x00},
{0x57, 0x00},
{0x58, 0x00},
{0x60, 0x00},
{0x61, 0x00},
{0x62, 0x00},
{0x63, 0x00},
{0x70, 0x01},
{0x71, 0xA5},
{0x72, 0xA0},
{0x73, 0x00},
{0x74, 0xF0},
{0x75, 0x00},
{0x76, 0x17},
{0x77, 0x05},
{0x78, 0x88},
{0x79, 0x06},
{0x7A, 0x28},
{0x7B, 0x46},
{0x7C, 0xB3},
{0x7D, 0x06},
{0x7E, 0x13},
{0x7F, 0x10},
{0x80, 0x05},
{0x81, 0xA0},
{0x82, 0x13},
{0x83, 0x11},
{0x84, 0x02},
{0x85, 0x0E},
{0x86, 0x08},
{0x87, 0x37},
{0x88, 0x00},
{0x89, 0x00},
{0x8A, 0x02},
{0x8B, 0x33},
{0x8C, 0x22},
{0x8D, 0x03},
{0x8E, 0x22},
{0x8F, 0x01},
{0x90, 0x00},
{0x91, 0x0C},
{0x92, 0x00},
{0x93, 0x0E},
{0x94, 0x07},
{0x95, 0xFF},
{0x96, 0x1A},
{0x9B, 0x02},
{0xA0, 0x00},
{0xA1, 0x00},
{0xA2, 0x30},
{0xA3, 0xC0},
{0xA4, 0x00},
{0xC0, 0x06},
{0xC1, 0x20},

sorry;
Due to network reasons, I replyed two times!

Hi DavidSoto;
Our expansion board come back today; and the two pieces tw9992 connect to i2c bus 1;

My device address is 0x3d and 0x44, I use the command “sudo i2cdetice -y -a -r 1”, it shows as follows:
ubuntu@tegra-ubuntu:~$ sudo i2cdetect -y -a -r 1
[sudo] password for ubuntu:
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: – – – – – – – – – – – – – – – –
10: – – – – – – – – – – – – – – – –
20: – – – – – – – – – – – – – – – –
30: – – – – – – – – – – – – – 3d – –
40: 40 – UU UU 44 – – – – – 4a – – – – –
50: – – – – – – – – – – – – – – – –
60: – – – – – – – – – – – – – – – –
70: – – – – UU – – UU – – – – – – – –

when I change “i2c@546c0000” to “i2c@7000c400” in arch/arm64/boot/dts/tegra210-platforms/tegra210-camera-e3326-a00.dtsi; compile error;

ERROR LOG:
ERROR (phandle_references): Reference to non-existent node or label “e3326_vi_in0”

ERROR: Input tree has errors, aborting (use -f to force output)
make[1]: *** [arch/arm64/boot/dts/tegra210-p4573-2180.dtb] Error 2
make: *** [dtbs] Error 2

thanks

Hi DividSoto;
the problem compiled error I have solved; but now I meet the new questions;

I run the command “v4l2-compliance -d /dev/video0” on the develop board;
Driver Info:
Driver name : tegra-video
Card type : vi-output-0, tw9992 1-0044
Bus info : platform:vi:0
Driver version: 3.10.96
Capabilities : 0x84200001
Video Capture
Streaming
Extended Pix Format
Device Capabilities
Device Caps : 0x04200001
Video Capture
Streaming
Extended Pix Format

Compliance test for device /dev/video0 (not using libv4l2):

Required ioctls:
test VIDIOC_QUERYCAP: OK

Allow for multiple opens:
test second video open: OK
test VIDIOC_QUERYCAP: OK
test VIDIOC_G/S_PRIORITY: OK

Debug ioctls:
test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
test VIDIOC_LOG_STATUS: OK (Not Supported)

Input ioctls:
test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
test VIDIOC_ENUMAUDIO: OK (Not Supported)
test VIDIOC_G/S/ENUMINPUT: OK
test VIDIOC_G/S_AUDIO: OK (Not Supported)
Inputs: 1 Audio Inputs: 0 Tuners: 0

Output ioctls:
test VIDIOC_G/S_MODULATOR: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_ENUMAUDOUT: OK (Not Supported)
test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
test VIDIOC_G/S_AUDOUT: OK (Not Supported)
Outputs: 0 Audio Outputs: 0 Modulators: 0

Input/Output configuration ioctls:
test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
test VIDIOC_G/S_EDID: OK (Not Supported)

Test input 0:

Control ioctls:
	test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
	test VIDIOC_QUERYCTRL: OK
	test VIDIOC_G/S_CTRL: OK
	test VIDIOC_G/S/TRY_EXT_CTRLS: OK
	test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK
	test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
	Standard Controls: 1 Private Controls: 7

Format ioctls:
	test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
	test VIDIOC_G/S_PARM: OK (Not Supported)
	test VIDIOC_G_FBUF: OK (Not Supported)
	test VIDIOC_G_FMT: OK
	test VIDIOC_TRY_FMT: OK
	test VIDIOC_S_FMT: OK
	test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
	test Cropping: OK (Not Supported)
	test Composing: OK (Not Supported)
	test Scaling: OK (Not Supported)

Codec ioctls:
	test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
	test VIDIOC_G_ENC_INDEX: OK (Not Supported)
	test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

Buffer ioctls:
	test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
	test VIDIOC_EXPBUF: OK

Test input 0:

Total: 42, Succeeded: 42, Failed: 0, Warnings: 0

but when I run the command “sudo ./yavta /dev/video0 -c1 -n1 -s720x480 -fUYVY -Fcam.raw”
Device /dev/video0 opened.
Device vi-output-0, tw9992 1-0044' on platform:vi:0’ (driver ‘tegra-video’) is a video capture (without mplanes) device.
Unable to set format: Invalid argument (22).

my code:

/*
 * tw9992_v4l2.c - tw9992 sensor driver
 *
 * Copyright (c) 2013-2016, NVIDIA CORPORATION.  All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
#include <linux/module.h>

#include <linux/seq_file.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>

#include <media/camera_common.h>
#include "cam_dev/camera_gpio.h"
#include "tw9992_mode_tbls.h"

#define TW9992_MAX_COARSE_DIFF		6
#define TW9992_GAIN_SHIFT		8
#define TW9992_REAL_GAIN_SHIFT		4
#define TW9992_MIN_GAIN		(1 << TW9992_GAIN_SHIFT)
#define TW9992_MAX_GAIN		(16 << TW9992_GAIN_SHIFT)
#define TW9992_DEFAULT_GAIN		TW9992_MIN_GAIN

#define TW9992_MIN_FRAME_LENGTH	(0x0)
#define TW9992_MAX_FRAME_LENGTH	(0x7fff)

#define TW9992_MIN_EXPOSURE_COARSE	(0x0002)
#define TW9992_MAX_EXPOSURE_COARSE	\
	(TW9992_MAX_FRAME_LENGTH-TW9992_MAX_COARSE_DIFF)
	
#define TW9992_DEFAULT_FRAME_LENGTH	(0x07C0)
#define TW9992_DEFAULT_EXPOSURE_COARSE	\
	(TW9992_DEFAULT_FRAME_LENGTH-TW9992_MAX_COARSE_DIFF)
	
#define TW9992_DEFAULT_WIDTH	720
#define TW9992_DEFAULT_HEIGHT	240
#define TW9992_DEFAULT_CLK_FREQ	24000000
#define TW9992_DEFAULT_MODE TW9992_MODE_720x480
#define TW9992_DEFAULT_DATAFMT	V4L2_MBUS_FMT_SRGGB10_1X10




#define TW9992_TABLE_WAIT_MS    0
#define TW9992_TABLE_END        1
#define TW9992_MAX_RETRIES      3

#define tw9992_reg struct reg_8

struct tw9992 {
	struct camera_common_power_rail	power;
	int				numctrls;
	struct v4l2_ctrl_handler	ctrl_handler;
	//struct camera_common_eeprom_data eeprom[TW9992_EEPROM_NUM_BLOCKS];
	//u8				eeprom_buf[TW9992_EEPROM_SIZE];
	struct i2c_client		*i2c_client;
	struct v4l2_subdev		*subdev;
	struct media_pad		pad;

	int				reg_offset;

	s32				group_hold_prev;
	bool				group_hold_en;
	struct regmap			*regmap;
	struct camera_common_data	*s_data;
	struct camera_common_pdata	*pdata;
	struct v4l2_ctrl		*ctrls[];
};

static struct regmap_config tw9992_regmap_config = {
	.reg_bits = 8,
	.val_bits = 8,
};

static const tw9992_reg reg_table[] = {
{0x00, 0x92},
{0x01, 0x00},
{0x02, 0x40},
{0x03, 0x68},
{0x04, 0x00},
{0x05, 0x09},
{0x06, 0x00},
{0x07, 0x02},
{0x08, 0x15},
{0x09, 0xF0},
{0x0A, 0x14},
{0x0B, 0xD0},
{0x0C, 0xCC},
{0x0D, 0x00},
{0x10, 0x00},
{0x11, 0x64},
{0x12, 0x11},
{0x13, 0x80},
{0x14, 0x80},
{0x15, 0x00},
{0x17, 0x80},
{0x18, 0x44},
{0x19, 0x06},
{0x1A, 0x10},
{0x1B, 0x00},
{0x1C, 0x0F},
{0x1D, 0x7F},
{0x1F, 0x00},
{0x20, 0x50},
{0x21, 0x22},
{0x22, 0xF0},
{0x23, 0xD8},
{0x24, 0xBC},
{0x25, 0xB8},
{0x26, 0x44},
{0x27, 0x38},
{0x28, 0x00},
{0x29, 0x00},
{0x2A, 0x78},
{0x2B, 0x44},
{0x2C, 0x30},
{0x2D, 0x14},
{0x2E, 0xA5},
{0x2F, 0xE0},
{0x30, 0x00},
{0x31, 0x10},
{0x32, 0xFF},
{0x33, 0x05},
{0x34, 0x1A},
{0x35, 0x00},
{0x36, 0x5A},
{0x37, 0x18},
{0x38, 0xDD},
{0x39, 0x00},
{0x3A, 0x30},
{0x3B, 0x00},
{0x3C, 0x00},
{0x3D, 0x00},
{0x3F, 0x1A},
{0x40, 0x80},
{0x41, 0x00},
{0x42, 0x00},
{0x48, 0x02},
{0x49, 0x00},
{0x4A, 0x81},
{0x4B, 0x0A},
{0x4C, 0x00},
{0x4D, 0x01},
{0x4E, 0x01},
{0x50, 0x00},
{0x51, 0x17},
{0x52, 0x00},
{0x53, 0x00},
{0x54, 0x06},
{0x55, 0x00},
{0x56, 0x00},
{0x57, 0x00},
{0x58, 0x00},
{0x60, 0x00},
{0x61, 0x00},
{0x62, 0x00},
{0x63, 0x00},
{0x70, 0x01},
{0x71, 0xA5},
{0x72, 0xA0},
{0x73, 0x00},
{0x74, 0xF0},
{0x75, 0x00},
{0x76, 0x17},
{0x77, 0x05},
{0x78, 0x88},
{0x79, 0x06},
{0x7A, 0x28},
{0x7B, 0x46},
{0x7C, 0xB3},
{0x7D, 0x06},
{0x7E, 0x13},
{0x7F, 0x10},
{0x80, 0x05},
{0x81, 0xA0},
{0x82, 0x13},
{0x83, 0x11},
{0x84, 0x02},
{0x85, 0x0E},
{0x86, 0x08},
{0x87, 0x37},
{0x88, 0x00},
{0x89, 0x00},
{0x8A, 0x02},
{0x8B, 0x33},
{0x8C, 0x22},
{0x8D, 0x03},
{0x8E, 0x22},
{0x8F, 0x01},
{0x90, 0x00},
{0x91, 0x0C},
{0x92, 0x00},
{0x93, 0x0E},
{0x94, 0x07},
{0x95, 0xFF},
{0x96, 0x1A},
{0x9B, 0x02},
{0xA0, 0x00},
{0xA1, 0x00},
{0xA2, 0x30},
{0xA3, 0xC0},
{0xA4, 0x00},
{0xC0, 0x06},
{0xC1, 0x20},
};

static int tw9992_g_volatile_ctrl(struct v4l2_ctrl *ctrl);
static int tw9992_s_ctrl(struct v4l2_ctrl *ctrl);
static void tw9992_update_ctrl_range(struct tw9992 *priv, s32 frame_length);

static const struct v4l2_ctrl_ops tw9992_ctrl_ops = {
	.g_volatile_ctrl = tw9992_g_volatile_ctrl,
	.s_ctrl		= tw9992_s_ctrl,
};

static struct v4l2_ctrl_config ctrl_config_list[] = {
/* Do not change the name field for the controls! */
	{
		.ops = &tw9992_ctrl_ops,
		.id = V4L2_CID_GAIN,
		.name = "Gain",
		.type = V4L2_CTRL_TYPE_INTEGER,
		.flags = V4L2_CTRL_FLAG_SLIDER,
		.min = TW9992_MIN_GAIN,
		.max = TW9992_MAX_GAIN,
		.def = TW9992_DEFAULT_GAIN,
		.step = 1,
	},
	{
		.ops = &tw9992_ctrl_ops,
		.id = V4L2_CID_FRAME_LENGTH,
		.name = "Frame Length",
		.type = V4L2_CTRL_TYPE_INTEGER,
		.flags = V4L2_CTRL_FLAG_SLIDER,
		.min = TW9992_MIN_FRAME_LENGTH,
		.max = TW9992_MAX_FRAME_LENGTH,
		.def = TW9992_DEFAULT_FRAME_LENGTH,
		.step = 1,
	},
	{
		.ops = &tw9992_ctrl_ops,
		.id = V4L2_CID_COARSE_TIME,
		.name = "Coarse Time",
		.type = V4L2_CTRL_TYPE_INTEGER,
		.flags = V4L2_CTRL_FLAG_SLIDER,
		.min = TW9992_MIN_EXPOSURE_COARSE,
		.max = TW9992_MAX_EXPOSURE_COARSE,
		.def = TW9992_DEFAULT_EXPOSURE_COARSE,
		.step = 1,
	},
	{
		.ops = &tw9992_ctrl_ops,
		.id = V4L2_CID_COARSE_TIME_SHORT,
		.name = "Coarse Time Short",
		.type = V4L2_CTRL_TYPE_INTEGER,
		.flags = V4L2_CTRL_FLAG_SLIDER,
		.min = TW9992_MIN_EXPOSURE_COARSE,
		.max = TW9992_MAX_EXPOSURE_COARSE,
		.def = TW9992_DEFAULT_EXPOSURE_COARSE,
		.step = 1,
	},
	{
		.ops = &tw9992_ctrl_ops,
		.id = V4L2_CID_GROUP_HOLD,
		.name = "Group Hold",
		.type = V4L2_CTRL_TYPE_INTEGER_MENU,
		.min = 0,
		.max = ARRAY_SIZE(switch_ctrl_qmenu) - 1,
		.menu_skip_mask = 0,
		.def = 0,
		.qmenu_int = switch_ctrl_qmenu,
	},
	{
		.ops = &tw9992_ctrl_ops,
		.id = V4L2_CID_HDR_EN,
		.name = "HDR enable",
		.type = V4L2_CTRL_TYPE_INTEGER_MENU,
		.min = 0,
		.max = ARRAY_SIZE(switch_ctrl_qmenu) - 1,
		.menu_skip_mask = 0,
		.def = 0,
		.qmenu_int = switch_ctrl_qmenu,
	},
	/*{
		.ops = &tw9992_ctrl_ops,
		.id = V4L2_CID_EEPROM_DATA,
		.name = "EEPROM Data",
		.type = V4L2_CTRL_TYPE_STRING,
		.flags = V4L2_CTRL_FLAG_VOLATILE,
		.min = 0,
		.max = TW9992_EEPROM_STR_SIZE,
		.step = 2,
	},
	{
		.ops = &tw9992_ctrl_ops,
		.id = V4L2_CID_OTP_DATA,
		.name = "OTP Data",
		.type = V4L2_CTRL_TYPE_STRING,
		.flags = V4L2_CTRL_FLAG_READ_ONLY,
		.min = 0,
		.max = TW9992_OTP_STR_SIZE,
		.step = 2,
	},
	{
		.ops = &tw9992_ctrl_ops,
		.id = V4L2_CID_FUSE_ID,
		.name = "Fuse ID",
		.type = V4L2_CTRL_TYPE_STRING,
		.flags = V4L2_CTRL_FLAG_READ_ONLY,
		.min = 0,
		.max = TW9992_FUSE_ID_STR_SIZE,
		.step = 2,
	},*/

};

static inline int tw9992_read_reg(struct camera_common_data *s_data,
				u16 addr, u8 *val)
{
	struct tw9992 *priv = (struct tw9992 *)s_data->priv;

	return regmap_read(priv->regmap, addr, (unsigned int *) val);
}

static int tw9992_write_reg(struct camera_common_data *s_data, u16 addr, u8 val)
{
	int err;
	struct tw9992 *priv = (struct tw9992 *)s_data->priv;

	err = regmap_write(priv->regmap, addr, val);
	if (err)
		pr_err("%s:i2c write failed, %x = %x\n",
			__func__, addr, val);

	return err;
}

static int tw9992_write_regs(struct camera_common_data *s_data)
{
	int i = 0;
	int count = sizeof(reg_table)/sizeof(struct reg_8);
	
	for (i = 0; i < count; i++)
	{
		tw9992_write_reg(s_data, reg_table[i].addr, reg_table[i].val);
	}
	
}

static int tw9992_write_table(struct tw9992 *priv,
			      const tw9992_reg table[])
{
	return regmap_util_write_table_8(priv->regmap,
					 table,
					 NULL, 0,
					 TW9992_TABLE_WAIT_MS,
					 TW9992_TABLE_END);
}

/*static void tw9992_gpio_set(struct tw9992 *priv,
			    unsigned int gpio, int val)
{
	if (priv->pdata->use_cam_gpio)
		cam_gpio_ctrl(priv->i2c_client, gpio, val, 1);
	else {
		if (gpio_cansleep(gpio))
			gpio_set_value_cansleep(gpio, val);
		else
			gpio_set_value(gpio, val);
	}
}*/

static int tw9992_power_on(struct camera_common_data *s_data)
{
	int err = 0;
	struct tw9992 *priv = (struct tw9992 *)s_data->priv;
	struct camera_common_power_rail *pw = &priv->power;

	dev_dbg(&priv->i2c_client->dev, "%s: power on\n", __func__);

	if (priv->pdata && priv->pdata->power_on) {
		err = priv->pdata->power_on(pw);
		if (err)
			pr_err("%s failed.\n", __func__);
		else
			pw->state = SWITCH_ON;
		return err;
	}

	/* sleeps calls in the sequence below are for internal device
	 * signal propagation as specified by sensor vendor */

	if (pw->avdd)
		err = regulator_enable(pw->avdd);
	if (err)
		goto tw9992_avdd_fail;

	if (pw->iovdd)
		err = regulator_enable(pw->iovdd);
	if (err)
		goto tw9992_iovdd_fail;

	usleep_range(1, 2);
	//if (pw->pwdn_gpio)
		//tw9992_gpio_set(priv, pw->pwdn_gpio, 1);

	/* datasheet 2.9: reset requires ~2ms settling time
	 * a power on reset is generated after core power becomes stable */
	usleep_range(2000, 2010);

	//if (pw->reset_gpio)
		//tw9992_gpio_set(priv, pw->reset_gpio, 1);

	/* datasheet fig 2-9: t3 */
	usleep_range(1350, 1360);

	pw->state = SWITCH_ON;
	return 0;

tw9992_iovdd_fail:
	regulator_disable(pw->avdd);

tw9992_avdd_fail:
	pr_err("%s failed.\n", __func__);
	return -ENODEV;
}

static int tw9992_power_off(struct camera_common_data *s_data)
{
	int err = 0;
	struct tw9992 *priv = (struct tw9992 *)s_data->priv;
	struct camera_common_power_rail *pw = &priv->power;

	dev_dbg(&priv->i2c_client->dev, "%s: power off\n", __func__);

	if (priv->pdata && priv->pdata->power_on) {
		err = priv->pdata->power_off(pw);
		if (!err)
			pw->state = SWITCH_OFF;
		else
			pr_err("%s failed.\n", __func__);
		return err;
	}

	/* sleeps calls in the sequence below are for internal device
	 * signal propagation as specified by sensor vendor */

	usleep_range(21, 25);
	//if (pw->pwdn_gpio)
		//tw9992_gpio_set(priv, pw->pwdn_gpio, 0);
	usleep_range(1, 2);
	//if (pw->reset_gpio)
		//tw9992_gpio_set(priv, pw->reset_gpio, 0);

	/* datasheet 2.9: reset requires ~2ms settling time*/
	usleep_range(2000, 2010);

	if (pw->iovdd)
		regulator_disable(pw->iovdd);
	if (pw->avdd)
		regulator_disable(pw->avdd);

	return 0;
}

static int tw9992_power_put(struct tw9992 *priv)
{
	struct camera_common_power_rail *pw = &priv->power;

	if (unlikely(!pw))
		return -EFAULT;

	if (likely(pw->avdd))
		regulator_put(pw->avdd);

	if (likely(pw->iovdd))
		regulator_put(pw->iovdd);

	pw->avdd = NULL;
	pw->iovdd = NULL;

	if (priv->pdata->use_cam_gpio)
		cam_gpio_deregister(priv->i2c_client, pw->pwdn_gpio);
	else {
		gpio_free(pw->pwdn_gpio);
		gpio_free(pw->reset_gpio);
	}

	return 0;
}

static int tw9992_power_get(struct tw9992 *priv)
{
	struct camera_common_power_rail *pw = &priv->power;
	struct camera_common_pdata *pdata = priv->pdata;
	const char *mclk_name;
	const char *parentclk_name;
	struct clk *parent;
	int err = 0;

	mclk_name = priv->pdata->mclk_name ?
		    priv->pdata->mclk_name : "cam_mclk1";
	pw->mclk = devm_clk_get(&priv->i2c_client->dev, mclk_name);
	if (IS_ERR(pw->mclk)) {
		dev_err(&priv->i2c_client->dev,
			"unable to get clock %s\n", mclk_name);
		return PTR_ERR(pw->mclk);
	}

	parentclk_name = priv->pdata->parentclk_name;
	if (parentclk_name) {
		parent = devm_clk_get(&priv->i2c_client->dev, parentclk_name);
		if (IS_ERR(parent))
			dev_err(&priv->i2c_client->dev,
				"unable to get parent clcok %s",
				parentclk_name);
		else
			clk_set_parent(pw->mclk, parent);
	}


#if 0
	/* analog 2.8v */
	err |= camera_common_regulator_get(priv->i2c_client,
			&pw->avdd, pdata->regulators.avdd);
	/* IO 1.8v */
	err |= camera_common_regulator_get(priv->i2c_client,
			&pw->iovdd, pdata->regulators.iovdd);
#endif
	if (!err) {
		pw->reset_gpio = pdata->reset_gpio;
		pw->pwdn_gpio = pdata->pwdn_gpio;
	}


	if (priv->pdata->use_cam_gpio) {
		err = cam_gpio_register(priv->i2c_client, pw->pwdn_gpio);
		if (err)
			dev_err(&priv->i2c_client->dev,
				"%s ERR can't register cam gpio %u!\n",
				 __func__, pw->pwdn_gpio);
	} else {
		gpio_request(pw->pwdn_gpio, "cam_pwdn_gpio");
		gpio_request(pw->reset_gpio, "cam_reset_gpio");
	}


	pw->state = SWITCH_OFF;
	return err;
}

static int tw9992_set_gain(struct tw9992 *priv, s32 val);
static int tw9992_set_frame_length(struct tw9992 *priv, s32 val);
static int tw9992_set_coarse_time(struct tw9992 *priv, s32 val);
static int tw9992_set_coarse_time_short(struct tw9992 *priv, s32 val);

static int tw9992_s_stream(struct v4l2_subdev *sd, int enable)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	struct camera_common_data *s_data = to_camera_common_data(client);
	struct tw9992 *priv = (struct tw9992 *)s_data->priv;
	struct v4l2_control control;
	int err;

	dev_dbg(&client->dev, "%s++\n", __func__);

	//err = tw9992_write_table(priv, reg_table);
	//if (err)
	//	printk("write reg table err\n");
	
#if 0
	if (!enable) {
		tw9992_update_ctrl_range(priv, TW9992_MAX_FRAME_LENGTH);

		return tw9992_write_table(priv,
			mode_table[TW9992_MODE_STOP_STREAM]);
	}
	
	printk(" ------------- s_data->mode = %d\n",s_data->mode);

	err = tw9992_write_table(priv, mode_table[s_data->mode]);
	if (err)
		goto exit;

	/* write list of override regs for the asking frame length,
	 * coarse integration time, and gain. Failures to write
	 * overrides are non-fatal */
	control.id = V4L2_CID_GAIN;
	err = v4l2_g_ctrl(&priv->ctrl_handler, &control);
	err |= tw9992_set_gain(priv, control.value);
	if (err)
		dev_dbg(&client->dev, "%s: warning gain override failed\n",
			__func__);

	control.id = V4L2_CID_FRAME_LENGTH;
	err = v4l2_g_ctrl(&priv->ctrl_handler, &control);
	err |= tw9992_set_frame_length(priv, control.value);
	if (err)
		dev_dbg(&client->dev,
			"%s: warning frame length override failed\n",
			__func__);

	control.id = V4L2_CID_COARSE_TIME;
	err = v4l2_g_ctrl(&priv->ctrl_handler, &control);
	err |= tw9992_set_coarse_time(priv, control.value);
	if (err)
		dev_dbg(&client->dev,
			"%s: warning coarse time override failed\n",
			__func__);

	control.id = V4L2_CID_COARSE_TIME_SHORT;
	err = v4l2_g_ctrl(&priv->ctrl_handler, &control);
	err |= tw9992_set_coarse_time_short(priv, control.value);
	if (err)
		dev_dbg(&client->dev,
			"%s: warning coarse time short override failed\n",
			__func__);

	err = tw9992_write_table(priv, mode_table[TW9992_MODE_START_STREAM]);
	if (err)
		goto exit;

	if (test_mode)
		err = tw9992_write_table(priv,
			mode_table[TW9992_MODE_TEST_PATTERN]);
#endif

	dev_dbg(&client->dev, "%s--\n", __func__);
	return 0;
exit:
	dev_dbg(&client->dev, "%s: error setting stream\n", __func__);
	return err;
}

static int tw9992_g_input_status(struct v4l2_subdev *sd, u32 *status)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	struct camera_common_data *s_data = to_camera_common_data(client);
	struct tw9992 *priv = (struct tw9992 *)s_data->priv;
	struct camera_common_power_rail *pw = &priv->power;

	*status = pw->state == SWITCH_ON;
	return 0;
}

static struct v4l2_subdev_video_ops tw9992_subdev_video_ops = {
	.s_stream	= tw9992_s_stream,
	.s_mbus_fmt	= camera_common_s_fmt,
	.g_mbus_fmt	= camera_common_g_fmt,
	.try_mbus_fmt	= camera_common_try_fmt,
	.enum_mbus_fmt	= camera_common_enum_fmt,
	.g_mbus_config	= camera_common_g_mbus_config,
	.g_input_status = tw9992_g_input_status,
	.enum_framesizes	= camera_common_enum_framesizes,
	.enum_frameintervals	= camera_common_enum_frameintervals,
};

static struct v4l2_subdev_core_ops tw9992_subdev_core_ops = {
	.s_power	= camera_common_s_power,
};

static int tw9992_get_fmt(struct v4l2_subdev *sd,
		struct v4l2_subdev_fh *fh,
		struct v4l2_subdev_format *format)
{
	return camera_common_g_fmt(sd, &format->format);
}

static int tw9992_set_fmt(struct v4l2_subdev *sd,
		struct v4l2_subdev_fh *fh,
	struct v4l2_subdev_format *format)
{
	int ret;

	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
		ret = camera_common_try_fmt(sd, &format->format);
	else
		ret = camera_common_s_fmt(sd, &format->format);

	return ret;
}

static struct v4l2_subdev_pad_ops tw9992_subdev_pad_ops = {
	.enum_mbus_code = camera_common_enum_mbus_code,
	.set_fmt = tw9992_set_fmt,
	.get_fmt = tw9992_get_fmt,
};

static struct v4l2_subdev_ops tw9992_subdev_ops = {
	.core	= &tw9992_subdev_core_ops,
	.video	= &tw9992_subdev_video_ops,
	.pad	= &tw9992_subdev_pad_ops,
};

static struct of_device_id tw9992_of_match[] = {
	{ .compatible = "nvidia,tw9992", },
	{ },
};

static struct camera_common_sensor_ops tw9992_common_ops = {
	.power_on = tw9992_power_on,
	.power_off = tw9992_power_off,
	.write_reg = tw9992_write_reg,
	.read_reg = tw9992_read_reg,
};

static int tw9992_set_group_hold(struct tw9992 *priv)
{
	int err;
	int gh_prev = switch_ctrl_qmenu[priv->group_hold_prev];

#if 0
	if (priv->group_hold_en == true && gh_prev == SWITCH_OFF) {
		/* enter group hold */
		err = tw9992_write_reg(priv->s_data,
				       TW9992_GROUP_HOLD_ADDR, 0x01);
		if (err)
			goto fail;

		priv->group_hold_prev = 1;

		dev_dbg(&priv->i2c_client->dev,
			 "%s: enter group hold\n", __func__);
	} else if (priv->group_hold_en == false && gh_prev == SWITCH_ON) {
		/* leave group hold */
		err = tw9992_write_reg(priv->s_data,
				       TW9992_GROUP_HOLD_ADDR, 0x11);
		if (err)
			goto fail;

		err = tw9992_write_reg(priv->s_data,
				       TW9992_GROUP_HOLD_ADDR, 0x61);
		if (err)
			goto fail;

		priv->group_hold_prev = 0;

		dev_dbg(&priv->i2c_client->dev,
			 "%s: leave group hold\n", __func__);
	}
#endif

	return 0;

fail:
	dev_dbg(&priv->i2c_client->dev,
		 "%s: Group hold control error\n", __func__);
	return err;
}

static u16 tw9992_to_real_gain(u32 rep, int shift)
{
	u16 gain;
	int gain_int;
	int gain_dec;
	int min_int = (1 << shift);
#if 0
	if (rep < TW9992_MIN_GAIN)
		rep = TW9992_MIN_GAIN;
	else if (rep > TW9992_MAX_GAIN)
		rep = TW9992_MAX_GAIN;

	gain_int = (int)(rep >> shift);
	gain_dec = (int)(rep & ~(0xffff << shift));

	/* derived from formulat gain = (x * 16 + 0.5) */
	gain = ((gain_int * min_int + gain_dec) * 32 + min_int) / (2 * min_int);
#endif
	return gain;
}

static int tw9992_set_gain(struct tw9992 *priv, s32 val)
{
	tw9992_reg reg_list[2];
	int err;
	u16 gain;
	int i;
#if 0
	if (!priv->group_hold_prev)
		tw9992_set_group_hold(priv);

	/* translate value */
	gain = tw9992_to_real_gain((u32)val, TW9992_GAIN_SHIFT);

	tw9992_get_gain_regs(reg_list, gain);
	dev_dbg(&priv->i2c_client->dev,
		 "%s: gain %04x val: %04x\n", __func__, val, gain);

	for (i = 0; i < 2; i++) {
		err = tw9992_write_reg(priv->s_data, reg_list[i].addr,
			 reg_list[i].val);
		if (err)
			goto fail;
	}
#endif
	return 0;

fail:
	dev_dbg(&priv->i2c_client->dev,
		 "%s: GAIN control error\n", __func__);
	return err;
}

static void tw9992_update_ctrl_range(struct tw9992 *priv, s32 frame_length)
{
	struct v4l2_ctrl *ctrl = NULL;
	int ctrl_ids[2] = {V4L2_CID_COARSE_TIME,
			V4L2_CID_COARSE_TIME_SHORT};
	s32 max, min, def;
	int i, j;
#if 0
	for (i = 0; i < ARRAY_SIZE(ctrl_ids); i++) {
		for (j = 0; j < priv->numctrls; j++) {
			if (priv->ctrls[j]->id == ctrl_ids[i]) {
				ctrl = priv->ctrls[j];
				break;
			}
		}

		if (j == priv->numctrls) {
			dev_err(&priv->i2c_client->dev,
				"could not find ctrl %x\n",
				ctrl_ids[i]);
			continue;
		}

		max = frame_length - TW9992_MAX_COARSE_DIFF;
		/* clamp the value in case above is negative */
		max = clamp_val(max, TW9992_MIN_EXPOSURE_COARSE,
			TW9992_MAX_EXPOSURE_COARSE);
		min = TW9992_MIN_EXPOSURE_COARSE;
		def = clamp_val(TW9992_DEFAULT_EXPOSURE_COARSE, min, max);
		if (__v4l2_ctrl_modify_range(ctrl, min, max, 1, def))
			dev_err(&priv->i2c_client->dev,
				"ctrl %x: range update failed\n",
				ctrl_ids[i]);
	}
#endif

}

static int tw9992_set_frame_length(struct tw9992 *priv, s32 val)
{
	tw9992_reg reg_list[2];
	int err;
	u32 frame_length;
	int i;
#if 0
	if (!priv->group_hold_prev)
		tw9992_set_group_hold(priv);

	frame_length = (u32)val;

	tw9992_get_frame_length_regs(reg_list, frame_length);
	dev_dbg(&priv->i2c_client->dev,
		 "%s: val: %d\n", __func__, frame_length);

	for (i = 0; i < 2; i++) {
		err = tw9992_write_reg(priv->s_data, reg_list[i].addr,
			 reg_list[i].val);
		if (err)
			goto fail;
	}

	tw9992_update_ctrl_range(priv, val);
	
#endif
	return 0;

fail:
	dev_dbg(&priv->i2c_client->dev,
		 "%s: FRAME_LENGTH control error\n", __func__);
	return err;
}

static int tw9992_set_coarse_time(struct tw9992 *priv, s32 val)
{
	tw9992_reg reg_list[3];
	int err;
	u32 coarse_time;
	int i;
#if 0
	if (!priv->group_hold_prev)
		tw9992_set_group_hold(priv);

	coarse_time = (u32)val;

	tw9992_get_coarse_time_regs(reg_list, coarse_time);
	dev_dbg(&priv->i2c_client->dev,
		 "%s: val: %d\n", __func__, coarse_time);

	for (i = 0; i < 3; i++) {
		err = tw9992_write_reg(priv->s_data, reg_list[i].addr,
			 reg_list[i].val);
		if (err)
			goto fail;
	}
#endif
	return 0;

fail:
	dev_dbg(&priv->i2c_client->dev,
		 "%s: COARSE_TIME control error\n", __func__);
	return err;
}

static int tw9992_set_coarse_time_short(struct tw9992 *priv, s32 val)
{
	tw9992_reg reg_list[3];
	int err;
	struct v4l2_control hdr_control;
	int hdr_en;
	u32 coarse_time_short;
	int i;
#if 0
	if (!priv->group_hold_prev)
		tw9992_set_group_hold(priv);

	/* check hdr enable ctrl */
	hdr_control.id = V4L2_CID_HDR_EN;

	err = camera_common_g_ctrl(priv->s_data, &hdr_control);
	if (err < 0) {
		dev_err(&priv->i2c_client->dev,
			"could not find device ctrl.\n");
		return err;
	}

	hdr_en = switch_ctrl_qmenu[hdr_control.value];
	if (hdr_en == SWITCH_OFF)
		return 0;

	coarse_time_short = (u32)val;

	tw9992_get_coarse_time_short_regs(reg_list, coarse_time_short);
	dev_dbg(&priv->i2c_client->dev,
		 "%s: val: %d\n", __func__, coarse_time_short);

	for (i = 0; i < 3; i++) {
		err = tw9992_write_reg(priv->s_data, reg_list[i].addr,
			 reg_list[i].val);
		if (err)
			goto fail;
	}
#endif
	return 0;

fail:
	dev_dbg(&priv->i2c_client->dev,
		 "%s: COARSE_TIME_SHORT control error\n", __func__);
	return err;
}
#if 0
static int tw9992_eeprom_device_release(struct tw9992 *priv)
{
	int i;

	for (i = 0; i < TW9992_EEPROM_NUM_BLOCKS; i++) {
		if (priv->eeprom[i].i2c_client != NULL) {
			i2c_unregister_device(priv->eeprom[i].i2c_client);
			priv->eeprom[i].i2c_client = NULL;
		}
	}

	return 0;
}

static int tw9992_eeprom_device_init(struct tw9992 *priv)
{
	char *dev_name = "eeprom_tw9992";
	static struct regmap_config eeprom_regmap_config = {
		.reg_bits = 8,
		.val_bits = 8,
	};
	int i;
	int err;

	if (!priv->pdata->has_eeprom)
		return -EINVAL;

	for (i = 0; i < TW9992_EEPROM_NUM_BLOCKS; i++) {
		priv->eeprom[i].adap = i2c_get_adapter(
				priv->i2c_client->adapter->nr);
		memset(&priv->eeprom[i].brd, 0, sizeof(priv->eeprom[i].brd));
		strncpy(priv->eeprom[i].brd.type, dev_name,
				sizeof(priv->eeprom[i].brd.type));
		priv->eeprom[i].brd.addr = TW9992_EEPROM_ADDRESS + i;
		priv->eeprom[i].i2c_client = i2c_new_device(
				priv->eeprom[i].adap, &priv->eeprom[i].brd);

		priv->eeprom[i].regmap = devm_regmap_init_i2c(
			priv->eeprom[i].i2c_client, &eeprom_regmap_config);
		if (IS_ERR(priv->eeprom[i].regmap)) {
			err = PTR_ERR(priv->eeprom[i].regmap);
			tw9992_eeprom_device_release(priv);
			return err;
		}
	}

	return 0;
}

static int tw9992_read_eeprom(struct tw9992 *priv,
				struct v4l2_ctrl *ctrl)
{
	int err, i;

	for (i = 0; i < TW9992_EEPROM_NUM_BLOCKS; i++) {
		err = regmap_bulk_read(priv->eeprom[i].regmap, 0,
			&priv->eeprom_buf[i * TW9992_EEPROM_BLOCK_SIZE],
			TW9992_EEPROM_BLOCK_SIZE);
		if (err)
			return err;
	}

	for (i = 0; i < TW9992_EEPROM_SIZE; i++)
		sprintf(&ctrl->string[i*2], "%02x",
			priv->eeprom_buf[i]);
	return 0;
}

static int tw9992_write_eeprom(struct tw9992 *priv,
				char *string)
{
	int err;
	int i;
	u8 curr[3];
	unsigned long data;

	for (i = 0; i < TW9992_EEPROM_SIZE; i++) {
		curr[0] = string[i*2];
		curr[1] = string[i*2+1];
		curr[2] = '

/*

  • tw9992_v4l2.c - tw9992 sensor driver
  • Copyright (c) 2013-2016, NVIDIA CORPORATION. All rights reserved.
  • This program is free software; you can redistribute it and/or modify it
  • under the terms and conditions of the GNU General Public License,
  • version 2, as published by the Free Software Foundation.
  • This program is distributed in the hope it will be useful, but WITHOUT
  • ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  • FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  • more details.
  • You should have received a copy of the GNU General Public License
  • along with this program. If not, see http://www.gnu.org/licenses/.
    */

#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
#include <linux/module.h>

#include <linux/seq_file.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>

#include <media/camera_common.h>
#include “cam_dev/camera_gpio.h”
#include “tw9992_mode_tbls.h”

#define TW9992_MAX_COARSE_DIFF 6
#define TW9992_GAIN_SHIFT 8
#define TW9992_REAL_GAIN_SHIFT 4
#define TW9992_MIN_GAIN (1 << TW9992_GAIN_SHIFT)
#define TW9992_MAX_GAIN (16 << TW9992_GAIN_SHIFT)
#define TW9992_DEFAULT_GAIN TW9992_MIN_GAIN

#define TW9992_MIN_FRAME_LENGTH (0x0)
#define TW9992_MAX_FRAME_LENGTH (0x7fff)

#define TW9992_MIN_EXPOSURE_COARSE (0x0002)
#define TW9992_MAX_EXPOSURE_COARSE
(TW9992_MAX_FRAME_LENGTH-TW9992_MAX_COARSE_DIFF)

#define TW9992_DEFAULT_FRAME_LENGTH (0x07C0)
#define TW9992_DEFAULT_EXPOSURE_COARSE
(TW9992_DEFAULT_FRAME_LENGTH-TW9992_MAX_COARSE_DIFF)

#define TW9992_DEFAULT_WIDTH 720
#define TW9992_DEFAULT_HEIGHT 240
#define TW9992_DEFAULT_CLK_FREQ 24000000
#define TW9992_DEFAULT_MODE TW9992_MODE_720x480
#define TW9992_DEFAULT_DATAFMT V4L2_MBUS_FMT_SRGGB10_1X10

#define TW9992_TABLE_WAIT_MS 0
#define TW9992_TABLE_END 1
#define TW9992_MAX_RETRIES 3

#define tw9992_reg struct reg_8

struct tw9992 {
struct camera_common_power_rail power;
int numctrls;
struct v4l2_ctrl_handler ctrl_handler;
//struct camera_common_eeprom_data eeprom[TW9992_EEPROM_NUM_BLOCKS];
//u8 eeprom_buf[TW9992_EEPROM_SIZE];
struct i2c_client *i2c_client;
struct v4l2_subdev *subdev;
struct media_pad pad;

int				reg_offset;

s32				group_hold_prev;
bool				group_hold_en;
struct regmap			*regmap;
struct camera_common_data	*s_data;
struct camera_common_pdata	*pdata;
struct v4l2_ctrl		*ctrls[];

};

static struct regmap_config tw9992_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};

static const tw9992_reg reg_table = {
{0x00, 0x92},
{0x01, 0x00},
{0x02, 0x40},
{0x03, 0x68},
{0x04, 0x00},
{0x05, 0x09},
{0x06, 0x00},
{0x07, 0x02},
{0x08, 0x15},
{0x09, 0xF0},
{0x0A, 0x14},
{0x0B, 0xD0},
{0x0C, 0xCC},
{0x0D, 0x00},
{0x10, 0x00},
{0x11, 0x64},
{0x12, 0x11},
{0x13, 0x80},
{0x14, 0x80},
{0x15, 0x00},
{0x17, 0x80},
{0x18, 0x44},
{0x19, 0x06},
{0x1A, 0x10},
{0x1B, 0x00},
{0x1C, 0x0F},
{0x1D, 0x7F},
{0x1F, 0x00},
{0x20, 0x50},
{0x21, 0x22},
{0x22, 0xF0},
{0x23, 0xD8},
{0x24, 0xBC},
{0x25, 0xB8},
{0x26, 0x44},
{0x27, 0x38},
{0x28, 0x00},
{0x29, 0x00},
{0x2A, 0x78},
{0x2B, 0x44},
{0x2C, 0x30},
{0x2D, 0x14},
{0x2E, 0xA5},
{0x2F, 0xE0},
{0x30, 0x00},
{0x31, 0x10},
{0x32, 0xFF},
{0x33, 0x05},
{0x34, 0x1A},
{0x35, 0x00},
{0x36, 0x5A},
{0x37, 0x18},
{0x38, 0xDD},
{0x39, 0x00},
{0x3A, 0x30},
{0x3B, 0x00},
{0x3C, 0x00},
{0x3D, 0x00},
{0x3F, 0x1A},
{0x40, 0x80},
{0x41, 0x00},
{0x42, 0x00},
{0x48, 0x02},
{0x49, 0x00},
{0x4A, 0x81},
{0x4B, 0x0A},
{0x4C, 0x00},
{0x4D, 0x01},
{0x4E, 0x01},
{0x50, 0x00},
{0x51, 0x17},
{0x52, 0x00},
{0x53, 0x00},
{0x54, 0x06},
{0x55, 0x00},
{0x56, 0x00},
{0x57, 0x00},
{0x58, 0x00},
{0x60, 0x00},
{0x61, 0x00},
{0x62, 0x00},
{0x63, 0x00},
{0x70, 0x01},
{0x71, 0xA5},
{0x72, 0xA0},
{0x73, 0x00},
{0x74, 0xF0},
{0x75, 0x00},
{0x76, 0x17},
{0x77, 0x05},
{0x78, 0x88},
{0x79, 0x06},
{0x7A, 0x28},
{0x7B, 0x46},
{0x7C, 0xB3},
{0x7D, 0x06},
{0x7E, 0x13},
{0x7F, 0x10},
{0x80, 0x05},
{0x81, 0xA0},
{0x82, 0x13},
{0x83, 0x11},
{0x84, 0x02},
{0x85, 0x0E},
{0x86, 0x08},
{0x87, 0x37},
{0x88, 0x00},
{0x89, 0x00},
{0x8A, 0x02},
{0x8B, 0x33},
{0x8C, 0x22},
{0x8D, 0x03},
{0x8E, 0x22},
{0x8F, 0x01},
{0x90, 0x00},
{0x91, 0x0C},
{0x92, 0x00},
{0x93, 0x0E},
{0x94, 0x07},
{0x95, 0xFF},
{0x96, 0x1A},
{0x9B, 0x02},
{0xA0, 0x00},
{0xA1, 0x00},
{0xA2, 0x30},
{0xA3, 0xC0},
{0xA4, 0x00},
{0xC0, 0x06},
{0xC1, 0x20},
};

static int tw9992_g_volatile_ctrl(struct v4l2_ctrl *ctrl);
static int tw9992_s_ctrl(struct v4l2_ctrl *ctrl);
static void tw9992_update_ctrl_range(struct tw9992 *priv, s32 frame_length);

static const struct v4l2_ctrl_ops tw9992_ctrl_ops = {
.g_volatile_ctrl = tw9992_g_volatile_ctrl,
.s_ctrl = tw9992_s_ctrl,
};

static struct v4l2_ctrl_config ctrl_config_list = {
/* Do not change the name field for the controls! /
{
.ops = &tw9992_ctrl_ops,
.id = V4L2_CID_GAIN,
.name = “Gain”,
.type = V4L2_CTRL_TYPE_INTEGER,
.flags = V4L2_CTRL_FLAG_SLIDER,
.min = TW9992_MIN_GAIN,
.max = TW9992_MAX_GAIN,
.def = TW9992_DEFAULT_GAIN,
.step = 1,
},
{
.ops = &tw9992_ctrl_ops,
.id = V4L2_CID_FRAME_LENGTH,
.name = “Frame Length”,
.type = V4L2_CTRL_TYPE_INTEGER,
.flags = V4L2_CTRL_FLAG_SLIDER,
.min = TW9992_MIN_FRAME_LENGTH,
.max = TW9992_MAX_FRAME_LENGTH,
.def = TW9992_DEFAULT_FRAME_LENGTH,
.step = 1,
},
{
.ops = &tw9992_ctrl_ops,
.id = V4L2_CID_COARSE_TIME,
.name = “Coarse Time”,
.type = V4L2_CTRL_TYPE_INTEGER,
.flags = V4L2_CTRL_FLAG_SLIDER,
.min = TW9992_MIN_EXPOSURE_COARSE,
.max = TW9992_MAX_EXPOSURE_COARSE,
.def = TW9992_DEFAULT_EXPOSURE_COARSE,
.step = 1,
},
{
.ops = &tw9992_ctrl_ops,
.id = V4L2_CID_COARSE_TIME_SHORT,
.name = “Coarse Time Short”,
.type = V4L2_CTRL_TYPE_INTEGER,
.flags = V4L2_CTRL_FLAG_SLIDER,
.min = TW9992_MIN_EXPOSURE_COARSE,
.max = TW9992_MAX_EXPOSURE_COARSE,
.def = TW9992_DEFAULT_EXPOSURE_COARSE,
.step = 1,
},
{
.ops = &tw9992_ctrl_ops,
.id = V4L2_CID_GROUP_HOLD,
.name = “Group Hold”,
.type = V4L2_CTRL_TYPE_INTEGER_MENU,
.min = 0,
.max = ARRAY_SIZE(switch_ctrl_qmenu) - 1,
.menu_skip_mask = 0,
.def = 0,
.qmenu_int = switch_ctrl_qmenu,
},
{
.ops = &tw9992_ctrl_ops,
.id = V4L2_CID_HDR_EN,
.name = “HDR enable”,
.type = V4L2_CTRL_TYPE_INTEGER_MENU,
.min = 0,
.max = ARRAY_SIZE(switch_ctrl_qmenu) - 1,
.menu_skip_mask = 0,
.def = 0,
.qmenu_int = switch_ctrl_qmenu,
},
/
{
.ops = &tw9992_ctrl_ops,
.id = V4L2_CID_EEPROM_DATA,
.name = “EEPROM Data”,
.type = V4L2_CTRL_TYPE_STRING,
.flags = V4L2_CTRL_FLAG_VOLATILE,
.min = 0,
.max = TW9992_EEPROM_STR_SIZE,
.step = 2,
},
{
.ops = &tw9992_ctrl_ops,
.id = V4L2_CID_OTP_DATA,
.name = “OTP Data”,
.type = V4L2_CTRL_TYPE_STRING,
.flags = V4L2_CTRL_FLAG_READ_ONLY,
.min = 0,
.max = TW9992_OTP_STR_SIZE,
.step = 2,
},
{
.ops = &tw9992_ctrl_ops,
.id = V4L2_CID_FUSE_ID,
.name = “Fuse ID”,
.type = V4L2_CTRL_TYPE_STRING,
.flags = V4L2_CTRL_FLAG_READ_ONLY,
.min = 0,
.max = TW9992_FUSE_ID_STR_SIZE,
.step = 2,
},*/

};

static inline int tw9992_read_reg(struct camera_common_data *s_data,
u16 addr, u8 *val)
{
struct tw9992 *priv = (struct tw9992 *)s_data->priv;

return regmap_read(priv->regmap, addr, (unsigned int *) val);

}

static int tw9992_write_reg(struct camera_common_data *s_data, u16 addr, u8 val)
{
int err;
struct tw9992 *priv = (struct tw9992 *)s_data->priv;

err = regmap_write(priv->regmap, addr, val);
if (err)
	pr_err("%s:i2c write failed, %x = %x\n",
		__func__, addr, val);

return err;

}

static int tw9992_write_regs(struct camera_common_data *s_data)
{
int i = 0;
int count = sizeof(reg_table)/sizeof(struct reg_8);

for (i = 0; i < count; i++)
{
	tw9992_write_reg(s_data, reg_table[i].addr, reg_table[i].val);
}

}

static int tw9992_write_table(struct tw9992 *priv,
const tw9992_reg table)
{
return regmap_util_write_table_8(priv->regmap,
table,
NULL, 0,
TW9992_TABLE_WAIT_MS,
TW9992_TABLE_END);
}

/*static void tw9992_gpio_set(struct tw9992 priv,
unsigned int gpio, int val)
{
if (priv->pdata->use_cam_gpio)
cam_gpio_ctrl(priv->i2c_client, gpio, val, 1);
else {
if (gpio_cansleep(gpio))
gpio_set_value_cansleep(gpio, val);
else
gpio_set_value(gpio, val);
}
}
/

static int tw9992_power_on(struct camera_common_data *s_data)
{
int err = 0;
struct tw9992 *priv = (struct tw9992 *)s_data->priv;
struct camera_common_power_rail *pw = &priv->power;

dev_dbg(&priv->i2c_client->dev, "%s: power on\n", __func__);

if (priv->pdata && priv->pdata->power_on) {
	err = priv->pdata->power_on(pw);
	if (err)
		pr_err("%s failed.\n", __func__);
	else
		pw->state = SWITCH_ON;
	return err;
}

/* sleeps calls in the sequence below are for internal device
 * signal propagation as specified by sensor vendor */

if (pw->avdd)
	err = regulator_enable(pw->avdd);
if (err)
	goto tw9992_avdd_fail;

if (pw->iovdd)
	err = regulator_enable(pw->iovdd);
if (err)
	goto tw9992_iovdd_fail;

usleep_range(1, 2);
//if (pw->pwdn_gpio)
	//tw9992_gpio_set(priv, pw->pwdn_gpio, 1);

/* datasheet 2.9: reset requires ~2ms settling time
 * a power on reset is generated after core power becomes stable */
usleep_range(2000, 2010);

//if (pw->reset_gpio)
	//tw9992_gpio_set(priv, pw->reset_gpio, 1);

/* datasheet fig 2-9: t3 */
usleep_range(1350, 1360);

pw->state = SWITCH_ON;
return 0;

tw9992_iovdd_fail:
regulator_disable(pw->avdd);

tw9992_avdd_fail:
pr_err(“%s failed.\n”, func);
return -ENODEV;
}

static int tw9992_power_off(struct camera_common_data *s_data)
{
int err = 0;
struct tw9992 *priv = (struct tw9992 *)s_data->priv;
struct camera_common_power_rail *pw = &priv->power;

dev_dbg(&priv->i2c_client->dev, "%s: power off\n", __func__);

if (priv->pdata && priv->pdata->power_on) {
	err = priv->pdata->power_off(pw);
	if (!err)
		pw->state = SWITCH_OFF;
	else
		pr_err("%s failed.\n", __func__);
	return err;
}

/* sleeps calls in the sequence below are for internal device
 * signal propagation as specified by sensor vendor */

usleep_range(21, 25);
//if (pw->pwdn_gpio)
	//tw9992_gpio_set(priv, pw->pwdn_gpio, 0);
usleep_range(1, 2);
//if (pw->reset_gpio)
	//tw9992_gpio_set(priv, pw->reset_gpio, 0);

/* datasheet 2.9: reset requires ~2ms settling time*/
usleep_range(2000, 2010);

if (pw->iovdd)
	regulator_disable(pw->iovdd);
if (pw->avdd)
	regulator_disable(pw->avdd);

return 0;

}

static int tw9992_power_put(struct tw9992 *priv)
{
struct camera_common_power_rail *pw = &priv->power;

if (unlikely(!pw))
	return -EFAULT;

if (likely(pw->avdd))
	regulator_put(pw->avdd);

if (likely(pw->iovdd))
	regulator_put(pw->iovdd);

pw->avdd = NULL;
pw->iovdd = NULL;

if (priv->pdata->use_cam_gpio)
	cam_gpio_deregister(priv->i2c_client, pw->pwdn_gpio);
else {
	gpio_free(pw->pwdn_gpio);
	gpio_free(pw->reset_gpio);
}

return 0;

}

static int tw9992_power_get(struct tw9992 *priv)
{
struct camera_common_power_rail *pw = &priv->power;
struct camera_common_pdata *pdata = priv->pdata;
const char *mclk_name;
const char *parentclk_name;
struct clk *parent;
int err = 0;

mclk_name = priv->pdata->mclk_name ?
	    priv->pdata->mclk_name : "cam_mclk1";
pw->mclk = devm_clk_get(&priv->i2c_client->dev, mclk_name);
if (IS_ERR(pw->mclk)) {
	dev_err(&priv->i2c_client->dev,
		"unable to get clock %s\n", mclk_name);
	return PTR_ERR(pw->mclk);
}

parentclk_name = priv->pdata->parentclk_name;
if (parentclk_name) {
	parent = devm_clk_get(&priv->i2c_client->dev, parentclk_name);
	if (IS_ERR(parent))
		dev_err(&priv->i2c_client->dev,
			"unable to get parent clcok %s",
			parentclk_name);
	else
		clk_set_parent(pw->mclk, parent);
}

#if 0
/* analog 2.8v /
err |= camera_common_regulator_get(priv->i2c_client,
&pw->avdd, pdata->regulators.avdd);
/
IO 1.8v */
err |= camera_common_regulator_get(priv->i2c_client,
&pw->iovdd, pdata->regulators.iovdd);
#endif
if (!err) {
pw->reset_gpio = pdata->reset_gpio;
pw->pwdn_gpio = pdata->pwdn_gpio;
}

if (priv->pdata->use_cam_gpio) {
	err = cam_gpio_register(priv->i2c_client, pw->pwdn_gpio);
	if (err)
		dev_err(&priv->i2c_client->dev,
			"%s ERR can't register cam gpio %u!\n",
			 __func__, pw->pwdn_gpio);
} else {
	gpio_request(pw->pwdn_gpio, "cam_pwdn_gpio");
	gpio_request(pw->reset_gpio, "cam_reset_gpio");
}


pw->state = SWITCH_OFF;
return err;

}

static int tw9992_set_gain(struct tw9992 *priv, s32 val);
static int tw9992_set_frame_length(struct tw9992 *priv, s32 val);
static int tw9992_set_coarse_time(struct tw9992 *priv, s32 val);
static int tw9992_set_coarse_time_short(struct tw9992 *priv, s32 val);

static int tw9992_s_stream(struct v4l2_subdev *sd, int enable)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct camera_common_data *s_data = to_camera_common_data(client);
struct tw9992 *priv = (struct tw9992 *)s_data->priv;
struct v4l2_control control;
int err;

dev_dbg(&client->dev, "%s++\n", __func__);

//err = tw9992_write_table(priv, reg_table);
//if (err)
//	printk("write reg table err\n");

#if 0
if (!enable) {
tw9992_update_ctrl_range(priv, TW9992_MAX_FRAME_LENGTH);

	return tw9992_write_table(priv,
		mode_table[TW9992_MODE_STOP_STREAM]);
}

printk(" ------------- s_data->mode = %d\n",s_data->mode);

err = tw9992_write_table(priv, mode_table[s_data->mode]);
if (err)
	goto exit;

/* write list of override regs for the asking frame length,
 * coarse integration time, and gain. Failures to write
 * overrides are non-fatal */
control.id = V4L2_CID_GAIN;
err = v4l2_g_ctrl(&priv->ctrl_handler, &control);
err |= tw9992_set_gain(priv, control.value);
if (err)
	dev_dbg(&client->dev, "%s: warning gain override failed\n",
		__func__);

control.id = V4L2_CID_FRAME_LENGTH;
err = v4l2_g_ctrl(&priv->ctrl_handler, &control);
err |= tw9992_set_frame_length(priv, control.value);
if (err)
	dev_dbg(&client->dev,
		"%s: warning frame length override failed\n",
		__func__);

control.id = V4L2_CID_COARSE_TIME;
err = v4l2_g_ctrl(&priv->ctrl_handler, &control);
err |= tw9992_set_coarse_time(priv, control.value);
if (err)
	dev_dbg(&client->dev,
		"%s: warning coarse time override failed\n",
		__func__);

control.id = V4L2_CID_COARSE_TIME_SHORT;
err = v4l2_g_ctrl(&priv->ctrl_handler, &control);
err |= tw9992_set_coarse_time_short(priv, control.value);
if (err)
	dev_dbg(&client->dev,
		"%s: warning coarse time short override failed\n",
		__func__);

err = tw9992_write_table(priv, mode_table[TW9992_MODE_START_STREAM]);
if (err)
	goto exit;

if (test_mode)
	err = tw9992_write_table(priv,
		mode_table[TW9992_MODE_TEST_PATTERN]);

#endif

dev_dbg(&client->dev, "%s--\n", __func__);
return 0;

exit:
dev_dbg(&client->dev, “%s: error setting stream\n”, func);
return err;
}

static int tw9992_g_input_status(struct v4l2_subdev *sd, u32 *status)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct camera_common_data *s_data = to_camera_common_data(client);
struct tw9992 *priv = (struct tw9992 *)s_data->priv;
struct camera_common_power_rail *pw = &priv->power;

*status = pw->state == SWITCH_ON;
return 0;

}

static struct v4l2_subdev_video_ops tw9992_subdev_video_ops = {
.s_stream = tw9992_s_stream,
.s_mbus_fmt = camera_common_s_fmt,
.g_mbus_fmt = camera_common_g_fmt,
.try_mbus_fmt = camera_common_try_fmt,
.enum_mbus_fmt = camera_common_enum_fmt,
.g_mbus_config = camera_common_g_mbus_config,
.g_input_status = tw9992_g_input_status,
.enum_framesizes = camera_common_enum_framesizes,
.enum_frameintervals = camera_common_enum_frameintervals,
};

static struct v4l2_subdev_core_ops tw9992_subdev_core_ops = {
.s_power = camera_common_s_power,
};

static int tw9992_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_fh *fh,
struct v4l2_subdev_format *format)
{
return camera_common_g_fmt(sd, &format->format);
}

static int tw9992_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_fh *fh,
struct v4l2_subdev_format *format)
{
int ret;

if (format->which == V4L2_SUBDEV_FORMAT_TRY)
	ret = camera_common_try_fmt(sd, &format->format);
else
	ret = camera_common_s_fmt(sd, &format->format);

return ret;

}

static struct v4l2_subdev_pad_ops tw9992_subdev_pad_ops = {
.enum_mbus_code = camera_common_enum_mbus_code,
.set_fmt = tw9992_set_fmt,
.get_fmt = tw9992_get_fmt,
};

static struct v4l2_subdev_ops tw9992_subdev_ops = {
.core = &tw9992_subdev_core_ops,
.video = &tw9992_subdev_video_ops,
.pad = &tw9992_subdev_pad_ops,
};

static struct of_device_id tw9992_of_match = {
{ .compatible = “nvidia,tw9992”, },
{ },
};

static struct camera_common_sensor_ops tw9992_common_ops = {
.power_on = tw9992_power_on,
.power_off = tw9992_power_off,
.write_reg = tw9992_write_reg,
.read_reg = tw9992_read_reg,
};

static int tw9992_set_group_hold(struct tw9992 *priv)
{
int err;
int gh_prev = switch_ctrl_qmenu[priv->group_hold_prev];

#if 0
if (priv->group_hold_en == true && gh_prev == SWITCH_OFF) {
/* enter group hold */
err = tw9992_write_reg(priv->s_data,
TW9992_GROUP_HOLD_ADDR, 0x01);
if (err)
goto fail;

	priv->group_hold_prev = 1;

	dev_dbg(&priv->i2c_client->dev,
		 "%s: enter group hold\n", __func__);
} else if (priv->group_hold_en == false && gh_prev == SWITCH_ON) {
	/* leave group hold */
	err = tw9992_write_reg(priv->s_data,
			       TW9992_GROUP_HOLD_ADDR, 0x11);
	if (err)
		goto fail;

	err = tw9992_write_reg(priv->s_data,
			       TW9992_GROUP_HOLD_ADDR, 0x61);
	if (err)
		goto fail;

	priv->group_hold_prev = 0;

	dev_dbg(&priv->i2c_client->dev,
		 "%s: leave group hold\n", __func__);
}

#endif

return 0;

fail:
dev_dbg(&priv->i2c_client->dev,
“%s: Group hold control error\n”, func);
return err;
}

static u16 tw9992_to_real_gain(u32 rep, int shift)
{
u16 gain;
int gain_int;
int gain_dec;
int min_int = (1 << shift);
#if 0
if (rep < TW9992_MIN_GAIN)
rep = TW9992_MIN_GAIN;
else if (rep > TW9992_MAX_GAIN)
rep = TW9992_MAX_GAIN;

gain_int = (int)(rep >> shift);
gain_dec = (int)(rep & ~(0xffff << shift));

/* derived from formulat gain = (x * 16 + 0.5) */
gain = ((gain_int * min_int + gain_dec) * 32 + min_int) / (2 * min_int);

#endif
return gain;
}

static int tw9992_set_gain(struct tw9992 *priv, s32 val)
{
tw9992_reg reg_list[2];
int err;
u16 gain;
int i;
#if 0
if (!priv->group_hold_prev)
tw9992_set_group_hold(priv);

/* translate value */
gain = tw9992_to_real_gain((u32)val, TW9992_GAIN_SHIFT);

tw9992_get_gain_regs(reg_list, gain);
dev_dbg(&priv->i2c_client->dev,
	 "%s: gain %04x val: %04x\n", __func__, val, gain);

for (i = 0; i < 2; i++) {
	err = tw9992_write_reg(priv->s_data, reg_list[i].addr,
		 reg_list[i].val);
	if (err)
		goto fail;
}

#endif
return 0;

fail:
dev_dbg(&priv->i2c_client->dev,
“%s: GAIN control error\n”, func);
return err;
}

static void tw9992_update_ctrl_range(struct tw9992 *priv, s32 frame_length)
{
struct v4l2_ctrl *ctrl = NULL;
int ctrl_ids[2] = {V4L2_CID_COARSE_TIME,
V4L2_CID_COARSE_TIME_SHORT};
s32 max, min, def;
int i, j;
#if 0
for (i = 0; i < ARRAY_SIZE(ctrl_ids); i++) {
for (j = 0; j < priv->numctrls; j++) {
if (priv->ctrls[j]->id == ctrl_ids[i]) {
ctrl = priv->ctrls[j];
break;
}
}

	if (j == priv->numctrls) {
		dev_err(&priv->i2c_client->dev,
			"could not find ctrl %x\n",
			ctrl_ids[i]);
		continue;
	}

	max = frame_length - TW9992_MAX_COARSE_DIFF;
	/* clamp the value in case above is negative */
	max = clamp_val(max, TW9992_MIN_EXPOSURE_COARSE,
		TW9992_MAX_EXPOSURE_COARSE);
	min = TW9992_MIN_EXPOSURE_COARSE;
	def = clamp_val(TW9992_DEFAULT_EXPOSURE_COARSE, min, max);
	if (__v4l2_ctrl_modify_range(ctrl, min, max, 1, def))
		dev_err(&priv->i2c_client->dev,
			"ctrl %x: range update failed\n",
			ctrl_ids[i]);
}

#endif

}

static int tw9992_set_frame_length(struct tw9992 *priv, s32 val)
{
tw9992_reg reg_list[2];
int err;
u32 frame_length;
int i;
#if 0
if (!priv->group_hold_prev)
tw9992_set_group_hold(priv);

frame_length = (u32)val;

tw9992_get_frame_length_regs(reg_list, frame_length);
dev_dbg(&priv->i2c_client->dev,
	 "%s: val: %d\n", __func__, frame_length);

for (i = 0; i < 2; i++) {
	err = tw9992_write_reg(priv->s_data, reg_list[i].addr,
		 reg_list[i].val);
	if (err)
		goto fail;
}

tw9992_update_ctrl_range(priv, val);

#endif
return 0;

fail:
dev_dbg(&priv->i2c_client->dev,
“%s: FRAME_LENGTH control error\n”, func);
return err;
}

static int tw9992_set_coarse_time(struct tw9992 *priv, s32 val)
{
tw9992_reg reg_list[3];
int err;
u32 coarse_time;
int i;
#if 0
if (!priv->group_hold_prev)
tw9992_set_group_hold(priv);

coarse_time = (u32)val;

tw9992_get_coarse_time_regs(reg_list, coarse_time);
dev_dbg(&priv->i2c_client->dev,
	 "%s: val: %d\n", __func__, coarse_time);

for (i = 0; i < 3; i++) {
	err = tw9992_write_reg(priv->s_data, reg_list[i].addr,
		 reg_list[i].val);
	if (err)
		goto fail;
}

#endif
return 0;

fail:
dev_dbg(&priv->i2c_client->dev,
“%s: COARSE_TIME control error\n”, func);
return err;
}

static int tw9992_set_coarse_time_short(struct tw9992 *priv, s32 val)
{
tw9992_reg reg_list[3];
int err;
struct v4l2_control hdr_control;
int hdr_en;
u32 coarse_time_short;
int i;
#if 0
if (!priv->group_hold_prev)
tw9992_set_group_hold(priv);

/* check hdr enable ctrl */
hdr_control.id = V4L2_CID_HDR_EN;

err = camera_common_g_ctrl(priv->s_data, &hdr_control);
if (err < 0) {
	dev_err(&priv->i2c_client->dev,
		"could not find device ctrl.\n");
	return err;
}

hdr_en = switch_ctrl_qmenu[hdr_control.value];
if (hdr_en == SWITCH_OFF)
	return 0;

coarse_time_short = (u32)val;

tw9992_get_coarse_time_short_regs(reg_list, coarse_time_short);
dev_dbg(&priv->i2c_client->dev,
	 "%s: val: %d\n", __func__, coarse_time_short);

for (i = 0; i < 3; i++) {
	err = tw9992_write_reg(priv->s_data, reg_list[i].addr,
		 reg_list[i].val);
	if (err)
		goto fail;
}

#endif
return 0;

fail:
dev_dbg(&priv->i2c_client->dev,
“%s: COARSE_TIME_SHORT control error\n”, func);
return err;
}
#if 0
static int tw9992_eeprom_device_release(struct tw9992 *priv)
{
int i;

for (i = 0; i < TW9992_EEPROM_NUM_BLOCKS; i++) {
	if (priv->eeprom[i].i2c_client != NULL) {
		i2c_unregister_device(priv->eeprom[i].i2c_client);
		priv->eeprom[i].i2c_client = NULL;
	}
}

return 0;

}

static int tw9992_eeprom_device_init(struct tw9992 *priv)
{
char *dev_name = “eeprom_tw9992”;
static struct regmap_config eeprom_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
int i;
int err;

if (!priv->pdata->has_eeprom)
	return -EINVAL;

for (i = 0; i < TW9992_EEPROM_NUM_BLOCKS; i++) {
	priv->eeprom[i].adap = i2c_get_adapter(
			priv->i2c_client->adapter->nr);
	memset(&priv->eeprom[i].brd, 0, sizeof(priv->eeprom[i].brd));
	strncpy(priv->eeprom[i].brd.type, dev_name,
			sizeof(priv->eeprom[i].brd.type));
	priv->eeprom[i].brd.addr = TW9992_EEPROM_ADDRESS + i;
	priv->eeprom[i].i2c_client = i2c_new_device(
			priv->eeprom[i].adap, &priv->eeprom[i].brd);

	priv->eeprom[i].regmap = devm_regmap_init_i2c(
		priv->eeprom[i].i2c_client, &eeprom_regmap_config);
	if (IS_ERR(priv->eeprom[i].regmap)) {
		err = PTR_ERR(priv->eeprom[i].regmap);
		tw9992_eeprom_device_release(priv);
		return err;
	}
}

return 0;

}

static int tw9992_read_eeprom(struct tw9992 *priv,
struct v4l2_ctrl *ctrl)
{
int err, i;

for (i = 0; i < TW9992_EEPROM_NUM_BLOCKS; i++) {
	err = regmap_bulk_read(priv->eeprom[i].regmap, 0,
		&priv->eeprom_buf[i * TW9992_EEPROM_BLOCK_SIZE],
		TW9992_EEPROM_BLOCK_SIZE);
	if (err)
		return err;
}

for (i = 0; i < TW9992_EEPROM_SIZE; i++)
	sprintf(&ctrl->string[i*2], "%02x",
		priv->eeprom_buf[i]);
return 0;

}

static int tw9992_write_eeprom(struct tw9992 *priv,
char *string)
{
int err;
int i;
u8 curr[3];
unsigned long data;

for (i = 0; i < TW9992_EEPROM_SIZE; i++) {
	curr[0] = string[i*2];
	curr[1] = string[i*2+1];
	curr[2] = '\0';

	err = kstrtol(curr, 16, &data);
	if (err) {
		dev_err(&priv->i2c_client->dev,
			"invalid eeprom string\n");
		return -EINVAL;
	}

	priv->eeprom_buf[i] = (u8)data;
	err = regmap_write(priv->eeprom[i >> 8].regmap,
			   i & 0xFF, (u8)data);
	if (err)
		return err;
	msleep(20);
}
return 0;

}

static int tw9992_read_otp_bank(struct tw9992 *priv,
u8 *buf, int bank, u16 addr, int size)
{
int err;

/* sleeps calls in the sequence below are for internal device
 * signal propagation as specified by sensor vendor */

usleep_range(10000, 11000);
err = tw9992_write_table(priv, mode_table[TW9992_MODE_START_STREAM]);
if (err)
	return err;

err = tw9992_write_reg(priv->s_data, TW9992_OTP_BANK_SELECT_ADDR,
		       0xC0 | bank);
if (err)
	return err;

err = tw9992_write_reg(priv->s_data, TW9992_OTP_LOAD_CTRL_ADDR, 0x01);
if (err)
	return err;

usleep_range(10000, 11000);
err = regmap_bulk_read(priv->regmap, addr, buf, size);
if (err)
	return err;

err = tw9992_write_table(priv,
		mode_table[TW9992_MODE_STOP_STREAM]);
if (err)
	return err;

return 0;

}

static int tw9992_otp_setup(struct tw9992 *priv)
{
int err;
int i;
struct v4l2_ctrl *ctrl;
u8 otp_buf[TW9992_OTP_SIZE];

err = camera_common_s_power(priv->subdev, true);
if (err)
	return -ENODEV;

for (i = 0; i < TW9992_OTP_NUM_BANKS; i++) {
	err = tw9992_read_otp_bank(priv,
				&otp_buf[i * TW9992_OTP_BANK_SIZE],
				i,
				TW9992_OTP_BANK_START_ADDR,
				TW9992_OTP_BANK_SIZE);
	if (err)
		return -ENODEV;
}

ctrl = v4l2_ctrl_find(&priv->ctrl_handler, V4L2_CID_OTP_DATA);
if (!ctrl) {
	dev_err(&priv->i2c_client->dev,
		"could not find device ctrl.\n");
	return -EINVAL;
}

for (i = 0; i < TW9992_OTP_SIZE; i++)
	sprintf(&ctrl->string[i*2], "%02x",
		otp_buf[i]);
ctrl->cur.string = ctrl->string;

err = camera_common_s_power(priv->subdev, false);
if (err)
	return -ENODEV;

return 0;

}

static int tw9992_fuse_id_setup(struct tw9992 *priv)
{
int err;
int i;
struct v4l2_ctrl *ctrl;
u8 fuse_id[TW9992_FUSE_ID_SIZE];

err = camera_common_s_power(priv->subdev, true);
if (err)
	return -ENODEV;

err = tw9992_read_otp_bank(priv,
			&fuse_id[0],
			TW9992_FUSE_ID_OTP_BANK,
			TW9992_FUSE_ID_OTP_START_ADDR,
			TW9992_FUSE_ID_SIZE);
if (err)
	return -ENODEV;

ctrl = v4l2_ctrl_find(&priv->ctrl_handler, V4L2_CID_FUSE_ID);
if (!ctrl) {
	dev_err(&priv->i2c_client->dev,
		"could not find device ctrl.\n");
	return -EINVAL;
}

for (i = 0; i < TW9992_FUSE_ID_SIZE; i++)
	sprintf(&ctrl->string[i*2], "%02x",
		fuse_id[i]);
ctrl->cur.string = ctrl->string;

err = camera_common_s_power(priv->subdev, false);
if (err)
	return -ENODEV;

return 0;

}
#endif
static int tw9992_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
struct tw9992 *priv =
container_of(ctrl->handler, struct tw9992, ctrl_handler);
int err = 0;

if (priv->power.state == SWITCH_OFF)
	return 0;

/*switch (ctrl->id) {
case V4L2_CID_EEPROM_DATA:
	err = tw9992_read_eeprom(priv, ctrl);
	if (err)
		return err;
	break;
default:
		pr_err("%s: unknown ctrl id.\n", __func__);
		return -EINVAL;
}*/

return err;

}

static int tw9992_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct tw9992 *priv =
container_of(ctrl->handler, struct tw9992, ctrl_handler);
int err = 0;

if (priv->power.state == SWITCH_OFF)
	return 0;

switch (ctrl->id) {
case V4L2_CID_GAIN:
	err = tw9992_set_gain(priv, ctrl->val);
	break;
case V4L2_CID_FRAME_LENGTH:
	err = tw9992_set_frame_length(priv, ctrl->val);
	break;
case V4L2_CID_COARSE_TIME:
	err = tw9992_set_coarse_time(priv, ctrl->val);
	break;
case V4L2_CID_COARSE_TIME_SHORT:
	err = tw9992_set_coarse_time_short(priv, ctrl->val);
	break;
case V4L2_CID_GROUP_HOLD:
	if (switch_ctrl_qmenu[ctrl->val] == SWITCH_ON) {
		priv->group_hold_en = true;
	} else {
		priv->group_hold_en = false;
		err = tw9992_set_group_hold(priv);
	}
	break;
case V4L2_CID_EEPROM_DATA:
	/*if (!ctrl->string[0])
		break;
	err = tw9992_write_eeprom(priv, ctrl->string);
	if (err)
		return err;*/
	break;
case V4L2_CID_HDR_EN:
	break;
default:
	//pr_err("%s: unknown ctrl id.\n", __func__);
	return -EINVAL;
}

return err;

}

static int tw9992_ctrls_init(struct tw9992 *priv, bool eeprom_ctrl)
{
struct i2c_client *client = priv->i2c_client;
struct camera_common_data *common_data = priv->s_data;
struct v4l2_ctrl *ctrl;
int numctrls;
int err;
int i;

dev_dbg(&client->dev, "%s++\n", __func__);

numctrls = ARRAY_SIZE(ctrl_config_list);
v4l2_ctrl_handler_init(&priv->ctrl_handler, numctrls);

for (i = 0; i < numctrls; i++) {
	/* Skip control 'V4L2_CID_EEPROM_DATA' if eeprom inint err */
/*	if (ctrl_config_list[i].id == V4L2_CID_EEPROM_DATA) {
		if (!eeprom_ctrl) {
			common_data->numctrls -= 1;
			continue;
		}
	}*/

	ctrl = v4l2_ctrl_new_custom(&priv->ctrl_handler,
		&ctrl_config_list[i], NULL);
	if (ctrl == NULL) {
		dev_err(&client->dev, "Failed to init %s ctrl\n",
			ctrl_config_list[i].name);
		continue;
	}

	if (ctrl_config_list[i].type == V4L2_CTRL_TYPE_STRING &&
		ctrl_config_list[i].flags & V4L2_CTRL_FLAG_READ_ONLY) {
		ctrl->string = devm_kzalloc(&client->dev,
			ctrl_config_list[i].max + 1, GFP_KERNEL);
		if (!ctrl->string)
			return -ENOMEM;
	}
	priv->ctrls[i] = ctrl;
}

priv->numctrls = numctrls;
priv->subdev->ctrl_handler = &priv->ctrl_handler;
if (priv->ctrl_handler.error) {
	dev_err(&client->dev, "Error %d adding controls\n",
		priv->ctrl_handler.error);
	err = priv->ctrl_handler.error;
	goto error;
}

err = v4l2_ctrl_handler_setup(&priv->ctrl_handler);
if (err) {
	dev_err(&client->dev,
		"Error %d setting default controls\n", err);
	goto error;
}

/*err = tw9992_otp_setup(priv);
if (err) {
	dev_err(&client->dev,
		"Error %d reading otp data\n", err);
	goto error;
}

err = tw9992_fuse_id_setup(priv);
if (err) {
	dev_err(&client->dev,
		"Error %d reading fuse id data\n", err);
	goto error;
}*/

return 0;

error:
v4l2_ctrl_handler_free(&priv->ctrl_handler);
return err;
}

MODULE_DEVICE_TABLE(of, tw9992_of_match);
static struct camera_common_pdata *tw9992_parse_dt(struct i2c_client *client)
{
struct device_node *node = client->dev.of_node;
struct camera_common_pdata *board_priv_pdata;
const struct of_device_id *match;
int gpio;
int err;

if (!node)
	return NULL;

match = of_match_device(tw9992_of_match, &client->dev);
if (!match) {
	dev_err(&client->dev, "Failed to find matching dt id\n");
	return NULL;
}

board_priv_pdata = devm_kzalloc(&client->dev,
		   sizeof(*board_priv_pdata), GFP_KERNEL);
if (!board_priv_pdata)
	return NULL;

err = camera_common_parse_clocks(client, board_priv_pdata);
if (err) {
	dev_err(&client->dev, "Failed to find clocks\n");
	goto error;
}

gpio = of_get_named_gpio(node, "pwdn-gpios", 0);
if (gpio < 0) {
	dev_err(&client->dev, "pwdn gpios not in DT\n");
	goto error;
}
board_priv_pdata->pwdn_gpio = (unsigned int)gpio;

gpio = of_get_named_gpio(node, "reset-gpios", 0);
if (gpio < 0) {
	/* reset-gpio is not absoluctly needed */
	dev_dbg(&client->dev, "reset gpios not in DT\n");
	gpio = 0;
}
board_priv_pdata->reset_gpio = (unsigned int)gpio;

board_priv_pdata->use_cam_gpio =
	of_property_read_bool(node, "cam,use-cam-gpio");

#if 0
err = of_property_read_string(node, “avdd-reg”,
&board_priv_pdata->regulators.avdd);
if (err) {
dev_err(&client->dev, “avdd-reg not in DT\n”);
goto error;
}
err = of_property_read_string(node, “iovdd-reg”,
&board_priv_pdata->regulators.iovdd);
if (err) {
dev_err(&client->dev, “iovdd-reg not in DT\n”);
goto error;
}

board_priv_pdata->has_eeprom =
	of_property_read_bool(node, "has-eeprom");

#endif

return board_priv_pdata;

error:
devm_kfree(&client->dev, board_priv_pdata);
return NULL;
}

static int tw9992_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);

dev_dbg(&client->dev, "%s:\n", __func__);
return 0;

}

static const struct v4l2_subdev_internal_ops tw9992_subdev_internal_ops = {
.open = tw9992_open,
};

static const struct media_entity_operations tw9992_media_ops = {
.link_validate = v4l2_subdev_link_validate,
};

static int tw9992_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct camera_common_data *common_data;
struct device_node *node = client->dev.of_node;
struct tw9992 *priv;
char debugfs_name[10];
int err;

printk("Detected TW9992 sensor\n");

if (!IS_ENABLED(CONFIG_OF) || !node)
	return -EINVAL;

common_data = devm_kzalloc(&client->dev,
		    sizeof(struct camera_common_data), GFP_KERNEL);
if (!common_data)
	return -ENOMEM;

priv = devm_kzalloc(&client->dev,
		    sizeof(struct tw9992) + sizeof(struct v4l2_ctrl *) *
		    ARRAY_SIZE(ctrl_config_list),
		    GFP_KERNEL);
if (!priv)
	return -ENOMEM;

printk(" 11111111111111111\n");
priv->regmap = devm_regmap_init_i2c(client, &tw9992_regmap_config);
if (IS_ERR(priv->regmap)) {
	dev_err(&client->dev,
		"regmap init failed: %ld\n", PTR_ERR(priv->regmap));
	return -ENODEV;
}

printk(" 2222222222222222\n");
priv->pdata = tw9992_parse_dt(client);
if (!priv->pdata) {
	dev_err(&client->dev, "unable to get platform data\n");
	return -EFAULT;
}

common_data->ops		= &tw9992_common_ops;
common_data->ctrl_handler	= &priv->ctrl_handler;
common_data->i2c_client		= client;
common_data->frmfmt		= tw9992_frmfmt;
common_data->colorfmt		= camera_common_find_datafmt(
				  TW9992_DEFAULT_DATAFMT);
common_data->power		= &priv->power;
common_data->ctrls		= priv->ctrls;
common_data->priv		= (void *)priv;
common_data->numctrls		= ARRAY_SIZE(ctrl_config_list);
common_data->numfmts		= ARRAY_SIZE(tw9992_frmfmt);
common_data->def_mode		= TW9992_DEFAULT_MODE;
common_data->def_width		= TW9992_DEFAULT_WIDTH;
common_data->def_height		= TW9992_DEFAULT_HEIGHT;
common_data->fmt_width		= common_data->def_width;
common_data->fmt_height		= common_data->def_height;
common_data->def_clk_freq	= TW9992_DEFAULT_CLK_FREQ;

priv->i2c_client = client;
priv->s_data			= common_data;
priv->subdev			= &common_data->subdev;
priv->subdev->dev		= &client->dev;
priv->s_data->dev		= &client->dev;

err = tw9992_power_get(priv);
if (err)
	return err;

printk(" 333333333333333333\n");
err = camera_common_parse_ports(client, common_data);
if (err) {
	dev_err(&client->dev, "Failed to find port info\n");
	return err;
}
//sprintf(debugfs_name, "tw9992_%c", common_data->csi_port + 'a');
//dev_dbg(&client->dev, "%s: name %s\n", __func__, debugfs_name);
//camera_common_create_debugfs(common_data, debugfs_name);

v4l2_i2c_subdev_init(priv->subdev, client, &tw9992_subdev_ops);

/* eeprom interface */
//err = tw9992_eeprom_device_init(priv);
//if (err)
	//dev_err(&client->dev,
		//"Failed to allocate eeprom reg map: %d\n", err);

err = tw9992_write_table(priv, reg_table);
if (err)
	printk("write reg table err\n");


//tw9992_write_regs(priv->s_data);  

err = tw9992_ctrls_init(priv, !err);
if (err)
	return err;

printk(" 4444444444444444444\n");
priv->subdev->internal_ops = &tw9992_subdev_internal_ops;
priv->subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
		       V4L2_SUBDEV_FL_HAS_EVENTS;

#if defined(CONFIG_MEDIA_CONTROLLER)
priv->pad.flags = MEDIA_PAD_FL_SOURCE;
priv->subdev->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
priv->subdev->entity.ops = &tw9992_media_ops;
err = media_entity_init(&priv->subdev->entity, 1, &priv->pad, 0);
if (err < 0) {
dev_err(&client->dev, “unable to init media entity\n”);
return err;
}
#endif

err = v4l2_async_register_subdev(priv->subdev);
if (err)
	return err;

dev_dbg(&client->dev, "Detected TW9992 sensor\n");

return 0;

}

static int tw9992_remove(struct i2c_client *client)
{
struct camera_common_data *s_data = to_camera_common_data(client);
struct tw9992 *priv = (struct tw9992 *)s_data->priv;

v4l2_async_unregister_subdev(priv->subdev);

#if defined(CONFIG_MEDIA_CONTROLLER)
media_entity_cleanup(&priv->subdev->entity);
#endif

v4l2_ctrl_handler_free(&priv->ctrl_handler);
tw9992_power_put(priv);
camera_common_remove_debugfs(s_data);

return 0;

}

static const struct i2c_device_id tw9992_id = {
{ “tw9992”, 0 },
{ }
};

MODULE_DEVICE_TABLE(i2c, tw9992_id);

static struct i2c_driver tw9992_i2c_driver = {
.driver = {
.name = “tw9992”,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(tw9992_of_match),
},
.probe = tw9992_probe,
.remove = tw9992_remove,
.id_table = tw9992_id,
};

module_i2c_driver(tw9992_i2c_driver);

MODULE_DESCRIPTION(“SoC Camera driver for TW9992”);
MODULE_AUTHOR(“David Wang davidw@nvidia.com”);
MODULE_LICENSE(“GPL v2”);

';

		err = kstrtol(curr, 16, &data);
		if (err) {
			dev_err(&priv->i2c_client->dev,
				"invalid eeprom string\n");
			return -EINVAL;
		}

		priv->eeprom_buf[i] = (u8)data;
		err = regmap_write(priv->eeprom[i >> 8].regmap,
				   i & 0xFF, (u8)data);
		if (err)
			return err;
		msleep(20);
	}
	return 0;
}

static int tw9992_read_otp_bank(struct tw9992 *priv,
				u8 *buf, int bank, u16 addr, int size)
{
	int err;

	/* sleeps calls in the sequence below are for internal device
	 * signal propagation as specified by sensor vendor */

	usleep_range(10000, 11000);
	err = tw9992_write_table(priv, mode_table[TW9992_MODE_START_STREAM]);
	if (err)
		return err;

	err = tw9992_write_reg(priv->s_data, TW9992_OTP_BANK_SELECT_ADDR,
			       0xC0 | bank);
	if (err)
		return err;

	err = tw9992_write_reg(priv->s_data, TW9992_OTP_LOAD_CTRL_ADDR, 0x01);
	if (err)
		return err;

	usleep_range(10000, 11000);
	err = regmap_bulk_read(priv->regmap, addr, buf, size);
	if (err)
		return err;

	err = tw9992_write_table(priv,
			mode_table[TW9992_MODE_STOP_STREAM]);
	if (err)
		return err;

	return 0;
}

static int tw9992_otp_setup(struct tw9992 *priv)
{
	int err;
	int i;
	struct v4l2_ctrl *ctrl;
	u8 otp_buf[TW9992_OTP_SIZE];

	err = camera_common_s_power(priv->subdev, true);
	if (err)
		return -ENODEV;

	for (i = 0; i < TW9992_OTP_NUM_BANKS; i++) {
		err = tw9992_read_otp_bank(priv,
					&otp_buf[i * TW9992_OTP_BANK_SIZE],
					i,
					TW9992_OTP_BANK_START_ADDR,
					TW9992_OTP_BANK_SIZE);
		if (err)
			return -ENODEV;
	}

	ctrl = v4l2_ctrl_find(&priv->ctrl_handler, V4L2_CID_OTP_DATA);
	if (!ctrl) {
		dev_err(&priv->i2c_client->dev,
			"could not find device ctrl.\n");
		return -EINVAL;
	}

	for (i = 0; i < TW9992_OTP_SIZE; i++)
		sprintf(&ctrl->string[i*2], "%02x",
			otp_buf[i]);
	ctrl->cur.string = ctrl->string;

	err = camera_common_s_power(priv->subdev, false);
	if (err)
		return -ENODEV;

	return 0;
}

static int tw9992_fuse_id_setup(struct tw9992 *priv)
{
	int err;
	int i;
	struct v4l2_ctrl *ctrl;
	u8 fuse_id[TW9992_FUSE_ID_SIZE];

	err = camera_common_s_power(priv->subdev, true);
	if (err)
		return -ENODEV;

	err = tw9992_read_otp_bank(priv,
				&fuse_id[0],
				TW9992_FUSE_ID_OTP_BANK,
				TW9992_FUSE_ID_OTP_START_ADDR,
				TW9992_FUSE_ID_SIZE);
	if (err)
		return -ENODEV;

	ctrl = v4l2_ctrl_find(&priv->ctrl_handler, V4L2_CID_FUSE_ID);
	if (!ctrl) {
		dev_err(&priv->i2c_client->dev,
			"could not find device ctrl.\n");
		return -EINVAL;
	}

	for (i = 0; i < TW9992_FUSE_ID_SIZE; i++)
		sprintf(&ctrl->string[i*2], "%02x",
			fuse_id[i]);
	ctrl->cur.string = ctrl->string;

	err = camera_common_s_power(priv->subdev, false);
	if (err)
		return -ENODEV;

	return 0;
}
#endif
static int tw9992_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
	struct tw9992 *priv =
		container_of(ctrl->handler, struct tw9992, ctrl_handler);
	int err = 0;

	if (priv->power.state == SWITCH_OFF)
		return 0;

	/*switch (ctrl->id) {
	case V4L2_CID_EEPROM_DATA:
		err = tw9992_read_eeprom(priv, ctrl);
		if (err)
			return err;
		break;
	default:
			pr_err("%s: unknown ctrl id.\n", __func__);
			return -EINVAL;
	}*/

	return err;
}

static int tw9992_s_ctrl(struct v4l2_ctrl *ctrl)
{
	struct tw9992 *priv =
		container_of(ctrl->handler, struct tw9992, ctrl_handler);
	int err = 0;

	if (priv->power.state == SWITCH_OFF)
		return 0;

	switch (ctrl->id) {
	case V4L2_CID_GAIN:
		err = tw9992_set_gain(priv, ctrl->val);
		break;
	case V4L2_CID_FRAME_LENGTH:
		err = tw9992_set_frame_length(priv, ctrl->val);
		break;
	case V4L2_CID_COARSE_TIME:
		err = tw9992_set_coarse_time(priv, ctrl->val);
		break;
	case V4L2_CID_COARSE_TIME_SHORT:
		err = tw9992_set_coarse_time_short(priv, ctrl->val);
		break;
	case V4L2_CID_GROUP_HOLD:
		if (switch_ctrl_qmenu[ctrl->val] == SWITCH_ON) {
			priv->group_hold_en = true;
		} else {
			priv->group_hold_en = false;
			err = tw9992_set_group_hold(priv);
		}
		break;
	case V4L2_CID_EEPROM_DATA:
		/*if (!ctrl->string[0])
			break;
		err = tw9992_write_eeprom(priv, ctrl->string);
		if (err)
			return err;*/
		break;
	case V4L2_CID_HDR_EN:
		break;
	default:
		//pr_err("%s: unknown ctrl id.\n", __func__);
		return -EINVAL;
	}

	return err;
}

static int tw9992_ctrls_init(struct tw9992 *priv, bool eeprom_ctrl)
{
	struct i2c_client *client = priv->i2c_client;
	struct camera_common_data *common_data = priv->s_data;
	struct v4l2_ctrl *ctrl;
	int numctrls;
	int err;
	int i;

	dev_dbg(&client->dev, "%s++\n", __func__);

	numctrls = ARRAY_SIZE(ctrl_config_list);
	v4l2_ctrl_handler_init(&priv->ctrl_handler, numctrls);

	for (i = 0; i < numctrls; i++) {
		/* Skip control 'V4L2_CID_EEPROM_DATA' if eeprom inint err */
	/*	if (ctrl_config_list[i].id == V4L2_CID_EEPROM_DATA) {
			if (!eeprom_ctrl) {
				common_data->numctrls -= 1;
				continue;
			}
		}*/

		ctrl = v4l2_ctrl_new_custom(&priv->ctrl_handler,
			&ctrl_config_list[i], NULL);
		if (ctrl == NULL) {
			dev_err(&client->dev, "Failed to init %s ctrl\n",
				ctrl_config_list[i].name);
			continue;
		}

		if (ctrl_config_list[i].type == V4L2_CTRL_TYPE_STRING &&
			ctrl_config_list[i].flags & V4L2_CTRL_FLAG_READ_ONLY) {
			ctrl->string = devm_kzalloc(&client->dev,
				ctrl_config_list[i].max + 1, GFP_KERNEL);
			if (!ctrl->string)
				return -ENOMEM;
		}
		priv->ctrls[i] = ctrl;
	}

	priv->numctrls = numctrls;
	priv->subdev->ctrl_handler = &priv->ctrl_handler;
	if (priv->ctrl_handler.error) {
		dev_err(&client->dev, "Error %d adding controls\n",
			priv->ctrl_handler.error);
		err = priv->ctrl_handler.error;
		goto error;
	}

	err = v4l2_ctrl_handler_setup(&priv->ctrl_handler);
	if (err) {
		dev_err(&client->dev,
			"Error %d setting default controls\n", err);
		goto error;
	}

	/*err = tw9992_otp_setup(priv);
	if (err) {
		dev_err(&client->dev,
			"Error %d reading otp data\n", err);
		goto error;
	}

	err = tw9992_fuse_id_setup(priv);
	if (err) {
		dev_err(&client->dev,
			"Error %d reading fuse id data\n", err);
		goto error;
	}*/

	return 0;

error:
	v4l2_ctrl_handler_free(&priv->ctrl_handler);
	return err;
}

MODULE_DEVICE_TABLE(of, tw9992_of_match);
static struct camera_common_pdata *tw9992_parse_dt(struct i2c_client *client)
{
	struct device_node *node = client->dev.of_node;
	struct camera_common_pdata *board_priv_pdata;
	const struct of_device_id *match;
	int gpio;
	int err;

	if (!node)
		return NULL;

	match = of_match_device(tw9992_of_match, &client->dev);
	if (!match) {
		dev_err(&client->dev, "Failed to find matching dt id\n");
		return NULL;
	}

	board_priv_pdata = devm_kzalloc(&client->dev,
			   sizeof(*board_priv_pdata), GFP_KERNEL);
	if (!board_priv_pdata)
		return NULL;

	err = camera_common_parse_clocks(client, board_priv_pdata);
	if (err) {
		dev_err(&client->dev, "Failed to find clocks\n");
		goto error;
	}

	gpio = of_get_named_gpio(node, "pwdn-gpios", 0);
	if (gpio < 0) {
		dev_err(&client->dev, "pwdn gpios not in DT\n");
		goto error;
	}
	board_priv_pdata->pwdn_gpio = (unsigned int)gpio;

	gpio = of_get_named_gpio(node, "reset-gpios", 0);
	if (gpio < 0) {
		/* reset-gpio is not absoluctly needed */
		dev_dbg(&client->dev, "reset gpios not in DT\n");
		gpio = 0;
	}
	board_priv_pdata->reset_gpio = (unsigned int)gpio;

	board_priv_pdata->use_cam_gpio =
		of_property_read_bool(node, "cam,use-cam-gpio");

#if 0
	err = of_property_read_string(node, "avdd-reg",
			&board_priv_pdata->regulators.avdd);
	if (err) {
		dev_err(&client->dev, "avdd-reg not in DT\n");
		goto error;
	}
	err = of_property_read_string(node, "iovdd-reg",
			&board_priv_pdata->regulators.iovdd);
	if (err) {
		dev_err(&client->dev, "iovdd-reg not in DT\n");
		goto error;
	}

	board_priv_pdata->has_eeprom =
		of_property_read_bool(node, "has-eeprom");
#endif

	return board_priv_pdata;

error:
	devm_kfree(&client->dev, board_priv_pdata);
	return NULL;
}

static int tw9992_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);

	dev_dbg(&client->dev, "%s:\n", __func__);
	return 0;
}

static const struct v4l2_subdev_internal_ops tw9992_subdev_internal_ops = {
	.open = tw9992_open,
};

static const struct media_entity_operations tw9992_media_ops = {
	.link_validate = v4l2_subdev_link_validate,
};

static int tw9992_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
{
	struct camera_common_data *common_data;
	struct device_node *node = client->dev.of_node;
	struct tw9992 *priv;
	char debugfs_name[10];
	int err;

	printk("Detected TW9992 sensor\n");
	
	if (!IS_ENABLED(CONFIG_OF) || !node)
		return -EINVAL;

	common_data = devm_kzalloc(&client->dev,
			    sizeof(struct camera_common_data), GFP_KERNEL);
	if (!common_data)
		return -ENOMEM;

	priv = devm_kzalloc(&client->dev,
			    sizeof(struct tw9992) + sizeof(struct v4l2_ctrl *) *
			    ARRAY_SIZE(ctrl_config_list),
			    GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

	printk(" 11111111111111111\n");
	priv->regmap = devm_regmap_init_i2c(client, &tw9992_regmap_config);
	if (IS_ERR(priv->regmap)) {
		dev_err(&client->dev,
			"regmap init failed: %ld\n", PTR_ERR(priv->regmap));
		return -ENODEV;
	}
	
	printk(" 2222222222222222\n");
	priv->pdata = tw9992_parse_dt(client);
	if (!priv->pdata) {
		dev_err(&client->dev, "unable to get platform data\n");
		return -EFAULT;
	}
	
	common_data->ops		= &tw9992_common_ops;
	common_data->ctrl_handler	= &priv->ctrl_handler;
	common_data->i2c_client		= client;
	common_data->frmfmt		= tw9992_frmfmt;
	common_data->colorfmt		= camera_common_find_datafmt(
					  TW9992_DEFAULT_DATAFMT);
	common_data->power		= &priv->power;
	common_data->ctrls		= priv->ctrls;
	common_data->priv		= (void *)priv;
	common_data->numctrls		= ARRAY_SIZE(ctrl_config_list);
	common_data->numfmts		= ARRAY_SIZE(tw9992_frmfmt);
	common_data->def_mode		= TW9992_DEFAULT_MODE;
	common_data->def_width		= TW9992_DEFAULT_WIDTH;
	common_data->def_height		= TW9992_DEFAULT_HEIGHT;
	common_data->fmt_width		= common_data->def_width;
	common_data->fmt_height		= common_data->def_height;
	common_data->def_clk_freq	= TW9992_DEFAULT_CLK_FREQ;
	
	priv->i2c_client = client;
	priv->s_data			= common_data;
	priv->subdev			= &common_data->subdev;
	priv->subdev->dev		= &client->dev;
	priv->s_data->dev		= &client->dev;
	
	err = tw9992_power_get(priv);
	if (err)
		return err;

	printk(" 333333333333333333\n");
	err = camera_common_parse_ports(client, common_data);
	if (err) {
		dev_err(&client->dev, "Failed to find port info\n");
		return err;
	}
	//sprintf(debugfs_name, "tw9992_%c", common_data->csi_port + 'a');
	//dev_dbg(&client->dev, "%s: name %s\n", __func__, debugfs_name);
	//camera_common_create_debugfs(common_data, debugfs_name);
	
	v4l2_i2c_subdev_init(priv->subdev, client, &tw9992_subdev_ops);
	
	/* eeprom interface */
	//err = tw9992_eeprom_device_init(priv);
	//if (err)
		//dev_err(&client->dev,
			//"Failed to allocate eeprom reg map: %d\n", err);

	err = tw9992_write_table(priv, reg_table);
	if (err)
		printk("write reg table err\n");


	//tw9992_write_regs(priv->s_data);  

	err = tw9992_ctrls_init(priv, !err);
	if (err)
		return err;

	printk(" 4444444444444444444\n");
	priv->subdev->internal_ops = &tw9992_subdev_internal_ops;
	priv->subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
			       V4L2_SUBDEV_FL_HAS_EVENTS;
				   
#if defined(CONFIG_MEDIA_CONTROLLER)
	priv->pad.flags = MEDIA_PAD_FL_SOURCE;
	priv->subdev->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
	priv->subdev->entity.ops = &tw9992_media_ops;
	err = media_entity_init(&priv->subdev->entity, 1, &priv->pad, 0);
	if (err < 0) {
		dev_err(&client->dev, "unable to init media entity\n");
		return err;
	}
#endif

	err = v4l2_async_register_subdev(priv->subdev);
	if (err)
		return err;

	dev_dbg(&client->dev, "Detected TW9992 sensor\n");

	return 0;
}

static int tw9992_remove(struct i2c_client *client)
{
	struct camera_common_data *s_data = to_camera_common_data(client);
	struct tw9992 *priv = (struct tw9992 *)s_data->priv;

	v4l2_async_unregister_subdev(priv->subdev);
#if defined(CONFIG_MEDIA_CONTROLLER)
	media_entity_cleanup(&priv->subdev->entity);
#endif

	v4l2_ctrl_handler_free(&priv->ctrl_handler);
	tw9992_power_put(priv);
	camera_common_remove_debugfs(s_data);
	
	return 0;
}

static const struct i2c_device_id tw9992_id[] = {
	{ "tw9992", 0 },
	{ }
};

MODULE_DEVICE_TABLE(i2c, tw9992_id);

static struct i2c_driver tw9992_i2c_driver = {
	.driver = {
		.name = "tw9992",
		.owner = THIS_MODULE,
		.of_match_table = of_match_ptr(tw9992_of_match),
	},
	.probe = tw9992_probe,
	.remove = tw9992_remove,
	.id_table = tw9992_id,
};

module_i2c_driver(tw9992_i2c_driver);

MODULE_DESCRIPTION("SoC Camera driver for TW9992");
MODULE_AUTHOR("David Wang <davidw@nvidia.com>");
MODULE_LICENSE("GPL v2");

my device tree:

/*
 * Copyright (c) 2015-2016, NVIDIA CORPORATION.  All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <dt-bindings/media/camera.h>
#include <dt-bindings/platform/t210/t210.h>

#define GANG_MODE_L_R 1
#define GANG_MODE_T_B 2
#define GANG_MODE_R_L 3
#define GANG_MODE_B_T 4

#define CAM0_RST_L	TEGRA_GPIO(E, 5)

#define CAM_MUX0    TEGRA_GPIO(T, 1)
#define CAM_MUX1    TEGRA_GPIO(S, 6)
#define CAM0_PWDN	TEGRA_GPIO(S, 7)

//GPIOs
/ {
	/* set camera gpio direction to output */
	gpio: gpio@6000d000 {
		camera-control {
			gpio-output-low = <
						CAM0_RST_L
						CAM_MUX0
						CAM_MUX1
						CAM0_PWDN
							>;
		};
	};
};


/ {
	host1x {
		vi {
			num-channels = <1>;
			ports {
				#address-cells = <1>;
				#size-cells = <0>;
				port@0 {
					status = "okay";
					reg = <0>;
					tw9992_vi_in0: endpoint {
						status = "okay";
						csi-port = <0>;
						bus-width = <1>;
						remote-endpoint = <&tw9992_out0>;
					};
				};
			};
		};
	};

	i2c@7000c400 {
		status = "okay";
		#address-cells = <1>;
		#size-cells = <0>;
		tw9992_a@44 {
			compatible = "nvidia,tw9992";
			/* I2C device address */
			reg = <0x44>;
			reset-gpios = <&gpio CAM0_RST_L GPIO_ACTIVE_LOW>;
			pwdn-gpios = <&gpio CAM0_PWDN GPIO_ACTIVE_HIGH>;

		/* Physical dimensions of sensor */
			physical_w = "3.674";
			physical_h = "2.738";


			/* Sensor Model */
			sensor_model ="tw9992";

			/* Define any required hw resources needed by driver */
			/* ie. clocks, io pins, power sources */
			//avdd-reg = "vana";
			//iovdd-reg = "vif";
			//dvdd-reg = "vdig";
			clocks = <&tegra_car TEGRA210_CLK_ID_CLK_OUT_3>;
			clock-names = "mclk";
			clock-frequency = <24000000>;
			mclk = "cam_mclk1";

			/* Defines number of frames to be dropped by driver internally after applying */
			/* sensor crop settings. Some sensors send corrupt frames after applying */
			/* crop co-ordinates */
			post_crop_frame_drop = "0";

			/**
			* A modeX node is required to support v4l2 driver
				* implementation with NVIDIA camera software stack
			*
			* mclk_khz = "";
			* Standard MIPI driving clock, typically 24MHz
			*
			* num_lanes = "";
			* Number of lane channels sensor is programmed to output
			*
			* tegra_sinterface = "";
			* The base tegra serial interface lanes are connected to
			*
			* discontinuous_clk = "";
			* The sensor is programmed to use a discontinuous clock on MIPI lanes
			*
			* dpcm_enable = "true";
			* The sensor is programmed to use a DPCM modes
			*
			* cil_settletime = "";
			* MIPI lane settle time value.
			* A "0" value attempts to autocalibrate based on mclk_multiplier
			*
			*
			*
			*
			* active_w = "";
			* Pixel active region width
			*
			* active_h = "";
			* Pixel active region height
			*
			* pixel_t = "";
			* The sensor readout pixel pattern
			*
			* readout_orientation = "0";
			* Based on camera module orientation.
			* Only change readout_orientation if you specifically
			* Program a different readout order for this mode
			*
			* line_length = "";
			* Pixel line length (width) for sensor mode.
			* This is used to calibrate features in our camera stack.
			*
			* mclk_multiplier = "";
			* Multiplier to MCLK to help time hardware capture sequence
			* TODO: Assign to PLL_Multiplier as well until fixed in core
			*
			* pix_clk_hz = "";
			* Sensor pixel clock used for calculations like exposure and framerate
			*
			*
			*
			*
			* inherent_gain = "";
			* Gain obtained inherently from mode (ie. pixel binning)
			*
			* min_gain_val = ""; (floor to 6 decimal places)
			* max_gain_val = ""; (floor to 6 decimal places)
			* Gain limits for mode
			*
			* min_exp_time = ""; (ceil to integer)
			* max_exp_time = ""; (ceil to integer)
			* Exposure Time limits for mode (us)
			*
			*
			* min_hdr_ratio = "";
			* max_hdr_ratio = "";
			* HDR Ratio limits for mode
			*
			* min_framerate = "";
			* max_framerate = "";
			* Framerate limits for mode (fps)
			*
			* embedded_metadata_height = "";
			* Sensor embedded metadata height in units of rows.
			* If sensor does not support embedded metadata value should be 0.
			*/
				mode0 { // TW9992_MODE_720X480
				mclk_khz = "24000";
				num_lanes = "1";
				//mclk_multiplier = "49.0";
         //My Stuff
				//pix_clk_hz = "1176000000";
				//pix_clk_hz   =  "588000000";
				//line_length = "2416";

         //Their Stuff
				mclk_multiplier = "3.0";
				pix_clk_hz = "27000000";
				line_length = "760";
         //Done


				tegra_sinterface = "serial_a";
				discontinuous_clk = "yes";
				cil_settletime = "0";
				pixel_t = "bayer_bggr";
				readout_orientation = "0";
				inherent_gain = "1";
				active_w = "720";
				active_h = "480";
				min_gain_val = "1.0";
				max_gain_val = "16.0";
				min_hdr_ratio = "1";
				max_hdr_ratio = "1";
				min_framerate = "1";
				max_framerate = "30";
				min_exp_time = "25";
				max_exp_time = "683709";
			};
			/*mode1 { // TW9992_MODE_1280X720
				mclk_khz = "24000";
				num_lanes = "1";
				mclk_multiplier = "52.5";
				pix_clk_hz = "1260000000";
				tegra_sinterface = "serial_a";
				discontinuous_clk = "yes";
				cil_settletime = "0";
				pixel_t = "bayer_bggr";
				readout_orientation = "0";
				inherent_gain = "1";

				active_w = "720";
				active_h = "480";
				//line_length = "2623";
				line_length = "1896";
				min_gain_val = "1.0";
				max_gain_val = "16.0";
				min_hdr_ratio = "1";
				max_hdr_ratio = "1";
				min_framerate = "1";
				max_framerate = "60";
				min_exp_time = "22";
				max_exp_time = "683709";
				};*/

			ports {
				#address-cells = <1>;
				#size-cells = <0>;
					port@0 {
					reg = <0>;
					tw9992_out0: endpoint {
						csi-port = <0>;
						bus-width = <1>;
						remote-endpoint = <&tw9992_vi_in0>;
					};
				};
			};
		};
	};
	
	tegra-camera-platform {
		compatible = "nvidia, tegra-camera-platform";

		/**
		* The general guideline for naming badge_info contains 3 parts, and is as follows,
		* The first part is the camera_board_id for the module; if the module is in a FFD
		* platform, then use the platform name for this part.
		* The second part contains the position of the module, ex. “rear” or “front”.
		* The third part contains the last 6 characters of a part number which is found
		* in the module's specsheet from the vender.
		*/
		modules {
			cam_module0: module0 {
				badge = "uav_back_tw9992";
				position = "rear";
				orientation = "1";
				cam_module0_drivernode0: drivernode0 {
					/* Declare PCL support driver (classically known as guid)  */
					pcl_id = "v4l2_sensor";
					/* Driver's v4l2 device name */
					devname = "tw9992 1-0044";
					/* Declare the device-tree hierarchy to driver instance */
					proc-device-tree = "/proc/device-tree/i2c@7000c400/tw9992_a@44";
          status = "okay";
				};
				cam_module0_dirvernode1: drivernode1 {
					status = "disabled";
					pcl_id = "v4l2_focuser_stub";
					proc-device-tree = "";

        };
			};
		};
	};
};

the hardware we designed don’t need to consider the power control. when power on the devlop board, the tw9992 reset automatically.

As the front input is CVBS signal;
In the probe function “common_data->colorfmt = camera_common_find_datafmt(V4L2_MBUS_FMT_SRGGB10_1X10)”, is it correct?

can you help me check the code? thanks a lot!!

The colorfmt is the sensor output format. You need to know what type of format is out from the tw9992. And your can use the below command to capture the raw image.

v4l2-ctl -d /dev/video0 --set-fmt-video=width=720,height=480,pixelformat=RG10 --set-ctrl bypass_mode=0 --stream-mmap --stream-count=1 --stream-to=ov1080.raw

In the probe function “common_data->colorfmt = camera_common_find_datafmt(V4L2_MBUS_FMT_SRGGB10_1X10)”, is it correct?