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.

OV5640 driver on AM437X



Hi all,

In our design we are using OV5640 camera module chip with AM437x processor. Is there any driver is available for OV5640?

I searched from internet but I can not find an abailable driver for OV5640.

Any helps would be appreciated.

Thanks & Warm regards,

Jakebo

  • Hi,

    The AM437X EVM includes a camera board with the OV2659 sensor. I don't think there are drivers for other sensors currently included in the SDK.

  • Thanks Biser,

    Yes there are no drivers for OV5640 sensor included in the SDK.
    I had tried&modified several OV5640 drivers got from internet, but all are not work.

    Best Regards,
    Jakebo
  • Hi Jakebo ,

    You have any updates on this? You have made any progress for OV5640 driver fro AM437x? 

    We are facing same problem, Recently started on working Camera driver for OV5640 on our custom board based on AM437x. Currently we are using OV5642 driver from SDk7.0 (kernel version 3.12.10) as reference and Driver for OV5640 are taken from :

    https://gitorious.org/omap4-v4l2-camera/pages/Home

    Idea is to use initialization sequence , register configuration of OV5640  in OV5642 driver from SDK 7.0 keeping v4l/v4l sub-device   framwork as per ov5642 driver.

    Let me know your point of view on this?

  • Hi Debi,

    We are still struggling on OV5640, it can not work normally.
    I had tried the same way with you, but I got fail, I don't know where is wrong in my driver and kernel.
    And I have not any ideas now, Kindly let me know if you have any ideas, :)

    Best Regards,
    Jakebo

  • Hi Jakebo,

    We have just started, porting OV5640 sensor driver for linux kernel 3.12.10 in SDK 7.0. There are couple of problem we are facing

    1. Driver from internet  are not sure for there testing/performance/functionality.

    2. Comparability of  OV5640 driver from mentioned source. API for SOC camera/V4L subdev ops are  has changed.

    3. There are many undocumented registers for both sensors (OV5640 and OV5642)

    4. We are using initialization sequence of OV5640 blindly, not gone through hundreds of register in initialization array.   

    Considering these points : We have taken approach for going step by step   

    1. Probing of OV5640 sensor as v4l sub-device (/dev/video0)  and basic v4l ioctls should be working. This very first step  I am looking for.

    Its look like there is no other way than looking at OV5640 data sheet  in details and proceeding further.

    Currently what problem you are facing ? Are you able to create device for OV5640 and at least able to test with basic v4l ioctls/cmds on your modified driver? 

    If you can share your modified driver code for OV5640 , I can help. We can combinely  work to make driver functional ..!!

  • Hi Debi,

    Sorry for the late reply and Glad to combinely work with you.

    the attachment is the ov5640 driver.

    Use this driver I could probe ov5640 as /dev/video0 and able to test with ioctls, but in my application could not read the video data from ov5640 via VIDIOC_DQBUF cmd with ioctl invoking (got the EAGAIN).

    I use the following configure in devicetree:

    &i2c0 {
        status = "okay";
        pinctrl-names = "default";
        pinctrl-0 = <&i2c0_pins &eeprom_wp_pin>;
    
        ov5640@3c {
            compatible = "ti,ov5640";
            reg = <0x3c>;
    
            port {
                ov5640_0: endpoint {
                    remote-endpoint = <&vpfe0_ep>;
                };
            };
        };
    
        cat24c256@50 {
            compatible = "24c256";
            reg = <0x50>;
    
            pagesize = <64>;
        };
    };
    
    &vpfe0 {
        status = "okay";
        pinctrl-names = "default", "sleep";
        pinctrl-0 = <&vpfe0_pins_default>;
        pinctrl-1 = <&vpfe0_pins_sleep>;
    
        /* Camera port */
        port {
    	vpfe0_ep: endpoint {
                remote-endpoint = <&ov5640_0>;
                if_type = <2>;
                bus_width = <8>;
                hdpol = <0>;
                vdpol = <0>;
    	};
        };
    };

    /*
     * OmniVision OV5640 sensor driver
     *
     * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
     *
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License as
     * published by the Free Software Foundation version 2.
     *
     * This program is distributed "as is" WITHOUT ANY WARRANTY of any
     * kind, whether express or implied; without even the implied warranty
     * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU General Public License for more details.
     */
    #include <linux/videodev2.h>
    #include <linux/slab.h>
    #include <linux/i2c.h>
    #include <linux/log2.h>
    #include <linux/delay.h>
    #include <linux/module.h>
    
    #include <linux/gpio.h>
    #include <linux/clk.h>
    #include <linux/regulator/consumer.h>
    
    #include <media/v4l2-device.h>
    #include <media/v4l2-subdev.h>
    #include <media/v4l2-ctrls.h>
    #include <media/v4l2-of.h>
    
    #include <media/ov5640.h>
    
    /* OV5640 has only one fixed colorspace per pixelcode */
    struct ov5640_datafmt {
    	enum v4l2_mbus_pixelcode	code;
    	enum v4l2_colorspace		colorspace;
    };
    
    struct ov5640_timing_cfg {
    	u16 x_addr_start;
    	u16 y_addr_start;
    	u16 x_addr_end;
    	u16 y_addr_end;
    	u16 h_output_size;
    	u16 v_output_size;
    	u16 h_total_size;
    	u16 v_total_size;
    	u16 isp_h_offset;
    	u16 isp_v_offset;
    	u8 h_odd_ss_inc;
    	u8 h_even_ss_inc;
    	u8 v_odd_ss_inc;
    	u8 v_even_ss_inc;
    };
    
    struct ov5640_clk_cfg {
    	u8 sc_pll_prediv;
    	u8 sc_pll_rdiv;
    	u8 sc_pll_mult;
    	u8 sysclk_div;
    	u8 mipi_div;
    };
    
    enum ov5640_size {
    	OV5640_SIZE_QVGA,
    	OV5640_SIZE_VGA,
    	OV5640_SIZE_720P,
    	OV5640_SIZE_1080P,
    	OV5640_SIZE_5MP,
    	OV5640_SIZE_LAST,
    };
    
    static const struct v4l2_frmsize_discrete ov5640_frmsizes[OV5640_SIZE_LAST] = {
    	{  320,  240 },
    	{  640,  480 },
    	{ 1280,  720 },
    	{ 1920, 1080 },
    	{ 2592, 1944 },
    };
    
    /* Find a frame size in an array */
    static int ov5640_find_framesize(u32 width, u32 height)
    {
    	int i;
    
    	for (i = 0; i < OV5640_SIZE_LAST; i++) {
    		if ((ov5640_frmsizes[i].width >= width) &&
    		    (ov5640_frmsizes[i].height >= height))
    			break;
    	}
    
    	/* If not found, select biggest */
    	if (i >= OV5640_SIZE_LAST)
    		i = OV5640_SIZE_LAST - 1;
    
    	return i;
    }
    
    struct ov5640 {
    	unsigned short id;
    	struct v4l2_subdev subdev;
    	struct media_pad pad;
    	struct v4l2_mbus_framefmt format;
    
    	struct v4l2_ctrl_handler ctrl_handler;
    
    	const struct ov5640_platform_data *pdata;
    
    	struct v4l2_ctrl *pixel_rate;
    
    	/* HW control */
    	struct clk *xvclk;
    	struct regulator *avdd;
    	struct regulator *dovdd;
    
    	/* System Clock config */
    	struct ov5640_clk_cfg clk_cfg;
    };
    
    static inline struct ov5640 *to_ov5640(struct v4l2_subdev *sd)
    {
    	return container_of(sd, struct ov5640, subdev);
    }
    
    /**
     * struct ov5640_reg - ov5640 register format
     * @reg: 16-bit offset to register
     * @val: 8/16/32-bit register value
     * @length: length of the register
     *
     * Define a structure for OV5640 register initialization values
     */
    struct ov5640_reg {
    	u16	reg;
    	u8	val;
    };
    
    /* TODO: Divide this properly */
    static const struct ov5640_reg configscript_common1[] = {
    	{ 0x3103, 0x03 },
    	{ 0x3017, 0x00 },
    	{ 0x3018, 0x00 },
    	{ 0x3630, 0x2e },
    	{ 0x3632, 0xe2 },
    	{ 0x3633, 0x23 },
    	{ 0x3634, 0x44 },
    	{ 0x3621, 0xe0 },
    	{ 0x3704, 0xa0 },
    	{ 0x3703, 0x5a },
    	{ 0x3715, 0x78 },
    	{ 0x3717, 0x01 },
    	{ 0x370b, 0x60 },
    	{ 0x3705, 0x1a },
    	{ 0x3905, 0x02 },
    	{ 0x3906, 0x10 },
    	{ 0x3901, 0x0a },
    	{ 0x3731, 0x12 },
    	{ 0x3600, 0x04 },
    	{ 0x3601, 0x22 },
    	{ 0x471c, 0x50 },
    	{ 0x3002, 0x1c },
    	{ 0x3006, 0xc3 },
    	{ 0x300e, 0x05 },
    	{ 0x302e, 0x08 },
    	{ 0x3612, 0x4b },
    	{ 0x3618, 0x04 },
    	{ 0x3034, 0x18 },
    	{ 0x3035, 0x11 },
    	{ 0x3036, 0x54 },
    	{ 0x3037, 0x13 },
    	{ 0x3708, 0x21 },
    	{ 0x3709, 0x12 },
    	{ 0x370c, 0x00 },
    };
    
    /* TODO: Divide this properly */
    static const struct ov5640_reg configscript_common2[] = {
    	{ 0x3a02, 0x01 },
    	{ 0x3a03, 0xec },
    	{ 0x3a08, 0x01 },
    	{ 0x3a09, 0x27 },
    	{ 0x3a0a, 0x00 },
    	{ 0x3a0b, 0xf6 },
    	{ 0x3a0e, 0x06 },
    	{ 0x3a0d, 0x08 },
    	{ 0x3a14, 0x01 },
    	{ 0x3a15, 0xec },
    	{ 0x4001, 0x02 },
    	{ 0x4004, 0x06 },
    	{ 0x460b, 0x37 },
    	{ 0x4750, 0x00 },
    	{ 0x4751, 0x00 },
    	{ 0x4800, 0x24 },
    	{ 0x5a00, 0x08 },
    	{ 0x5a21, 0x00 },
    	{ 0x5a24, 0x00 },
    	{ 0x5000, 0x27 },
    	{ 0x5001, 0x87 },
    	{ 0x3820, 0x40 },
    	{ 0x3821, 0x06 },
    	{ 0x3824, 0x01 },
    	{ 0x5481, 0x08 },
    	{ 0x5482, 0x14 },
    	{ 0x5483, 0x28 },
    	{ 0x5484, 0x51 },
    	{ 0x5485, 0x65 },
    	{ 0x5486, 0x71 },
    	{ 0x5487, 0x7d },
    	{ 0x5488, 0x87 },
    	{ 0x5489, 0x91 },
    	{ 0x548a, 0x9a },
    	{ 0x548b, 0xaa },
    	{ 0x548c, 0xb8 },
    	{ 0x548d, 0xcd },
    	{ 0x548e, 0xdd },
    	{ 0x548f, 0xea },
    	{ 0x5490, 0x1d },
    	{ 0x5381, 0x20 },
    	{ 0x5382, 0x64 },
    	{ 0x5383, 0x08 },
    	{ 0x5384, 0x20 },
    	{ 0x5385, 0x80 },
    	{ 0x5386, 0xa0 },
    	{ 0x5387, 0xa2 },
    	{ 0x5388, 0xa0 },
    	{ 0x5389, 0x02 },
    	{ 0x538a, 0x01 },
    	{ 0x538b, 0x98 },
    	{ 0x5300, 0x08 },
    	{ 0x5301, 0x30 },
    	{ 0x5302, 0x10 },
    	{ 0x5303, 0x00 },
    	{ 0x5304, 0x08 },
    	{ 0x5305, 0x30 },
    	{ 0x5306, 0x08 },
    	{ 0x5307, 0x16 },
    	{ 0x5580, 0x00 },
    	{ 0x5587, 0x00 },
    	{ 0x5588, 0x00 },
    	{ 0x5583, 0x40 },
    	{ 0x5584, 0x10 },
    	{ 0x5589, 0x10 },
    	{ 0x558a, 0x00 },
    	{ 0x558b, 0xf8 },
    	{ 0x3a0f, 0x36 },
    	{ 0x3a10, 0x2e },
    	{ 0x3a1b, 0x38 },
    	{ 0x3a1e, 0x2c },
    	{ 0x3a11, 0x70 },
    	{ 0x3a1f, 0x18 },
    	{ 0x3a18, 0x00 },
    	{ 0x3a19, 0xf8 },
    	{ 0x3003, 0x03 },
    	{ 0x3003, 0x01 },
    };
    
    static const struct ov5640_timing_cfg timing_cfg[OV5640_SIZE_LAST] = {
    	[OV5640_SIZE_QVGA] = {
    		.x_addr_start = 0,
    		.y_addr_start = 0,
    		.x_addr_end = 2623,
    		.y_addr_end = 1951,
    		.h_output_size = 320,
    		.v_output_size = 240,
    		.h_total_size = 2844,
    		.v_total_size = 1968,
    		.isp_h_offset = 16,
    		.isp_v_offset = 6,
    		.h_odd_ss_inc = 1,
    		.h_even_ss_inc = 1,
    		.v_odd_ss_inc = 1,
    		.v_even_ss_inc = 1,
    	},
    	[OV5640_SIZE_VGA] = {
    		.x_addr_start = 0,
    		.y_addr_start = 0,
    		.x_addr_end = 2623,
    		.y_addr_end = 1951,
    		.h_output_size = 640,
    		.v_output_size = 480,
    		.h_total_size = 2844,
    		.v_total_size = 1968,
    		.isp_h_offset = 16,
    		.isp_v_offset = 6,
    		.h_odd_ss_inc = 1,
    		.h_even_ss_inc = 1,
    		.v_odd_ss_inc = 1,
    		.v_even_ss_inc = 1,
    	},
    	[OV5640_SIZE_720P] = {
    		.x_addr_start = 336,
    		.y_addr_start = 434,
    		.x_addr_end = 2287,
    		.y_addr_end = 1522,
    		.h_output_size = 1280,
    		.v_output_size = 720,
    		.h_total_size = 2500,
    		.v_total_size = 1120,
    		.isp_h_offset = 16,
    		.isp_v_offset = 4,
    		.h_odd_ss_inc = 1,
    		.h_even_ss_inc = 1,
    		.v_odd_ss_inc = 1,
    		.v_even_ss_inc = 1,
    	},
    	[OV5640_SIZE_1080P] = {
    		.x_addr_start = 336,
    		.y_addr_start = 434,
    		.x_addr_end = 2287,
    		.y_addr_end = 1522,
    		.h_output_size = 1920,
    		.v_output_size = 1080,
    		.h_total_size = 2500,
    		.v_total_size = 1120,
    		.isp_h_offset = 16,
    		.isp_v_offset = 4,
    		.h_odd_ss_inc = 1,
    		.h_even_ss_inc = 1,
    		.v_odd_ss_inc = 1,
    		.v_even_ss_inc = 1,
    	},
    	[OV5640_SIZE_5MP] = {
    		.x_addr_start = 0,
    		.y_addr_start = 0,
    		.x_addr_end = 2623,
    		.y_addr_end = 1951,
    		.h_output_size = 2592,
    		.v_output_size = 1944,
    		.h_total_size = 2844,
    		.v_total_size = 1968,
    		.isp_h_offset = 16,
    		.isp_v_offset = 6,
    		.h_odd_ss_inc = 1,
    		.h_even_ss_inc = 1,
    		.v_odd_ss_inc = 1,
    		.v_even_ss_inc = 1,
    	},
    };
    
    /**
     * ov5640_reg_read - Read a value from a register in an ov5640 sensor device
     * @client: i2c driver client structure
     * @reg: register address / offset
     * @val: stores the value that gets read
     *
     * Read a value from a register in an ov5640 sensor device.
     * The value is returned in 'val'.
     * Returns zero if successful, or non-zero otherwise.
     */
    static int ov5640_reg_read(struct i2c_client *client, u16 reg, u8 *val)
    {
    	int ret;
    	u8 data[2] = {0};
    	struct i2c_msg msg = {
    		.addr	= client->addr,
    		.flags	= 0,
    		.len	= 2,
    		.buf	= data,
    	};
    
    	data[0] = (u8)(reg >> 8);
    	data[1] = (u8)(reg & 0xff);
    
    	ret = i2c_transfer(client->adapter, &msg, 1);
    	if (ret < 0)
    		goto err;
    
    	msg.flags = I2C_M_RD;
    	msg.len = 1;
    	ret = i2c_transfer(client->adapter, &msg, 1);
    	if (ret < 0)
    		goto err;
    
    	*val = data[0];
    	return 0;
    
    err:
    	dev_err(&client->dev, "Failed reading register 0x%02x!\n", reg);
    	return ret;
    }
    
    /**
     * Write a value to a register in ov5640 sensor device.
     * @client: i2c driver client structure.
     * @reg: Address of the register to read value from.
     * @val: Value to be written to a specific register.
     * Returns zero if successful, or non-zero otherwise.
     */
    static int ov5640_reg_write(struct i2c_client *client, u16 reg, u8 val)
    {
    	int ret;
    	unsigned char data[3] = { (u8)(reg >> 8), (u8)(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%02x!\n", reg);
    		return ret;
    	}
    
    	return 0;
    }
    
    /**
     * Initialize a list of ov5640 registers.
     * The list of registers is terminated by the pair of values
     * @client: i2c driver client structure.
     * @reglist[]: List of address of the registers to write data.
     * Returns zero if successful, or non-zero otherwise.
     */
    static int ov5640_reg_writes(struct i2c_client *client,
    			     const struct ov5640_reg reglist[],
    			     int size)
    {
    	int err = 0, i;
    
    	for (i = 0; i < size; i++) {
    		err = ov5640_reg_write(client, reglist[i].reg,
    				reglist[i].val);
    		if (err)
    			return err;
    	}
    	return 0;
    }
    
    static int ov5640_reg_set(struct i2c_client *client, u16 reg, u8 val)
    {
    	int ret;
    	u8 tmpval = 0;
    
    	ret = ov5640_reg_read(client, reg, &tmpval);
    	if (ret)
    		return ret;
    
    	return ov5640_reg_write(client, reg, tmpval | val);
    }
    
    static int ov5640_reg_clr(struct i2c_client *client, u16 reg, u8 val)
    {
    	int ret;
    	u8 tmpval = 0;
    
    	ret = ov5640_reg_read(client, reg, &tmpval);
    	if (ret)
    		return ret;
    
    	return ov5640_reg_write(client, reg, tmpval & ~val);
    }
    
    static unsigned long ov5640_get_pclk(struct v4l2_subdev *sd)
    {
    	struct ov5640 *ov5640 = to_ov5640(sd);
    	unsigned long xvclk, vco, mipi_pclk;
    
    	xvclk = clk_get_rate(ov5640->xvclk);
    
    	vco = (xvclk / ov5640->clk_cfg.sc_pll_prediv) *
    		ov5640->clk_cfg.sc_pll_mult;
    
    	mipi_pclk = vco /
    		ov5640->clk_cfg.sysclk_div /
    		ov5640->clk_cfg.mipi_div;
    
    	return mipi_pclk;
    }
    
    static int ov5640_config_timing(struct v4l2_subdev *sd)
    {
    	struct i2c_client *client = v4l2_get_subdevdata(sd);
    	struct ov5640 *ov5640 = to_ov5640(sd);
    	int ret, i;
    
    	i = ov5640_find_framesize(ov5640->format.width, ov5640->format.height);
    
    	ret = ov5640_reg_write(client,
    			0x3800,
    			(timing_cfg[i].x_addr_start & 0xFF00) >> 8);
    	if (ret)
    		return ret;
    
    	ret = ov5640_reg_write(client,
    			0x3801,
    			timing_cfg[i].x_addr_start & 0xFF);
    	if (ret)
    		return ret;
    
    	ret = ov5640_reg_write(client,
    			0x3802,
    			(timing_cfg[i].y_addr_start & 0xFF00) >> 8);
    	if (ret)
    		return ret;
    
    	ret = ov5640_reg_write(client,
    			0x3803,
    			timing_cfg[i].y_addr_start & 0xFF);
    	if (ret)
    		return ret;
    
    	ret = ov5640_reg_write(client,
    			0x3804,
    			(timing_cfg[i].x_addr_end & 0xFF00) >> 8);
    	if (ret)
    		return ret;
    
    	ret = ov5640_reg_write(client,
    			0x3805,
    			timing_cfg[i].x_addr_end & 0xFF);
    	if (ret)
    		return ret;
    
    	ret = ov5640_reg_write(client,
    			0x3806,
    			(timing_cfg[i].y_addr_end & 0xFF00) >> 8);
    	if (ret)
    		return ret;
    
    	ret = ov5640_reg_write(client,
    			0x3807,
    			timing_cfg[i].y_addr_end & 0xFF);
    	if (ret)
    		return ret;
    
    	ret = ov5640_reg_write(client,
    			0x3808,
    			(timing_cfg[i].h_output_size & 0xFF00) >> 8);
    	if (ret)
    		return ret;
    
    	ret = ov5640_reg_write(client,
    			0x3809,
    			timing_cfg[i].h_output_size & 0xFF);
    	if (ret)
    		return ret;
    
    	ret = ov5640_reg_write(client,
    			0x380A,
    			(timing_cfg[i].v_output_size & 0xFF00) >> 8);
    	if (ret)
    		return ret;
    
    	ret = ov5640_reg_write(client,
    			0x380B,
    			timing_cfg[i].v_output_size & 0xFF);
    	if (ret)
    		return ret;
    
    	ret = ov5640_reg_write(client,
    			0x380C,
    			(timing_cfg[i].h_total_size & 0xFF00) >> 8);
    	if (ret)
    		return ret;
    
    	ret = ov5640_reg_write(client,
    			0x380D,
    			timing_cfg[i].h_total_size & 0xFF);
    	if (ret)
    		return ret;
    
    	ret = ov5640_reg_write(client,
    			0x380E,
    			(timing_cfg[i].v_total_size & 0xFF00) >> 8);
    	if (ret)
    		return ret;
    
    	ret = ov5640_reg_write(client,
    			0x380F,
    			timing_cfg[i].v_total_size & 0xFF);
    	if (ret)
    		return ret;
    
    	ret = ov5640_reg_write(client,
    			0x3810,
    			(timing_cfg[i].isp_h_offset & 0xFF00) >> 8);
    	if (ret)
    		return ret;
    
    	ret = ov5640_reg_write(client,
    			0x3811,
    			timing_cfg[i].isp_h_offset & 0xFF);
    	if (ret)
    		return ret;
    
    	ret = ov5640_reg_write(client,
    			0x3812,
    			(timing_cfg[i].isp_v_offset & 0xFF00) >> 8);
    	if (ret)
    		return ret;
    
    	ret = ov5640_reg_write(client,
    			0x3813,
    			timing_cfg[i].isp_v_offset & 0xFF);
    	if (ret)
    		return ret;
    
    	ret = ov5640_reg_write(client,
    			0x3814,
    			((timing_cfg[i].h_odd_ss_inc & 0xF) << 4) |
    			(timing_cfg[i].h_even_ss_inc & 0xF));
    	if (ret)
    		return ret;
    
    	ret = ov5640_reg_write(client,
    			0x3815,
    			((timing_cfg[i].v_odd_ss_inc & 0xF) << 4) |
    			(timing_cfg[i].v_even_ss_inc & 0xF));
    
    	return ret;
    }
    
    static struct v4l2_mbus_framefmt *
    __ov5640_get_pad_format(struct ov5640 *ov5640, struct v4l2_subdev_fh *fh,
    			 unsigned int pad, enum v4l2_subdev_format_whence which)
    {
    	switch (which) {
    	case V4L2_SUBDEV_FORMAT_TRY:
    		return v4l2_subdev_get_try_format(fh, pad);
    	case V4L2_SUBDEV_FORMAT_ACTIVE:
    		return &ov5640->format;
    	default:
    		return NULL;
    	}
    }
    
    /* -----------------------------------------------------------------------------
     * V4L2 subdev internal operations
     */
    
    static int ov5640_s_power(struct v4l2_subdev *sd, int on)
    {
    	struct ov5640 *ov5640 = to_ov5640(sd);
    	struct i2c_client *client = v4l2_get_subdevdata(sd);
    	struct device *dev = &client->dev;
    
    	if (on) {
    		int ret;
    
    		if (ov5640->pdata->pre_poweron) {
    			ret = ov5640->pdata->pre_poweron(sd);
    			if (ret) {
    				dev_err(dev,
    					"Error in pre_poweron (%d)\n", ret);
    				return ret;
    			}
    		}
    
    		if (ov5640->dovdd) {
    			ret = regulator_enable(ov5640->dovdd);
    			if (ret) {
    				dev_err(dev,
    					"Error in enabling DOVDD (%d)\n", ret);
    				if (ov5640->pdata->post_poweroff)
    					ov5640->pdata->post_poweroff(sd);
    				return ret;
    			}
    		}
    
    		if (ov5640->avdd) {
    			ret = regulator_enable(ov5640->avdd);
    			if (ret) {
    				dev_err(dev,
    					"Error in enabling AVDD (%d)\n", ret);
    				if (ov5640->dovdd)
    					regulator_disable(ov5640->dovdd);
    				if (ov5640->pdata->post_poweroff)
    					ov5640->pdata->post_poweroff(sd);
    				return ret;
    			}
    			usleep_range(5000, 5000);
    		}
    
    		ret = clk_enable(ov5640->xvclk);
    		if (ret) {
    			dev_err(dev, "Error in enabling XVCLK (%d)\n", ret);
    			if (ov5640->avdd)
    				regulator_disable(ov5640->avdd);
    			if (ov5640->dovdd)
    				regulator_disable(ov5640->dovdd);
    			if (ov5640->pdata->post_poweroff)
    				ov5640->pdata->post_poweroff(sd);
    			return ret;
    		}
    		if (gpio_is_valid(ov5640->pdata->gpio_pwdn)) {
    			gpio_set_value(ov5640->pdata->gpio_pwdn,
    				       ov5640->pdata->is_gpio_pwdn_acthi ?
    				       1 : 0);
    		}
    		usleep_range(2000, 2000);
    	} else {
    		if (gpio_is_valid(ov5640->pdata->gpio_pwdn)) {
    			gpio_set_value(ov5640->pdata->gpio_pwdn,
    				       ov5640->pdata->is_gpio_pwdn_acthi ?
    				       0 : 1);
    		}
    		clk_disable(ov5640->xvclk);
    		if (ov5640->avdd)
    			regulator_disable(ov5640->avdd);
    		if (ov5640->dovdd)
    			regulator_disable(ov5640->dovdd);
    		if (ov5640->pdata->post_poweroff)
    			ov5640->pdata->post_poweroff(sd);
    	}
    
    	return 0;
    }
    
    static struct v4l2_subdev_core_ops ov5640_subdev_core_ops = {
    	.s_power	= ov5640_s_power,
    };
    
    static int ov5640_g_fmt(struct v4l2_subdev *sd,
    			struct v4l2_subdev_fh *fh,
    			struct v4l2_subdev_format *format)
    {
    	struct ov5640 *ov5640 = to_ov5640(sd);
    
    	format->format = *__ov5640_get_pad_format(ov5640, fh, format->pad,
    						   format->which);
    
    	return 0;
    }
    
    static int ov5640_s_fmt(struct v4l2_subdev *sd,
    			struct v4l2_subdev_fh *fh,
    			struct v4l2_subdev_format *format)
    {
    	struct ov5640 *ov5640 = to_ov5640(sd);
    	struct v4l2_mbus_framefmt *__format;
    
    	__format = __ov5640_get_pad_format(ov5640, fh, format->pad,
    					    format->which);
    
    	ov5640->pixel_rate->cur.val64 = ov5640_get_pclk(sd) / 16;
    
    	return 0;
    }
    
    static int ov5640_enum_fmt(struct v4l2_subdev *subdev,
    			   struct v4l2_subdev_fh *fh,
    			   struct v4l2_subdev_mbus_code_enum *code)
    {
    	if (code->index >= 2)
    		return -EINVAL;
    
    	switch (code->index) {
    	case 0:
    		code->code = V4L2_MBUS_FMT_UYVY8_2X8;
    		break;
    	case 1:
    		code->code = V4L2_MBUS_FMT_YUYV8_2X8;
    		break;
    	}
    	return 0;
    }
    
    static int ov5640_enum_framesizes(struct v4l2_subdev *subdev,
    				   struct v4l2_subdev_fh *fh,
    				   struct v4l2_subdev_frame_size_enum *fse)
    {
    	if ((fse->index >= OV5640_SIZE_LAST) ||
    	    (fse->code != V4L2_MBUS_FMT_UYVY8_2X8 &&
    	     fse->code != V4L2_MBUS_FMT_YUYV8_2X8))
    		return -EINVAL;
    
    	fse->min_width = ov5640_frmsizes[fse->index].width;
    	fse->max_width = fse->min_width;
    	fse->min_height = ov5640_frmsizes[fse->index].height;
    	fse->max_height = fse->min_height;
    
    	return 0;
    }
    
    static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
    {
    	struct ov5640 *ov5640 = to_ov5640(sd);
    	struct i2c_client *client = v4l2_get_subdevdata(sd);
    	int ret = 0;
    
    	if (enable) {
    		ov5640_s_power(&ov5640->subdev, 1);
    		u8 fmtreg = 0, fmtmuxreg = 0;
    		int i;
    
    		switch ((u32)ov5640->format.code) {
    		case V4L2_MBUS_FMT_UYVY8_2X8:
    			fmtreg = 0x32;
    			fmtmuxreg = 0;
    			break;
    		case V4L2_MBUS_FMT_YUYV8_2X8:
    			fmtreg = 0x30;
    			fmtmuxreg = 0;
    			break;
    		default:
    			/* This shouldn't happen */
    			ret = -EINVAL;
    			return ret;
    		}
    
    		ret = ov5640_reg_write(client, 0x4300, fmtreg);
    		if (ret)
    			return ret;
    
    		ret = ov5640_reg_write(client, 0x501F, fmtmuxreg);
    		if (ret)
    			return ret;
    
    		ret = ov5640_config_timing(sd);
    		if (ret)
    			return ret;
    
    		i = ov5640_find_framesize(ov5640->format.width, ov5640->format.height);
    		if ((i == OV5640_SIZE_QVGA) ||
    		    (i == OV5640_SIZE_VGA) ||
    		    (i == OV5640_SIZE_720P)) {
    			ret = ov5640_reg_write(client, 0x3108,
    					(i == OV5640_SIZE_720P) ? 0x1 : 0);
    			if (ret)
    				return ret;
    			ret = ov5640_reg_set(client, 0x5001, 0x20);
    		} else {
    			ret = ov5640_reg_clr(client, 0x5001, 0x20);
    			if (ret)
    				return ret;
    			ret = ov5640_reg_write(client, 0x3108, 0x2);
    		}
    
    		ret = ov5640_reg_clr(client, 0x3008, 0x40);
    		if (ret)
    			goto out;
    	} else {
    		u8 tmpreg = 0;
    
    		ret = ov5640_reg_read(client, 0x3008, &tmpreg);
    		if (ret)
    			goto out;
    
    		ret = ov5640_reg_write(client, 0x3008, tmpreg | 0x40);
    		if (ret)
    			goto out;
    		ov5640_s_power(&ov5640->subdev, 0);
    	}
    
     out:
    	return ret;
    }
    
    static struct v4l2_subdev_video_ops ov5640_subdev_video_ops = {
    	.s_stream	= ov5640_s_stream,
    };
    
    static struct v4l2_subdev_pad_ops ov5640_subdev_pad_ops = {
    	.enum_mbus_code = ov5640_enum_fmt,
    	.enum_frame_size = ov5640_enum_framesizes,
    	.get_fmt = ov5640_g_fmt,
    	.set_fmt = ov5640_s_fmt,
    };
    
    static int ov5640_g_skip_frames(struct v4l2_subdev *sd, u32 *frames)
    {
    	/* Quantity of initial bad frames to skip. Revisit. */
    	*frames = 3;
    
    	return 0;
    }
    
    static struct v4l2_subdev_sensor_ops ov5640_subdev_sensor_ops = {
    	.g_skip_frames	= ov5640_g_skip_frames,
    };
    
    static struct v4l2_subdev_ops ov5640_subdev_ops = {
    	.core	= &ov5640_subdev_core_ops,
    	.video	= &ov5640_subdev_video_ops,
    	.pad	= &ov5640_subdev_pad_ops,
    	.sensor	= &ov5640_subdev_sensor_ops,
    };
    
    static int ov5640_registered(struct v4l2_subdev *subdev)
    {
    	struct i2c_client *client = v4l2_get_subdevdata(subdev);
    	struct ov5640 *ov5640 = to_ov5640(subdev);
    	int ret = 0;
    	u8 revision = 0;
    	u8 msb;
    	u8 lsb;
    
    	ret = ov5640_s_power(subdev, 1);
    	if (ret < 0) {
    		dev_err(&client->dev, "OV5640 power up failed\n");
    		return ret;
    	}
    
    	ret = ov5640_reg_read(client, 0x302A, &revision);
    	if (ret) {
    		dev_err(&client->dev, "Failure to detect OV5640 chip\n");
    		goto out;
    	}
    
    	revision &= 0xF;
    
    	dev_info(&client->dev, "Detected a OV5640 chip, revision %x\n",
    		 revision);
    
    	/* SW Reset */
    	ret = ov5640_reg_set(client, 0x3008, 0x80);
    	if (ret)
    		goto out;
    
    	msleep(2);
    
    	ret = ov5640_reg_clr(client, 0x3008, 0x80);
    	if (ret)
    		goto out;
    
    	/* SW Powerdown */
    	ret = ov5640_reg_set(client, 0x3008, 0x40);
    	if (ret)
    		goto out;
    
    	/* Check chip id */
    	ret = ov5640_reg_read(client, 0x300A, &msb);
    	if (!ret)
    		ret = ov5640_reg_read(client, 0x300B, &lsb);
    	if (!ret) {
    		ov5640->id = (msb << 8) | lsb;
    		if (ov5640->id == 0x5640)
    			dev_info(&client->dev, "Sensor ID: %04X\n", ov5640->id);
    		else
    			dev_err(&client->dev, "Sensor detection failed (%04X, %d)\n",
    					ov5640->id, ret);
    	}
    	
    	ret = ov5640_reg_writes(client, configscript_common1,
    			ARRAY_SIZE(configscript_common1));
    	if (ret)
    		goto out;
    
    	ret = ov5640_reg_writes(client, configscript_common2,
    			ARRAY_SIZE(configscript_common2));
    	if (ret)
    		goto out;
    
    	/* Init controls */
    	ret = v4l2_ctrl_handler_init(&ov5640->ctrl_handler, 1);
    	if (ret)
    		goto out;
    
    	ov5640->pixel_rate = v4l2_ctrl_new_std(
    				&ov5640->ctrl_handler, NULL,
    				V4L2_CID_PIXEL_RATE,
    				0, 0, 1, 0);
    
    	subdev->ctrl_handler = &ov5640->ctrl_handler;
    out:
    	ov5640_s_power(subdev, 0);
    
    	return ret;
    }
    
    static int ov5640_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
    {
    	struct v4l2_mbus_framefmt *format;
    
    	format = v4l2_subdev_get_try_format(fh, 0);
    	format->code = V4L2_MBUS_FMT_YUYV8_2X8;/*V4L2_MBUS_FMT_UYVY8_2X8;*/
    	format->width = ov5640_frmsizes[OV5640_SIZE_VGA].width;
    	format->height = ov5640_frmsizes[OV5640_SIZE_VGA].height;
    	format->field = V4L2_FIELD_NONE;
    	format->colorspace = V4L2_COLORSPACE_JPEG;
    
    	return 0;
    }
    
    static int ov5640_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
    {
    	return 0;
    }
    
    static struct v4l2_subdev_internal_ops ov5640_subdev_internal_ops = {
    	.registered = ov5640_registered,
    	.open = ov5640_open,
    	.close = ov5640_close,
    };
    
    static int ov5640_get_resources(struct ov5640 *ov5640, struct device *dev)
    {
    	const struct ov5640_platform_data *pdata = ov5640->pdata;
    	int ret = 0;
    
    	ov5640->xvclk = clk_get(dev, pdata->clk_xvclk);
    	if (IS_ERR(ov5640->xvclk)) {
    		dev_err(dev, "Unable to get XVCLK (%s)\n", pdata->clk_xvclk);
    		return -ENODEV;
    	}
    
    	if (clk_round_rate(ov5640->xvclk, 24000000) != 24000000)
    		dev_warn(dev, "XVCLK set to rounded aproximate (%lu Hz)",
    			 clk_round_rate(ov5640->xvclk, 24000000));
    
    	if (clk_set_rate(ov5640->xvclk,
    			 clk_round_rate(ov5640->xvclk, 24000000))) {
    		dev_err(dev, "Unable to change XVCLK (%s) rate!\n",
    			pdata->clk_xvclk);
    		ret = -EINVAL;
    		goto err_clk_set_rate;
    	}
    
    	if (!pdata->reg_avdd)
    		goto get_reg_dovdd;
    
    	ov5640->avdd = devm_regulator_get(dev, pdata->reg_avdd);
    	if (IS_ERR(ov5640->avdd)) {
    		dev_err(dev, "Unable to get AVDD (%s) regulator\n",
    			pdata->reg_avdd);
    		ret = -ENODEV;
    		goto err_reg_avdd;
    	}
    
    	if (regulator_set_voltage(ov5640->avdd, 2800000, 2800000)) {
    		dev_err(dev, "Unable to set valid AVDD (%s) regulator"
    			" voltage to: 2.8V\n", pdata->reg_avdd);
    		ret = -ENODEV;
    		goto err_reg_avdd;
    	}
    
    get_reg_dovdd:
    	if (!pdata->reg_dovdd)
    		goto get_gpio_pwdn;
    
    	ov5640->dovdd = devm_regulator_get(dev, pdata->reg_dovdd);
    	if (IS_ERR(ov5640->dovdd)) {
    		dev_err(dev, "Unable to get DOVDD (%s) regulator\n",
    			pdata->reg_dovdd);
    		ret = -ENODEV;
    		goto err_reg_dovdd;
    	}
    
    	if (regulator_set_voltage(ov5640->dovdd, 1800000, 1800000)) {
    		dev_err(dev, "Unable to set valid DOVDD (%s) regulator"
    			" voltage to: 1.8V\n", pdata->reg_dovdd);
    		ret = -ENODEV;
    		goto err_reg_dovdd;
    	}
    
    get_gpio_pwdn:
    	if (!gpio_is_valid(pdata->gpio_pwdn))
    		goto get_gpio_resetb;
    
    	if (gpio_request_one(pdata->gpio_pwdn,
    			     pdata->is_gpio_pwdn_acthi ?
    			     GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
    			     "OV5640_PWDN")) {
    		dev_err(dev, "Cannot request GPIO %d\n", pdata->gpio_pwdn);
    		ret = -ENODEV;
    		goto err_gpio_pwdn;
    	}
    
    get_gpio_resetb:
    	if (!gpio_is_valid(pdata->gpio_resetb))
    		goto out;
    
    	if (gpio_request_one(pdata->gpio_resetb,
    			     pdata->is_gpio_resetb_acthi ?
    			     GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
    			     "OV5640_RESETB")) {
    		dev_err(dev, "Cannot request GPIO %d\n", pdata->gpio_resetb);
    		ret = -ENODEV;
    		goto err_gpio_resetb;
    	}
    
    out:
    	return 0;
    
    err_gpio_resetb:
    	if (gpio_is_valid(pdata->gpio_pwdn))
    		gpio_free(pdata->gpio_pwdn);
    err_gpio_pwdn:
    err_reg_dovdd:
    err_reg_avdd:
    err_clk_set_rate:
    	clk_put(ov5640->xvclk);
    
    	return ret;
    }
    
    static void ov5640_put_resources(struct ov5640 *ov5640)
    {
    	if (gpio_is_valid(ov5640->pdata->gpio_resetb))
    		gpio_free(ov5640->pdata->gpio_resetb);
    	if (gpio_is_valid(ov5640->pdata->gpio_pwdn))
    		gpio_free(ov5640->pdata->gpio_pwdn);
    	clk_put(ov5640->xvclk);
    }
    
    static struct ov5640_platform_data *
    ov5640_get_pdata(struct i2c_client *client)
    {
    	struct ov5640_platform_data *pdata;
    	struct device_node *endpoint;
    
    	dev_dbg(&client->dev, "ov5640_get_pdata invoked\n");
    
    	if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
    		return client->dev.platform_data;
    
    	dev_dbg(&client->dev, "ov5640_get_pdata: DT Node found\n");
    
    	endpoint = v4l2_of_get_next_endpoint(client->dev.of_node, NULL);
    	if (!endpoint)
    		return NULL;
    
    	dev_dbg(&client->dev, "ov5640_get_data: endpoint found\n");
    
    	pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
    	if (!pdata)
    		goto done;
    
     done:
    	of_node_put(endpoint);
    
    	return pdata;
    }
    
    static int ov5640_probe(struct i2c_client *client,
    			 const struct i2c_device_id *did)
    {
    	struct ov5640 *ov5640;
    	int ret;
    	/*
    	if (!client->dev.platform_data) {
    		dev_err(&client->dev, "No platform data!!\n");
    		return -ENODEV;
    	}
    	*/
    
    	ov5640 = kzalloc(sizeof(*ov5640), GFP_KERNEL);
    	if (!ov5640)
    		return -ENOMEM;
    
    	ov5640->pdata = ov5640_get_pdata(client);//client->dev.platform_data;
    	/*
    	ret = ov5640_get_resources(ov5640, &client->dev);
    	if (ret) {
    		kfree(ov5640);
    		return ret;
    	}
    	*/
    	ov5640->format.code = V4L2_MBUS_FMT_YUYV8_2X8;/*V4L2_MBUS_FMT_UYVY8_2X8;*/
    	ov5640->format.width = ov5640_frmsizes[OV5640_SIZE_VGA].width;
    	ov5640->format.height = ov5640_frmsizes[OV5640_SIZE_VGA].height;
    	ov5640->format.field = V4L2_FIELD_NONE;
    	ov5640->format.colorspace = V4L2_COLORSPACE_JPEG;
    
    	ov5640->clk_cfg.sc_pll_prediv = 3;
    	ov5640->clk_cfg.sc_pll_rdiv = 1;
    	ov5640->clk_cfg.sc_pll_mult = 84;
    	ov5640->clk_cfg.sysclk_div = 1;
    	ov5640->clk_cfg.mipi_div = 1;
    
    	v4l2_i2c_subdev_init(&ov5640->subdev, client, &ov5640_subdev_ops);
    	strlcpy(ov5640->subdev.name, "ov5640", sizeof(ov5640->subdev.name)); /* Jakebo */
    	ov5640->subdev.internal_ops = &ov5640_subdev_internal_ops;
    	ov5640->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
    	
    	ov5640->subdev.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
    	ov5640->pad.flags = MEDIA_PAD_FL_SOURCE;
    	ret = media_entity_init(&ov5640->subdev.entity, 1, &ov5640->pad, 0);
    	if (ret < 0) {
    		media_entity_cleanup(&ov5640->subdev.entity);
    		ov5640_put_resources(ov5640);
    		kfree(ov5640);
    	}
    
    	/* aync sub device resgister, Jakebo */
    	ret = v4l2_async_register_subdev(&ov5640->subdev);
    	if (ret)
    		dev_err(&client->dev, "v4l2 subdev async failed\n");;
    
    	dev_info(&client->dev, "%s sensor driver registered !!\n",
    			 ov5640->subdev.name);
    
    	return ret;
    }
    
    static int ov5640_remove(struct i2c_client *client)
    {
    	struct v4l2_subdev *subdev = i2c_get_clientdata(client);
    	struct ov5640 *ov5640 = to_ov5640(subdev);
    
    	v4l2_ctrl_handler_free(&ov5640->ctrl_handler);
    	media_entity_cleanup(&subdev->entity);
    	v4l2_async_unregister_subdev(subdev); /* Jakebo */
    	v4l2_device_unregister_subdev(subdev);
    	// ov5640_put_resources(ov5640);
    	kfree(ov5640);
    	return 0;
    }
    
    static const struct i2c_device_id ov5640_id[] = {
    	{ "ov5640", 0 },
    	{ }
    };
    MODULE_DEVICE_TABLE(i2c, ov5640_id);
    
    /* ov5640 of match, Jakebo */
    #if IS_ENABLED(CONFIG_OF)
    static const struct of_device_id ov5640_of_match[] = {
    	{ .compatible = "ti,ov5640", },
    	{ /* sentinel */ }
    };
    MODULE_DEVICE_TABLE(of, ov5640_of_match);
    #endif
    
    static struct i2c_driver ov5640_i2c_driver = {
    	.driver = {
    		.name = "ov5640",
    		.of_match_table = of_match_ptr(ov5640_of_match), /* Jakebo */
    	},
    	.probe		= ov5640_probe,
    	.remove		= ov5640_remove,
    	.id_table	= ov5640_id,
    };
    
    static int __init ov5640_mod_init(void)
    {
    	return i2c_add_driver(&ov5640_i2c_driver);
    }
    
    static void __exit ov5640_mod_exit(void)
    {
    	i2c_del_driver(&ov5640_i2c_driver);
    }
    
    module_init(ov5640_mod_init);
    module_exit(ov5640_mod_exit);
    
    MODULE_DESCRIPTION("OmniVision OV5640 Camera driver");
    MODULE_AUTHOR("Sergio Aguirre <sergio.a.aguirre@gmail.com>");
    MODULE_LICENSE("GPL v2");
    

    Do you have ideas?

    Hope this will help you to understand the problem,  otherwise please don't hesitate to ask for more information.

    Best Regards,

    Jakebo

  • Hi Jakebo,

    Thanks for reply.  I will check same driver  for our board and test application as well.

    Few things to know

    1. Which interface you using for sensor MIPI or 8 bit parallel mode?

    2. If you are using  MIPI interface, can you check on your clock setting in driver.

    3. Which resolution and format you are using for test ?

    You are facing issue  "VIDIOC_DQBUF" so VIDIOC_QBUF is working? if VIDIOC_QBUF is working can you check data before Application dequeue it?

  • Hi Debi,

    1. I am using 8 bit parallel mode

    2. I am using 640x480 resolution and V4L2_PIX_FMT_YUYV format


    yes the VIDIOC_QBUF is working correctly, I will check the data befor application dequeue.

    Below is the camera relative design in my product:


    Thanks & Best Regards,

    Jakebo

  • Hi Debi,
    Following the previous reply...
    I can use OV2659 on my product, so the hardware design should be correctly.
  • Hi Jakebo,

    Any updates for this from your side?

    I tried to compile your driver , but compilation errors are coming because of  OV5640.h file is missing. I have tried to download 5640.h file from net , looks like you are using own modified header file. Can you please share your ov5640.h file.

    We are using 8 bit parallel  interface for our sensor with AM437x based custom board.

  • Oh! Sorry I forgot the ov5640.h! And I am on holiday these days, I will send this file to you ASAP when I back at Monday.
  • Hi Debi,

    This file is the ov5640.h, hope that is some helps.

    ov5640.h

  • Hi Jakebo,

        I am also working with a OV5640 module with the AM437x EVM . Would appreciate your help in knowing your progress. I am still trying to detect the sensor. Saw your code on the forum, can you attached the 0v6540.h?  Thanks.

    Best Regards,

    Khim.

  • Hi, I use the files you provided for ov5640 on AM437x board, and found the kernel can detect the sensor correctly.
    But when I ran the ti example "dual_camera", it shows "select timeout" error.
    I have checked the pclk, hsync, and vsync, found I can got pclk and hsync, but can't get vsync.
    Could you please give me some suggesttion? Like which registers need to be checked?
    Thanks.
  • Hi Khim,
    What's the status of the OV5640 driver on your Am437x board?
    Thanks.
  • Hi Khim,
    Sorry for the late reply, but I am not longer work with OV5640 and have not the ov5640.h now, you can search this file from google.