This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Linux/PROCESSOR-SDK-AM57X: OV10635 capture issue

Part Number: PROCESSOR-SDK-AM57X


Tool/software: Linux

Hi all,

I am using latest linux processor sdk am57xx with ov10635 camera module.

I did some changes in driver code similar to mt9t11x.c.

Probing is done. The driver is registered. But while using yavta command, it only gives-

Device /dev/video1 opened.
Device `vip' on `platform:vip' is a video output (without mplanes) device.
Video format set: YUYV (56595559) 640x480 (stride 1280) field none buffer size 614400
Video format: YUYV (56595559) 640x480 (stride 1280) field none buffer size 614400
8 buffers requested.
length: 614400 offset: 0 timestamp type/source: mono/EoF
Buffer 0/0 mapped at address 0xb6e27000.
length: 614400 offset: 614400 timestamp type/source: mono/EoF
Buffer 1/0 mapped at address 0xb6d91000.
length: 614400 offset: 1228800 timestamp type/source: mono/EoF
Buffer 2/0 mapped at address 0xb6cfb000.
length: 614400 offset: 1843200 timestamp type/source: mono/EoF
Buffer 3/0 mapped at address 0xb6c65000.
length: 614400 offset: 2457600 timestamp type/source: mono/EoF
Buffer 4/0 mapped at address 0xb6bcf000.
length: 614400 offset: 3072000 timestamp type/source: mono/EoF
Buffer 5/0 mapped at address 0xb6b39000.
length: 614400 offset: 3686400 timestamp type/source: mono/EoF
Buffer 6/0 mapped at address 0xb6aa3000.
length: 614400 offset: 4300800 timestamp type/source: mono/EoF
Buffer 7/0 mapped at address 0xb6a0d000.

I also enable all logs but there are no error displayed.

Please find the driver code if there is any requirement for checking my changes.

/*
 * OmniVision OV1063X Camera Driver
 *
 * Based on the original driver written by Phil Edworthy.
 * Copyright (C) 2013 Phil Edworthy
 * Copyright (C) 2013 Renesas Electronics
 *
 * This driver has been tested at QVGA, VGA and 720p, and 1280x800 at up to
 * 30fps and it should work at any resolution in between and any frame rate
 * up to 30fps.
 *
 * FIXME:
 *  Horizontal flip (mirroring) does not work correctly. The image is flipped,
 *  but the colors are wrong.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 */
#define DEBUG

#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <linux/pm_runtime.h>
#include <linux/of_gpio.h>
#include <linux/of_device.h>

#include <linux/v4l2-mediabus.h>
#include <media/media-entity.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-event.h>
#include <media/v4l2-image-sizes.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-mediabus.h>
#include <media/v4l2-common.h>
#include <media/v4l2-of.h>

#include "ov1063x_regs.h"

/* Register definitions */
#define	OV1063X_VFLIP			0x381c
#define	 OV1063X_VFLIP_ON		(0x3 << 6)
#define	 OV1063X_VFLIP_SUBSAMPLE	0x1
#define	OV1063X_HMIRROR			0x381d
#define	 OV1063X_HMIRROR_ON		0x3
#define OV1063X_PID			0x300a
#define OV1063X_VER			0x300b

#define OV1063X_FORMAT_CTRL00		0x4300
#define   OV1063X_FORMAT_YUYV		0x38
#define   OV1063X_FORMAT_YYYU		0x39
#define   OV1063X_FORMAT_UYVY		0x3A
#define   OV1063X_FORMAT_VYUY		0x3B

/* IDs */
#define OV10633_VERSION_REG		0xa630
#define OV10635_VERSION_REG		0xa635
#define OV1063X_VERSION(pid, ver)	(((pid) << 8) | ((ver) & 0xff))

enum ov1063x_model {
	SENSOR_OV10633,
	SENSOR_OV10635,
};

#define OV1063X_SENSOR_WIDTH		1312
#define OV1063X_SENSOR_HEIGHT		814

#define OV1063X_MAX_WIDTH		1280
#define OV1063X_MAX_HEIGHT		800

#define MAX_NUM_GPIOS			20

struct ov1063x_color_format {
	u32 code;
	u32 colorspace;
};

struct ov1063x_framesize {
	u16 width;
	u16 height;
};

struct ov1063x_priv {
	struct v4l2_subdev		subdev;
	struct v4l2_async_subdev	asd;
	struct v4l2_ctrl_handler	hdl;
	int				model;
	int				revision;
	int				xvclk;
	/* Protects the struct fields below */
	struct mutex lock;

	int				fps_numerator;
	int				fps_denominator;
	int				power;
	int				streaming;

	struct v4l2_mbus_framefmt	format;
	int				width;
	int				height;

	struct gpio_desc		*powerdown_gpio;
	struct gpio			mux_gpios[MAX_NUM_GPIOS];
	int				num_gpios;
};

static int ov1063x_init_gpios(struct i2c_client *client);

static const struct ov1063x_framesize ov1063x_framesizes[] = {
	{
		.width		= 1280,
		.height		= 800,
	}, {
		.width		= 1280,
		.height		= 720,
	}, {
		.width		= 752,
		.height		= 480,
	}, {
		.width		= 640,
		.height		= 480,
	}, {
		.width		= 600,
		.height		= 400,
	}, {
		.width		= 352,
		.height		= 288,
	}, {
		.width		= 320,
		.height		= 240,
	},
};

/*
 * supported color format list
 */
static const struct ov1063x_color_format ov1063x_cfmts[] = {
//	{
//		.code		= MEDIA_BUS_FMT_YUYV8_2X8,
//		.colorspace	= V4L2_COLORSPACE_SMPTE170M,
//	},
	{
		.code		= MEDIA_BUS_FMT_UYVY8_2X8,
		.colorspace	= V4L2_COLORSPACE_SMPTE170M,
	},
//	{
//		.code		= MEDIA_BUS_FMT_VYUY8_2X8,
//		.colorspace	= V4L2_COLORSPACE_SMPTE170M,
//	},
//	{
//		.code		= MEDIA_BUS_FMT_YVYU8_2X8,
//		.colorspace	= V4L2_COLORSPACE_SMPTE170M,
//	},
//	{
//		.code		= MEDIA_BUS_FMT_YUYV10_2X10,
//		.colorspace	= V4L2_COLORSPACE_SMPTE170M,
//	},
};

static struct ov1063x_priv *to_ov1063x(const struct i2c_client *client)
{
	return container_of(i2c_get_clientdata(client), struct ov1063x_priv,
			subdev);
}

/* read a register */
static int ov1063x_reg_read(struct i2c_client *client, u16 reg, u8 *val)
{
//dev_err(&client->dev, "PS-SE Enter %s:", __func__);
	
	int ret;
	u8 data[2] = { reg >> 8, reg & 0xff };
	struct i2c_msg msg = {
		.addr	= client->addr,
		.flags	= 0,
		.len	= 2,
		.buf	= data,
	};

	ret = i2c_transfer(client->adapter, &msg, 1);
	if (ret < 0)
		goto err;

	msg.flags = I2C_M_RD;
	msg.len	= 1;
	msg.buf	= &data[0];

	ret = i2c_transfer(client->adapter, &msg, 1);
	if (ret < 0)
		goto err;

	*val = data[0];
//dev_err(&client->dev, "PS-SE Exit %s:\n", __func__);
	return 0;
err:
	dev_err(&client->dev, "Failed reading register 0x%04x!\n", reg);
	return ret;
}

/* write a register */
static int ov1063x_reg_write(struct i2c_client *client, u16 reg, u8 val)
{
//dev_err(&client->dev, "PS-SE Enter %s:", __func__);
	int ret;
	u8 data[3] = { reg >> 8, reg & 0xff, val };

	struct i2c_msg msg = {
		.addr	= client->addr,
		.flags	= 0,
		.len	= 3,
		.buf	= data,
	};

	ret = i2c_transfer(client->adapter, &msg, 1);
	if (ret < 0) {
		dev_err(&client->dev, "Failed writing register 0x%04x!\n", reg);
		return ret;
	}
//dev_err(&client->dev, "PS-SE Exit %s:\n", __func__);
	return 0;
}

static int ov1063x_reg_write16(struct i2c_client *client, u16 reg, u16 val)
{
	//dev_err(&client->dev, "PS-SE Enter %s:", __func__);
	int ret;

	ret = ov1063x_reg_write(client, reg, val >> 8);
	if (ret)
		return ret;

	ret = ov1063x_reg_write(client, reg + 1, val & 0xff);
	if (ret)
		return ret;
//dev_err(&client->dev, "PS-SE Exit %s:\n", __func__);
	return 0;
}

/* Read a register, alter its bits, write it back */
static int ov1063x_reg_rmw(struct i2c_client *client, u16 reg, u8 set, u8 unset)
{
//dev_err(&client->dev, "PS-SE Enter %s:", __func__);
	u8 val;
	int ret;

	ret = ov1063x_reg_read(client, reg, &val);
	if (ret) {
		dev_err(&client->dev,
			"[Read]-Modify-Write of register %04x failed!\n", reg);
		return ret;
	}

	val |= set;
	val &= ~unset;

	ret = ov1063x_reg_write(client, reg, val);
	if (ret)
		dev_err(&client->dev,
			"Read-Modify-[Write] of register %04x failed!\n", reg);
//dev_err(&client->dev, "PS-SE Exit %s:\n", __func__);
	return ret;
}

//changes
static void __ov1063x_set_power(struct i2c_client *client, int on)
{
//dev_err(&client->dev, "PS-SE Enter %s:", __func__);
int gpio_read;
	//struct i2c_client *client = v4l2_get_subdevdata(priv->subdev);
	struct ov1063x_priv *priv = i2c_get_clientdata(client);

	dev_dbg(&client->dev, "%s: on: %d\n", __func__, on);
	on = (on) ? 1 : 0;
	if (priv->power == on){
	printk("priv_power_on_returning\n");
		return;}
	if (on) {
		if (priv->powerdown_gpio){
			gpiod_set_value_cansleep(priv->powerdown_gpio, 1);
			gpio_read = gpiod_get_raw_value(priv->powerdown_gpio);
 			dev_err(&client->dev, "POWERDOWN_GPIO_After_IN_ON %d", gpio_read);			
			}
					

		usleep_range(25000, 26000);
	} else {
		if (priv->powerdown_gpio){
			gpiod_set_value_cansleep(priv->powerdown_gpio, 0);
			gpio_read = gpiod_get_raw_value(priv->powerdown_gpio);
 			dev_err(&client->dev, "POWERDOWN_GPIO_After_IN_OFF %d", gpio_read);
			}

	}
	//dev_err(&client->dev, "PS-SE Exit %s:\n", __func__);
	priv->power = on;
}

/* Start/Stop streaming from the device */
static int ov1063x_s_stream(struct v4l2_subdev *sd, int enable)
{
	
	struct i2c_client *client = v4l2_get_subdevdata(sd);
//change
	struct ov1063x_priv *priv = to_ov1063x(client);
//change
	int ret;
	//dev_err(&client->dev, "PS-SE Enter %s:", __func__);

	mutex_lock(&priv->lock);
	//if (priv->streaming == enable) {
//		mutex_unlock(&priv->lock);
	//	return 0;
	//}

	printk("Enable_stream\n");printk("%d\n",enable);

	//if (!enable) {
		/* Stop Streaming Sequence */
		//__ov1063x_set_power(client, 0);
	//	priv->streaming = enable;
	//	mutex_unlock(&priv->lock);printk("Enable_stream_return\n");
	//	return 0;
	//}
	//changes
	__ov1063x_set_power(client, 1);
	ret = ov1063x_init_gpios(client);
	if (ret) {
		dev_err(&client->dev, "Failed to request gpios");
		return ret;
	}
	
	ov1063x_reg_write(client, 0x0100, enable);

	if (enable){
		ov1063x_reg_write(client, 0x301c, 0xf0);
	//printk("enable_ov_reg_write\n");
	}
	else{
		ov1063x_reg_write(client, 0x301c, 0x70);
	//printk("disable_ov_reg_write\n");
	}

	//dev_err(&client->dev, "PS-SE Exit %s:\n", __func__);
	
	
	//priv->streaming = enable;
	mutex_unlock(&priv->lock);

	return 0;
}

/* Set status of additional camera capabilities */
static int ov1063x_s_ctrl(struct v4l2_ctrl *ctrl)
{

	struct ov1063x_priv *priv = container_of(ctrl->handler,
					struct ov1063x_priv, hdl);
	struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
	//dev_err(&client->dev, "PS-SE Enter %s:", __func__);
	
//	mutex_lock(&priv->lock);
	/*
	 * If the device is not powered up now, postpone applying control's
	 * value to the hardware, until it is ready to accept commands.
	 */
//	if (priv->power == 0) {
//		printk("priv->power\n");
//		mutex_unlock(&priv->lock);
//		return 0;
//	}

	switch (ctrl->id) {
	case V4L2_CID_VFLIP:
		if (ctrl->val)
			return ov1063x_reg_rmw(client, OV1063X_VFLIP,
				OV1063X_VFLIP_ON, 0);
		else
			return ov1063x_reg_rmw(client, OV1063X_VFLIP,
				0, OV1063X_VFLIP_ON);
		break;
	case V4L2_CID_HFLIP:
		if (ctrl->val)
			return ov1063x_reg_rmw(client, OV1063X_HMIRROR,
				OV1063X_HMIRROR_ON, 0);
		else
			return ov1063x_reg_rmw(client, OV1063X_HMIRROR,
				0, OV1063X_HMIRROR_ON);
		break;
	}
	//dev_err(&client->dev, "PS-SE Exit %s:\n", __func__);
//	mutex_unlock(&priv->lock);
	return -EINVAL;
}

/*
 * Get the best pixel clock (pclk) that meets minimum hts/vts requirements.
 * xvclk => pre-divider => clk1 => multiplier => clk2 => post-divider => pclk
 * We try all valid combinations of settings for the 3 blocks to get the pixel
 * clock, and from that calculate the actual hts/vts to use. The vts is
 * extended so as to achieve the required frame rate. The function also returns
 * the PLL register contents needed to set the pixel clock.
 */
static int ov1063x_get_pclk(int xvclk, int *htsmin, int *vtsmin,
			    int fps_numerator, int fps_denominator,
			    u8 *r3003, u8 *r3004)
{
	int pre_divs[] = { 2, 3, 4, 6, 8, 10, 12, 14 };
	int pclk;
	int best_pclk = INT_MAX;
	int best_hts = 0;
	int i, j, k;
	int best_i = 0, best_j = 0, best_k = 0;
	int clk1, clk2;
	int hts;
//printk("PS-SE Enter, ov1063x_get_pclk\n");
	/* Pre-div, reg 0x3004, bits 6:4 */
	for (i = 0; i < ARRAY_SIZE(pre_divs); i++) {
		clk1 = (xvclk / pre_divs[i]) * 2;

		if ((clk1 < 3000000) || (clk1 > 27000000))
			continue;

		/* Mult = reg 0x3003, bits 5:0 */
		for (j = 1; j < 32; j++) {
			clk2 = (clk1 * j);

			if ((clk2 < 200000000) || (clk2 > 500000000))
				continue;

			/* Post-div, reg 0x3004, bits 2:0 */
			for (k = 0; k < 8; k++) {
				pclk = clk2 / (2 * (k + 1));

				if (pclk > 96000000)
					continue;

				hts = *htsmin + 200 + pclk / 300000;

				/* 2 clock cycles for every YUV422 pixel */
				if (pclk < (((hts * *vtsmin) / fps_denominator)
					* fps_numerator * 2))
					continue;

				if (pclk < best_pclk) {
					best_pclk = pclk;
					best_hts = hts;
					best_i = i;
					best_j = j;
					best_k = k;
				}
			}
		}
	}

	/* register contents */
	*r3003 = (u8)best_j;
	*r3004 = ((u8)best_i << 4) | (u8)best_k;

	/* Did we get a valid PCLK? */
	if (best_pclk == INT_MAX)
		return -1;

	*htsmin = best_hts;

	/* Adjust vts to get as close to the desired frame rate as we can */
	*vtsmin = best_pclk / ((best_hts / fps_denominator) *
		  fps_numerator * 2);
//printk("PS-SE Exit, ov1063x_get_pclk\n");
	return best_pclk;
}

static int ov1063x_set_regs(struct i2c_client *client,
			    const struct ov1063x_reg *regs, int nr_regs)
{
//dev_err(&client->dev, "PS-SE Enter %s:", __func__);
	int i, ret;
	u8 val;
	for (i = 0; i < nr_regs; i++) {
		if (regs[i].reg == 0x300c) {
			val = ((client->addr * 2) | 0x1);
			//printk("val\n");//printk("%d\n",val);
			ret = ov1063x_reg_write(client, regs[i].reg, val);
			//printk("ov1063x_reg_write ret value\n");//printk("%d\n", ret);
			if (ret)
				return ret;
		} else {
			ret = ov1063x_reg_write(client, regs[i].reg,
						regs[i].val);
			//printk("ov1063x_reg_write in else\n");//printk("%d\n",ret);
			if (ret)
				return ret;
		}
	}
//dev_err(&client->dev, "PS-SE Exit %s:\n", __func__);
	return 0;
}

/* Setup registers according to resolution and color encoding */
static int ov1063x_set_params(struct i2c_client *client, u32 width, u32 height)
{
//dev_err(&client->dev, "PS-SE Enter %s:", __func__);
	struct ov1063x_priv *priv = to_ov1063x(client);
	int ret = -EINVAL;
	int pclk;
	int hts, vts;
	u8 r3003, r3004, r4300;
	int tmp;
	u32 height_pre_subsample;
	u32 width_pre_subsample;
	u8 horiz_crop_mode;
	int nr_isp_pixels;
	int vert_sub_sample = 0;
	int horiz_sub_sample = 0;
	int sensor_width;
	int tmp_array_size;

	if ((width > OV1063X_MAX_WIDTH) || (height > OV1063X_MAX_HEIGHT))
		return ret;

	priv->width = width;
	priv->height = height;

	/* Vertical sub-sampling? */
	height_pre_subsample = priv->height;
	if (priv->height <= 400) {
		vert_sub_sample = 1;
		height_pre_subsample <<= 1;
	}

	/* Horizontal sub-sampling? */
	width_pre_subsample = priv->width;
	if (priv->width <= 640) {
		horiz_sub_sample = 1;
		width_pre_subsample <<= 1;
	}

	/* Horizontal cropping */
	if (width_pre_subsample > 768) {
		sensor_width = OV1063X_SENSOR_WIDTH;
		horiz_crop_mode = 0x63;
	} else if (width_pre_subsample > 656) {
		sensor_width = 768;
		horiz_crop_mode = 0x6b;
	} else {
		sensor_width = 656;
		horiz_crop_mode = 0x73;
	}

	/* minimum values for hts and vts */
	hts = sensor_width;
	vts = height_pre_subsample + 50;
	dev_dbg(&client->dev, "fps=(%d/%d), hts=%d, vts=%d\n",
		priv->fps_numerator, priv->fps_denominator, hts, vts);

	/* Get the best PCLK & adjust hts,vts accordingly */
	pclk = ov1063x_get_pclk(priv->xvclk, &hts, &vts, priv->fps_numerator,
				priv->fps_denominator, &r3003, &r3004);
	if (pclk < 0)
		return ret;
	dev_dbg(&client->dev, "pclk=%d, hts=%d, vts=%d\n", pclk, hts, vts);
	dev_dbg(&client->dev, "r3003=0x%X r3004=0x%X\n", r3003, r3004);

	/* Disable ISP & program all registers that we might modify */
	ret = ov1063x_set_regs(client, ov1063x_regs_change_mode,
			       ARRAY_SIZE(ov1063x_regs_change_mode));
	if (ret){
		//printk("ov1063x_set_regs_ret_set\n");
		return ret;}

	/* Set to 1280x720 */
	
	ret = ov1063x_reg_write(client, 0x380f, 0x80);

	if (ret)
		return ret;

	/* Set PLL */

	ret = ov1063x_reg_write(client, 0x3003, r3003);

	if (ret)
		return ret;
	
	ret = ov1063x_reg_write(client, 0x3004, r3004);
	
	if (ret)
		return ret;

	/* Set HSYNC */
	
	ret = ov1063x_reg_write(client, 0x4700, 0x00);
	
	if (ret)
		return ret;

	switch (priv->format.code) {
	case MEDIA_BUS_FMT_UYVY8_2X8:
		r4300 = OV1063X_FORMAT_UYVY;
		break;
	case MEDIA_BUS_FMT_VYUY8_2X8:
		r4300 = OV1063X_FORMAT_VYUY;
		break;
	case MEDIA_BUS_FMT_YUYV8_2X8:
		r4300 = OV1063X_FORMAT_YUYV;
		break;
	case MEDIA_BUS_FMT_YVYU8_2X8:
		r4300 = OV1063X_FORMAT_YYYU;
		break;
	default:
		r4300 = OV1063X_FORMAT_UYVY;
		break;
	}

	/* Set format to UYVY */
	ret = ov1063x_reg_write(client, OV1063X_FORMAT_CTRL00, r4300);
	if (ret)
		return ret;

	dev_dbg(&client->dev, "r4300=0x%X\n", r4300);

	/* Set output to 8-bit yuv */
	ret = ov1063x_reg_write(client, 0x4605, 0x08);
	if (ret)
		return ret;

	/* Horizontal cropping */
	ret = ov1063x_reg_write(client, 0x3621, horiz_crop_mode);
	if (ret)
		return ret;

	ret = ov1063x_reg_write(client, 0x3702, (pclk + 1500000) / 3000000);
	if (ret)
		return ret;
	ret = ov1063x_reg_write(client, 0x3703, (pclk + 666666) / 1333333);
	if (ret)
		return ret;
	ret = ov1063x_reg_write(client, 0x3704, (pclk + 961500) / 1923000);
	if (ret)
		return ret;

	/* Vertical cropping */
	tmp = ((OV1063X_SENSOR_HEIGHT - height_pre_subsample) / 2) & ~0x1;
	ret = ov1063x_reg_write16(client, 0x3802, tmp);
	if (ret)
		return ret;
	tmp = tmp + height_pre_subsample + 3;
	ret = ov1063x_reg_write16(client, 0x3806, tmp);
	if (ret)
		return ret;

	dev_dbg(&client->dev, "width x height = %x x %x\n",
		priv->width, priv->height);
	/* Output size */
	ret = ov1063x_reg_write16(client, 0x3808, priv->width);
	if (ret)
		return ret;
	ret = ov1063x_reg_write16(client, 0x380a, priv->height);
	if (ret)
		return ret;

	dev_dbg(&client->dev, "hts x vts = %x x %x\n", hts, vts);

	ret = ov1063x_reg_write16(client, 0x380c, hts);
	if (ret)
		return ret;

	ret = ov1063x_reg_write16(client, 0x380e, vts);
	if (ret)
		return ret;

	if (vert_sub_sample) {
		ret = ov1063x_reg_rmw(client, OV1063X_VFLIP,
				      OV1063X_VFLIP_SUBSAMPLE, 0);
		if (ret)
			return ret;
		tmp_array_size = ARRAY_SIZE(ov1063x_regs_vert_sub_sample);
		ret = ov1063x_set_regs(client, ov1063x_regs_vert_sub_sample,
				       tmp_array_size);
		if (ret)
			return ret;
	}

	ret = ov1063x_reg_write16(client, 0x4606, 2 * hts);
	if (ret)
		return ret;
	ret = ov1063x_reg_write16(client, 0x460a,
				  2 * (hts - width_pre_subsample));
	if (ret)
		return ret;

	tmp = (vts - 8) * 16;
	ret = ov1063x_reg_write16(client, 0xc488, tmp);
	if (ret)
		return ret;
	ret = ov1063x_reg_write16(client, 0xc48a, tmp);
	if (ret)
		return ret;

	nr_isp_pixels = sensor_width * (priv->height + 4);
	ret = ov1063x_reg_write16(client, 0xc4cc, nr_isp_pixels / 256);
	if (ret)
		return ret;
	ret = ov1063x_reg_write16(client, 0xc4ce, nr_isp_pixels / 256);
	if (ret)
		return ret;
	ret = ov1063x_reg_write16(client, 0xc512, nr_isp_pixels / 16);
	if (ret)
		return ret;

	/* Horizontal sub-sampling */
	if (horiz_sub_sample) {
		ret = ov1063x_reg_write(client, 0x5005, 0x9);
		if (ret)
			return ret;

		ret = ov1063x_reg_write(client, 0x3007, 0x2);
		if (ret)
			return ret;
	}

	ret = ov1063x_reg_write16(client, 0xc518, vts);
	if (ret)
		return ret;
	ret = ov1063x_reg_write16(client, 0xc51a, hts);
	if (ret)
		return ret;

	/* Enable ISP blocks */
		//printk("ov1063x_set_enter5\n");
	ret = ov1063x_set_regs(client, ov1063x_regs_enable,
			       ARRAY_SIZE(ov1063x_regs_enable));
	//printk("ov1063x_set_exit5\n");
	if (ret){
	printk("ov1063x_set_regs_ret_set\n");
		return ret;}

//dev_err(&client->dev, "PS-SE Exit %s:\n", __func__);
	return 0;
}

/*
 * V4L2 subdev video and pad level operations
 */

static void ov1063x_get_default_format(struct v4l2_mbus_framefmt *mf)
{
//printk("Enter ov1063x_get_default_format\n");
	mf->width = ov1063x_framesizes[0].width;
	mf->height = ov1063x_framesizes[0].height;
	mf->colorspace = ov1063x_cfmts[0].colorspace;
	mf->code = ov1063x_cfmts[0].code;
	mf->field = V4L2_FIELD_NONE;
//printk("Exit ov1063x_get_default_format\n");
}

static int ov1063x_get_fmt(struct v4l2_subdev *sd,
			   struct v4l2_subdev_pad_config *cfg,
			   struct v4l2_subdev_format *fmt)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	struct ov1063x_priv *priv = to_ov1063x(client);
	struct v4l2_mbus_framefmt *mf;
//dev_err(&client->dev, "PS-SE Enter %s:", __func__);
	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
		mf = v4l2_subdev_get_try_format(sd, cfg, 0);
		mutex_lock(&priv->lock);
		fmt->format = *mf;
		mutex_unlock(&priv->lock);
		return 0;
	}

	mutex_lock(&priv->lock);
	fmt->format = priv->format;
	mutex_unlock(&priv->lock);
//dev_err(&client->dev, "PS-SE Exit %s:\n", __func__);
	return 0;
}

static void __ov1063x_try_frame_size(struct v4l2_mbus_framefmt *mf)
{
	//printk("Enter __ov1063x_try_frame_size\n");
	const struct ov1063x_framesize *fsize = &ov1063x_framesizes[0];
	const struct ov1063x_framesize *match = NULL;
	int i = ARRAY_SIZE(ov1063x_framesizes);
	unsigned int min_err = UINT_MAX;

	while (i--) {
		int err = abs(fsize->width - mf->width)
				+ abs(fsize->height - mf->height);
		if (err < min_err) {
			min_err = err;
			match = fsize;
		}
		fsize++;
	}

	if (!match)
		match = &ov1063x_framesizes[0];

	mf->width  = match->width;
	mf->height = match->height;
	//printk("Exit __ov1063x_try_frame_size\n");
}

static int ov1063x_set_fmt(struct v4l2_subdev *sd,
			   struct v4l2_subdev_pad_config *cfg,
			   struct v4l2_subdev_format *fmt)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	unsigned int index = ARRAY_SIZE(ov1063x_cfmts);
	struct ov1063x_priv *priv = to_ov1063x(client);
	struct v4l2_mbus_framefmt *mf = &fmt->format;
//dev_err(&client->dev, "PS-SE Enter %s:", __func__);
	int ret = 0;

	__ov1063x_try_frame_size(mf);

	while (--index >= 0)
		if (ov1063x_cfmts[index].code == mf->code)
			break;

	if (index < 0)
		return -EINVAL;

	mf->colorspace = ov1063x_cfmts[index].colorspace;
	mf->code = ov1063x_cfmts[index].code;
	mf->field = V4L2_FIELD_NONE;

	mutex_lock(&priv->lock);

	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
		mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
		*mf = fmt->format;
	} else {
		priv->format = fmt->format;
		ret = ov1063x_set_params(client, mf->width, mf->height);
	}

	mutex_unlock(&priv->lock);
//dev_err(&client->dev, "PS-SE Exit %s:\n", __func__);
	return ret;
}

static int ov1063x_enum_mbus_code(struct v4l2_subdev *sd,
				  struct v4l2_subdev_pad_config *cfg,
				  struct v4l2_subdev_mbus_code_enum *code)
{
//printk("Enter ov1063x_enum_mbus_code\n");
	if (code->index >= ARRAY_SIZE(ov1063x_cfmts))
		return -EINVAL;

	code->code = ov1063x_cfmts[code->index].code;
//printk("Exit ov1063x_enum_mbus_code\n");
	return 0;
}

static int ov1063x_enum_frame_sizes(struct v4l2_subdev *sd,
				    struct v4l2_subdev_pad_config *cfg,
				    struct v4l2_subdev_frame_size_enum *fse)
{
	int i = ARRAY_SIZE(ov1063x_cfmts);
//printk("Enter ov1063x_enum_frame_sizes\n");
	if (fse->index >= ARRAY_SIZE(ov1063x_framesizes))
		return -EINVAL;

	while (--i)
		if (ov1063x_cfmts[i].code == fse->code)
			break;

	fse->code = ov1063x_cfmts[i].code;

	fse->min_width  = ov1063x_framesizes[fse->index].width;
	fse->max_width  = fse->min_width;
	fse->max_height = ov1063x_framesizes[fse->index].height;
	fse->min_height = fse->max_height;
//printk("Exit ov1063x_enum_frame_sizes\n");
	return 0;
}

static int ov1063x_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	struct ov1063x_priv *priv = to_ov1063x(client);
	struct v4l2_captureparm *cp = &parms->parm.capture;
//dev_err(&client->dev, "PS-SE Enter %s:", __func__);
	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return -EINVAL;

	memset(cp, 0, sizeof(struct v4l2_captureparm));
	cp->capability = V4L2_CAP_TIMEPERFRAME;
	cp->timeperframe.denominator = priv->fps_numerator;
	cp->timeperframe.numerator = priv->fps_denominator;
//dev_err(&client->dev, "PS-SE Exit %s:\n", __func__);
	return 0;
}

static int ov1063x_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	struct ov1063x_priv *priv = to_ov1063x(client);
	struct v4l2_captureparm *cp = &parms->parm.capture;
	int ret;
//dev_err(&client->dev, "PS-SE Enter %s:", __func__);
	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return -EINVAL;
	if (cp->extendedmode != 0)
		return -EINVAL;

	/* FIXME Check we can handle the requested framerate */
	priv->fps_denominator = cp->timeperframe.numerator;
	priv->fps_numerator = cp->timeperframe.denominator;

	ret = ov1063x_set_params(client, priv->width, priv->height);
	if (ret < 0)
		return ret;
//dev_err(&client->dev, "PS-SE Exit %s:\n", __func__);
	return 0;
}

static int ov1063x_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a)
{
	struct v4l2_crop a_writable = *a;
	struct v4l2_rect *rect = &a_writable.c;
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	struct ov1063x_priv *priv = to_ov1063x(client);
	int ret = -EINVAL;
//dev_err(&client->dev, "PS-SE Enter %s:", __func__);
	ret = ov1063x_set_params(client, rect->width, rect->height);
	if (!ret)
		return -EINVAL;

	rect->width = priv->width;
	rect->height = priv->height;
	rect->left = 0;
	rect->top = 0;
//dev_err(&client->dev, "PS-SE Exit %s:\n", __func__);
	return ret;
}

static int ov1063x_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	struct ov1063x_priv *priv = to_ov1063x(client);
//dev_err(&client->dev, "PS-SE Enter %s:", __func__);
	if (priv) {
		a->c.width = priv->width;
		a->c.height = priv->height;
	} else {
		a->c.width = OV1063X_MAX_WIDTH;
		a->c.height = OV1063X_MAX_HEIGHT;
	}

	a->c.left = 0;
	a->c.top = 0;
	a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
//dev_err(&client->dev, "PS-SE Exit %s:\n", __func__);
	return 0;
}

static int ov1063x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
{
//printk("Enter ov1063x_cropcap\n");
	a->bounds.left = 0;
	a->bounds.top = 0;
	a->bounds.width = OV1063X_MAX_WIDTH;
	a->bounds.height = OV1063X_MAX_HEIGHT;
	a->defrect = a->bounds;
	a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	a->pixelaspect.numerator = 1;
	a->pixelaspect.denominator = 1;
//printk("Exit ov1063x_cropcap\n");
	return 0;
}

static int ov1063x_init_gpios(struct i2c_client *client)
{
	struct ov1063x_priv *priv = to_ov1063x(client);
	int ret = 0;
	//dev_err(&client->dev, "PS-SE Enter %s:", __func__);
	ret = gpio_request_array(priv->mux_gpios, priv->num_gpios);
	//printk("gpio_request_array_ret\n");
	//printk("%d\n",ret);
	if (ret)
		goto done;
	gpio_free_array(priv->mux_gpios, priv->num_gpios);

done:
	//dev_err(&client->dev, "PS-SE Exit %s:\n", __func__);
	return ret;
}


//changes

static int ov1063x_video_probe(struct i2c_client *client)
{
//dev_err(&client->dev, "PS-SE Enter %s:", __func__);
	struct ov1063x_priv *priv = to_ov1063x(client);
	u8 pid, ver;
	u16 id;
	int ret=0, value;

	__ov1063x_set_power(client, 1);

	
	ret = ov1063x_set_regs(client, ov1063x_regs_default,
			       ARRAY_SIZE(ov1063x_regs_default));
	if (ret)
		return ret;
	
	usleep_range(500, 510);

	/* check and show product ID and manufacturer ID */

	ret = ov1063x_reg_read(client, OV1063X_PID, &pid);
	if (ret)
		return ret;

	id = pid << 8;

	ret = ov1063x_reg_read(client, OV1063X_VER, &ver);
	if (ret)
		return ret;
	
	id |= ver;
	if (OV1063X_VERSION(pid, ver) == OV10635_VERSION_REG) {
		priv->model = SENSOR_OV10635;
		priv->revision = 1;
	} else if (OV1063X_VERSION(pid, ver) == OV10633_VERSION_REG) {
		priv->model = SENSOR_OV10633;
		priv->revision = 1;
	} else {
		dev_err(&client->dev, "Product ID error %x:%x\n", pid, ver);
				return -ENODEV;
//changes
				goto done;
//changes
	}

	dev_info(&client->dev, "ov1063x Product ID %x Manufacturer ID %x\n",
		 pid, ver);

	/* Program all the 'standard' registers */
//changes
done:
	
	//dev_err(&client->dev, "PS-SE Exit %s:\n", __func__);
	value =  v4l2_ctrl_handler_setup(&priv->hdl);
	printk("Value-\n");printk("%d\n",value);
	//__ov1063x_set_power(client, 0); //pwerdown pin high
	return value;
}

/*
 * V4L2 subdev internal operations
 */
static int ov1063x_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	struct v4l2_mbus_framefmt *mf;

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

	mf = v4l2_subdev_get_try_format(sd, fh->pad, 0);
	ov1063x_get_default_format(mf);
	return 0;
}

static const struct v4l2_ctrl_ops ov1063x_ctrl_ops = {
	.s_ctrl = ov1063x_s_ctrl,
};

static struct v4l2_subdev_video_ops ov1063x_subdev_video_ops = {
	.s_stream	= ov1063x_s_stream,
	.cropcap	= ov1063x_cropcap,
	.g_crop		= ov1063x_g_crop,
	.s_crop		= ov1063x_s_crop,
	.g_parm		= ov1063x_g_parm,
	.s_parm		= ov1063x_s_parm,
};

static const struct v4l2_subdev_internal_ops ov1063x_sd_internal_ops = {
	.open		= ov1063x_open,
};

static const struct v4l2_subdev_core_ops ov1063x_subdev_core_ops = {
	.log_status		= v4l2_ctrl_subdev_log_status,
	.subscribe_event	= v4l2_ctrl_subdev_subscribe_event,
	.unsubscribe_event	= v4l2_event_subdev_unsubscribe,
	
};

static const struct v4l2_subdev_pad_ops ov1063x_subdev_pad_ops = {
	.enum_mbus_code		= ov1063x_enum_mbus_code,
	.enum_frame_size	= ov1063x_enum_frame_sizes,
	.get_fmt		= ov1063x_get_fmt,
	.set_fmt		= ov1063x_set_fmt,
};

static struct v4l2_subdev_ops ov1063x_subdev_ops = {
	.core	= &ov1063x_subdev_core_ops,
	.video	= &ov1063x_subdev_video_ops,
	.pad	= &ov1063x_subdev_pad_ops,
};

/*
 * i2c_driver function
 */

static int ov1063x_of_probe(struct i2c_client *client,
			    struct device_node *node)
{
//dev_err(&client->dev, "PS-SE Enter %s:", __func__);
	struct ov1063x_priv *priv = to_ov1063x(client);
	struct gpio *gpios = &priv->mux_gpios[0];
	unsigned int flags;
	int i, gpio;

	/*
	 * Iterate over all the gpios in the device tree
	 * ENOENT is returned when trying to access last + 1 gpio
	 */
	for (i = 0; i < MAX_NUM_GPIOS; i++) {
		gpio = of_get_named_gpio_flags(node, "mux-gpios", i, &flags);
		if (gpio_is_valid(gpio)) {
			gpios[i].gpio	= gpio;
			gpios[i].flags	= (flags & OF_GPIO_ACTIVE_LOW) ?
				GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH;
			gpios[i].label	= client->name;
		} else {
			if (gpio == -ENOENT)
				break;

			return gpio;
		}
	}
	priv->num_gpios = i;
//dev_err(&client->dev, "PS-SE Exit %s:\n", __func__);
	return 0;
}

static int ov1063x_probe(struct i2c_client *client,
			 const struct i2c_device_id *did)
{
//dev_err(&client->dev, "PS-SE Enter %s:", __func__);
	struct device_node *node = client->dev.of_node;
	struct ov1063x_priv *priv;
	struct v4l2_subdev *sd;
	int ret = 0;
	int gpio_read;
	//changes
	struct gpio_desc *gpio;
	//changes

	priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
	////printk("devm_kzalloc\n");
	if (!priv)
		return -ENOMEM;

	gpio = devm_gpiod_get(&client->dev, "powerdown", GPIOD_OUT_LOW);
	if (IS_ERR(gpio)) {
		if (PTR_ERR(gpio) != -ENOENT)
			return PTR_ERR(gpio);
		gpio = NULL;
	}
	gpio_read = gpiod_get_raw_value(priv->powerdown_gpio);
 	dev_err(&client->dev, "POWERDOWN_GPIO\n %d", gpio_read);
	priv->powerdown_gpio = gpio;

	i2c_set_clientdata(client, priv);
	//printk("i2c_set_clientdata\n");

	ret = ov1063x_of_probe(client, node);
	
	if (ret){//printk("ov1063x_of_probe ret error\n");
		goto err;}

	/* TODO External XVCLK is board specific */
	priv->xvclk = 24000000; //initially 24000000
	/* Default framerate */
	priv->fps_numerator = 30;
	priv->fps_denominator = 1;
	ov1063x_get_default_format(&priv->format);
	priv->width = priv->format.width;
	priv->height = priv->format.height;

	sd = &priv->subdev;
	v4l2_i2c_subdev_init(sd, client, &ov1063x_subdev_ops);

	sd->internal_ops = &ov1063x_sd_internal_ops;
	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
		     V4L2_SUBDEV_FL_HAS_EVENTS;

	v4l2_ctrl_handler_init(&priv->hdl, 2);
	v4l2_ctrl_new_std(&priv->hdl, &ov1063x_ctrl_ops,
			  V4L2_CID_VFLIP, 0, 1, 1, 0);
	v4l2_ctrl_new_std(&priv->hdl, &ov1063x_ctrl_ops,
			  V4L2_CID_HFLIP, 0, 1, 1, 0);
	priv->subdev.ctrl_handler = &priv->hdl;
	if (priv->hdl.error) {
		ret = priv->hdl.error;
		goto err;
	}

	mutex_init(&priv->lock);

	ret = ov1063x_init_gpios(client);
	//printk("ov1063x_init_gpios exit\n");
	if (ret) {
		dev_err(&client->dev, "Failed to request gpios");
		goto err;
	}

	ret = ov1063x_video_probe(client);
	if (ret) {
		v4l2_ctrl_handler_free(&priv->hdl);
		goto err;
	}

	sd->dev = &client->dev;
	ret = v4l2_async_register_subdev(sd);
	if (ret){
		v4l2_ctrl_handler_free(&priv->hdl);
		goto err;
	}

	dev_info(&client->dev, "%s sensor driver registered !!\n", sd->name);
	
	pm_runtime_enable(&client->dev);
	//dev_err(&client->dev, "PS-SE Exit %s:\n", __func__);

err:
	return ret;
}

static int ov1063x_remove(struct i2c_client *client)
{
//dev_err(&client->dev, "PS-SE Enter %s:", __func__);
	struct ov1063x_priv *priv = i2c_get_clientdata(client);

	v4l2_device_unregister_subdev(&priv->subdev);
	v4l2_async_unregister_subdev(&priv->subdev);
	v4l2_ctrl_handler_free(&priv->hdl);
	pm_runtime_disable(&client->dev);
//dev_err(&client->dev, "PS-SE Exit %s:\n", __func__);
	return 0;
}

static const struct i2c_device_id ov1063x_id[] = {
	{ "ov10635", 0 },
	{ "ov10633", 0 },
	{ }
};
MODULE_DEVICE_TABLE(i2c, ov1063x_id);

#if defined(CONFIG_OF)
static const struct of_device_id ov1063x_dt_id[] = {
	{
		.compatible = "ovti,ov10635", .data = "ov10635"
	},
	{
		.compatible = "ovti,ov10633", .data = "ov10633"
	},
	{
	}
};
#endif

static struct i2c_driver ov1063x_i2c_driver = {
	.driver = {
		.name	= "ov1063x",
		.of_match_table = of_match_ptr(ov1063x_dt_id),
	},
	.probe = ov1063x_probe,
	.remove = ov1063x_remove,
	.id_table = ov1063x_id,
};

module_i2c_driver(ov1063x_i2c_driver);

MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV1063X");
MODULE_AUTHOR("Phil Edworthy <phil.edworthy@renesas.com>");
MODULE_LICENSE("GPL v2");

Any suggestion.