CSI OV2710 camera module driver

Hi. I develop custom board on Tegra K1. Nov has an issue with right connection OV2710 camera module to Tegra. I use this module https://www.alibaba.com/product-detail/720p-ov2710-camera-module-omnivision-micro_60453798154.html
This module has 1-lane and controlling by i2c-bus
http://s020.radikal.ru/i712/1608/9f/9eb252829486.png
Acording to this foto I need connect module to “camera 2” port?
I have Jetson TK1 and we use L4T software package. Installed latest JatPack 2.2.1 and kernel from grinch “linux-grinch-21.3.4”
Question is, where to find the driver for this module and what I need to change is this driver to make it work with Tegra?

You can refer to the following driver,
$KERNEL/drivers/media/platform/tegra/ov2710.c
It needs probably some modifications to adapt your hw connection.

Can tell anyone, do I need for proper work a base driver from “/drivers/media/platform/tegra/ov2710.c”?
I can enable this driver on kernel .config file, this driver compiles like kernel object (.ko), but he doesn’t know anything about Tegra hardware.
Can someone see my code and tell me what I mast to write?
I totally new in driver developing, on last two weeks I read to many information about drivers… Now I have a big mess of information in my head :)

The sensor power sequence may be different among camera modules. Please let me know when you have specific issue.

Hi. I already have this issue))
I connect camera module thru connector that has his own power regulators, also I made clock generator on 24MHz.
By using i2c-tools (sudo i2cdetect -y 2) I can see my camera on i2c-bus. The address is 0x36. So I think camera powered correctly.

ov2710_v4l2.c

#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/i2c.h>
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/videodev2.h>

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

#include <mach/io_dpd.h>

#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-chip-ident.h>
#include <media/soc_camera.h>
#include <media/ov2710.h>


#define SIZEOF_I2C_TRANSBUF 32

#define CAM_RSTN 219 /* TEGRA_GPIO_PBB3 */
#define CAM2_PWDN 222 /* TEGRA_GPIO_PBB6 */

static struct tegra_io_dpd csie_io = {
	.name			= "CSIE",
	.io_dpd_reg_index	= 1,
	.io_dpd_bit		= 12,
};

struct ov2710_reg {
	u16 addr;
	u8 val;
};

struct ov2710_datafmt {
	enum v4l2_mbus_pixelcode	code;
	enum v4l2_colorspace		colorspace;
};

struct ov2710_info {
	struct v4l2_subdev		subdev;
	const struct ov2710_datafmt	*fmt;

	int				mode;
	struct ov2710_power_rail	power;
	struct ov2710_sensordata	sensor_data;
	struct i2c_client		*i2c_client;
	struct ov2710_platform_data	*pdata;
	struct clk			*mclk;
	struct mutex			ov2710_camera_lock;
	struct dentry			*debugdir;

	int ident;
	u16 chip_id;
	u8 i2c_trans_buf;
};

static const struct ov2710_datafmt ov2710_colour_fmts[] = {
	{V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_COLORSPACE_SRGB},
	{V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_COLORSPACE_SRGB},
};

static inline struct ov2710_info *to_ov2710(const struct i2c_client *client)
{
	return container_of(i2c_get_clientdata(client), struct ov2710_info, subdev);
}

#define OV2710_TABLE_WAIT_MS 0
#define OV2710_TABLE_END 1
#define OV2710_MAX_RETRIES 3
#define OV2710_WAIT_MS 3

#define MAX_BUFFER_SIZE 32
#define OV2710_FRAME_LENGTH_ADDR_MSB 0x0340
#define OV2710_FRAME_LENGTH_ADDR_LSB 0x0341
#define OV2710_COARSE_TIME_ADDR_MSB 0x0202
#define OV2710_COARSE_TIME_ADDR_LSB 0x0203
#define OV2710_COARSE_TIME_SHORT_ADDR_MSB 0x0230
#define OV2710_COARSE_TIME_SHORT_ADDR_LSB 0x0231
#define OV2710_GAIN_ADDR 0x0205
#define OV2710_GAIN_SHORT_ADDR 0x0233

static struct ov2710_reg mode_1920x1080[] = {
	{0x3103, 0x93},
	{0x3008, 0x82},
	{OV2710_TABLE_WAIT_MS, 5},
	{0x3008, 0x42},
	{OV2710_TABLE_WAIT_MS, 5},
	{0x3017, 0x7f},
	{0x3018, 0xfc},
	{0x3706, 0x61},
	{0x3712, 0x0c},
	{0x3630, 0x6d},
	{0x3801, 0xb4},

	{0x3621, 0x04},
	{0x3604, 0x60},
	{0x3603, 0xa7},
	{0x3631, 0x26},
	{0x3600, 0x04},
	{0x3620, 0x37},
	{0x3623, 0x00},
	{0x3702, 0x9e},
	{0x3703, 0x5c},
	{0x3704, 0x40},
	{0x370d, 0x0f},
	{0x3713, 0x9f},
	{0x3714, 0x4c},
	{0x3710, 0x9e},
	{0x3801, 0xc4},
	{0x3605, 0x05},
	{0x3606, 0x3f},
	{0x302d, 0x90},
	{0x370b, 0x40},
	{0x3716, 0x31},
	{0x3707, 0x52},
	{0x380d, 0x74},
	{0x5181, 0x20},
	{0x518f, 0x00},
	{0x4301, 0xff},
	{0x4303, 0x00},
	{0x3a00, 0x78},
	{0x300f, 0x88},
	{0x3011, 0x28},
	{0x3a1a, 0x06},
	{0x3a18, 0x00},
	{0x3a19, 0x7a},
	{0x3a13, 0x54},
	{0x382e, 0x0f},
	{0x381a, 0x1a},
	{0x401d, 0x02},

	{0x381c, 0x00},
	{0x381d, 0x02},
	{0x381e, 0x04},
	{0x381f, 0x38},
	{0x3820, 0x00},
	{0x3821, 0x98},
	{0x3800, 0x01},
	{0x3802, 0x00},
	{0x3803, 0x0a},
	{0x3804, 0x07},
	{0x3805, 0x90},
	{0x3806, 0x04},
	{0x3807, 0x40},
	{0x3808, 0x07},
	{0x3809, 0x90},
	{0x380a, 0x04},
	{0x380b, 0x40},
	{0x380e, 0x04},
	{0x380f, 0x50},
	{0x380c, 0x09},
	{0x380d, 0x74},
	{0x3810, 0x08},
	{0x3811, 0x02},

	{0x5688, 0x03},
	{0x5684, 0x07},
	{0x5685, 0xa0},
	{0x5686, 0x04},
	{0x5687, 0x43},
	{0x3011, 0x0a},
	{0x300f, 0x8a},
	{0x3017, 0x00},
	{0x3018, 0x00},
	{0x4800, 0x24},
	{0x300e, 0x04},
	{0x4801, 0x0f},

	{0x300f, 0xc3},
	{0x3010, 0x00},
	{0x3011, 0x0a},
	{0x3012, 0x01},

	{0x3a0f, 0x40},
	{0x3a10, 0x38},
	{0x3a1b, 0x48},
	{0x3a1e, 0x30},
	{0x3a11, 0x90},
	{0x3a1f, 0x10},

	{0x3a0e, 0x03},
	{0x3a0d, 0x04},
	{0x3a08, 0x14},
	{0x3a09, 0xc0},
	{0x3a0a, 0x11},
	{0x3a0b, 0x40},

	{0x300f, 0xc3},
	{0x3010, 0x00},
	{0x3011, 0x0e},
	{0x3012, 0x02},
	{0x380c, 0x09},
	{0x380d, 0xec},
	{0x3703, 0x61},
	{0x3704, 0x44},
	{0x3801, 0xd2},

	{0x3503, 0x33},
	{0x3500, 0x00},
	{0x3501, 0x00},
	{0x3502, 0x00},
	{0x350a, 0x00},
	{0x350b, 0x00},
	{0x5001, 0x4e},
	{0x5000, 0x5f},
	{0x3008, 0x02},

	{OV2710_TABLE_END, 0x0000}
};


static struct ov2710_reg mode_1280x720[] = {
	{0x3103, 0x93},
	{0x3008, 0x82},
	{OV2710_TABLE_WAIT_MS, 5},
	{0x3008, 0x42},
	{OV2710_TABLE_WAIT_MS, 5},
	{0x3017, 0x7f},
	{0x3018, 0xfc},

	{0x3706, 0x61},
	{0x3712, 0x0c},
	{0x3630, 0x6d},
	{0x3801, 0xb4},
	{0x3621, 0x04},
	{0x3604, 0x60},
	{0x3603, 0xa7},
	{0x3631, 0x26},
	{0x3600, 0x04},
	{0x3620, 0x37},
	{0x3623, 0x00},
	{0x3702, 0x9e},
	{0x3703, 0x5c},
	{0x3704, 0x40},
	{0x370d, 0x0f},
	{0x3713, 0x9f},
	{0x3714, 0x4c},
	{0x3710, 0x9e},
	{0x3801, 0xc4},
	{0x3605, 0x05},
	{0x3606, 0x3f},
	{0x302d, 0x90},
	{0x370b, 0x40},
	{0x3716, 0x31},
	{0x3707, 0x52},
	{0x380d, 0x74},
	{0x5181, 0x20},
	{0x518f, 0x00},
	{0x4301, 0xff},
	{0x4303, 0x00},
	{0x3a00, 0x78},
	{0x300f, 0x88},
	{0x3011, 0x28},
	{0x3a1a, 0x06},
	{0x3a18, 0x00},
	{0x3a19, 0x7a},
	{0x3a13, 0x54},
	{0x382e, 0x0f},
	{0x381a, 0x1a},
	{0x401d, 0x02},

	{0x381c, 0x10},
	{0x381d, 0xb0},
	{0x381e, 0x02},
	{0x381f, 0xec},
	{0x3800, 0x01},
	{0x3820, 0x0a},
	{0x3821, 0x2a},
	{0x3804, 0x05},
	{0x3805, 0x10},
	{0x3802, 0x00},
	{0x3803, 0x04},
	{0x3806, 0x02},
	{0x3807, 0xe0},
	{0x3808, 0x05},
	{0x3809, 0x10},
	{0x380a, 0x02},
	{0x380b, 0xe0},
	{0x380e, 0x02},
	{0x380f, 0xf0},
	{0x380c, 0x07},
	{0x380d, 0x00},
	{0x3810, 0x10},
	{0x3811, 0x06},

	{0x5688, 0x03},
	{0x5684, 0x05},
	{0x5685, 0x00},
	{0x5686, 0x02},
	{0x5687, 0xd0},

	{0x3a08, 0x1b},
	{0x3a09, 0xe6},
	{0x3a0a, 0x17},
	{0x3a0b, 0x40},
	{0x3a0e, 0x01},
	{0x3a0d, 0x02},
	{0x3011, 0x0a},
	{0x300f, 0x8a},
	{0x3017, 0x00},
	{0x3018, 0x00},
	{0x4800, 0x24},
	{0x300e, 0x04},
	{0x4801, 0x0f},
	{0x300f, 0xc3},
	{0x3a0f, 0x40},
	{0x3a10, 0x38},
	{0x3a1b, 0x48},
	{0x3a1e, 0x30},
	{0x3a11, 0x90},
	{0x3a1f, 0x10},

	{0x3010, 0x10},
	{0x3a0e, 0x02},
	{0x3a0d, 0x03},
	{0x3a08, 0x0d},
	{0x3a09, 0xf3},
	{0x3a0a, 0x0b},
	{0x3a0b, 0xa0},

	{0x300f, 0xc3},
	{0x3011, 0x0e},
	{0x3012, 0x02},
	{0x380c, 0x07},
	{0x380d, 0x6a},
	{0x3703, 0x5c},
	{0x3704, 0x40},
	{0x3801, 0xbc},

	{0x3503, 0x33},
	{0x3500, 0x00},
	{0x3501, 0x00},
	{0x3502, 0x00},
	{0x350a, 0x00},
	{0x350b, 0x00},
	{0x5001, 0x4e},
	{0x5000, 0x5f},
	{0x3008, 0x02},

	{OV2710_TABLE_END, 0x0000}
};

static struct ov2710_reg tp_colorbars[] = {
	{0x0503D, 0xa0},

	{OV2710_TABLE_END, 0x0000}
};

enum {
	OV2710_MODE_1920X1080,
	OV2710_MODE_1280X720,
};

static struct ov2710_reg *mode_table[] = {
	[OV2710_MODE_1920X1080] = mode_1920x1080,
	[OV2710_MODE_1280X720]  = mode_1280x720,
};

static int test_mode;
module_param(test_mode, int, 0644);

static const struct v4l2_frmsize_discrete ov2710_frmsizes[] = {
	{1920, 1080},
	{1280, 720},
};

/* Find a data format by a pixel code in an array */
static const struct ov2710_datafmt *ov2710_find_datafmt(
		enum v4l2_mbus_pixelcode code)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(ov2710_colour_fmts); i++)
		if (ov2710_colour_fmts[i].code == code)
			return ov2710_colour_fmts + i;

	return NULL;
}

#define OV2710_MODE	OV2710_MODE_1920X1080
#define OV2710_WIDTH	1920
#define OV2710_HEIGHT	1080

static int ov2710_find_mode(struct v4l2_subdev *sd,
			    u32 width, u32 height)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(ov2710_frmsizes); i++) {
		if (width == ov2710_frmsizes[i].width &&
		    height == ov2710_frmsizes[i].height)
			return i;
	}

	dev_err(sd->v4l2_dev->dev, "%dx%d is not supported\n", width, height);
	return OV2710_MODE_1920X1080;
}

static inline void msleep_range(unsigned int delay_base)
{
	usleep_range(delay_base*1000, delay_base*1000+500);
}

static int ov2710_read_reg(struct i2c_client *client, u16 addr, u8 *val)
{
	int err;
	struct i2c_msg msg[2];
	unsigned char data[3];

	if (!client->adapter)
		return -ENODEV;

	msg[0].addr = client->addr;
	msg[0].flags = 0;
	msg[0].len = 2;
	msg[0].buf = data;

	/* high byte goes out first */
	data[0] = (u8) (addr >> 8);
	data[1] = (u8) (addr & 0xff);

	msg[1].addr = client->addr;
	msg[1].flags = I2C_M_RD;
	msg[1].len = 1;
	msg[1].buf = data + 2;

	err = i2c_transfer(client->adapter, msg, 2);

	if (err != 2)
		return -EINVAL;

	*val = data[2];
	return 0;
}

static int ov2710_write_reg(struct i2c_client *client, u16 addr, u8 val)
{
	int err;
	struct i2c_msg msg;
	unsigned char data[3];
	int retry = 0;

	if (!client->adapter)
		return -ENODEV;

	data[0] = (u8) (addr >> 8);;
	data[1] = (u8) (addr & 0xff);
	data[2] = (u8) (val & 0xff);

	msg.addr = client->addr;
	msg.flags = 0;
	msg.len = 3;
	msg.buf = data;

	do {
		err = i2c_transfer(client->adapter, &msg, 1);
		if (err == 1)
			return 0;
		retry++;
		pr_err("ov2710: i2c transfer failed, retrying %x %x\n",
		       addr, val);

		msleep(3);
	} while (retry <= OV2710_MAX_RETRIES);

	return err;
}

static int ov2710_write_table(struct i2c_client *client,
			      const struct ov2710_reg table[])
{
	int err;
	const struct ov2710_reg *next;
	u16 val;

	for (next = table; next->addr != OV2710_TABLE_END; next++) {
		if (next->addr == OV2710_TABLE_WAIT_MS) {
			msleep_range(next->val);
			continue;
		}

		val = next->val;

		err = ov2710_write_reg(client, next->addr, val);
		if (err) {
			pr_err("%s:ov2710_write_table:%d", __func__, err);
			return err;
		}
	}
	return 0;
}

static void ov2710_mclk_disable(struct ov2710_info *priv)
{
	return;
	dev_dbg(&priv->i2c_client->dev, "%s: disable MCLK\n", __func__);
	clk_disable_unprepare(priv->mclk);
}

static int ov2710_mclk_enable(struct ov2710_info *priv)
{
	int err;
	unsigned long mclk_init_rate = 24000000;

	dev_dbg(&priv->i2c_client->dev, "%s: enable MCLK with %lu Hz\n",
		__func__, mclk_init_rate);

	err = clk_set_rate(priv->mclk, mclk_init_rate);
	if (!err)
		err = clk_prepare_enable(priv->mclk);
	return err;
}


static int ov2710_debugfs_show(struct seq_file *s, void *unused)
{
	struct ov2710_info *dev = s->private;

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

	mutex_lock(&dev->ov2710_camera_lock);
	mutex_unlock(&dev->ov2710_camera_lock);

	return 0;
}

static ssize_t ov2710_debugfs_write(
	struct file *file,
	char const __user *buf,
	size_t count,
	loff_t *offset)
{
	struct ov2710_info *dev =
			((struct seq_file *)file->private_data)->private;
	struct i2c_client *i2c_client = dev->i2c_client;
	int ret = 0;
	char buffer[MAX_BUFFER_SIZE];
	u32 address;
	u32 data;
	u8 readback;

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

	if (copy_from_user(&buffer, buf, sizeof(buffer)))
		goto debugfs_write_fail;

	if (sscanf(buf, "0x%x 0x%x", &address, &data) == 2)
		goto set_attr;
	if (sscanf(buf, "0X%x 0X%x", &address, &data) == 2)
		goto set_attr;
	if (sscanf(buf, "%d %d", &address, &data) == 2)
		goto set_attr;

	if (sscanf(buf, "0x%x 0x%x", &address, &data) == 1)
		goto read;
	if (sscanf(buf, "0X%x 0X%x", &address, &data) == 1)
		goto read;
	if (sscanf(buf, "%d %d", &address, &data) == 1)
		goto read;

	dev_err(&i2c_client->dev, "SYNTAX ERROR: %s\n", buf);
	return -EFAULT;

set_attr:
	dev_info(&i2c_client->dev,
			"new address = %x, data = %x\n", address, data);
	ret |= ov2710_write_reg(i2c_client, address, data);
read:
	ret |= ov2710_read_reg(i2c_client, address, &readback);
	dev_info(&i2c_client->dev,
			"wrote to address 0x%x with value 0x%x\n",
			address, readback);

	if (ret)
		goto debugfs_write_fail;

	return count;

debugfs_write_fail:
	dev_err(&i2c_client->dev,
			"%s: test pattern write failed\n", __func__);
	return -EFAULT;
}

static int ov2710_debugfs_open(struct inode *inode, struct file *file)
{
	struct ov2710_info *dev = inode->i_private;
	struct i2c_client *i2c_client = dev->i2c_client;

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

	return single_open(file, ov2710_debugfs_show, inode->i_private);
}

static const struct file_operations ov2710_debugfs_fops = {
	.open		= ov2710_debugfs_open,
	.read		= seq_read,
	.write		= ov2710_debugfs_write,
	.llseek		= seq_lseek,
	.release	= single_release,
};

static void ov2710_remove_debugfs(struct ov2710_info *dev)
{
	struct i2c_client *i2c_client = dev->i2c_client;

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

	debugfs_remove_recursive(dev->debugdir);
	dev->debugdir = NULL;
}

static void ov2710_create_debugfs(struct ov2710_info *dev)
{
	struct dentry *ret;
	struct i2c_client *i2c_client = dev->i2c_client;

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

	dev->debugdir =
		debugfs_create_dir("ov2710", NULL);
	if (!dev->debugdir)
		goto remove_debugfs;

	ret = debugfs_create_file("d",
				S_IWUSR | S_IRUGO,
				dev->debugdir, dev,
				&ov2710_debugfs_fops);
	if (!ret)
		goto remove_debugfs;

	return;
remove_debugfs:
	dev_err(&i2c_client->dev, "couldn't create debugfs\n");
	ov2710_remove_debugfs(dev);
}

static int ov2710_power_on(struct ov2710_power_rail *pw)
{
	int err;
	struct ov2710_info *priv = container_of(pw, struct ov2710_info, power);

	if (unlikely(WARN_ON(!pw || !pw->iovdd || !pw->avdd)))
		return -EFAULT;

	/* disable CSIE IOs DPD mode to turn on front camera for ardbeg */
	tegra_io_dpd_disable(&csie_io);

	gpio_set_value(CAM2_PWDN, 0);
	usleep_range(1000, 1020);

	err = regulator_enable(pw->avdd);
	if (unlikely(err))
		goto ov2710_avdd_fail;
	usleep_range(300, 320);

	err = regulator_enable(pw->iovdd);
	if (unlikely(err))
		goto ov2710_iovdd_fail;
	usleep_range(1000, 1020);

	gpio_set_value(CAM2_PWDN, 1);
	usleep_range(1000, 1020);


	return 0;

ov2710_iovdd_fail:
	regulator_disable(pw->avdd);

ov2710_avdd_fail:
	gpio_set_value(CAM_RSTN, 0);
	/* put CSIE IOs into DPD mode to save additional power for ardbeg */
	tegra_io_dpd_enable(&csie_io);
	return -ENODEV;
}

static int ov2710_power_off(struct ov2710_power_rail *pw)
{
	if (unlikely(WARN_ON(!pw || !pw->avdd || !pw->iovdd))) {
		/* put CSIE IOs into DPD mode to
		 * save additional power for ardbeg
		 */
		tegra_io_dpd_enable(&csie_io);
		return -EFAULT;
	}
	usleep_range(100, 120);

	gpio_set_value(CAM2_PWDN, 0);
	usleep_range(100, 120);

	regulator_disable(pw->iovdd);
	usleep_range(100, 120);

	regulator_disable(pw->avdd);

	/* put CSIE IOs into DPD mode to save additional power for ardbeg */
	tegra_io_dpd_enable(&csie_io);
	return 0;
}

static int ov2710_power_put(struct ov2710_power_rail *pw)
{
	if (unlikely(!pw))
		return -EFAULT;

	pw->avdd = NULL;
	pw->iovdd = NULL;
	
	return 0;
}

static int ov2710_power_get(struct ov2710_info *priv)
{
	struct ov2710_power_rail *pw = &priv->power;
	int err;

	/* ananlog 2.7v */
	pw->avdd = devm_regulator_get(&priv->i2c_client->dev, "vana");
	if (IS_ERR(pw->avdd)) {
		err = PTR_ERR(pw->avdd);
		pw->avdd = NULL;
		dev_err(&priv->i2c_client->dev, "Failed to get regulator vana\n");
		return err;
	}

	/* IO 1.8v */
	pw->iovdd = devm_regulator_get(&priv->i2c_client->dev, "vif");
	if (IS_ERR(pw->iovdd)) {
		err = PTR_ERR(pw->iovdd);
		pw->iovdd = NULL;
		dev_err(&priv->i2c_client->dev, "Failed to get regulator vif\n");
		return err;
	}

	return 0;
}

static int ov2710_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	struct ov2710_info *priv = to_ov2710(client);
	int mode = ov2710_find_mode(sd, mf->width, mf->height);

	mf->width = ov2710_frmsizes[mode].width;
	mf->height = ov2710_frmsizes[mode].height;

	if (mf->code != V4L2_MBUS_FMT_SRGGB8_1X8 &&
	    mf->code != V4L2_MBUS_FMT_SRGGB10_1X10)
		mf->code = V4L2_MBUS_FMT_SRGGB10_1X10;

	mf->field = V4L2_FIELD_NONE;
	mf->colorspace = V4L2_COLORSPACE_SRGB;

	priv->mode = mode;

	return 0;
}

static int ov2710_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	struct ov2710_info *priv = to_ov2710(client);

	dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code);

	/* MIPI CSI could have changed the format, double-check */
	if (!ov2710_find_datafmt(mf->code))
		return -EINVAL;

	ov2710_try_fmt(sd, mf);

	priv->fmt = ov2710_find_datafmt(mf->code);

	return 0;
}

static int ov2710_g_fmt(struct v4l2_subdev *sd,	struct v4l2_mbus_framefmt *mf)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	struct ov2710_info *priv = to_ov2710(client);

	const struct ov2710_datafmt *fmt = priv->fmt;

	mf->code	= fmt->code;
	mf->colorspace	= fmt->colorspace;
	mf->width	= OV2710_WIDTH;
	mf->height	= OV2710_HEIGHT;
	mf->field	= V4L2_FIELD_NONE;

	return 0;
}

static int ov2710_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
	struct v4l2_rect *rect = &a->c;

	a->type		= V4L2_BUF_TYPE_VIDEO_CAPTURE;
	rect->top	= 0;
	rect->left	= 0;
	rect->width	= OV2710_WIDTH;
	rect->height	= OV2710_HEIGHT;

	return 0;
}

static int ov2710_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
{
	a->bounds.left			= 0;
	a->bounds.top			= 0;
	a->bounds.width			= OV2710_WIDTH;
	a->bounds.height		= OV2710_HEIGHT;
	a->defrect			= a->bounds;
	a->type				= V4L2_BUF_TYPE_VIDEO_CAPTURE;
	a->pixelaspect.numerator	= 1;
	a->pixelaspect.denominator	= 1;

	return 0;
}

static int ov2710_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
			   enum v4l2_mbus_pixelcode *code)
{
	if ((unsigned int)index >= ARRAY_SIZE(ov2710_colour_fmts))
		return -EINVAL;

	*code = ov2710_colour_fmts[index].code;
	return 0;
}

static int ov2710_s_stream(struct v4l2_subdev *sd, int enable)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	struct ov2710_info *priv = to_ov2710(client);
	int err = 0;

	if (!enable)
		return 0;

	err = ov2710_write_table(priv->i2c_client, mode_table[priv->mode]);
	if (err)
		return err;

	if (test_mode)
		ov2710_write_table(priv->i2c_client, tp_colorbars);

	return err;
	
}

static int ov2710_g_chip_ident(struct v4l2_subdev *sd,
			       struct v4l2_dbg_chip_ident *id)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);

	if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
		return -EINVAL;

	if (id->match.addr != client->addr)
		return -ENODEV;

	id->ident	= V4L2_IDENT_OV2710;
	id->revision	= 0;

	return 0;
}

static int ov2710_s_power(struct v4l2_subdev *sd, int on)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	struct ov2710_info *priv = to_ov2710(client);
	int err;

	if (on) {
		err = ov2710_mclk_enable(priv);
		if (!err)
			err = ov2710_power_on(&priv->power);
		if (err < 0)
			ov2710_mclk_disable(priv);
		return err;
	} else if (!on) {
		ov2710_power_off(&priv->power);
		ov2710_mclk_disable(priv);
		return 0;
	} else
		return -EINVAL;
}

static int ov2710_g_mbus_config(struct v4l2_subdev *sd,
				struct v4l2_mbus_config *cfg)
{
	cfg->type = V4L2_MBUS_CSI2;
	cfg->flags = V4L2_MBUS_CSI2_1_LANE |
		V4L2_MBUS_CSI2_CHANNEL_0 |
		V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;

	return 0;
}

static struct v4l2_subdev_video_ops ov2710_subdev_video_ops = {
	.s_stream	= ov2710_s_stream,
	.s_mbus_fmt	= ov2710_s_fmt,
	.g_mbus_fmt	= ov2710_g_fmt,
	.try_mbus_fmt	= ov2710_try_fmt,
	.enum_mbus_fmt	= ov2710_enum_fmt,
	.g_crop		= ov2710_g_crop,
	.cropcap	= ov2710_cropcap,
	.g_mbus_config	= ov2710_g_mbus_config,
};

static struct v4l2_subdev_core_ops ov2710_subdev_core_ops = {
	.g_chip_ident	= ov2710_g_chip_ident,
	.s_power	= ov2710_s_power,
};

static struct v4l2_subdev_ops ov2710_subdev_ops = {
	.core	= &ov2710_subdev_core_ops,
	.video	= &ov2710_subdev_video_ops,
};

static struct of_device_id ov2710_of_match[] = {
	{ .compatible = "nvidia,ov2710", },
	{ },
};

MODULE_DEVICE_TABLE(of, ov2710_of_match);


static struct ov2710_platform_data *ov2710_parse_dt(struct i2c_client *client)
{
	struct device_node *np = client->dev.of_node;
	struct ov2710_platform_data *board_priv_pdata;
	const struct of_device_id *match;

	match = of_match_device(ov2710_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) {
		dev_err(&client->dev, "Failed to allocate pdata\n");
		return NULL;
	}

	board_priv_pdata->cam1_gpio = of_get_named_gpio(np, "cam1-gpios", 0);
	board_priv_pdata->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0);

	//board_priv_pdata->ext_reg = of_property_read_bool(np, "nvidia,ext_reg");

	board_priv_pdata->power_on = ov2710_power_on;
	board_priv_pdata->power_off = ov2710_power_off;

	return board_priv_pdata;
}

/*
static int ov2710_get_sensor_id(struct ov2710_info *priv)
{
	u8 chipid[2];
	int ret;

	ov2710_mclk_enable(priv);
	ov2710_power_on(&priv->power);
	
	priv->ident = V4L2_IDENT_OV2710;
	
	// Detecting OV2710 sensor

	ret = ov2710_read_reg(priv->i2c_client, 0x300A, &chipid[0]);
	if (ret) {
		dev_err(&i2c_client->dev, "Failure to read Chip ID (high byte)\n");
		goto err;
	}

	ret = ov2710_read_reg(client, 0x300B, &chipid[1]);
	if (ret) {
		dev_err(&i2c_client->dev, "Failure to read Chip ID (low byte)\n");
		goto err;
	}

	priv->chip_id = (chipid[0] << 8) | chipid[1];

	if (priv->chip_id != V4L2_IDENT_OV2710){
		dev_err(&i2c_client->dev, "Chip ID: %x not supported!\n",
			priv->chip_id);
		ret = -ENODEV;
		goto err;
	}

	ov2710_power_off(&priv->power);
	ov2710_mclk_disable(priv);

	return 0;
}
*/


static int ov2710_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
{
printk(KERN_CRIT "START OV2710 Probe\n");

	struct ov2710_info *priv;
	const char *mclk_name;
	int err;
	u8 chipid[2];
	int ret;

	priv = devm_kzalloc(&client->dev,
			sizeof(struct ov2710_info), GFP_KERNEL);
	if (!priv) {
		dev_err(&client->dev, "unable to allocate memory!\n");
		return -ENOMEM;
	}

	if (client->dev.of_node)
		priv->pdata = ov2710_parse_dt(client);
	else
		priv->pdata = client->dev.platform_data;

	if (!priv->pdata) {
		dev_err(&client->dev, "unable to get platform data\n");
		return -EFAULT;
	}
/**/
	priv->i2c_client = client;
	priv->mode = OV2710_MODE;
	priv->fmt = &ov2710_colour_fmts[0];

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

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

	i2c_set_clientdata(client, priv);

	//ov2710_get_sensor_id(priv);

	//GET SENSOR ID

printk(KERN_CRIT "GET SENSOR ID\n");

	
	priv->ident = V4L2_IDENT_OV2710;

	ov2710_mclk_enable(priv);
	ov2710_power_on(&priv->power);
		
	// Detecting OV2710 sensor

	ret = ov2710_read_reg(client, 0x300A, &chipid[0]);
printk(KERN_CRIT "Camera High: %x\n", &chipid[0]);
	if (ret < 0) {
		dev_err(&client->dev, "Failure to read Chip ID (high byte)\n");
		return err;
	}


	ret = ov2710_read_reg(client, 0x300B, &chipid[1]);
printk(KERN_CRIT "Camera Low: %x\n", &chipid[1]);
	if (ret < 0) {
		dev_err(&client->dev, "Failure to read Chip ID (low byte)\n");
		return err;
	}

	priv->chip_id = (chipid[0] << 8) | chipid[1];
printk(KERN_CRIT "Camera ID: %x\n", priv->chip_id);
	if (priv->chip_id != 0x2710){
		dev_err(&client->dev, "Chip ID: %x not supported!\n",
			priv->chip_id);
		ret = -ENODEV;
		return err;
	}

	ov2710_power_off(&priv->power);
	ov2710_mclk_disable(priv);

	//GET SENSOR ID END
	ov2710_create_debugfs(priv);

	v4l2_i2c_subdev_init(&priv->subdev, client, &ov2710_subdev_ops);
printk(KERN_CRIT "END PROBE!\n");

	return 0;
}

static int ov2710_remove(struct i2c_client *client)
{
	struct soc_camera_subdev_desc *ssdd;
	struct ov2710_info *priv;

	ssdd = soc_camera_i2c_to_desc(client);
	if (ssdd->free_bus)
		ssdd->free_bus(ssdd);

	priv = i2c_get_clientdata(client);
	ov2710_power_put(&priv->power);
	ov2710_remove_debugfs(priv);

	return 0;
}

static const struct i2c_device_id ov2710_id[] = {
	{ "ov2710_v4l2", 0 },
	{ }
};

MODULE_DEVICE_TABLE(i2c, ov2710_id);

static struct i2c_driver ov2710_i2c_driver = {
	.driver = {
		.name = "ov2710_v4l2",
		.owner = THIS_MODULE,
	},
	.probe = ov2710_probe,
	.remove = ov2710_remove,
	.id_table = ov2710_id,
};

module_i2c_driver(ov2710_i2c_driver);

MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV2710");
MODULE_AUTHOR("Kornuta Taras <taraskornuta@gmail.com>");
MODULE_LICENSE("GPL v2");

board-ardbeg-sensors.c

[code]
/*

  • arch/arm/mach-tegra/board-ardbeg-sensors.c
  • Copyright © 2013-2014, 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.
    */

#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/mpu.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/nct1008.h>
#include <linux/pid_thermal_gov.h>
#include <linux/tegra-fuse.h>
#include <linux/of_platform.h>
#include <mach/edp.h>
#include <mach/pinmux-t12.h>
#include <mach/pinmux.h>
#include <mach/io_dpd.h>
#include <media/camera.h>
#include <media/ar0330.h>
#include <media/ar0261.h>
#include <media/imx135.h>
#include <media/ov2710.h>
#include <media/imx179.h>
#include <media/dw9718.h>
#include <media/as364x.h>
#include <media/ov5693.h>
#include <media/ov7695.h>
#include <media/mt9m114.h>
#include <media/ad5823.h>
#include <media/max77387.h>

#include <linux/platform_device.h>
#include <media/soc_camera.h>
#include <media/soc_camera_platform.h>
#include <media/tegra_v4l2_camera.h>
#include <linux/generic_adc_thermal.h>

#include “cpu-tegra.h”
#include “devices.h”
#include “board.h”
#include “board-common.h”
#include “board-ardbeg.h”
#include “tegra-board-id.h”

#if defined(ARCH_TEGRA_12x_SOC)
static struct i2c_board_info ardbeg_i2c_board_info_cm32181 = {
{
I2C_BOARD_INFO(“cm32181”, 0x48),
},
};
#endif

/* MPU board file definition /
static struct mpu_platform_data mpu9250_gyro_data = {
.int_config = 0x10,
.level_shifter = 0,
/
Located in board_[platformname].h */
.orientation = MPU_GYRO_ORIENTATION,
.sec_slave_type = SECONDARY_SLAVE_TYPE_NONE,
.key = {0x4E, 0xCC, 0x7E, 0xEB, 0xF6, 0x1E, 0x35, 0x22,
0x00, 0x34, 0x0D, 0x65, 0x32, 0xE9, 0x94, 0x89},
};

static struct mpu_platform_data mpu9250_gyro_data_e1762 = {
.int_config = 0x10,
.level_shifter = 0,
/* Located in board_[platformname].h */
.orientation = MPU_GYRO_ORIENTATION_E1762,
.sec_slave_type = SECONDARY_SLAVE_TYPE_NONE,
.key = {0x4E, 0xCC, 0x7E, 0xEB, 0xF6, 0x1E, 0x35, 0x22,
0x00, 0x34, 0x0D, 0x65, 0x32, 0xE9, 0x94, 0x89},
};

static struct mpu_platform_data mpu_compass_data = {
.orientation = MPU_COMPASS_ORIENTATION,
.config = NVI_CONFIG_BOOT_MPU,
};

static struct mpu_platform_data mpu_bmp_pdata = {
.config = NVI_CONFIG_BOOT_MPU,
};

static struct i2c_board_info __initdata inv_mpu9250_i2c0_board_info = {
{
I2C_BOARD_INFO(MPU_GYRO_NAME, MPU_GYRO_ADDR),
.platform_data = &mpu9250_gyro_data,
},
{
/* The actual BMP180 address is 0x77 but because this conflicts
* with another device, this address is hacked so Linux will
* call the driver. The conflict is technically okay since the
* BMP180 is behind the MPU. Also, the BMP180 driver uses a
* hard-coded address of 0x77 since it can’t be changed anyway.
*/
I2C_BOARD_INFO(MPU_BMP_NAME, MPU_BMP_ADDR),
.platform_data = &mpu_bmp_pdata,
},
{
I2C_BOARD_INFO(MPU_COMPASS_NAME, MPU_COMPASS_ADDR),
.platform_data = &mpu_compass_data,
},
};

static void mpuirq_init(void)
{
int ret = 0;
unsigned gyro_irq_gpio = MPU_GYRO_IRQ_GPIO;
unsigned gyro_bus_num = MPU_GYRO_BUS_NUM;
char *gyro_name = MPU_GYRO_NAME;
struct board_info board_info;

pr_info("*** MPU START *** mpuirq_init...\n");

tegra_get_board_info(&board_info);

ret = gpio_request(gyro_irq_gpio, gyro_name);
if (ret < 0) {
	pr_err("%s: gpio_request failed %d\n", __func__, ret);
	return;
}

ret = gpio_direction_input(gyro_irq_gpio);
if (ret < 0) {
	pr_err("%s: gpio_direction_input failed %d\n", __func__, ret);
	gpio_free(gyro_irq_gpio);
	return;
}
pr_info("*** MPU END *** mpuirq_init...\n");

/* TN8 with diferent Compass address from ardbeg */
if (of_machine_is_compatible("nvidia,tn8"))
	inv_mpu9250_i2c0_board_info[2].addr = MPU_COMPASS_ADDR_TN8;

if (board_info.board_id == BOARD_E1762)
	inv_mpu9250_i2c0_board_info[0].platform_data =
				&mpu9250_gyro_data_e1762;
inv_mpu9250_i2c0_board_info[0].irq = gpio_to_irq(MPU_GYRO_IRQ_GPIO);
i2c_register_board_info(gyro_bus_num, inv_mpu9250_i2c0_board_info,
	ARRAY_SIZE(inv_mpu9250_i2c0_board_info));

}

/*

  • Soc Camera platform driver for testing
    */
    #if IS_ENABLED(CONFIG_SOC_CAMERA_PLATFORM)
    static int ardbeg_soc_camera_add(struct soc_camera_device *icd);
    static void ardbeg_soc_camera_del(struct soc_camera_device *icd);

static int ardbeg_soc_camera_set_capture(struct soc_camera_platform_info info,
int enable)
{
/
TODO: probably add clk opertaion here /
return 0; /
camera sensor always enabled */
}

static struct soc_camera_platform_info ardbeg_soc_camera_info = {
.format_name = “RGB4”,
.format_depth = 32,
.format = {
.code = V4L2_MBUS_FMT_RGBA8888_4X8_LE,
.colorspace = V4L2_COLORSPACE_SRGB,
.field = V4L2_FIELD_NONE,
.width = 1280,
.height = 720,
},
.set_capture = ardbeg_soc_camera_set_capture,
};

static struct tegra_camera_platform_data ardbeg_camera_platform_data = {
.flip_v = 0,
.flip_h = 0,
.port = TEGRA_CAMERA_PORT_CSI_A,
.lanes = 4,
.continuous_clk = 0,
};

static struct soc_camera_link ardbeg_soc_camera_link = {
.bus_id = 1, /* This must match the .id of tegra_vi01_device */
.add_device = ardbeg_soc_camera_add,
.del_device = ardbeg_soc_camera_del,
.module_name = “soc_camera_platform”,
.priv = &ardbeg_camera_platform_data,
.dev_priv = &ardbeg_soc_camera_info,
};

static struct platform_device *ardbeg_pdev;

static void ardbeg_soc_camera_release(struct device *dev)
{
soc_camera_platform_release(&ardbeg_pdev);
}

static int ardbeg_soc_camera_add(struct soc_camera_device *icd)
{
return soc_camera_platform_add(icd, &ardbeg_pdev,
&ardbeg_soc_camera_link,
ardbeg_soc_camera_release, 0);
}

static void ardbeg_soc_camera_del(struct soc_camera_device *icd)
{
soc_camera_platform_del(icd, ardbeg_pdev, &ardbeg_soc_camera_link);
}

static struct platform_device ardbeg_soc_camera_device = {
.name = “soc-camera-pdrv”,
.id = 1,
.dev = {
.platform_data = &ardbeg_soc_camera_link,
},
};
#endif

#if IS_ENABLED(CONFIG_SOC_CAMERA_IMX135)
static int ardbeg_imx135_power(struct device *dev, int enable)
{
return 0;
}

struct imx135_platform_data ardbeg_imx135_data;

static struct i2c_board_info ardbeg_imx135_camera_i2c_device = {
I2C_BOARD_INFO(“imx135_v4l2”, 0x10),
.platform_data = &ardbeg_imx135_data,
};

static struct tegra_camera_platform_data ardbeg_imx135_camera_platform_data = {
.flip_v = 0,
.flip_h = 0,
.port = TEGRA_CAMERA_PORT_CSI_A,
.lanes = 4,
.continuous_clk = 0,
};

static struct soc_camera_link imx135_iclink = {
.bus_id = 0, /* This must match the .id of tegra_vi01_device */
.board_info = &ardbeg_imx135_camera_i2c_device,
.module_name = “imx135_v4l2”,
.i2c_adapter_id = 2,
.power = ardbeg_imx135_power,
.priv = &ardbeg_imx135_camera_platform_data,
};

static struct platform_device ardbeg_imx135_soc_camera_device = {
.name = “soc-camera-pdrv”,
.id = 0,
.dev = {
.platform_data = &imx135_iclink,
},
};
#endif

#if IS_ENABLED(CONFIG_SOC_CAMERA_AR0261)
static int ardbeg_ar0261_power(struct device *dev, int enable)
{
return 0;
}

struct ar0261_platform_data ardbeg_ar0261_data;

static struct i2c_board_info ardbeg_ar0261_camera_i2c_device = {
I2C_BOARD_INFO(“ar0261_v4l2”, 0x36),
.platform_data = &ardbeg_ar0261_data,
};

static struct tegra_camera_platform_data ardbeg_ar0261_camera_platform_data = {
.flip_v = 0,
.flip_h = 0,
.port = TEGRA_CAMERA_PORT_CSI_C,
.lanes = 1,
.continuous_clk = 0,
};

static struct soc_camera_link ar0261_iclink = {
.bus_id = 1, /* This must match the .id of tegra_vi01_device */
.board_info = &ardbeg_ar0261_camera_i2c_device,
.module_name = “ar0261_v4l2”,
.i2c_adapter_id = 2,
.power = ardbeg_ar0261_power,
.priv = &ardbeg_ar0261_camera_platform_data,
};

static struct platform_device ardbeg_ar0261_soc_camera_device = {
.name = “soc-camera-pdrv”,
.id = 1,
.dev = {
.platform_data = &ar0261_iclink,
},
};
#endif

/////////////////////////////////////////////////////////////////////////////////////////
#if IS_ENABLED(CONFIG_SOC_CAMERA_OV2710)
static int ardbeg_ov2710_power(struct device *dev, int enable)
{
return 0;
}

struct ov2710_platform_data ardbeg_ov2710_data;

static struct i2c_board_info ardbeg_ov2710_camera_i2c_device = {
I2C_BOARD_INFO(“ov2710_v4l2”, 0x36),
.platform_data = &ardbeg_ov2710_data,
};

static struct tegra_camera_platform_data ardbeg_ov2710_camera_platform_data = {
.flip_v = 0,
.flip_h = 0,
.port = TEGRA_CAMERA_PORT_CSI_C,
.lanes = 1,
.continuous_clk = 1,
};

static struct soc_camera_link ov2710_iclink = {
.bus_id = 0, /* This must match the .id of tegra_vi01_device */
.board_info = &ardbeg_ov2710_camera_i2c_device,
.module_name = “ov2710_v4l2”,
.i2c_adapter_id = 2,
.power = ardbeg_ov2710_power,
.priv = &ardbeg_ov2710_camera_platform_data,
};

static struct platform_device ardbeg_ov2710_soc_camera_device = {
.name = “soc-camera-pdrv”,
.id = 0,
.dev = {
.platform_data = &ov2710_iclink,
},
};
#endif
////////////////////////////////////////////////////////////////////////////////////////

static struct regulator *ardbeg_vcmvdd;

static int ardbeg_get_extra_regulators(void)
{
if (!ardbeg_vcmvdd) {
ardbeg_vcmvdd = regulator_get(NULL, “avdd_af1_cam”);
if (WARN_ON(IS_ERR(ardbeg_vcmvdd))) {
pr_err("%s: can’t get regulator avdd_af1_cam: %ld\n",
func, PTR_ERR(ardbeg_vcmvdd));
regulator_put(ardbeg_vcmvdd);
ardbeg_vcmvdd = NULL;
return -ENODEV;
}
}

return 0;

}

static struct tegra_io_dpd csia_io = {
.name = “CSIA”,
.io_dpd_reg_index = 0,
.io_dpd_bit = 0,
};

static struct tegra_io_dpd csib_io = {
.name = “CSIB”,
.io_dpd_reg_index = 0,
.io_dpd_bit = 1,
};

static struct tegra_io_dpd csie_io = {
.name = “CSIE”,
.io_dpd_reg_index = 1,
.io_dpd_bit = 12,
};

static int ardbeg_ar0330_front_power_on(struct ar0330_power_rail *pw)
{
int err;

if (unlikely(WARN_ON(!pw || !pw->avdd || !pw->iovdd)))
	return -EFAULT;

/* disable CSIE IOs DPD mode to turn on front camera for ardbeg */
tegra_io_dpd_disable(&csie_io);

gpio_set_value(CAM2_PWDN, 0);

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

usleep_range(1000, 1100);
err = regulator_enable(pw->avdd);
if (unlikely(err))
	goto ar0330_front_avdd_fail;

usleep_range(1, 2);
gpio_set_value(CAM2_PWDN, 1);

return 0;

ar0330_front_avdd_fail:
regulator_disable(pw->iovdd);

ar0330_front_iovdd_fail:
/* put CSIE IOs into DPD mode to save additional power for ardbeg */
tegra_io_dpd_enable(&csie_io);
pr_err("%s failed.\n", func);
return -ENODEV;
}

static int ardbeg_ar0330_front_power_off(struct ar0330_power_rail pw)
{
if (unlikely(WARN_ON(!pw || !pw->avdd || !pw->iovdd))) {
/
put CSIE IOs into DPD mode to
* save additional power for ardbeg
*/
tegra_io_dpd_enable(&csie_io);
return -EFAULT;
}

gpio_set_value(CAM2_PWDN, 0);

usleep_range(1, 2);

regulator_disable(pw->iovdd);
regulator_disable(pw->avdd);
/* put CSIE IOs into DPD mode to save additional power for ardbeg */
tegra_io_dpd_enable(&csie_io);
return 0;

}

struct ar0330_platform_data ardbeg_ar0330_front_data = {
.power_on = ardbeg_ar0330_front_power_on,
.power_off = ardbeg_ar0330_front_power_off,
.dev_name = “ar0330.1”,
.mclk_name = “mclk2”,
};

static int ardbeg_ar0330_power_on(struct ar0330_power_rail *pw)
{
int err;

if (unlikely(WARN_ON(!pw || !pw->avdd || !pw->iovdd)))
	return -EFAULT;

/* disable CSIE IOs DPD mode to turn on front camera for ardbeg */
tegra_io_dpd_disable(&csia_io);
tegra_io_dpd_disable(&csib_io);

gpio_set_value(CAM1_PWDN, 0);

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

usleep_range(1000, 1100);
err = regulator_enable(pw->avdd);
if (unlikely(err))
	goto ar0330_avdd_fail;

usleep_range(1, 2);
gpio_set_value(CAM1_PWDN, 1);

return 0;

ar0330_avdd_fail:
regulator_disable(pw->iovdd);

ar0330_iovdd_fail:
/* put CSIE IOs into DPD mode to save additional power for ardbeg */
tegra_io_dpd_enable(&csia_io);
tegra_io_dpd_enable(&csib_io);
pr_err("%s failed.\n", func);
return -ENODEV;
}

static int ardbeg_ar0330_power_off(struct ar0330_power_rail pw)
{
if (unlikely(WARN_ON(!pw || !pw->avdd || !pw->iovdd))) {
/
put CSIE IOs into DPD mode to
* save additional power for ardbeg
*/
tegra_io_dpd_enable(&csia_io);
tegra_io_dpd_enable(&csib_io);
return -EFAULT;
}

gpio_set_value(CAM1_PWDN, 0);

usleep_range(1, 2);

regulator_disable(pw->iovdd);
regulator_disable(pw->avdd);
/* put CSIE IOs into DPD mode to save additional power for ardbeg */
tegra_io_dpd_enable(&csia_io);
tegra_io_dpd_enable(&csib_io);
return 0;

}

struct ar0330_platform_data ardbeg_ar0330_data = {
.power_on = ardbeg_ar0330_power_on,
.power_off = ardbeg_ar0330_power_off,
.dev_name = “ar0330”,
};

static int ardbeg_ar0261_power_on(struct ar0261_power_rail *pw)
{
int err;

if (unlikely(WARN_ON(!pw || !pw->avdd || !pw->iovdd || !pw->dvdd)))
	return -EFAULT;

/* disable CSIE IOs DPD mode to turn on front camera for ardbeg */
tegra_io_dpd_disable(&csie_io);

if (ardbeg_get_extra_regulators())
	goto ardbeg_ar0261_poweron_fail;

gpio_set_value(CAM_RSTN, 0);
gpio_set_value(CAM_AF_PWDN, 1);


err = regulator_enable(ardbeg_vcmvdd);
if (unlikely(err))
	goto ar0261_vcm_fail;

err = regulator_enable(pw->dvdd);
if (unlikely(err))
	goto ar0261_dvdd_fail;

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

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

usleep_range(1, 2);
gpio_set_value(CAM2_PWDN, 1);

gpio_set_value(CAM_RSTN, 1);

return 0;

ar0261_iovdd_fail:
regulator_disable(pw->dvdd);

ar0261_dvdd_fail:
regulator_disable(pw->avdd);

ar0261_avdd_fail:
regulator_disable(ardbeg_vcmvdd);

ar0261_vcm_fail:
pr_err("%s vcmvdd failed.\n", func);
return -ENODEV;

ardbeg_ar0261_poweron_fail:
/* put CSIE IOs into DPD mode to save additional power for ardbeg */
tegra_io_dpd_enable(&csie_io);
pr_err("%s failed.\n", func);
return -ENODEV;
}

static int ardbeg_ar0261_power_off(struct ar0261_power_rail pw)
{
if (unlikely(WARN_ON(!pw || !pw->avdd || !pw->iovdd || !pw->dvdd ||
!ardbeg_vcmvdd))) {
/
put CSIE IOs into DPD mode to
* save additional power for ardbeg
*/
tegra_io_dpd_enable(&csie_io);
return -EFAULT;
}

gpio_set_value(CAM_RSTN, 0);

usleep_range(1, 2);

regulator_disable(pw->iovdd);
regulator_disable(pw->dvdd);
regulator_disable(pw->avdd);
regulator_disable(ardbeg_vcmvdd);
/* put CSIE IOs into DPD mode to save additional power for ardbeg */
tegra_io_dpd_enable(&csie_io);
return 0;

}

struct ar0261_platform_data ardbeg_ar0261_data = {
.power_on = ardbeg_ar0261_power_on,
.power_off = ardbeg_ar0261_power_off,
.mclk_name = “mclk2”,
};

static int ardbeg_imx135_get_extra_regulators(struct imx135_power_rail *pw)
{
if (!pw->ext_reg1) {
pw->ext_reg1 = regulator_get(NULL, “imx135_reg1”);
if (WARN_ON(IS_ERR(pw->ext_reg1))) {
pr_err("%s: can’t get regulator imx135_reg1: %ld\n",
func, PTR_ERR(pw->ext_reg1));
pw->ext_reg1 = NULL;
return -ENODEV;
}
}

if (!pw->ext_reg2) {
	pw->ext_reg2 = regulator_get(NULL, "imx135_reg2");
	if (WARN_ON(IS_ERR(pw->ext_reg2))) {
		pr_err("%s: can't get regulator imx135_reg2: %ld\n",
			__func__, PTR_ERR(pw->ext_reg2));
		pw->ext_reg2 = NULL;
		return -ENODEV;
	}
}

return 0;

}

static int ardbeg_imx135_power_on(struct imx135_power_rail *pw)
{
int err;

if (unlikely(WARN_ON(!pw || !pw->iovdd || !pw->avdd)))
	return -EFAULT;

/* disable CSIA/B IOs DPD mode to turn on camera for ardbeg */
tegra_io_dpd_disable(&csia_io);
tegra_io_dpd_disable(&csib_io);

if (ardbeg_imx135_get_extra_regulators(pw))
	goto imx135_poweron_fail;

err = regulator_enable(pw->ext_reg1);
if (unlikely(err))
	goto imx135_ext_reg1_fail;

err = regulator_enable(pw->ext_reg2);
if (unlikely(err))
	goto imx135_ext_reg2_fail;


gpio_set_value(CAM_AF_PWDN, 1);
gpio_set_value(CAM1_PWDN, 0);
usleep_range(10, 20);

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

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

usleep_range(1, 2);
gpio_set_value(CAM1_PWDN, 1);

usleep_range(300, 310);

return 1;

imx135_iovdd_fail:
regulator_disable(pw->avdd);

imx135_avdd_fail:
if (pw->ext_reg2)
regulator_disable(pw->ext_reg2);

imx135_ext_reg2_fail:
if (pw->ext_reg1)
regulator_disable(pw->ext_reg1);
gpio_set_value(CAM_AF_PWDN, 0);

imx135_ext_reg1_fail:
imx135_poweron_fail:
tegra_io_dpd_enable(&csia_io);
tegra_io_dpd_enable(&csib_io);
pr_err("%s failed.\n", func);
return -ENODEV;
}

static int ardbeg_imx135_power_off(struct imx135_power_rail *pw)
{
if (unlikely(WARN_ON(!pw || !pw->iovdd || !pw->avdd))) {
tegra_io_dpd_enable(&csia_io);
tegra_io_dpd_enable(&csib_io);
return -EFAULT;
}

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

regulator_disable(pw->ext_reg1);
regulator_disable(pw->ext_reg2);

/* put CSIA/B IOs into DPD mode to save additional power for ardbeg */
tegra_io_dpd_enable(&csia_io);
tegra_io_dpd_enable(&csib_io);
return 0;

}

//////////////////////////////////////////////////////////////////////////////////

static int ardbeg_ov2710_power_on(struct ov2710_power_rail *pw)
{
int err;

if (unlikely(WARN_ON(!pw || !pw->avdd || !pw->iovdd)))
	return -EFAULT;

/* disable CSIE IOs DPD mode to turn on front camera for ardbeg */
tegra_io_dpd_disable(&csie_io);

gpio_set_value(CAM2_PWDN, 0);
usleep_range(1000, 1020);

err = regulator_enable(pw->avdd);
if (unlikely(err))
	goto ov2710_avdd_fail;
usleep_range(300, 320);

err = regulator_enable(pw->iovdd);
if (unlikely(err))
	goto ov2710_iovdd_fail;
usleep_range(1000, 1020);

gpio_set_value(CAM2_PWDN, 1);
usleep_range(1000, 1020);

return 0;

ov2710_iovdd_fail:
regulator_disable(pw->avdd);

ov2710_avdd_fail:
gpio_set_value(CAM_RSTN, 0);
/* put CSIE IOs into DPD mode to save additional power for ardbeg */
tegra_io_dpd_enable(&csie_io);
return -ENODEV;
}

static int ardbeg_ov2710_power_off(struct ov2710_power_rail pw)
{
if (unlikely(WARN_ON(!pw || !pw->avdd || !pw->iovdd))) {
/
put CSIE IOs into DPD mode to
* save additional power for ardbeg
*/
tegra_io_dpd_enable(&csie_io);
return -EFAULT;
}
usleep_range(100, 120);

gpio_set_value(CAM2_PWDN, 0);
usleep_range(100, 120);

regulator_disable(pw->iovdd);
usleep_range(100, 120);

regulator_disable(pw->avdd);

/* put CSIE IOs into DPD mode to save additional power for ardbeg */
tegra_io_dpd_enable(&csie_io);
return 0;

}
///////////////////////////////////////////////////////////////////////
struct ov2710_platform_data ardbeg_ov2710_pdata = {
.power_on = ardbeg_ov2710_power_on,
.power_off = ardbeg_ov2710_power_off,
.mclk_name = “mclk2”,
};

//////////////////////////////////////////////////////////////////////////////////
static int ardbeg_imx179_power_on(struct imx179_power_rail *pw)
{
int err;

if (unlikely(WARN_ON(!pw || !pw->iovdd || !pw->avdd)))
	return -EFAULT;

/* disable CSIA/B IOs DPD mode to turn on camera for ardbeg */
tegra_io_dpd_disable(&csia_io);
tegra_io_dpd_disable(&csib_io);

gpio_set_value(CAM_AF_PWDN, 1);
gpio_set_value(CAM_RSTN, 0);
gpio_set_value(CAM1_PWDN, 0);
usleep_range(10, 20);

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

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

err = regulator_enable(pw->dvdd);
if (err)
	goto imx179_dvdd_fail;

usleep_range(1, 2);
gpio_set_value(CAM_RSTN, 1);

usleep_range(300, 310);

return 1;

imx179_dvdd_fail:
regulator_disable(pw->iovdd);

imx179_iovdd_fail:
regulator_disable(pw->avdd);

imx179_avdd_fail:
tegra_io_dpd_enable(&csia_io);
tegra_io_dpd_enable(&csib_io);
pr_err("%s failed.\n", func);
return -ENODEV;
}

static int ardbeg_imx179_power_off(struct imx179_power_rail *pw)
{
if (unlikely(WARN_ON(!pw || !pw->iovdd || !pw->avdd))) {
tegra_io_dpd_enable(&csia_io);
tegra_io_dpd_enable(&csib_io);
return -EFAULT;
}

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

/* put CSIA/B IOs into DPD mode to save additional power for ardbeg */
tegra_io_dpd_enable(&csia_io);
tegra_io_dpd_enable(&csib_io);
return 0;

}

struct imx135_platform_data ardbeg_imx135_data = {
.flash_cap = {
.enable = 1,
.edge_trig_en = 1,
.start_edge = 0,
.repeat = 1,
.delay_frm = 0,
},
.ext_reg = true,
.power_on = ardbeg_imx135_power_on,
.power_off = ardbeg_imx135_power_off,
};

struct imx179_platform_data ardbeg_imx179_data = {
.flash_cap = {
.enable = 1,
.edge_trig_en = 1,
.start_edge = 0,
.repeat = 1,
.delay_frm = 0,
},
.power_on = ardbeg_imx179_power_on,
.power_off = ardbeg_imx179_power_off,
};

static int ardbeg_dw9718_power_on(struct dw9718_power_rail *pw)
{
int err;
pr_info("%s\n", func);

if (unlikely(!pw || !pw->vdd || !pw->vdd_i2c || !pw->vana))
	return -EFAULT;

err = regulator_enable(pw->vdd);
if (unlikely(err))
	goto dw9718_vdd_fail;

err = regulator_enable(pw->vdd_i2c);
if (unlikely(err))
	goto dw9718_i2c_fail;

err = regulator_enable(pw->vana);
if (unlikely(err))
	goto dw9718_ana_fail;

usleep_range(1000, 1020);

/* return 1 to skip the in-driver power_on sequence */
pr_debug("%s --\n", __func__);
return 1;

dw9718_ana_fail:
regulator_disable(pw->vdd_i2c);

dw9718_i2c_fail:
regulator_disable(pw->vdd);

dw9718_vdd_fail:
pr_err("%s FAILED\n", func);
return -ENODEV;
}

static int ardbeg_dw9718_power_off(struct dw9718_power_rail *pw)
{
pr_info("%s\n", func);

if (unlikely(!pw || !pw->vdd || !pw->vdd_i2c || !pw->vana))
	return -EFAULT;

regulator_disable(pw->vdd);
regulator_disable(pw->vdd_i2c);
regulator_disable(pw->vana);

return 1;

}

static u16 dw9718_devid;
static int ardbeg_dw9718_detect(void *buf, size_t size)
{
dw9718_devid = 0x9718;
return 0;
}

static struct nvc_focus_cap dw9718_cap = {
.settle_time = 30,
.slew_rate = 0x3A200C,
.focus_macro = 450,
.focus_infinity = 200,
.focus_hyper = 200,
};

static struct dw9718_platform_data ardbeg_dw9718_data = {
.cfg = NVC_CFG_NODEV,
.num = 0,
.sync = 0,
.dev_name = “focuser”,
.cap = &dw9718_cap,
.power_on = ardbeg_dw9718_power_on,
.power_off = ardbeg_dw9718_power_off,
.detect = ardbeg_dw9718_detect,
};

static struct as364x_platform_data ardbeg_as3648_data = {
.config = {
.led_mask = 3,
.max_total_current_mA = 1000,
.max_peak_current_mA = 600,
.max_torch_current_mA = 600,
.vin_low_v_run_mV = 3070,
.strobe_type = 1,
},
.pinstate = {
.mask = 1 << (CAM_FLASH_STROBE - TEGRA_GPIO_PBB0),
.values = 1 << (CAM_FLASH_STROBE - TEGRA_GPIO_PBB0)
},
.dev_name = “torch”,
.type = AS3648,
.gpio_strobe = CAM_FLASH_STROBE,
};

static int ardbeg_ov7695_power_on(struct ov7695_power_rail *pw)
{
int err;

if (unlikely(WARN_ON(!pw || !pw->avdd || !pw->iovdd)))
	return -EFAULT;

/* disable CSIE IOs DPD mode to turn on front camera for ardbeg */
tegra_io_dpd_disable(&csie_io);

gpio_set_value(CAM2_PWDN, 0);
usleep_range(1000, 1020);

err = regulator_enable(pw->avdd);
if (unlikely(err))
	goto ov7695_avdd_fail;
usleep_range(300, 320);

err = regulator_enable(pw->iovdd);
if (unlikely(err))
	goto ov7695_iovdd_fail;
usleep_range(1000, 1020);

gpio_set_value(CAM2_PWDN, 1);
usleep_range(1000, 1020);

return 0;

ov7695_iovdd_fail:
regulator_disable(pw->avdd);

ov7695_avdd_fail:
gpio_set_value(CAM_RSTN, 0);
/* put CSIE IOs into DPD mode to save additional power for ardbeg */
tegra_io_dpd_enable(&csie_io);
return -ENODEV;
}

static int ardbeg_ov7695_power_off(struct ov7695_power_rail pw)
{
if (unlikely(WARN_ON(!pw || !pw->avdd || !pw->iovdd))) {
/
put CSIE IOs into DPD mode to
* save additional power for ardbeg
*/
tegra_io_dpd_enable(&csie_io);
return -EFAULT;
}
usleep_range(100, 120);

gpio_set_value(CAM2_PWDN, 0);
usleep_range(100, 120);

regulator_disable(pw->iovdd);
usleep_range(100, 120);

regulator_disable(pw->avdd);

/* put CSIE IOs into DPD mode to save additional power for ardbeg */
tegra_io_dpd_enable(&csie_io);
return 0;

}

struct ov7695_platform_data ardbeg_ov7695_pdata = {
.power_on = ardbeg_ov7695_power_on,
.power_off = ardbeg_ov7695_power_off,
.mclk_name = “mclk2”,
};

static int ardbeg_mt9m114_power_on(struct mt9m114_power_rail *pw)
{
int err;
if (unlikely(!pw || !pw->avdd || !pw->iovdd))
return -EFAULT;

/* disable CSIE IOs DPD mode to turn on front camera for ardbeg */
tegra_io_dpd_disable(&csie_io);

gpio_set_value(CAM_RSTN, 0);
gpio_set_value(CAM2_PWDN, 1);
usleep_range(1000, 1020);

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

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

usleep_range(1000, 1020);
gpio_set_value(CAM_RSTN, 1);
gpio_set_value(CAM2_PWDN, 0);
usleep_range(1000, 1020);

/* return 1 to skip the in-driver power_on swquence */
return 1;

mt9m114_avdd_fail:
regulator_disable(pw->iovdd);

mt9m114_iovdd_fail:
gpio_set_value(CAM_RSTN, 0);
/* put CSIE IOs into DPD mode to save additional power for ardbeg */
tegra_io_dpd_enable(&csie_io);
return -ENODEV;
}

static int ardbeg_mt9m114_power_off(struct mt9m114_power_rail pw)
{
if (unlikely(!pw || !pw->avdd || !pw->iovdd)) {
/
put CSIE IOs into DPD mode to
* save additional power for ardbeg
*/
tegra_io_dpd_enable(&csie_io);
return -EFAULT;
}

usleep_range(100, 120);
gpio_set_value(CAM_RSTN, 0);
usleep_range(100, 120);
regulator_disable(pw->avdd);
usleep_range(100, 120);
regulator_disable(pw->iovdd);

/* put CSIE IOs into DPD mode to save additional power for ardbeg */
tegra_io_dpd_enable(&csie_io);
return 1;

}

struct mt9m114_platform_data ardbeg_mt9m114_pdata = {
.power_on = ardbeg_mt9m114_power_on,
.power_off = ardbeg_mt9m114_power_off,
.mclk_name = “mclk2”,
};

static int ardbeg_ov5693_power_on(struct ov5693_power_rail *pw)
{
int err;

if (unlikely(WARN_ON(!pw || !pw->dovdd || !pw->avdd)))
	return -EFAULT;

/* disable CSIA/B IOs DPD mode to turn on camera for ardbeg */
tegra_io_dpd_disable(&csia_io);
tegra_io_dpd_disable(&csib_io);

if (ardbeg_get_extra_regulators())
	goto ov5693_poweron_fail;

gpio_set_value(CAM1_PWDN, 0);
usleep_range(10, 20);

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

err = regulator_enable(pw->dovdd);
if (err)
	goto ov5693_iovdd_fail;

udelay(2);
gpio_set_value(CAM1_PWDN, 1);

err = regulator_enable(ardbeg_vcmvdd);
if (unlikely(err))
	goto ov5693_vcmvdd_fail;

usleep_range(1000, 1110);

return 0;

ov5693_vcmvdd_fail:
regulator_disable(pw->dovdd);

ov5693_iovdd_fail:
regulator_disable(pw->avdd);

ov5693_avdd_fail:
gpio_set_value(CAM1_PWDN, 0);

ov5693_poweron_fail:
/* put CSIA/B IOs into DPD mode to save additional power for ardbeg */
tegra_io_dpd_enable(&csia_io);
tegra_io_dpd_enable(&csib_io);
pr_err("%s FAILED\n", func);
return -ENODEV;
}

static int ardbeg_ov5693_power_off(struct ov5693_power_rail pw)
{
if (unlikely(WARN_ON(!pw || !pw->dovdd || !pw->avdd))) {
/
put CSIA/B IOs into DPD mode to
* save additional power for ardbeg
*/
tegra_io_dpd_enable(&csia_io);
tegra_io_dpd_enable(&csib_io);
return -EFAULT;
}

usleep_range(21, 25);
gpio_set_value(CAM1_PWDN, 0);
udelay(2);

regulator_disable(ardbeg_vcmvdd);
regulator_disable(pw->dovdd);
regulator_disable(pw->avdd);

/* put CSIA/B IOs into DPD mode to save additional power for ardbeg */
tegra_io_dpd_enable(&csia_io);
tegra_io_dpd_enable(&csib_io);
return 0;

}

static struct nvc_gpio_pdata ov5693_gpio_pdata = {
{ OV5693_GPIO_TYPE_PWRDN, CAM1_PWDN, true, 0, },
};

#define NV_GUID(a, b, c, d, e, f, g, h)
((u64) ((((a)&0xffULL) << 56ULL) | (((b)&0xffULL) << 48ULL) |
((©&0xffULL) << 40ULL) | (((d)&0xffULL) << 32ULL) |
(((e)&0xffULL) << 24ULL) | (((f)&0xffULL) << 16ULL) |
(((g)&0xffULL) << 8ULL) | (((h)&0xffULL))))

static struct nvc_imager_cap ov5693_cap = {
.identifier = “OV5693”,
.sensor_nvc_interface = 3,
.pixel_types[0] = 0x101,
.orientation = 0,
.direction = 0,
.initial_clock_rate_khz = 6000,
.clock_profiles[0] = {
.external_clock_khz = 24000,
.clock_multiplier = 8000000, /* value * 1000000 */
},
.clock_profiles[1] = {
.external_clock_khz = 0,
.clock_multiplier = 0,
},
.h_sync_edge = 0,
.v_sync_edge = 0,
.mclk_on_vgp0 = 0,
.csi_port = 0,
.data_lanes = 2,
.virtual_channel_id = 0,
.discontinuous_clk_mode = 1,
.cil_threshold_settle = 0,
.min_blank_time_width = 16,
.min_blank_time_height = 16,
.preferred_mode_index = 0,
.focuser_guid =
NV_GUID(‘f’, ‘’, ‘A’, ‘D’, ‘5’, ‘8’, ‘2’, ‘3’),
.torch_guid =
NV_GUID(‘l’, '
’, ‘N’, ‘V’, ‘C’, ‘A’, ‘M’, ‘0’),
.cap_version = NVC_IMAGER_CAPABILITIES_VERSION2,
.flash_control_enabled = 0,
.adjustable_flash_timing = 0,
.is_hdr = 1,
};

static struct ov5693_platform_data ardbeg_ov5693_pdata = {
.gpio_count = ARRAY_SIZE(ov5693_gpio_pdata),
.gpio = ov5693_gpio_pdata,
.power_on = ardbeg_ov5693_power_on,
.power_off = ardbeg_ov5693_power_off,
.dev_name = “ov5693”,
.cap = &ov5693_cap,
.mclk_name = “mclk”,
.regulators = {
.avdd = “avdd_ov5693”,
.dvdd = “dvdd”,
.dovdd = “dovdd”,
},
.has_eeprom = 1,
};

static int ardbeg_ov5693_front_power_on(struct ov5693_power_rail *pw)
{
int err;

if (unlikely(WARN_ON(!pw || !pw->dovdd || !pw->avdd)))
	return -EFAULT;

if (ardbeg_get_extra_regulators())
	goto ov5693_front_poweron_fail;

gpio_set_value(CAM2_PWDN, 0);
gpio_set_value(CAM_RSTN, 0);
usleep_range(10, 20);

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

err = regulator_enable(pw->dovdd);
if (err)
	goto ov5693_front_iovdd_fail;

udelay(2);
gpio_set_value(CAM2_PWDN, 1);
gpio_set_value(CAM_RSTN, 1);

err = regulator_enable(ardbeg_vcmvdd);
if (unlikely(err))
	goto ov5693_front_vcmvdd_fail;

usleep_range(1000, 1110);

return 0;

ov5693_front_vcmvdd_fail:
regulator_disable(pw->dovdd);

ov5693_front_iovdd_fail:
regulator_disable(pw->avdd);

ov5693_front_avdd_fail:
gpio_set_value(CAM2_PWDN, 0);
gpio_set_value(CAM_RSTN, 0);

ov5693_front_poweron_fail:
pr_err("%s FAILED\n", func);
return -ENODEV;
}

static int ardbeg_ov5693_front_power_off(struct ov5693_power_rail *pw)
{
if (unlikely(WARN_ON(!pw || !pw->dovdd || !pw->avdd))) {
return -EFAULT;
}

usleep_range(21, 25);
gpio_set_value(CAM2_PWDN, 0);
gpio_set_value(CAM_RSTN, 0);
udelay(2);

regulator_disable(ardbeg_vcmvdd);
regulator_disable(pw->dovdd);
regulator_disable(pw->avdd);

return 0;

}

static struct nvc_gpio_pdata ov5693_front_gpio_pdata = {
{ OV5693_GPIO_TYPE_PWRDN, CAM2_PWDN, true, 0, },
{ OV5693_GPIO_TYPE_PWRDN, CAM_RSTN, true, 0, },
};

static struct nvc_imager_cap ov5693_front_cap = {
.identifier = “OV5693.1”,
.sensor_nvc_interface = 4,
.pixel_types[0] = 0x101,
.orientation = 0,
.direction = 1,
.initial_clock_rate_khz = 6000,
.clock_profiles[0] = {
.external_clock_khz = 24000,
.clock_multiplier = 8000000, /* value * 1000000 */
},
.clock_profiles[1] = {
.external_clock_khz = 0,
.clock_multiplier = 0,
},
.h_sync_edge = 0,
.v_sync_edge = 0,
.mclk_on_vgp0 = 0,
.csi_port = 1,
.data_lanes = 2,
.virtual_channel_id = 0,
.discontinuous_clk_mode = 1,
.cil_threshold_settle = 0,
.min_blank_time_width = 16,
.min_blank_time_height = 16,
.preferred_mode_index = 0,
.focuser_guid = 0,
.torch_guid = 0,
.cap_version = NVC_IMAGER_CAPABILITIES_VERSION2,
.flash_control_enabled = 0,
.adjustable_flash_timing = 0,
.is_hdr = 1,
};

static struct ov5693_platform_data ardbeg_ov5693_front_pdata = {
.gpio_count = ARRAY_SIZE(ov5693_front_gpio_pdata),
.gpio = ov5693_front_gpio_pdata,
.power_on = ardbeg_ov5693_front_power_on,
.power_off = ardbeg_ov5693_front_power_off,
.dev_name = “ov5693.1”,
.mclk_name = “mclk2”,
.cap = &ov5693_front_cap,
.regulators = {
.avdd = “vana”,
.dvdd = “vdig”,
.dovdd = “vif”,
},
.has_eeprom = 0,
};

static int ardbeg_ad5823_power_on(struct ad5823_platform_data *pdata)
{
int err = 0;

pr_info("%s\n", __func__);
gpio_set_value_cansleep(pdata->gpio, 1);
pdata->pwr_dev = AD5823_PWR_DEV_ON;

return err;

}

static int ardbeg_ad5823_power_off(struct ad5823_platform_data *pdata)
{
pr_info("%s\n", func);
gpio_set_value_cansleep(pdata->gpio, 0);
pdata->pwr_dev = AD5823_PWR_DEV_OFF;

return 0;

}

static struct ad5823_platform_data ardbeg_ad5823_pdata = {
.gpio = CAM_AF_PWDN,
.power_on = ardbeg_ad5823_power_on,
.power_off = ardbeg_ad5823_power_off,
};

static struct camera_data_blob ardbeg_camera_lut = {
{“ardbeg_imx135_pdata”, &ardbeg_imx135_data},
{“ardbeg_ov2710_pdata”, &ardbeg_ov2710_data},
{“ardbeg_dw9718_pdata”, &ardbeg_dw9718_data},
{“ardbeg_ar0261_pdata”, &ardbeg_ar0261_data},
{“ardbeg_mt9m114_pdata”, &ardbeg_mt9m114_pdata},
{“ardbeg_ov5693_pdata”, &ardbeg_ov5693_pdata},
{“ardbeg_ad5823_pdata”, &ardbeg_ad5823_pdata},
{“ardbeg_as3648_pdata”, &ardbeg_as3648_data},
{“ardbeg_ov7695_pdata”, &ardbeg_ov7695_pdata},
{“ardbeg_ov5693f_pdata”, &ardbeg_ov5693_front_pdata},
{“ardbeg_ar0330_pdata”, &ardbeg_ar0330_data},
{“ardbeg_ar0330_front_pdata”, &ardbeg_ar0330_front_data},
{},
};

void __init ardbeg_camera_auxdata(void *data)
{
struct of_dev_auxdata *aux_lut = data;
while (aux_lut && aux_lut->compatible) {
if (!strcmp(aux_lut->compatible, “nvidia,tegra124-camera”)) {
pr_info("%s: update camera lookup table.\n", func);
aux_lut->platform_data = ardbeg_camera_lut;
}
aux_lut++;
}
}

static int ardbeg_camera_init(void)
{
struct board_info board_info;

pr_debug("%s: ++\n", __func__);
tegra_get_board_info(&board_info);

/* put CSIA/B/C/D/E IOs into DPD mode to
 * save additional power for ardbeg
 */
tegra_io_dpd_enable(&csia_io);
tegra_io_dpd_enable(&csib_io);
tegra_io_dpd_enable(&csie_io);

#if IS_ENABLED(CONFIG_SOC_CAMERA_PLATFORM)
platform_device_register(&ardbeg_soc_camera_device);
#endif

#if IS_ENABLED(CONFIG_SOC_CAMERA_IMX135)
platform_device_register(&ardbeg_imx135_soc_camera_device);
#endif

#if IS_ENABLED(CONFIG_SOC_CAMERA_AR0261)
platform_device_register(&ardbeg_ar0261_soc_camera_device);
#endif

#if IS_ENABLED(CONFIG_SOC_CAMERA_OV2710)
platform_device_register(&ardbeg_ov2710_s

Sorry about that

Leno11t,

Not very clear about why you pasted the source file here, and what is your issue?

Sorry, I forget wrote my issues.
So when I make modprobe tegra_camera, this module also load my driver ov2710_v4l2.
So now I stack on ov2710_probe. Module loading stack on

ret = ov2710_read_reg(client, 0x300A, &chipid[0]);

This I can see on dmesg with error mesg something like “tegra-i2c: No acknowledge from 0x36”…
On an oscilloscope, I see how line SDA and SCL goes from HI level to LOW, but newer gets to HI back. Ewen when I make rmmod to tegra_camera and ov2710_v4l2.
I no idea why i2c behaves like that.

[  526.494022] START OV2710 Probe
[  526.497297] GET SENSOR ID
[  526.504160] tegra-i2c tegra12-i2c.2: no acknowledge from address 0x36
[  526.504226] ov2710_v4l2 2-0036: ov2710_read_reg: i2c read error, reg: 300a
[  526.511173] Camera High: 3928931268
[  526.514673] ov2710_v4l2 2-0036: Failure to read Chip ID (high byte)
[  526.521105] tegra-i2c tegra12-i2c.2: no acknowledge from address 0x36
[  526.521162] ov2710_v4l2 2-0036: ov2710_read_reg: i2c read error, reg: 300b
[  526.528033] Camera Low: 3928931269
[  526.531504] ov2710_v4l2 2-0036: Failure to read Chip ID (low byte)
[  526.537680] Camera ID: 9382
[  526.540559] ov2710_v4l2 2-0036: Chip ID: 24a6 not supported!
[  526.546932] END PROBE!
[  526.549405] vi vi.0: Not supporting mbus format code 0x3014
[  526.550127] vi vi.0: Supporting mbus format code 0x300f using Bayer 8 BGBG.. GRGR..
[  526.550137] vi vi.0: Supporting mbus format code 0x300f using Bayer 8 GBGB.. RGRG..
[  526.550142] vi vi.0: Supporting mbus format code 0x300f using Bayer 10 BGBG.. GRGR..
[  526.550155] vi vi.0: Supporting mbus format code 0x300f using Bayer 10 RGRG.. GBGB..
[  526.550161] vi vi.0: Not supporting mbus format code 0x3014
[  526.552648] vi vi.1: initialized
[  526.554131] vi vi.0: Tegra camera driver loaded.
[  526.554449] vi vi.1: Tegra camera driver loaded.

i2c error can be resulted by many reasons, such as, power sequence, hw connection, or sw configuration(if you specify the correct i2c bus), mclk and etc. You can refer to the sensor and module specification for detailed requirement.

I solved this issues with i2c.
So now I can’t change mclk from Camera1 to Camera2. As I understand it should be “mclk2” - and I should change this parameter in “tegra124-pm359-camera-a00.dtsi” I make the changes in dtsi file, clear all device tree cache, build a new kernel and *.dtb device tree blob, change a kernel and dtb on my, and nothing’s happened. After reboot I try to start “sudo modprobe tegra_camera”, but clock signal steel generated for Camera1
How to change clock signal to Camera2?

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

/ {
	camera-pcl {
		compatible = "nvidia,tegra124-camera", "simple-bus";
		configuration = <0xAA55AA55>;

		modules {
			module1: module1@modules {
				/* Camera Module NVD9A951 */
				compatible = "sensor,front";
				badge_info = "pm359_erss_front_D9A951";

				sensor {
					profile = <&imx135_1>;
					platformdata = "ardbeg_imx135_pdata";
				};
				focuser {
					profile = <&dw9718_1>;
					platformdata = "ardbeg_dw9718_pdata";
				};
				flash {
					profile = <&as3648_1>;
					platformdata = "ardbeg_as3648_pdata";
				};
			};
			module3: module3@modules {
				compatible = "sensor,rear";
				badge_info = "e1633_rear_camera";

				sensor {
					profile = <&ar0330_1>;
					platformdata = "ardbeg_ar0330_pdata";
				};
			};
			module4: module4@modules {
				compatible = "sensor,front";
				badge_info = "e1633_front_camera";

				sensor {
					profile = <&ar0330_2>;
					platformdata = "ardbeg_ar0330_front_pdata";
				};
			};
			module5: module5@modules {
				compatible = "sensor,rear";
				badge_info = "e1793_rear_camera";

				sensor {
					profile = <&ov2710_1>;
					platformdata = "ardbeg_ov2710_pdata";
				};
			};				
		};
		profiles {
			imx135_1: imx135@2_0036 {
				index = <1>;
				chipname = "pcl_IMX135";
				type = "sensor";
				guid = "s_IMX135";
				position = <0>;
				bustype = "i2c";
				busnum = <2>;
				addr = <0x36>;
				datalen = <2>;
				pinmuxgrp = <0xFFFF>;
				gpios = <3>;
				regulators = "vana", "vdig_lv", "vif";
				clocks = "mclk";
				drivername = "imx135";
				detect = <0x0002 0x300A 0xFFFF 0x2710>;
				devid = <0x2710>;
				poweron = <
					CAMERA_IND_CLK_SET(10000)
					CAMERA_GPIO_CLR(221)
					CAMERA_WAITUS(10)
					CAMERA_REGULATOR_ON(2)
					CAMERA_REGULATOR_ON(1)
					CAMERA_REGULATOR_ON(0)
					CAMERA_WAITMS(5)
					CAMERA_GPIO_SET(221)
					CAMERA_WAITUS(300)
					CAMERA_END
					>;
				poweroff = <
					CAMERA_IND_CLK_CLR
					CAMERA_GPIO_CLR(221)
					CAMERA_WAITUS(10)
					CAMERA_REGULATOR_OFF(2)
					CAMERA_REGULATOR_OFF(1)
					CAMERA_REGULATOR_OFF(0)
					CAMERA_END
					>;
			};
			dw9718_1: dw9718@2_000c {
				index = <2>;
				chipname = "pcl_DW9718";
				type = "focuser";
				guid = "f_NVCAM0";
				position = <0>;
				bustype = "i2c";
				busnum = <2>;
				addr = <0xc>;
				datalen = <1>;
				pinmuxgrp = <0xFFFF>;
				gpios = <3>;
				regulators = "vdd", "vdd_i2c";
				drivername = "dw9718";
				detect = <0x0002 0x0004 0xFFFF 0x0060>;
				devid = <0x9718>;
				poweron = <
					CAMERA_REGULATOR_ON(1)
					CAMERA_REGULATOR_ON(0)
					CAMERA_WAITUS(10)
					CAMERA_GPIO_SET(223)
					CAMERA_WAITUS(10)
					CAMERA_END
					>;
				poweroff = <
					CAMERA_REGULATOR_OFF(0)
					CAMERA_REGULATOR_OFF(1)
					CAMERA_GPIO_CLR(223)
					CAMERA_WAITUS(10)
					CAMERA_END
					>;
			};
			as3648_1: as3648@2_0030 {
				index = <6>;
				chipname = "pcl_AS3648";
				type = "flash";
				guid = "l_NVCAM0";
				position = <0>;
				bustype = "i2c";
				busnum = <2>;
				addr = <0x30>;
				datalen = <1>;
				pinmuxgrp = <0xFFFF>;
				gpios = <3>;
				regulators = "vi2c", "vin";
				drivername = "as3648";
				detect = <0x0001 0x0000 0x00F0 0x00b0>;
				devid = <0x3648>;
				poweron = <
					CAMERA_REGULATOR_ON(1)
					CAMERA_REGULATOR_ON(0)
					CAMERA_WAITUS(1000)
					CAMERA_END
					>;
				poweroff = <
					CAMERA_REGULATOR_OFF(0)
					CAMERA_REGULATOR_OFF(1)
					CAMERA_WAITUS(10)
					CAMERA_END
					>;
			};
			ar0261_1: ar0261@2_0036 {
				index = <3>;
				chipname = "pcl_AR0261";
				type = "sensor";
				guid = "s_AR0261";
				position = <1>;
				bustype = "i2c";
				busnum = <2>;
				addr = <0x36>;
				datalen = <2>;
				pinmuxgrp = <0xFFFF>;
				gpios = <3>;
				regulators = "vana", "vdig", "vif";
				clocks = "mclk2";
				drivername = "ar0261";
				detect = <0x0002 0x0003 0xFFFF 0x060A>;
				devid = <0x0261>;
				poweron = <
					CAMERA_IND_CLK_SET(10000)
					CAMERA_GPIO_CLR(219)
					CAMERA_REGULATOR_ON(0)
					CAMERA_REGULATOR_ON(1)
					CAMERA_REGULATOR_ON(2)
					CAMERA_WAITMS(40)
					CAMERA_GPIO_SET(219)
					CAMERA_WAITMS(20)
					CAMERA_END
					>;
				poweroff = <
					CAMERA_IND_CLK_CLR
					CAMERA_GPIO_CLR(219)
					CAMERA_WAITUS(10)
					CAMERA_REGULATOR_OFF(2)
					CAMERA_REGULATOR_OFF(1)
					CAMERA_REGULATOR_OFF(0)
					CAMERA_END
					>;
			};
			ov2710_1: ov2710@2_0036 {
				index = <7>;
				chipname = "pcl_OV2710";
				type = "sensor";
				guid = "s_OV2710";
				position = <1>;
				bustype = "i2c";
				busnum = <2>;
				addr = <0x36>;
				datalen = <2>;
				pinmuxgrp = <0xFFFF>;
				gpios = <3>;
				regulators = "vana", "vif";
				clocks = "mclk2";
				drivername = "ov2710";
				detect = <0x0002 0x300A 0xFFFF 0x2710>;
				devid = <0x2710>;
				poweron = <
					CAMERA_IND_CLK_SET(10000)
					CAMERA_GPIO_CLR(219)
					CAMERA_REGULATOR_ON(0)
					CAMERA_REGULATOR_ON(1)
					CAMERA_WAITMS(40)
					CAMERA_GPIO_SET(219)
					CAMERA_WAITMS(20)
					CAMERA_END
					>;
				poweroff = <
					CAMERA_IND_CLK_CLR
					CAMERA_GPIO_CLR(219)
					CAMERA_WAITUS(10)
					CAMERA_REGULATOR_OFF(1)
					CAMERA_REGULATOR_OFF(0)
					CAMERA_END
					>;
			};

			ar0330_1: ar0330@2_0018 {
				index = <4>;
				chipname = "pcl_AR0330";
				type = "sensor";
				guid = "s_AR0330";
				position = <0>;
				bustype = "i2c";
				busnum = <2>;
				addr = <0x18>;
				datalen = <2>;
				pinmuxgrp = <0xFFFF>;
				gpios = <3>;
				regulators = "vana", "vdig", "vif";
				clocks = "mclk";
				drivername = "ar0330";
				detect = <0x0002 0x3000 0xFFFF 0x2604>;
				devid = <0x0330>;
				poweron = <
					CAMERA_IND_CLK_SET(10000)
					CAMERA_GPIO_CLR(221)
					CAMERA_GPIO_CLR(222)
					CAMERA_REGULATOR_ON(0)
					CAMERA_WAITMS(10)
					CAMERA_REGULATOR_ON(1)
					CAMERA_REGULATOR_ON(2)
					CAMERA_WAITMS(40)
					CAMERA_GPIO_SET(221)
					CAMERA_GPIO_SET(222)
					CAMERA_WAITMS(20)
					CAMERA_END
					>;
				poweroff = <
					CAMERA_IND_CLK_CLR
					CAMERA_GPIO_CLR(221)
					CAMERA_GPIO_CLR(222)
					CAMERA_WAITUS(10)
					CAMERA_REGULATOR_OFF(2)
					CAMERA_REGULATOR_OFF(1)
					CAMERA_REGULATOR_OFF(0)
					CAMERA_END
					>;
			};
			ar0330_2: ar0330@2_0010 {
				index = <5>;
				chipname = "pcl_AR0330";
				type = "sensor";
				guid = "sAR0330f";
				position = <1>;
				bustype = "i2c";
				busnum = <2>;
				addr = <0x10>;
				datalen = <2>;
				pinmuxgrp = <0xFFFF>;
				gpios = <3>;
				regulators = "vana", "vdig", "vif";
				clocks = "mclk2";
				drivername = "ar0330";
				detect = <0x0002 0x3000 0xFFFF 0x2604>;
				devid = <0x0330>;
				poweron = <
					CAMERA_IND_CLK_SET(10000)
					CAMERA_GPIO_CLR(221)
					CAMERA_GPIO_CLR(222)
					CAMERA_REGULATOR_ON(0)
					CAMERA_WAITMS(10)
					CAMERA_REGULATOR_ON(1)
					CAMERA_REGULATOR_ON(2)
					CAMERA_WAITMS(40)
					CAMERA_GPIO_SET(221)
					CAMERA_GPIO_SET(222)
					CAMERA_WAITMS(20)
					CAMERA_END
					>;
				poweroff = <
					CAMERA_IND_CLK_CLR
					CAMERA_GPIO_CLR(221)
					CAMERA_GPIO_CLR(222)
					CAMERA_WAITUS(10)
					CAMERA_REGULATOR_OFF(2)
					CAMERA_REGULATOR_OFF(1)
					CAMERA_REGULATOR_OFF(0)
					CAMERA_END
					>;
			};
		};
	};
};

And what mean “badge_info = “e1793_rear_camera”;” and “position = <1>;” and what parameter I must use?

You can print mclk_name to check you are enable the mclk or mclk2 in the probe function.
If you want to apply the clock from the DT you have to assign the mclk_name in the parse_dt().
The badge_info and position are used by non v4l2 soc camera driver.

static int ov2710_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
{
printk(KERN_CRIT "START OV2710 Probe\n");

	struct ov2710_info *priv;
	const char *mclk_name;
	int err;
	u8 chipid[2];
	int ret;

	priv = devm_kzalloc(&client->dev,
			sizeof(struct ov2710_info), GFP_KERNEL);
	if (!priv) {
		dev_err(&client->dev, "unable to allocate memory!\n");
		return -ENOMEM;
	}

	if (client->dev.of_node)
		priv->pdata = ov2710_parse_dt(client);
	else
		priv->pdata = client->dev.platform_data;

	if (!priv->pdata) {
		dev_err(&client->dev, "unable to get platform data\n");
		return -EFAULT;
	}
        .
        .
        .
        .
	mclk_name = priv->pdata->mclk_name ?
		    priv->pdata->mclk_name : "default_mclk";
	priv->mclk = devm_clk_get(&client->dev, mclk_name);
	if (IS_ERR(priv->mclk)) {
		dev_err(&client->dev, "unable to get clock %s\n", mclk_name);
		return PTR_ERR(priv->mclk);
	}
        .
        .
        .
        .

	v4l2_i2c_subdev_init(&priv->subdev, client, &ov2710_subdev_ops);
printk(KERN_CRIT "END PROBE!\n");

	return 0;
}

Hi,can you tell where to get ov2710_v4l2.c file(also media/ov2710.h), I can’t find in google.

Thanks you

There is no driver for this module and Tegra K1. A few years ago I and my team work on this driver and we even capture the frame from ov2710 module, but on next day the project was closed by customer. Now I don’t have access to repo. You can try to use code pasted in this thread