diff --git a/arch/arm/configs/imx_v7_defconfig b/arch/arm/configs/imx_v7_defconfig index 2682d5526ef1..4884dacee43c 100644 --- a/arch/arm/configs/imx_v7_defconfig +++ b/arch/arm/configs/imx_v7_defconfig @@ -154,10 +154,10 @@ CONFIG_KEYBOARD_IMX=y CONFIG_MOUSE_PS2=m CONFIG_MOUSE_PS2_ELANTECH=y CONFIG_INPUT_TOUCHSCREEN=y -CONFIG_TOUCHSCREEN_IMX6UL_TSC=y CONFIG_TOUCHSCREEN_EGALAX=y CONFIG_TOUCHSCREEN_ELAN=y CONFIG_TOUCHSCREEN_MAX11801=y +CONFIG_TOUCHSCREEN_IMX6UL_TSC=y CONFIG_TOUCHSCREEN_MC13783=y CONFIG_TOUCHSCREEN_TSC2007=y CONFIG_TOUCHSCREEN_STMPE=y @@ -217,10 +217,20 @@ CONFIG_MEDIA_USB_SUPPORT=y CONFIG_USB_VIDEO_CLASS=m CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_VIDEO_MXC_OUTPUT=y -CONFIG_SOC_CAMERA=y -CONFIG_VIDEO_MX3=y +CONFIG_VIDEO_MXC_CAPTURE=m +CONFIG_MXC_CAMERA_OV5640=m +CONFIG_MXC_CAMERA_OV5642=m +CONFIG_MXC_CAMERA_OV5640_MIPI=m +CONFIG_MXC_TVIN_ADV7180=m +CONFIG_MXC_IPU_DEVICE_QUEUE_SDC=m CONFIG_VIDEO_MXC_IPU_OUTPUT=y CONFIG_VIDEO_MXC_PXP_V4L2=y +CONFIG_VIDEO_MXC_CSI_CAMERA=m +CONFIG_MXC_VADC=m +CONFIG_MXC_MIPI_CSI=m +CONFIG_MXC_CAMERA_OV5647_MIPI=m +CONFIG_SOC_CAMERA=y +CONFIG_VIDEO_MX3=y CONFIG_V4L_MEM2MEM_DRIVERS=y CONFIG_VIDEO_CODA=y CONFIG_RADIO_SI476X=y @@ -303,6 +313,8 @@ CONFIG_MXC_MLB150=m CONFIG_MXC_IPU_V3_PRE=y CONFIG_MXC_GPU_VIV=y CONFIG_MXC_SIM=y +CONFIG_MXC_MIPI_CSI2=y +CONFIG_MXC_HDMI_CEC=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_GPIO=y diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 6bf02b85f881..5b83cd5639d3 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -121,13 +121,21 @@ config VIDEO_MXC_OUTPUT ---help--- This is the video4linux2 output driver based on MXC module. +config VIDEO_MXC_CAPTURE + tristate "MXC Video For Linux Video Capture" + depends on VIDEO_V4L2 + ---help--- + This is the video4linux2 capture driver based on i.MX video-in module. + +source "drivers/media/platform/mxc/capture/Kconfig" +source "drivers/media/platform/mxc/output/Kconfig" +source "drivers/media/platform/mxc/subdev/Kconfig" source "drivers/media/platform/soc_camera/Kconfig" source "drivers/media/platform/exynos4-is/Kconfig" source "drivers/media/platform/s5p-tv/Kconfig" source "drivers/media/platform/am437x/Kconfig" source "drivers/media/platform/xilinx/Kconfig" -source "drivers/media/platform/mxc/output/Kconfig" endif # V4L_PLATFORM_DRIVERS diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index a4bfc7b7d284..8a8af784cd9a 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -50,6 +50,8 @@ obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/ obj-$(CONFIG_VIDEO_XILINX) += xilinx/ +obj-$(CONFIG_VIDEO_MXC_CAPTURE) += mxc/capture/ +obj-$(CONFIG_VIDEO_MXC_CAPTURE) += mxc/subdev/ obj-$(CONFIG_VIDEO_MXC_OUTPUT) += mxc/output/ ccflags-y += -I$(srctree)/drivers/media/i2c diff --git a/drivers/media/platform/mxc/capture/Kconfig b/drivers/media/platform/mxc/capture/Kconfig new file mode 100644 index 000000000000..e8728d9dedeb --- /dev/null +++ b/drivers/media/platform/mxc/capture/Kconfig @@ -0,0 +1,83 @@ +if VIDEO_MXC_CAPTURE +config VIDEO_V4L2_MXC_INT_DEVICE + tristate + +menu "MXC Camera/V4L2 PRP Features support" +config VIDEO_MXC_IPU_CAMERA + bool + select VIDEO_V4L2_MXC_INT_DEVICE + depends on VIDEO_MXC_CAPTURE && MXC_IPU + default y + +config MXC_CAMERA_OV5640 + tristate "OmniVision ov5640 camera support" + depends on !VIDEO_MXC_EMMA_CAMERA && I2C + ---help--- + If you plan to use the ov5640 Camera with your MXC system, say Y here. + +config MXC_CAMERA_OV5642 + tristate "OmniVision ov5642 camera support" + depends on !VIDEO_MXC_EMMA_CAMERA && I2C + ---help--- + If you plan to use the ov5642 Camera with your MXC system, say Y here. + +config MXC_CAMERA_OV5640_MIPI + tristate "OmniVision ov5640 camera support using mipi" + depends on !VIDEO_MXC_EMMA_CAMERA && I2C + ---help--- + If you plan to use the ov5640 Camera with mipi interface in your MXC system, say Y here. + +config MXC_TVIN_ADV7180 + tristate "Analog Device adv7180 TV Decoder Input support" + depends on !VIDEO_MXC_EMMA_CAMERA && I2C + ---help--- + If you plan to use the adv7180 video decoder with your MXC system, say Y here. + +choice + prompt "Select Overlay Rounting" + default MXC_IPU_DEVICE_QUEUE_SDC + depends on VIDEO_MXC_IPU_CAMERA && FB_MXC_SYNC_PANEL + +config MXC_IPU_DEVICE_QUEUE_SDC + tristate "Queue ipu device for overlay library" + depends on VIDEO_MXC_IPU_CAMERA + ---help--- + Use case CSI->MEM->IPU DEVICE->SDC: + Images from sensor will be frist recieved in memory,then + queue to ipu device for processing if needed, and displaying + it on synchronous display with SDC use case. + +config MXC_IPU_PRP_VF_SDC + bool "Pre-Processor VF SDC library" + depends on VIDEO_MXC_IPU_CAMERA + ---help--- + Use case PRP_VF_SDC: + Preprocessing image from smart sensor for viewfinder and + displaying it on synchronous display with SDC use case. + If SDC BG is selected, Rotation will not be supported. + CSI -> IC (PRP VF) -> MEM + MEM -> IC (ROT) -> MEM + MEM -> SDC (FG/BG) + +endchoice + +config MXC_IPU_PRP_ENC + tristate "Pre-processor Encoder library" + depends on VIDEO_MXC_IPU_CAMERA + default y + ---help--- + Use case PRP_ENC: + Preprocessing image from smart sensor for encoder. + CSI -> IC (PRP ENC) -> MEM + +config MXC_IPU_CSI_ENC + tristate "IPU CSI Encoder library" + depends on VIDEO_MXC_IPU_CAMERA + default y + ---help--- + Use case IPU_CSI_ENC: + Get raw image with CSI from smart sensor for encoder. + CSI -> MEM +endmenu + +endif diff --git a/drivers/media/platform/mxc/capture/Makefile b/drivers/media/platform/mxc/capture/Makefile new file mode 100644 index 000000000000..6c04faf70800 --- /dev/null +++ b/drivers/media/platform/mxc/capture/Makefile @@ -0,0 +1,21 @@ +ifeq ($(CONFIG_VIDEO_MXC_IPU_CAMERA),y) + obj-$(CONFIG_VIDEO_MXC_CAPTURE) += mxc_v4l2_capture.o + obj-$(CONFIG_MXC_IPU_PRP_VF_SDC) += ipu_prp_vf_sdc.o ipu_prp_vf_sdc_bg.o + obj-$(CONFIG_MXC_IPU_DEVICE_QUEUE_SDC) += ipu_fg_overlay_sdc.o ipu_bg_overlay_sdc.o + obj-$(CONFIG_MXC_IPU_PRP_ENC) += ipu_prp_enc.o ipu_still.o + obj-$(CONFIG_MXC_IPU_CSI_ENC) += ipu_csi_enc.o ipu_still.o +endif + +ov5640_camera_int-objs := ov5640.o +obj-$(CONFIG_MXC_CAMERA_OV5640) += ov5640_camera_int.o + +ov5642_camera-objs := ov5642.o +obj-$(CONFIG_MXC_CAMERA_OV5642) += ov5642_camera.o + +ov5640_camera_mipi_int-objs := ov5640_mipi.o +obj-$(CONFIG_MXC_CAMERA_OV5640_MIPI) += ov5640_camera_mipi_int.o + +adv7180_tvin-objs := adv7180.o +obj-$(CONFIG_MXC_TVIN_ADV7180) += adv7180_tvin.o + +obj-$(CONFIG_VIDEO_V4L2_MXC_INT_DEVICE) += v4l2-int-device.o diff --git a/drivers/media/platform/mxc/capture/adv7180.c b/drivers/media/platform/mxc/capture/adv7180.c new file mode 100644 index 000000000000..abd615927a48 --- /dev/null +++ b/drivers/media/platform/mxc/capture/adv7180.c @@ -0,0 +1,1380 @@ +/* + * Copyright 2005-2014 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file adv7180.c + * + * @brief Analog Device ADV7180 video decoder functions + * + * @ingroup Camera + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "v4l2-int-device.h" +#include "mxc_v4l2_capture.h" + +#define ADV7180_VOLTAGE_ANALOG 1800000 +#define ADV7180_VOLTAGE_DIGITAL_CORE 1800000 +#define ADV7180_VOLTAGE_DIGITAL_IO 3300000 +#define ADV7180_VOLTAGE_PLL 1800000 + +static struct regulator *dvddio_regulator; +static struct regulator *dvdd_regulator; +static struct regulator *avdd_regulator; +static struct regulator *pvdd_regulator; +static int pwn_gpio; + +static int adv7180_probe(struct i2c_client *adapter, + const struct i2c_device_id *id); +static int adv7180_detach(struct i2c_client *client); + +static const struct i2c_device_id adv7180_id[] = { + {"adv7180", 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, adv7180_id); + +static struct i2c_driver adv7180_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "adv7180", + }, + .probe = adv7180_probe, + .remove = adv7180_detach, + .id_table = adv7180_id, +}; + +/*! + * Maintains the information on the current state of the sensor. + */ +struct sensor { + struct sensor_data sen; + v4l2_std_id std_id; +} adv7180_data; + + +/*! List of input video formats supported. The video formats is corresponding + * with v4l2 id in video_fmt_t + */ +typedef enum { + ADV7180_NTSC = 0, /*!< Locked on (M) NTSC video signal. */ + ADV7180_PAL, /*!< (B, G, H, I, N)PAL video signal. */ + ADV7180_NOT_LOCKED, /*!< Not locked on a signal. */ +} video_fmt_idx; + +/*! Number of video standards supported (including 'not locked' signal). */ +#define ADV7180_STD_MAX (ADV7180_PAL + 1) + +/*! Video format structure. */ +typedef struct { + int v4l2_id; /*!< Video for linux ID. */ + char name[16]; /*!< Name (e.g., "NTSC", "PAL", etc.) */ + u16 raw_width; /*!< Raw width. */ + u16 raw_height; /*!< Raw height. */ + u16 active_width; /*!< Active width. */ + u16 active_height; /*!< Active height. */ + int frame_rate; /*!< Frame rate. */ +} video_fmt_t; + +/*! Description of video formats supported. + * + * PAL: raw=720x625, active=720x576. + * NTSC: raw=720x525, active=720x480. + */ +static video_fmt_t video_fmts[] = { + { /*! NTSC */ + .v4l2_id = V4L2_STD_NTSC, + .name = "NTSC", + .raw_width = 720, /* SENS_FRM_WIDTH */ + .raw_height = 525, /* SENS_FRM_HEIGHT */ + .active_width = 720, /* ACT_FRM_WIDTH plus 1 */ + .active_height = 480, /* ACT_FRM_WIDTH plus 1 */ + .frame_rate = 30, + }, + { /*! (B, G, H, I, N) PAL */ + .v4l2_id = V4L2_STD_PAL, + .name = "PAL", + .raw_width = 720, + .raw_height = 625, + .active_width = 720, + .active_height = 576, + .frame_rate = 25, + }, + { /*! Unlocked standard */ + .v4l2_id = V4L2_STD_ALL, + .name = "Autodetect", + .raw_width = 720, + .raw_height = 625, + .active_width = 720, + .active_height = 576, + .frame_rate = 0, + }, +}; + +/*!* Standard index of ADV7180. */ +static video_fmt_idx video_idx = ADV7180_PAL; + +/*! @brief This mutex is used to provide mutual exclusion. + * + * Create a mutex that can be used to provide mutually exclusive + * read/write access to the globally accessible data structures + * and variables that were defined above. + */ +static DEFINE_MUTEX(mutex); + +#define IF_NAME "adv7180" +#define ADV7180_INPUT_CTL 0x00 /* Input Control */ +#define ADV7180_STATUS_1 0x10 /* Status #1 */ +#define ADV7180_BRIGHTNESS 0x0a /* Brightness */ +#define ADV7180_IDENT 0x11 /* IDENT */ +#define ADV7180_VSYNC_FIELD_CTL_1 0x31 /* VSYNC Field Control #1 */ +#define ADV7180_MANUAL_WIN_CTL 0x3d /* Manual Window Control */ +#define ADV7180_SD_SATURATION_CB 0xe3 /* SD Saturation Cb */ +#define ADV7180_SD_SATURATION_CR 0xe4 /* SD Saturation Cr */ +#define ADV7180_PWR_MNG 0x0f /* Power Management */ + +/* supported controls */ +/* This hasn't been fully implemented yet. + * This is how it should work, though. */ +static struct v4l2_queryctrl adv7180_qctrl[] = { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, /* check this value */ + .maximum = 255, /* check this value */ + .step = 1, /* check this value */ + .default_value = 127, /* check this value */ + .flags = 0, + }, { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, /* check this value */ + .maximum = 255, /* check this value */ + .step = 0x1, /* check this value */ + .default_value = 127, /* check this value */ + .flags = 0, + } +}; + +static inline void adv7180_power_down(int enable) +{ + gpio_set_value_cansleep(pwn_gpio, !enable); + msleep(2); +} + +static int adv7180_regulator_enable(struct device *dev) +{ + int ret = 0; + + dvddio_regulator = devm_regulator_get(dev, "DOVDD"); + + if (!IS_ERR(dvddio_regulator)) { + regulator_set_voltage(dvddio_regulator, + ADV7180_VOLTAGE_DIGITAL_IO, + ADV7180_VOLTAGE_DIGITAL_IO); + ret = regulator_enable(dvddio_regulator); + if (ret) { + dev_err(dev, "set io voltage failed\n"); + return ret; + } else { + dev_dbg(dev, "set io voltage ok\n"); + } + } else { + dev_warn(dev, "cannot get io voltage\n"); + } + + dvdd_regulator = devm_regulator_get(dev, "DVDD"); + if (!IS_ERR(dvdd_regulator)) { + regulator_set_voltage(dvdd_regulator, + ADV7180_VOLTAGE_DIGITAL_CORE, + ADV7180_VOLTAGE_DIGITAL_CORE); + ret = regulator_enable(dvdd_regulator); + if (ret) { + dev_err(dev, "set core voltage failed\n"); + return ret; + } else { + dev_dbg(dev, "set core voltage ok\n"); + } + } else { + dev_warn(dev, "cannot get core voltage\n"); + } + + avdd_regulator = devm_regulator_get(dev, "AVDD"); + if (!IS_ERR(avdd_regulator)) { + regulator_set_voltage(avdd_regulator, + ADV7180_VOLTAGE_ANALOG, + ADV7180_VOLTAGE_ANALOG); + ret = regulator_enable(avdd_regulator); + if (ret) { + dev_err(dev, "set analog voltage failed\n"); + return ret; + } else { + dev_dbg(dev, "set analog voltage ok\n"); + } + } else { + dev_warn(dev, "cannot get analog voltage\n"); + } + + pvdd_regulator = devm_regulator_get(dev, "PVDD"); + if (!IS_ERR(pvdd_regulator)) { + regulator_set_voltage(pvdd_regulator, + ADV7180_VOLTAGE_PLL, + ADV7180_VOLTAGE_PLL); + ret = regulator_enable(pvdd_regulator); + if (ret) { + dev_err(dev, "set pll voltage failed\n"); + return ret; + } else { + dev_dbg(dev, "set pll voltage ok\n"); + } + } else { + dev_warn(dev, "cannot get pll voltage\n"); + } + + return ret; +} + + +/*********************************************************************** + * I2C transfert. + ***********************************************************************/ + +/*! Read one register from a ADV7180 i2c slave device. + * + * @param *reg register in the device we wish to access. + * + * @return 0 if success, an error code otherwise. + */ +static inline int adv7180_read(u8 reg) +{ + int val; + + val = i2c_smbus_read_byte_data(adv7180_data.sen.i2c_client, reg); + if (val < 0) { + dev_dbg(&adv7180_data.sen.i2c_client->dev, + "%s:read reg error: reg=%2x\n", __func__, reg); + return -1; + } + return val; +} + +/*! Write one register of a ADV7180 i2c slave device. + * + * @param *reg register in the device we wish to access. + * + * @return 0 if success, an error code otherwise. + */ +static int adv7180_write_reg(u8 reg, u8 val) +{ + s32 ret; + + ret = i2c_smbus_write_byte_data(adv7180_data.sen.i2c_client, reg, val); + if (ret < 0) { + dev_dbg(&adv7180_data.sen.i2c_client->dev, + "%s:write reg error:reg=%2x,val=%2x\n", __func__, + reg, val); + return -1; + } + return 0; +} + +/*********************************************************************** + * mxc_v4l2_capture interface. + ***********************************************************************/ + +/*! + * Return attributes of current video standard. + * Since this device autodetects the current standard, this function also + * sets the values that need to be changed if the standard changes. + * There is no set std equivalent function. + * + * @return None. + */ +static void adv7180_get_std(v4l2_std_id *std) +{ + int status_1, standard, idx; + bool locked; + + dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180_get_std\n"); + + status_1 = adv7180_read(ADV7180_STATUS_1); + locked = status_1 & 0x1; + standard = status_1 & 0x70; + + mutex_lock(&mutex); + *std = V4L2_STD_ALL; + idx = ADV7180_NOT_LOCKED; + if (locked) { + if (standard == 0x40) { + *std = V4L2_STD_PAL; + idx = ADV7180_PAL; + } else if (standard == 0) { + *std = V4L2_STD_NTSC; + idx = ADV7180_NTSC; + } + } + mutex_unlock(&mutex); + + /* This assumes autodetect which this device uses. */ + if (*std != adv7180_data.std_id) { + video_idx = idx; + adv7180_data.std_id = *std; + adv7180_data.sen.pix.width = video_fmts[video_idx].raw_width; + adv7180_data.sen.pix.height = video_fmts[video_idx].raw_height; + } +} + +/*********************************************************************** + * IOCTL Functions from v4l2_int_ioctl_desc. + ***********************************************************************/ + +/*! + * ioctl_g_ifparm - V4L2 sensor interface handler for vidioc_int_g_ifparm_num + * s: pointer to standard V4L2 device structure + * p: pointer to standard V4L2 vidioc_int_g_ifparm_num ioctl structure + * + * Gets slave interface parameters. + * Calculates the required xclk value to support the requested + * clock parameters in p. This value is returned in the p + * parameter. + * + * vidioc_int_g_ifparm returns platform-specific information about the + * interface settings used by the sensor. + * + * Called on open. + */ +static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p) +{ + dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_g_ifparm\n"); + + if (s == NULL) { + pr_err(" ERROR!! no slave device set!\n"); + return -1; + } + + /* Initialize structure to 0s then set any non-0 values. */ + memset(p, 0, sizeof(*p)); + p->if_type = V4L2_IF_TYPE_BT656; /* This is the only possibility. */ + p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT; + p->u.bt656.nobt_hs_inv = 1; + p->u.bt656.bt_sync_correct = 1; + + /* ADV7180 has a dedicated clock so no clock settings needed. */ + + return 0; +} + +/*! + * Sets the camera power. + * + * s pointer to the camera device + * on if 1, power is to be turned on. 0 means power is to be turned off + * + * ioctl_s_power - V4L2 sensor interface handler for vidioc_int_s_power_num + * @s: pointer to standard V4L2 device structure + * @on: power state to which device is to be set + * + * Sets devices power state to requrested state, if possible. + * This is called on open, close, suspend and resume. + */ +static int ioctl_s_power(struct v4l2_int_device *s, int on) +{ + struct sensor *sensor = s->priv; + + dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_s_power\n"); + + if (on && !sensor->sen.on) { + if (adv7180_write_reg(ADV7180_PWR_MNG, 0x04) != 0) + return -EIO; + + /* + * FIXME:Additional 400ms to wait the chip to be stable? + * This is a workaround for preview scrolling issue. + */ + msleep(400); + } else if (!on && sensor->sen.on) { + if (adv7180_write_reg(ADV7180_PWR_MNG, 0x24) != 0) + return -EIO; + } + + sensor->sen.on = on; + + return 0; +} + +/*! + * ioctl_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl + * @s: pointer to standard V4L2 device structure + * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure + * + * Returns the sensor's video CAPTURE parameters. + */ +static int ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) +{ + struct sensor *sensor = s->priv; + struct v4l2_captureparm *cparm = &a->parm.capture; + + dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_g_parm\n"); + + switch (a->type) { + /* These are all the possible cases. */ + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + pr_debug(" type is V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); + memset(a, 0, sizeof(*a)); + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + cparm->capability = sensor->sen.streamcap.capability; + cparm->timeperframe = sensor->sen.streamcap.timeperframe; + cparm->capturemode = sensor->sen.streamcap.capturemode; + break; + + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + break; + + default: + pr_debug("ioctl_g_parm:type is unknown %d\n", a->type); + break; + } + + return 0; +} + +/*! + * ioctl_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl + * @s: pointer to standard V4L2 device structure + * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure + * + * Configures the sensor to use the input parameters, if possible. If + * not possible, reverts to the old parameters and returns the + * appropriate error code. + * + * This driver cannot change these settings. + */ +static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) +{ + dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_s_parm\n"); + + switch (a->type) { + /* These are all the possible cases. */ + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + break; + + default: + pr_debug(" type is unknown - %d\n", a->type); + break; + } + + return 0; +} + +/*! + * ioctl_g_fmt_cap - V4L2 sensor interface handler for ioctl_g_fmt_cap + * @s: pointer to standard V4L2 device structure + * @f: pointer to standard V4L2 v4l2_format structure + * + * Returns the sensor's current pixel format in the v4l2_format + * parameter. + */ +static int ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) +{ + struct sensor *sensor = s->priv; + + dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_g_fmt_cap\n"); + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + pr_debug(" Returning size of %dx%d\n", + sensor->sen.pix.width, sensor->sen.pix.height); + f->fmt.pix = sensor->sen.pix; + break; + + case V4L2_BUF_TYPE_PRIVATE: { + v4l2_std_id std; + adv7180_get_std(&std); + f->fmt.pix.pixelformat = (u32)std; + } + break; + + default: + f->fmt.pix = sensor->sen.pix; + break; + } + + return 0; +} + +/*! + * ioctl_queryctrl - V4L2 sensor interface handler for VIDIOC_QUERYCTRL ioctl + * @s: pointer to standard V4L2 device structure + * @qc: standard V4L2 VIDIOC_QUERYCTRL ioctl structure + * + * If the requested control is supported, returns the control information + * from the video_control[] array. Otherwise, returns -EINVAL if the + * control is not supported. + */ +static int ioctl_queryctrl(struct v4l2_int_device *s, + struct v4l2_queryctrl *qc) +{ + int i; + + dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_queryctrl\n"); + + for (i = 0; i < ARRAY_SIZE(adv7180_qctrl); i++) + if (qc->id && qc->id == adv7180_qctrl[i].id) { + memcpy(qc, &(adv7180_qctrl[i]), + sizeof(*qc)); + return 0; + } + + return -EINVAL; +} + +/*! + * ioctl_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl + * @s: pointer to standard V4L2 device structure + * @vc: standard V4L2 VIDIOC_G_CTRL ioctl structure + * + * If the requested control is supported, returns the control's current + * value from the video_control[] array. Otherwise, returns -EINVAL + * if the control is not supported. + */ +static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) +{ + int ret = 0; + int sat = 0; + + dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_g_ctrl\n"); + + switch (vc->id) { + case V4L2_CID_BRIGHTNESS: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_BRIGHTNESS\n"); + adv7180_data.sen.brightness = adv7180_read(ADV7180_BRIGHTNESS); + vc->value = adv7180_data.sen.brightness; + break; + case V4L2_CID_CONTRAST: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_CONTRAST\n"); + vc->value = adv7180_data.sen.contrast; + break; + case V4L2_CID_SATURATION: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_SATURATION\n"); + sat = adv7180_read(ADV7180_SD_SATURATION_CB); + adv7180_data.sen.saturation = sat; + vc->value = adv7180_data.sen.saturation; + break; + case V4L2_CID_HUE: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_HUE\n"); + vc->value = adv7180_data.sen.hue; + break; + case V4L2_CID_AUTO_WHITE_BALANCE: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_AUTO_WHITE_BALANCE\n"); + break; + case V4L2_CID_DO_WHITE_BALANCE: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_DO_WHITE_BALANCE\n"); + break; + case V4L2_CID_RED_BALANCE: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_RED_BALANCE\n"); + vc->value = adv7180_data.sen.red; + break; + case V4L2_CID_BLUE_BALANCE: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_BLUE_BALANCE\n"); + vc->value = adv7180_data.sen.blue; + break; + case V4L2_CID_GAMMA: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_GAMMA\n"); + break; + case V4L2_CID_EXPOSURE: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_EXPOSURE\n"); + vc->value = adv7180_data.sen.ae_mode; + break; + case V4L2_CID_AUTOGAIN: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_AUTOGAIN\n"); + break; + case V4L2_CID_GAIN: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_GAIN\n"); + break; + case V4L2_CID_HFLIP: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_HFLIP\n"); + break; + case V4L2_CID_VFLIP: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_VFLIP\n"); + break; + default: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " Default case\n"); + vc->value = 0; + ret = -EPERM; + break; + } + + return ret; +} + +/*! + * ioctl_s_ctrl - V4L2 sensor interface handler for VIDIOC_S_CTRL ioctl + * @s: pointer to standard V4L2 device structure + * @vc: standard V4L2 VIDIOC_S_CTRL ioctl structure + * + * If the requested control is supported, sets the control's current + * value in HW (and updates the video_control[] array). Otherwise, + * returns -EINVAL if the control is not supported. + */ +static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) +{ + int retval = 0; + u8 tmp; + + dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_s_ctrl\n"); + + switch (vc->id) { + case V4L2_CID_BRIGHTNESS: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_BRIGHTNESS\n"); + tmp = vc->value; + adv7180_write_reg(ADV7180_BRIGHTNESS, tmp); + adv7180_data.sen.brightness = vc->value; + break; + case V4L2_CID_CONTRAST: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_CONTRAST\n"); + break; + case V4L2_CID_SATURATION: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_SATURATION\n"); + tmp = vc->value; + adv7180_write_reg(ADV7180_SD_SATURATION_CB, tmp); + adv7180_write_reg(ADV7180_SD_SATURATION_CR, tmp); + adv7180_data.sen.saturation = vc->value; + break; + case V4L2_CID_HUE: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_HUE\n"); + break; + case V4L2_CID_AUTO_WHITE_BALANCE: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_AUTO_WHITE_BALANCE\n"); + break; + case V4L2_CID_DO_WHITE_BALANCE: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_DO_WHITE_BALANCE\n"); + break; + case V4L2_CID_RED_BALANCE: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_RED_BALANCE\n"); + break; + case V4L2_CID_BLUE_BALANCE: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_BLUE_BALANCE\n"); + break; + case V4L2_CID_GAMMA: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_GAMMA\n"); + break; + case V4L2_CID_EXPOSURE: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_EXPOSURE\n"); + break; + case V4L2_CID_AUTOGAIN: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_AUTOGAIN\n"); + break; + case V4L2_CID_GAIN: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_GAIN\n"); + break; + case V4L2_CID_HFLIP: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_HFLIP\n"); + break; + case V4L2_CID_VFLIP: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " V4L2_CID_VFLIP\n"); + break; + default: + dev_dbg(&adv7180_data.sen.i2c_client->dev, + " Default case\n"); + retval = -EPERM; + break; + } + + return retval; +} + +/*! + * ioctl_enum_framesizes - V4L2 sensor interface handler for + * VIDIOC_ENUM_FRAMESIZES ioctl + * @s: pointer to standard V4L2 device structure + * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure + * + * Return 0 if successful, otherwise -EINVAL. + */ +static int ioctl_enum_framesizes(struct v4l2_int_device *s, + struct v4l2_frmsizeenum *fsize) +{ + if (fsize->index >= 1) + return -EINVAL; + + fsize->discrete.width = video_fmts[video_idx].active_width; + fsize->discrete.height = video_fmts[video_idx].active_height; + + return 0; +} + +/*! + * ioctl_enum_frameintervals - V4L2 sensor interface handler for + * VIDIOC_ENUM_FRAMEINTERVALS ioctl + * @s: pointer to standard V4L2 device structure + * @fival: standard V4L2 VIDIOC_ENUM_FRAMEINTERVALS ioctl structure + * + * Return 0 if successful, otherwise -EINVAL. + */ +static int ioctl_enum_frameintervals(struct v4l2_int_device *s, + struct v4l2_frmivalenum *fival) +{ + video_fmt_t fmt; + int i; + + if (fival->index != 0) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(video_fmts) - 1; i++) { + fmt = video_fmts[i]; + if (fival->width == fmt.active_width && + fival->height == fmt.active_height) { + fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; + fival->discrete.numerator = 1; + fival->discrete.denominator = fmt.frame_rate; + return 0; + } + } + + return -EINVAL; +} + +/*! + * ioctl_g_chip_ident - V4L2 sensor interface handler for + * VIDIOC_DBG_G_CHIP_IDENT ioctl + * @s: pointer to standard V4L2 device structure + * @id: pointer to int + * + * Return 0. + */ +static int ioctl_g_chip_ident(struct v4l2_int_device *s, int *id) +{ + ((struct v4l2_dbg_chip_ident *)id)->match.type = + V4L2_CHIP_MATCH_I2C_DRIVER; + strcpy(((struct v4l2_dbg_chip_ident *)id)->match.name, + "adv7180_decoder"); + ((struct v4l2_dbg_chip_ident *)id)->ident = V4L2_IDENT_ADV7180; + + return 0; +} + +/*! + * ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT + * @s: pointer to standard V4L2 device structure + */ +static int ioctl_init(struct v4l2_int_device *s) +{ + dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180:ioctl_init\n"); + return 0; +} + +/*! + * ioctl_dev_init - V4L2 sensor interface handler for vidioc_int_dev_init_num + * @s: pointer to standard V4L2 device structure + * + * Initialise the device when slave attaches to the master. + */ +static int ioctl_dev_init(struct v4l2_int_device *s) +{ + dev_dbg(&adv7180_data.sen.i2c_client->dev, "adv7180:ioctl_dev_init\n"); + return 0; +} + +/*! + * This structure defines all the ioctls for this module. + */ +static struct v4l2_int_ioctl_desc adv7180_ioctl_desc[] = { + + {vidioc_int_dev_init_num, (v4l2_int_ioctl_func*)ioctl_dev_init}, + + /*! + * Delinitialise the dev. at slave detach. + * The complement of ioctl_dev_init. + */ +/* {vidioc_int_dev_exit_num, (v4l2_int_ioctl_func *)ioctl_dev_exit}, */ + + {vidioc_int_s_power_num, (v4l2_int_ioctl_func*)ioctl_s_power}, + {vidioc_int_g_ifparm_num, (v4l2_int_ioctl_func*)ioctl_g_ifparm}, +/* {vidioc_int_g_needs_reset_num, + (v4l2_int_ioctl_func *)ioctl_g_needs_reset}, */ +/* {vidioc_int_reset_num, (v4l2_int_ioctl_func *)ioctl_reset}, */ + {vidioc_int_init_num, (v4l2_int_ioctl_func*)ioctl_init}, + + /*! + * VIDIOC_ENUM_FMT ioctl for the CAPTURE buffer type. + */ +/* {vidioc_int_enum_fmt_cap_num, + (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap}, */ + + /*! + * VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type. + * This ioctl is used to negotiate the image capture size and + * pixel format without actually making it take effect. + */ +/* {vidioc_int_try_fmt_cap_num, + (v4l2_int_ioctl_func *)ioctl_try_fmt_cap}, */ + + {vidioc_int_g_fmt_cap_num, (v4l2_int_ioctl_func*)ioctl_g_fmt_cap}, + + /*! + * If the requested format is supported, configures the HW to use that + * format, returns error code if format not supported or HW can't be + * correctly configured. + */ +/* {vidioc_int_s_fmt_cap_num, (v4l2_int_ioctl_func *)ioctl_s_fmt_cap}, */ + + {vidioc_int_g_parm_num, (v4l2_int_ioctl_func*)ioctl_g_parm}, + {vidioc_int_s_parm_num, (v4l2_int_ioctl_func*)ioctl_s_parm}, + {vidioc_int_queryctrl_num, (v4l2_int_ioctl_func*)ioctl_queryctrl}, + {vidioc_int_g_ctrl_num, (v4l2_int_ioctl_func*)ioctl_g_ctrl}, + {vidioc_int_s_ctrl_num, (v4l2_int_ioctl_func*)ioctl_s_ctrl}, + {vidioc_int_enum_framesizes_num, + (v4l2_int_ioctl_func *)ioctl_enum_framesizes}, + {vidioc_int_enum_frameintervals_num, + (v4l2_int_ioctl_func *) + ioctl_enum_frameintervals}, + {vidioc_int_g_chip_ident_num, + (v4l2_int_ioctl_func *)ioctl_g_chip_ident}, +}; + +static struct v4l2_int_slave adv7180_slave = { + .ioctls = adv7180_ioctl_desc, + .num_ioctls = ARRAY_SIZE(adv7180_ioctl_desc), +}; + +static struct v4l2_int_device adv7180_int_device = { + .module = THIS_MODULE, + .name = "adv7180", + .type = v4l2_int_type_slave, + .u = { + .slave = &adv7180_slave, + }, +}; + + +/*********************************************************************** + * I2C client and driver. + ***********************************************************************/ + +/*! ADV7180 Reset function. + * + * @return None. + */ +static void adv7180_hard_reset(bool cvbs) +{ + dev_dbg(&adv7180_data.sen.i2c_client->dev, + "In adv7180:adv7180_hard_reset\n"); + + if (cvbs) { + /* Set CVBS input on AIN1 */ + adv7180_write_reg(ADV7180_INPUT_CTL, 0x00); + } else { + /* + * Set YPbPr input on AIN1,4,5 and normal + * operations(autodection of all stds). + */ + adv7180_write_reg(ADV7180_INPUT_CTL, 0x09); + } + + /* Datasheet recommends */ + adv7180_write_reg(0x01, 0xc8); + adv7180_write_reg(0x02, 0x04); + adv7180_write_reg(0x03, 0x00); + adv7180_write_reg(0x04, 0x45); + adv7180_write_reg(0x05, 0x00); + adv7180_write_reg(0x06, 0x02); + adv7180_write_reg(0x07, 0x7F); + adv7180_write_reg(0x08, 0x80); + adv7180_write_reg(0x0A, 0x00); + adv7180_write_reg(0x0B, 0x00); + adv7180_write_reg(0x0C, 0x36); + adv7180_write_reg(0x0D, 0x7C); + adv7180_write_reg(0x0E, 0x00); + adv7180_write_reg(0x0F, 0x00); + adv7180_write_reg(0x13, 0x00); + adv7180_write_reg(0x14, 0x12); + adv7180_write_reg(0x15, 0x00); + adv7180_write_reg(0x16, 0x00); + adv7180_write_reg(0x17, 0x01); + adv7180_write_reg(0x18, 0x93); + adv7180_write_reg(0xF1, 0x19); + adv7180_write_reg(0x1A, 0x00); + adv7180_write_reg(0x1B, 0x00); + adv7180_write_reg(0x1C, 0x00); + adv7180_write_reg(0x1D, 0x40); + adv7180_write_reg(0x1E, 0x00); + adv7180_write_reg(0x1F, 0x00); + adv7180_write_reg(0x20, 0x00); + adv7180_write_reg(0x21, 0x00); + adv7180_write_reg(0x22, 0x00); + adv7180_write_reg(0x23, 0xC0); + adv7180_write_reg(0x24, 0x00); + adv7180_write_reg(0x25, 0x00); + adv7180_write_reg(0x26, 0x00); + adv7180_write_reg(0x27, 0x58); + adv7180_write_reg(0x28, 0x00); + adv7180_write_reg(0x29, 0x00); + adv7180_write_reg(0x2A, 0x00); + adv7180_write_reg(0x2B, 0xE1); + adv7180_write_reg(0x2C, 0xAE); + adv7180_write_reg(0x2D, 0xF4); + adv7180_write_reg(0x2E, 0x00); + adv7180_write_reg(0x2F, 0xF0); + adv7180_write_reg(0x30, 0x00); + adv7180_write_reg(0x31, 0x12); + adv7180_write_reg(0x32, 0x41); + adv7180_write_reg(0x33, 0x84); + adv7180_write_reg(0x34, 0x00); + adv7180_write_reg(0x35, 0x02); + adv7180_write_reg(0x36, 0x00); + adv7180_write_reg(0x37, 0x01); + adv7180_write_reg(0x38, 0x80); + adv7180_write_reg(0x39, 0xC0); + adv7180_write_reg(0x3A, 0x10); + adv7180_write_reg(0x3B, 0x05); + adv7180_write_reg(0x3C, 0x58); + adv7180_write_reg(0x3D, 0xB2); + adv7180_write_reg(0x3E, 0x64); + adv7180_write_reg(0x3F, 0xE4); + adv7180_write_reg(0x40, 0x90); + adv7180_write_reg(0x41, 0x01); + adv7180_write_reg(0x42, 0x7E); + adv7180_write_reg(0x43, 0xA4); + adv7180_write_reg(0x44, 0xFF); + adv7180_write_reg(0x45, 0xB6); + adv7180_write_reg(0x46, 0x12); + adv7180_write_reg(0x48, 0x00); + adv7180_write_reg(0x49, 0x00); + adv7180_write_reg(0x4A, 0x00); + adv7180_write_reg(0x4B, 0x00); + adv7180_write_reg(0x4C, 0x00); + adv7180_write_reg(0x4D, 0xEF); + adv7180_write_reg(0x4E, 0x08); + adv7180_write_reg(0x4F, 0x08); + adv7180_write_reg(0x50, 0x08); + adv7180_write_reg(0x51, 0x24); + adv7180_write_reg(0x52, 0x0B); + adv7180_write_reg(0x53, 0x4E); + adv7180_write_reg(0x54, 0x80); + adv7180_write_reg(0x55, 0x00); + adv7180_write_reg(0x56, 0x10); + adv7180_write_reg(0x57, 0x00); + adv7180_write_reg(0x58, 0x00); + adv7180_write_reg(0x59, 0x00); + adv7180_write_reg(0x5A, 0x00); + adv7180_write_reg(0x5B, 0x00); + adv7180_write_reg(0x5C, 0x00); + adv7180_write_reg(0x5D, 0x00); + adv7180_write_reg(0x5E, 0x00); + adv7180_write_reg(0x5F, 0x00); + adv7180_write_reg(0x60, 0x00); + adv7180_write_reg(0x61, 0x00); + adv7180_write_reg(0x62, 0x20); + adv7180_write_reg(0x63, 0x00); + adv7180_write_reg(0x64, 0x00); + adv7180_write_reg(0x65, 0x00); + adv7180_write_reg(0x66, 0x00); + adv7180_write_reg(0x67, 0x03); + adv7180_write_reg(0x68, 0x01); + adv7180_write_reg(0x69, 0x00); + adv7180_write_reg(0x6A, 0x00); + adv7180_write_reg(0x6B, 0xC0); + adv7180_write_reg(0x6C, 0x00); + adv7180_write_reg(0x6D, 0x00); + adv7180_write_reg(0x6E, 0x00); + adv7180_write_reg(0x6F, 0x00); + adv7180_write_reg(0x70, 0x00); + adv7180_write_reg(0x71, 0x00); + adv7180_write_reg(0x72, 0x00); + adv7180_write_reg(0x73, 0x10); + adv7180_write_reg(0x74, 0x04); + adv7180_write_reg(0x75, 0x01); + adv7180_write_reg(0x76, 0x00); + adv7180_write_reg(0x77, 0x3F); + adv7180_write_reg(0x78, 0xFF); + adv7180_write_reg(0x79, 0xFF); + adv7180_write_reg(0x7A, 0xFF); + adv7180_write_reg(0x7B, 0x1E); + adv7180_write_reg(0x7C, 0xC0); + adv7180_write_reg(0x7D, 0x00); + adv7180_write_reg(0x7E, 0x00); + adv7180_write_reg(0x7F, 0x00); + adv7180_write_reg(0x80, 0x00); + adv7180_write_reg(0x81, 0xC0); + adv7180_write_reg(0x82, 0x04); + adv7180_write_reg(0x83, 0x00); + adv7180_write_reg(0x84, 0x0C); + adv7180_write_reg(0x85, 0x02); + adv7180_write_reg(0x86, 0x03); + adv7180_write_reg(0x87, 0x63); + adv7180_write_reg(0x88, 0x5A); + adv7180_write_reg(0x89, 0x08); + adv7180_write_reg(0x8A, 0x10); + adv7180_write_reg(0x8B, 0x00); + adv7180_write_reg(0x8C, 0x40); + adv7180_write_reg(0x8D, 0x00); + adv7180_write_reg(0x8E, 0x40); + adv7180_write_reg(0x8F, 0x00); + adv7180_write_reg(0x90, 0x00); + adv7180_write_reg(0x91, 0x50); + adv7180_write_reg(0x92, 0x00); + adv7180_write_reg(0x93, 0x00); + adv7180_write_reg(0x94, 0x00); + adv7180_write_reg(0x95, 0x00); + adv7180_write_reg(0x96, 0x00); + adv7180_write_reg(0x97, 0xF0); + adv7180_write_reg(0x98, 0x00); + adv7180_write_reg(0x99, 0x00); + adv7180_write_reg(0x9A, 0x00); + adv7180_write_reg(0x9B, 0x00); + adv7180_write_reg(0x9C, 0x00); + adv7180_write_reg(0x9D, 0x00); + adv7180_write_reg(0x9E, 0x00); + adv7180_write_reg(0x9F, 0x00); + adv7180_write_reg(0xA0, 0x00); + adv7180_write_reg(0xA1, 0x00); + adv7180_write_reg(0xA2, 0x00); + adv7180_write_reg(0xA3, 0x00); + adv7180_write_reg(0xA4, 0x00); + adv7180_write_reg(0xA5, 0x00); + adv7180_write_reg(0xA6, 0x00); + adv7180_write_reg(0xA7, 0x00); + adv7180_write_reg(0xA8, 0x00); + adv7180_write_reg(0xA9, 0x00); + adv7180_write_reg(0xAA, 0x00); + adv7180_write_reg(0xAB, 0x00); + adv7180_write_reg(0xAC, 0x00); + adv7180_write_reg(0xAD, 0x00); + adv7180_write_reg(0xAE, 0x60); + adv7180_write_reg(0xAF, 0x00); + adv7180_write_reg(0xB0, 0x00); + adv7180_write_reg(0xB1, 0x60); + adv7180_write_reg(0xB2, 0x1C); + adv7180_write_reg(0xB3, 0x54); + adv7180_write_reg(0xB4, 0x00); + adv7180_write_reg(0xB5, 0x00); + adv7180_write_reg(0xB6, 0x00); + adv7180_write_reg(0xB7, 0x13); + adv7180_write_reg(0xB8, 0x03); + adv7180_write_reg(0xB9, 0x33); + adv7180_write_reg(0xBF, 0x02); + adv7180_write_reg(0xC0, 0x00); + adv7180_write_reg(0xC1, 0x00); + adv7180_write_reg(0xC2, 0x00); + adv7180_write_reg(0xC3, 0x00); + adv7180_write_reg(0xC4, 0x00); + adv7180_write_reg(0xC5, 0x81); + adv7180_write_reg(0xC6, 0x00); + adv7180_write_reg(0xC7, 0x00); + adv7180_write_reg(0xC8, 0x00); + adv7180_write_reg(0xC9, 0x04); + adv7180_write_reg(0xCC, 0x69); + adv7180_write_reg(0xCD, 0x00); + adv7180_write_reg(0xCE, 0x01); + adv7180_write_reg(0xCF, 0xB4); + adv7180_write_reg(0xD0, 0x00); + adv7180_write_reg(0xD1, 0x10); + adv7180_write_reg(0xD2, 0xFF); + adv7180_write_reg(0xD3, 0xFF); + adv7180_write_reg(0xD4, 0x7F); + adv7180_write_reg(0xD5, 0x7F); + adv7180_write_reg(0xD6, 0x3E); + adv7180_write_reg(0xD7, 0x08); + adv7180_write_reg(0xD8, 0x3C); + adv7180_write_reg(0xD9, 0x08); + adv7180_write_reg(0xDA, 0x3C); + adv7180_write_reg(0xDB, 0x9B); + adv7180_write_reg(0xDC, 0xAC); + adv7180_write_reg(0xDD, 0x4C); + adv7180_write_reg(0xDE, 0x00); + adv7180_write_reg(0xDF, 0x00); + adv7180_write_reg(0xE0, 0x14); + adv7180_write_reg(0xE1, 0x80); + adv7180_write_reg(0xE2, 0x80); + adv7180_write_reg(0xE3, 0x80); + adv7180_write_reg(0xE4, 0x80); + adv7180_write_reg(0xE5, 0x25); + adv7180_write_reg(0xE6, 0x44); + adv7180_write_reg(0xE7, 0x63); + adv7180_write_reg(0xE8, 0x65); + adv7180_write_reg(0xE9, 0x14); + adv7180_write_reg(0xEA, 0x63); + adv7180_write_reg(0xEB, 0x55); + adv7180_write_reg(0xEC, 0x55); + adv7180_write_reg(0xEE, 0x00); + adv7180_write_reg(0xEF, 0x4A); + adv7180_write_reg(0xF0, 0x44); + adv7180_write_reg(0xF1, 0x0C); + adv7180_write_reg(0xF2, 0x32); + adv7180_write_reg(0xF3, 0x00); + adv7180_write_reg(0xF4, 0x3F); + adv7180_write_reg(0xF5, 0xE0); + adv7180_write_reg(0xF6, 0x69); + adv7180_write_reg(0xF7, 0x10); + adv7180_write_reg(0xF8, 0x00); + adv7180_write_reg(0xF9, 0x03); + adv7180_write_reg(0xFA, 0xFA); + adv7180_write_reg(0xFB, 0x40); +} + +/*! ADV7180 I2C attach function. + * + * @param *adapter struct i2c_adapter *. + * + * @return Error code indicating success or failure. + */ + +/*! + * ADV7180 I2C probe function. + * Function set in i2c_driver struct. + * Called by insmod. + * + * @param *adapter I2C adapter descriptor. + * + * @return Error code indicating success or failure. + */ +static int adv7180_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rev_id; + int ret = 0; + u32 cvbs = true; + struct pinctrl *pinctrl; + struct device *dev = &client->dev; + + printk(KERN_ERR"DBG sensor data is at %p\n", &adv7180_data); + + /* ov5640 pinctrl */ + pinctrl = devm_pinctrl_get_select_default(dev); + if (IS_ERR(pinctrl)) { + dev_err(dev, "setup pinctrl failed\n"); + return PTR_ERR(pinctrl); + } + + /* request power down pin */ + pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0); + if (!gpio_is_valid(pwn_gpio)) { + dev_err(dev, "no sensor pwdn pin available\n"); + return -ENODEV; + } + ret = devm_gpio_request_one(dev, pwn_gpio, GPIOF_OUT_INIT_HIGH, + "adv7180_pwdn"); + if (ret < 0) { + dev_err(dev, "no power pin available!\n"); + return ret; + } + + adv7180_regulator_enable(dev); + + adv7180_power_down(0); + + msleep(1); + + /* Set initial values for the sensor struct. */ + memset(&adv7180_data, 0, sizeof(adv7180_data)); + adv7180_data.sen.i2c_client = client; + adv7180_data.sen.streamcap.timeperframe.denominator = 30; + adv7180_data.sen.streamcap.timeperframe.numerator = 1; + adv7180_data.std_id = V4L2_STD_ALL; + video_idx = ADV7180_NOT_LOCKED; + adv7180_data.sen.pix.width = video_fmts[video_idx].raw_width; + adv7180_data.sen.pix.height = video_fmts[video_idx].raw_height; + adv7180_data.sen.pix.pixelformat = V4L2_PIX_FMT_UYVY; /* YUV422 */ + adv7180_data.sen.pix.priv = 1; /* 1 is used to indicate TV in */ + adv7180_data.sen.on = true; + + adv7180_data.sen.sensor_clk = devm_clk_get(dev, "csi_mclk"); + if (IS_ERR(adv7180_data.sen.sensor_clk)) { + dev_err(dev, "get mclk failed\n"); + return PTR_ERR(adv7180_data.sen.sensor_clk); + } + + ret = of_property_read_u32(dev->of_node, "mclk", + &adv7180_data.sen.mclk); + if (ret) { + dev_err(dev, "mclk frequency is invalid\n"); + return ret; + } + + ret = of_property_read_u32( + dev->of_node, "mclk_source", + (u32 *) &(adv7180_data.sen.mclk_source)); + if (ret) { + dev_err(dev, "mclk_source invalid\n"); + return ret; + } + + ret = of_property_read_u32(dev->of_node, "csi_id", + &(adv7180_data.sen.csi)); + if (ret) { + dev_err(dev, "csi_id invalid\n"); + return ret; + } + + clk_prepare_enable(adv7180_data.sen.sensor_clk); + + dev_dbg(&adv7180_data.sen.i2c_client->dev, + "%s:adv7180 probe i2c address is 0x%02X\n", + __func__, adv7180_data.sen.i2c_client->addr); + + /*! Read the revision ID of the tvin chip */ + rev_id = adv7180_read(ADV7180_IDENT); + dev_dbg(dev, + "%s:Analog Device adv7%2X0 detected!\n", __func__, + rev_id); + + ret = of_property_read_u32(dev->of_node, "cvbs", &(cvbs)); + if (ret) { + dev_err(dev, "cvbs setting is not found\n"); + cvbs = true; + } + + /*! ADV7180 initialization. */ + adv7180_hard_reset(cvbs); + + pr_debug(" type is %d (expect %d)\n", + adv7180_int_device.type, v4l2_int_type_slave); + pr_debug(" num ioctls is %d\n", + adv7180_int_device.u.slave->num_ioctls); + + /* This function attaches this structure to the /dev/video0 device. + * The pointer in priv points to the adv7180_data structure here.*/ + adv7180_int_device.priv = &adv7180_data; + ret = v4l2_int_device_register(&adv7180_int_device); + + clk_disable_unprepare(adv7180_data.sen.sensor_clk); + + return ret; +} + +/*! + * ADV7180 I2C detach function. + * Called on rmmod. + * + * @param *client struct i2c_client*. + * + * @return Error code indicating success or failure. + */ +static int adv7180_detach(struct i2c_client *client) +{ + dev_dbg(&adv7180_data.sen.i2c_client->dev, + "%s:Removing %s video decoder @ 0x%02X from adapter %s\n", + __func__, IF_NAME, client->addr << 1, client->adapter->name); + + /* Power down via i2c */ + adv7180_write_reg(ADV7180_PWR_MNG, 0x24); + + if (dvddio_regulator) + regulator_disable(dvddio_regulator); + + if (dvdd_regulator) + regulator_disable(dvdd_regulator); + + if (avdd_regulator) + regulator_disable(avdd_regulator); + + if (pvdd_regulator) + regulator_disable(pvdd_regulator); + + v4l2_int_device_unregister(&adv7180_int_device); + + return 0; +} + +/*! + * ADV7180 init function. + * Called on insmod. + * + * @return Error code indicating success or failure. + */ +static __init int adv7180_init(void) +{ + u8 err = 0; + + pr_debug("In adv7180_init\n"); + + /* Tells the i2c driver what functions to call for this driver. */ + err = i2c_add_driver(&adv7180_i2c_driver); + if (err != 0) + pr_err("%s:driver registration failed, error=%d\n", + __func__, err); + + return err; +} + +/*! + * ADV7180 cleanup function. + * Called on rmmod. + * + * @return Error code indicating success or failure. + */ +static void __exit adv7180_clean(void) +{ + dev_dbg(&adv7180_data.sen.i2c_client->dev, "In adv7180_clean\n"); + i2c_del_driver(&adv7180_i2c_driver); +} + +module_init(adv7180_init); +module_exit(adv7180_clean); + +MODULE_AUTHOR("Freescale Semiconductor"); +MODULE_DESCRIPTION("Anolog Device ADV7180 video decoder driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c b/drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c new file mode 100644 index 000000000000..193cbd5ec0f7 --- /dev/null +++ b/drivers/media/platform/mxc/capture/ipu_bg_overlay_sdc.c @@ -0,0 +1,552 @@ + +/* + * Copyright 2004-2015 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file ipu_bg_overlay_sdc_bg.c + * + * @brief IPU Use case for PRP-VF back-ground + * + * @ingroup IPU + */ +#include +#include +#include +#include +#include +#include "mxc_v4l2_capture.h" +#include "ipu_prp_sw.h" + +static int csi_buffer_num; +static u32 bpp, csi_mem_bufsize = 3; +static u32 out_format; +static struct ipu_soc *disp_ipu; +static u32 offset; + +static void csi_buf_work_func(struct work_struct *work) +{ + int err = 0; + cam_data *cam = + container_of(work, struct _cam_data, csi_work_struct); + + struct ipu_task task; + memset(&task, 0, sizeof(task)); + + if (csi_buffer_num) + task.input.paddr = cam->vf_bufs[0]; + else + task.input.paddr = cam->vf_bufs[1]; + task.input.width = cam->crop_current.width; + task.input.height = cam->crop_current.height; + task.input.format = IPU_PIX_FMT_UYVY; + + task.output.paddr = offset; + task.output.width = cam->overlay_fb->var.xres; + task.output.height = cam->overlay_fb->var.yres; + task.output.format = out_format; + task.output.rotate = cam->rotation; + task.output.crop.pos.x = cam->win.w.left; + task.output.crop.pos.y = cam->win.w.top; + if (cam->win.w.width > 1024 || cam->win.w.height > 1024) { + task.output.crop.w = cam->overlay_fb->var.xres; + task.output.crop.h = cam->overlay_fb->var.yres; + } else { + task.output.crop.w = cam->win.w.width; + task.output.crop.h = cam->win.w.height; + } +again: + err = ipu_check_task(&task); + if (err != IPU_CHECK_OK) { + if (err > IPU_CHECK_ERR_MIN) { + if (err == IPU_CHECK_ERR_SPLIT_INPUTW_OVER) { + task.input.crop.w -= 8; + goto again; + } + if (err == IPU_CHECK_ERR_SPLIT_INPUTH_OVER) { + task.input.crop.h -= 8; + goto again; + } + if (err == IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER) { + task.output.width -= 8; + task.output.crop.w = task.output.width; + goto again; + } + if (err == IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER) { + task.output.height -= 8; + task.output.crop.h = task.output.height; + goto again; + } + printk(KERN_ERR "check ipu taks fail\n"); + return; + } + printk(KERN_ERR "check ipu taks fail\n"); + return; + } + err = ipu_queue_task(&task); + if (err < 0) + printk(KERN_ERR "queue ipu task error\n"); +} + +static void get_disp_ipu(cam_data *cam) +{ + if (cam->output > 2) + disp_ipu = ipu_get_soc(1); /* using DISP4 */ + else + disp_ipu = ipu_get_soc(0); +} + + +/*! + * csi ENC callback function. + * + * @param irq int irq line + * @param dev_id void * device id + * + * @return status IRQ_HANDLED for handled + */ +static irqreturn_t csi_enc_callback(int irq, void *dev_id) +{ + cam_data *cam = (cam_data *) dev_id; + ipu_channel_t chan = (irq == IPU_IRQ_CSI0_OUT_EOF) ? + CSI_MEM0 : CSI_MEM1; + + ipu_select_buffer(cam->ipu, chan, + IPU_OUTPUT_BUFFER, csi_buffer_num); + schedule_work(&cam->csi_work_struct); + csi_buffer_num = (csi_buffer_num == 0) ? 1 : 0; + return IRQ_HANDLED; +} + +static int csi_enc_setup(cam_data *cam) +{ + ipu_channel_params_t params; + u32 pixel_fmt; + int err = 0, sensor_protocol = 0; + ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1; + +#ifdef CONFIG_MXC_MIPI_CSI2 + void *mipi_csi2_info; + int ipu_id; + int csi_id; +#endif + + if (!cam) { + printk(KERN_ERR "cam private is NULL\n"); + return -ENXIO; + } + + memset(¶ms, 0, sizeof(ipu_channel_params_t)); + params.csi_mem.csi = cam->csi; + + sensor_protocol = ipu_csi_get_sensor_protocol(cam->ipu, cam->csi); + switch (sensor_protocol) { + case IPU_CSI_CLK_MODE_GATED_CLK: + case IPU_CSI_CLK_MODE_NONGATED_CLK: + case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE: + case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR: + case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR: + params.csi_mem.interlaced = false; + break; + case IPU_CSI_CLK_MODE_CCIR656_INTERLACED: + case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR: + case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR: + params.csi_mem.interlaced = true; + break; + default: + printk(KERN_ERR "sensor protocol unsupported\n"); + return -EINVAL; + } + +#ifdef CONFIG_MXC_MIPI_CSI2 + mipi_csi2_info = mipi_csi2_get_info(); + + if (mipi_csi2_info) { + if (mipi_csi2_get_status(mipi_csi2_info)) { + ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); + csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); + + if (cam->ipu == ipu_get_soc(ipu_id) + && cam->csi == csi_id) { + params.csi_mem.mipi_en = true; + params.csi_mem.mipi_vc = + mipi_csi2_get_virtual_channel(mipi_csi2_info); + params.csi_mem.mipi_id = + mipi_csi2_get_datatype(mipi_csi2_info); + + mipi_csi2_pixelclk_enable(mipi_csi2_info); + } else { + params.csi_mem.mipi_en = false; + params.csi_mem.mipi_vc = 0; + params.csi_mem.mipi_id = 0; + } + } else { + params.csi_mem.mipi_en = false; + params.csi_mem.mipi_vc = 0; + params.csi_mem.mipi_id = 0; + } + } +#endif + + if (cam->vf_bufs_vaddr[0]) { + dma_free_coherent(0, cam->vf_bufs_size[0], + cam->vf_bufs_vaddr[0], + (dma_addr_t) cam->vf_bufs[0]); + } + if (cam->vf_bufs_vaddr[1]) { + dma_free_coherent(0, cam->vf_bufs_size[1], + cam->vf_bufs_vaddr[1], + (dma_addr_t) cam->vf_bufs[1]); + } + csi_mem_bufsize = + cam->crop_current.width * cam->crop_current.height * 2; + cam->vf_bufs_size[0] = PAGE_ALIGN(csi_mem_bufsize); + cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0, + cam->vf_bufs_size[0], + (dma_addr_t *) & + cam->vf_bufs[0], + GFP_DMA | + GFP_KERNEL); + if (cam->vf_bufs_vaddr[0] == NULL) { + printk(KERN_ERR "Error to allocate vf buffer\n"); + err = -ENOMEM; + goto out_2; + } + cam->vf_bufs_size[1] = PAGE_ALIGN(csi_mem_bufsize); + cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0, + cam->vf_bufs_size[1], + (dma_addr_t *) & + cam->vf_bufs[1], + GFP_DMA | + GFP_KERNEL); + if (cam->vf_bufs_vaddr[1] == NULL) { + printk(KERN_ERR "Error to allocate vf buffer\n"); + err = -ENOMEM; + goto out_1; + } + pr_debug("vf_bufs %x %x\n", cam->vf_bufs[0], cam->vf_bufs[1]); + + err = ipu_init_channel(cam->ipu, chan, ¶ms); + if (err != 0) { + printk(KERN_ERR "ipu_init_channel %d\n", err); + goto out_1; + } + + pixel_fmt = IPU_PIX_FMT_UYVY; + err = ipu_init_channel_buffer( + cam->ipu, chan, IPU_OUTPUT_BUFFER, pixel_fmt, + cam->crop_current.width, cam->crop_current.height, + cam->crop_current.width, IPU_ROTATE_NONE, + cam->vf_bufs[0], cam->vf_bufs[1], 0, + cam->offset.u_offset, cam->offset.u_offset); + if (err != 0) { + printk(KERN_ERR "CSI_MEM output buffer\n"); + goto out_1; + } + err = ipu_enable_channel(cam->ipu, chan); + if (err < 0) { + printk(KERN_ERR "ipu_enable_channel CSI_MEM\n"); + goto out_1; + } + + csi_buffer_num = 0; + + ipu_select_buffer(cam->ipu, chan, IPU_OUTPUT_BUFFER, 0); + ipu_select_buffer(cam->ipu, chan, IPU_OUTPUT_BUFFER, 1); + return err; +out_1: + if (cam->vf_bufs_vaddr[0]) { + dma_free_coherent(0, cam->vf_bufs_size[0], + cam->vf_bufs_vaddr[0], + (dma_addr_t) cam->vf_bufs[0]); + cam->vf_bufs_vaddr[0] = NULL; + cam->vf_bufs[0] = 0; + } + if (cam->vf_bufs_vaddr[1]) { + dma_free_coherent(0, cam->vf_bufs_size[1], + cam->vf_bufs_vaddr[1], + (dma_addr_t) cam->vf_bufs[1]); + cam->vf_bufs_vaddr[1] = NULL; + cam->vf_bufs[1] = 0; + } +out_2: + return err; +} + +/*! + * Enable encoder task + * @param private struct cam_data * mxc capture instance + * + * @return status + */ +static int csi_enc_enabling_tasks(void *private) +{ + cam_data *cam = (cam_data *) private; + int err = 0; + + ipu_clear_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi); + err = ipu_request_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi, + csi_enc_callback, 0, "Mxc Camera", cam); + if (err != 0) { + printk(KERN_ERR "Error registering CSI_OUT_EOF irq\n"); + return err; + } + + INIT_WORK(&cam->csi_work_struct, csi_buf_work_func); + + err = csi_enc_setup(cam); + if (err != 0) { + printk(KERN_ERR "csi_enc_setup %d\n", err); + goto out1; + } + + return err; +out1: + ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi, cam); + return err; +} + +/*! + * bg_overlay_start - start the overlay task + * + * @param private cam_data * mxc v4l2 main structure + * + */ +static int bg_overlay_start(void *private) +{ + cam_data *cam = (cam_data *) private; + int err = 0; + + if (!cam) { + printk(KERN_ERR "private is NULL\n"); + return -EIO; + } + + if (cam->overlay_active == true) { + pr_debug("already start.\n"); + return 0; + } + + get_disp_ipu(cam); + + out_format = cam->v4l2_fb.fmt.pixelformat; + if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR24) { + bpp = 3, csi_mem_bufsize = 3; + pr_info("BGR24\n"); + } else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_RGB565) { + bpp = 2, csi_mem_bufsize = 2; + pr_info("RGB565\n"); + } else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR32) { + bpp = 4, csi_mem_bufsize = 4; + pr_info("BGR32\n"); + } else { + printk(KERN_ERR + "unsupported fix format from the framebuffer.\n"); + return -EINVAL; + } + + offset = cam->v4l2_fb.fmt.bytesperline * cam->win.w.top + + csi_mem_bufsize * cam->win.w.left; + + if (cam->v4l2_fb.base == 0) + printk(KERN_ERR "invalid frame buffer address.\n"); + else + offset += (u32) cam->v4l2_fb.base; + + csi_mem_bufsize = cam->win.w.width * cam->win.w.height + * csi_mem_bufsize; + + err = csi_enc_enabling_tasks(cam); + if (err != 0) { + printk(KERN_ERR "Error csi enc enable fail\n"); + return err; + } + + cam->overlay_active = true; + return err; +} + +/*! + * bg_overlay_stop - stop the overlay task + * + * @param private cam_data * mxc v4l2 main structure + * + */ +static int bg_overlay_stop(void *private) +{ + int err = 0; + cam_data *cam = (cam_data *) private; + ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1; +#ifdef CONFIG_MXC_MIPI_CSI2 + void *mipi_csi2_info; + int ipu_id; + int csi_id; +#endif + + if (cam->overlay_active == false) + return 0; + + err = ipu_disable_channel(cam->ipu, chan, true); + + ipu_uninit_channel(cam->ipu, chan); + + csi_buffer_num = 0; + +#ifdef CONFIG_MXC_MIPI_CSI2 + mipi_csi2_info = mipi_csi2_get_info(); + + if (mipi_csi2_info) { + if (mipi_csi2_get_status(mipi_csi2_info)) { + ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); + csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); + + if (cam->ipu == ipu_get_soc(ipu_id) + && cam->csi == csi_id) + mipi_csi2_pixelclk_disable(mipi_csi2_info); + } + } +#endif + + flush_work(&cam->csi_work_struct); + cancel_work_sync(&cam->csi_work_struct); + + if (cam->vf_bufs_vaddr[0]) { + dma_free_coherent(0, cam->vf_bufs_size[0], + cam->vf_bufs_vaddr[0], cam->vf_bufs[0]); + cam->vf_bufs_vaddr[0] = NULL; + cam->vf_bufs[0] = 0; + } + if (cam->vf_bufs_vaddr[1]) { + dma_free_coherent(0, cam->vf_bufs_size[1], + cam->vf_bufs_vaddr[1], cam->vf_bufs[1]); + cam->vf_bufs_vaddr[1] = NULL; + cam->vf_bufs[1] = 0; + } + if (cam->rot_vf_bufs_vaddr[0]) { + dma_free_coherent(0, cam->rot_vf_buf_size[0], + cam->rot_vf_bufs_vaddr[0], + cam->rot_vf_bufs[0]); + cam->rot_vf_bufs_vaddr[0] = NULL; + cam->rot_vf_bufs[0] = 0; + } + if (cam->rot_vf_bufs_vaddr[1]) { + dma_free_coherent(0, cam->rot_vf_buf_size[1], + cam->rot_vf_bufs_vaddr[1], + cam->rot_vf_bufs[1]); + cam->rot_vf_bufs_vaddr[1] = NULL; + cam->rot_vf_bufs[1] = 0; + } + + cam->overlay_active = false; + return err; +} + +/*! + * Enable csi + * @param private struct cam_data * mxc capture instance + * + * @return status + */ +static int bg_overlay_enable_csi(void *private) +{ + cam_data *cam = (cam_data *) private; + + return ipu_enable_csi(cam->ipu, cam->csi); +} + +/*! + * Disable csi + * @param private struct cam_data * mxc capture instance + * + * @return status + */ +static int bg_overlay_disable_csi(void *private) +{ + cam_data *cam = (cam_data *) private; + + /* free csi eof irq firstly. + * when disable csi, wait for idmac eof. + * it requests eof irq again */ + ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi, cam); + + return ipu_disable_csi(cam->ipu, cam->csi); +} + +/*! + * function to select bg as the working path + * + * @param private cam_data * mxc v4l2 main structure + * + * @return status + */ +int bg_overlay_sdc_select(void *private) +{ + cam_data *cam = (cam_data *) private; + + if (cam) { + cam->vf_start_sdc = bg_overlay_start; + cam->vf_stop_sdc = bg_overlay_stop; + cam->vf_enable_csi = bg_overlay_enable_csi; + cam->vf_disable_csi = bg_overlay_disable_csi; + cam->overlay_active = false; + } + + return 0; +} +EXPORT_SYMBOL(bg_overlay_sdc_select); + +/*! + * function to de-select bg as the working path + * + * @param private cam_data * mxc v4l2 main structure + * + * @return status + */ +int bg_overlay_sdc_deselect(void *private) +{ + cam_data *cam = (cam_data *) private; + + if (cam) { + cam->vf_start_sdc = NULL; + cam->vf_stop_sdc = NULL; + cam->vf_enable_csi = NULL; + cam->vf_disable_csi = NULL; + } + return 0; +} +EXPORT_SYMBOL(bg_overlay_sdc_deselect); + +/*! + * Init background overlay task. + * + * @return Error code indicating success or failure + */ +__init int bg_overlay_sdc_init(void) +{ + return 0; +} + +/*! + * Deinit background overlay task. + * + * @return Error code indicating success or failure + */ +void __exit bg_overlay_sdc_exit(void) +{ +} + +module_init(bg_overlay_sdc_init); +module_exit(bg_overlay_sdc_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("IPU PRP VF SDC Backgroud Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/mxc/capture/ipu_csi_enc.c b/drivers/media/platform/mxc/capture/ipu_csi_enc.c new file mode 100644 index 000000000000..3a824a9659e7 --- /dev/null +++ b/drivers/media/platform/mxc/capture/ipu_csi_enc.c @@ -0,0 +1,430 @@ +/* + * Copyright 2009-2015 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file ipu_csi_enc.c + * + * @brief CSI Use case for video capture + * + * @ingroup IPU + */ + +#include +#include +#include +#include +#include +#include "mxc_v4l2_capture.h" +#include "ipu_prp_sw.h" + +#ifdef CAMERA_DBG + #define CAMERA_TRACE(x) (printk)x +#else + #define CAMERA_TRACE(x) +#endif + +/* + * Function definitions + */ + +/*! + * csi ENC callback function. + * + * @param irq int irq line + * @param dev_id void * device id + * + * @return status IRQ_HANDLED for handled + */ +static irqreturn_t csi_enc_callback(int irq, void *dev_id) +{ + cam_data *cam = (cam_data *) dev_id; + + if (cam->enc_callback == NULL) + return IRQ_HANDLED; + + cam->enc_callback(irq, dev_id); + return IRQ_HANDLED; +} + +/*! + * CSI ENC enable channel setup function + * + * @param cam struct cam_data * mxc capture instance + * + * @return status + */ +static int csi_enc_setup(cam_data *cam) +{ + ipu_channel_params_t params; + u32 pixel_fmt; + int err = 0, sensor_protocol = 0; + dma_addr_t dummy = cam->dummy_frame.buffer.m.offset; + ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1; +#ifdef CONFIG_MXC_MIPI_CSI2 + void *mipi_csi2_info; + int ipu_id; + int csi_id; +#endif + + CAMERA_TRACE("In csi_enc_setup\n"); + if (!cam) { + printk(KERN_ERR "cam private is NULL\n"); + return -ENXIO; + } + + memset(¶ms, 0, sizeof(ipu_channel_params_t)); + params.csi_mem.csi = cam->csi; + + sensor_protocol = ipu_csi_get_sensor_protocol(cam->ipu, cam->csi); + switch (sensor_protocol) { + case IPU_CSI_CLK_MODE_GATED_CLK: + case IPU_CSI_CLK_MODE_NONGATED_CLK: + case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE: + case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR: + case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR: + params.csi_mem.interlaced = false; + break; + case IPU_CSI_CLK_MODE_CCIR656_INTERLACED: + case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR: + case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR: + params.csi_mem.interlaced = true; + break; + default: + printk(KERN_ERR "sensor protocol unsupported\n"); + return -EINVAL; + } + + if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) + pixel_fmt = IPU_PIX_FMT_YUV420P; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YVU420) + pixel_fmt = IPU_PIX_FMT_YVU420P; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) + pixel_fmt = IPU_PIX_FMT_YUV422P; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY) + pixel_fmt = IPU_PIX_FMT_UYVY; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) + pixel_fmt = IPU_PIX_FMT_YUYV; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12) + pixel_fmt = IPU_PIX_FMT_NV12; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24) + pixel_fmt = IPU_PIX_FMT_BGR24; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) + pixel_fmt = IPU_PIX_FMT_RGB24; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) + pixel_fmt = IPU_PIX_FMT_RGB565; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32) + pixel_fmt = IPU_PIX_FMT_BGR32; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB32) + pixel_fmt = IPU_PIX_FMT_RGB32; + else { + printk(KERN_ERR "format not supported\n"); + return -EINVAL; + } + +#ifdef CONFIG_MXC_MIPI_CSI2 + mipi_csi2_info = mipi_csi2_get_info(); + + if (mipi_csi2_info) { + if (mipi_csi2_get_status(mipi_csi2_info)) { + ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); + csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); + + if (cam->ipu == ipu_get_soc(ipu_id) + && cam->csi == csi_id) { + params.csi_mem.mipi_en = true; + params.csi_mem.mipi_vc = + mipi_csi2_get_virtual_channel(mipi_csi2_info); + params.csi_mem.mipi_id = + mipi_csi2_get_datatype(mipi_csi2_info); + + mipi_csi2_pixelclk_enable(mipi_csi2_info); + } else { + params.csi_mem.mipi_en = false; + params.csi_mem.mipi_vc = 0; + params.csi_mem.mipi_id = 0; + } + } else { + params.csi_mem.mipi_en = false; + params.csi_mem.mipi_vc = 0; + params.csi_mem.mipi_id = 0; + } + } +#endif + + err = ipu_init_channel(cam->ipu, chan, ¶ms); + if (err != 0) { + printk(KERN_ERR "ipu_init_channel %d\n", err); + return err; + } + + err = ipu_init_channel_buffer(cam->ipu, + chan, + IPU_OUTPUT_BUFFER, + pixel_fmt, cam->v2f.fmt.pix.width, + cam->v2f.fmt.pix.height, + cam->v2f.fmt.pix.bytesperline, + IPU_ROTATE_NONE, + dummy, dummy, 0, + cam->offset.u_offset, + cam->offset.v_offset); + if (err != 0) { + printk(KERN_ERR "CSI_MEM output buffer\n"); + return err; + } + err = ipu_enable_channel(cam->ipu, chan); + if (err < 0) { + printk(KERN_ERR "ipu_enable_channel CSI_MEM\n"); + return err; + } + + return err; +} + +/*! + * function to update physical buffer address for encorder IDMA channel + * + * @param *private pointer to the cam_data structure + * @param eba physical buffer address for encorder IDMA channel + * + * @return status + */ +static int csi_enc_eba_update(void *private, dma_addr_t eba) +{ + int err = 0; + cam_data *cam = (cam_data *) private; + struct ipu_soc *ipu = cam->ipu; + int *buffer_num = &cam->ping_pong_csi; + ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1; + + pr_debug("eba %x\n", eba); + err = ipu_update_channel_buffer(ipu, chan, IPU_OUTPUT_BUFFER, + *buffer_num, eba); + if (err != 0) { + ipu_clear_buffer_ready(ipu, chan, IPU_OUTPUT_BUFFER, + *buffer_num); + + err = ipu_update_channel_buffer(ipu, chan, + IPU_OUTPUT_BUFFER, *buffer_num, eba); + if (err != 0) { + pr_err("ERROR: v4l2 capture: fail to update " + "buf%d\n", *buffer_num); + return err; + } + } + + ipu_select_buffer(ipu, chan, IPU_OUTPUT_BUFFER, *buffer_num); + + *buffer_num = (*buffer_num == 0) ? 1 : 0; + + return 0; +} + +/*! + * Enable encoder task + * @param private struct cam_data * mxc capture instance + * + * @return status + */ +static int csi_enc_enabling_tasks(void *private) +{ + cam_data *cam = (cam_data *) private; + int err = 0; + uint32_t irq = (cam->csi == 0) ? + IPU_IRQ_CSI0_OUT_EOF : IPU_IRQ_CSI1_OUT_EOF; + + CAMERA_TRACE("IPU:In csi_enc_enabling_tasks\n"); + + cam->dummy_frame.vaddress = dma_alloc_coherent(0, + PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage), + &cam->dummy_frame.paddress, + GFP_DMA | GFP_KERNEL); + if (cam->dummy_frame.vaddress == 0) { + pr_err("ERROR: v4l2 capture: Allocate dummy frame " + "failed.\n"); + return -ENOBUFS; + } + cam->dummy_frame.buffer.type = V4L2_BUF_TYPE_PRIVATE; + cam->dummy_frame.buffer.length = + PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage); + cam->dummy_frame.buffer.m.offset = cam->dummy_frame.paddress; + + ipu_clear_irq(cam->ipu, irq); + err = ipu_request_irq( + cam->ipu, irq, csi_enc_callback, 0, "Mxc Camera", cam); + if (err != 0) { + printk(KERN_ERR "Error registering rot irq\n"); + return err; + } + + err = csi_enc_setup(cam); + if (err != 0) { + printk(KERN_ERR "csi_enc_setup %d\n", err); + return err; + } + + return err; +} + +/*! + * Disable encoder task + * @param private struct cam_data * mxc capture instance + * + * @return int + */ +static int csi_enc_disabling_tasks(void *private) +{ + cam_data *cam = (cam_data *) private; + int err = 0; + ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1; +#ifdef CONFIG_MXC_MIPI_CSI2 + void *mipi_csi2_info; + int ipu_id; + int csi_id; +#endif + + err = ipu_disable_channel(cam->ipu, chan, true); + + ipu_uninit_channel(cam->ipu, chan); + + if (cam->dummy_frame.vaddress != 0) { + dma_free_coherent(0, cam->dummy_frame.buffer.length, + cam->dummy_frame.vaddress, + cam->dummy_frame.paddress); + cam->dummy_frame.vaddress = 0; + } + +#ifdef CONFIG_MXC_MIPI_CSI2 + mipi_csi2_info = mipi_csi2_get_info(); + + if (mipi_csi2_info) { + if (mipi_csi2_get_status(mipi_csi2_info)) { + ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); + csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); + + if (cam->ipu == ipu_get_soc(ipu_id) + && cam->csi == csi_id) + mipi_csi2_pixelclk_disable(mipi_csi2_info); + } + } +#endif + + return err; +} + +/*! + * Enable csi + * @param private struct cam_data * mxc capture instance + * + * @return status + */ +static int csi_enc_enable_csi(void *private) +{ + cam_data *cam = (cam_data *) private; + + return ipu_enable_csi(cam->ipu, cam->csi); +} + +/*! + * Disable csi + * @param private struct cam_data * mxc capture instance + * + * @return status + */ +static int csi_enc_disable_csi(void *private) +{ + cam_data *cam = (cam_data *) private; + uint32_t irq = (cam->csi == 0) ? + IPU_IRQ_CSI0_OUT_EOF : IPU_IRQ_CSI1_OUT_EOF; + + /* free csi eof irq firstly. + * when disable csi, wait for idmac eof. + * it requests eof irq again */ + ipu_free_irq(cam->ipu, irq, cam); + + return ipu_disable_csi(cam->ipu, cam->csi); +} + +/*! + * function to select CSI ENC as the working path + * + * @param private struct cam_data * mxc capture instance + * + * @return int + */ +int csi_enc_select(void *private) +{ + cam_data *cam = (cam_data *) private; + int err = 0; + + if (cam) { + cam->enc_update_eba = csi_enc_eba_update; + cam->enc_enable = csi_enc_enabling_tasks; + cam->enc_disable = csi_enc_disabling_tasks; + cam->enc_enable_csi = csi_enc_enable_csi; + cam->enc_disable_csi = csi_enc_disable_csi; + } else { + err = -EIO; + } + + return err; +} +EXPORT_SYMBOL(csi_enc_select); + +/*! + * function to de-select CSI ENC as the working path + * + * @param private struct cam_data * mxc capture instance + * + * @return int + */ +int csi_enc_deselect(void *private) +{ + cam_data *cam = (cam_data *) private; + int err = 0; + + if (cam) { + cam->enc_update_eba = NULL; + cam->enc_enable = NULL; + cam->enc_disable = NULL; + cam->enc_enable_csi = NULL; + cam->enc_disable_csi = NULL; + } + + return err; +} +EXPORT_SYMBOL(csi_enc_deselect); + +/*! + * Init the Encorder channels + * + * @return Error code indicating success or failure + */ +__init int csi_enc_init(void) +{ + return 0; +} + +/*! + * Deinit the Encorder channels + * + */ +void __exit csi_enc_exit(void) +{ +} + +module_init(csi_enc_init); +module_exit(csi_enc_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("CSI ENC Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c b/drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c new file mode 100644 index 000000000000..4d6b1365bb0d --- /dev/null +++ b/drivers/media/platform/mxc/capture/ipu_fg_overlay_sdc.c @@ -0,0 +1,638 @@ +/* + * Copyright 2004-2015 Freescale Semiconductor, Inc. All Rights Reserved. + */ +/* * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file ipu_foreground_sdc.c + * + * @brief IPU Use case for PRP-VF + * + * @ingroup IPU + */ + +#include +#include +#include +#include +#include +#include + +#include "mxc_v4l2_capture.h" +#include "ipu_prp_sw.h" + +#ifdef CAMERA_DBG + #define CAMERA_TRACE(x) (printk)x +#else + #define CAMERA_TRACE(x) +#endif + +static int csi_buffer_num, buffer_num; +static u32 csi_mem_bufsize; +static struct ipu_soc *disp_ipu; +static struct fb_info *fbi; +static struct fb_var_screeninfo fbvar; +static u32 vf_out_format; +static void csi_buf_work_func(struct work_struct *work) +{ + int err = 0; + cam_data *cam = + container_of(work, struct _cam_data, csi_work_struct); + + struct ipu_task task; + memset(&task, 0, sizeof(task)); + + if (csi_buffer_num) + task.input.paddr = cam->vf_bufs[0]; + else + task.input.paddr = cam->vf_bufs[1]; + task.input.width = cam->crop_current.width; + task.input.height = cam->crop_current.height; + task.input.format = IPU_PIX_FMT_NV12; + + if (buffer_num == 0) + task.output.paddr = fbi->fix.smem_start + + (fbi->fix.line_length * fbvar.yres); + else + task.output.paddr = fbi->fix.smem_start; + task.output.width = cam->win.w.width; + task.output.height = cam->win.w.height; + task.output.format = vf_out_format; + task.output.rotate = cam->rotation; +again: + err = ipu_check_task(&task); + if (err != IPU_CHECK_OK) { + if (err > IPU_CHECK_ERR_MIN) { + if (err == IPU_CHECK_ERR_SPLIT_INPUTW_OVER) { + task.input.crop.w -= 8; + goto again; + } + if (err == IPU_CHECK_ERR_SPLIT_INPUTH_OVER) { + task.input.crop.h -= 8; + goto again; + } + if (err == IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER) { + task.output.width -= 8; + task.output.crop.w = task.output.width; + goto again; + } + if (err == IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER) { + task.output.height -= 8; + task.output.crop.h = task.output.height; + goto again; + } + printk(KERN_ERR "check ipu taks fail\n"); + return; + } + printk(KERN_ERR "check ipu taks fail\n"); + return; + } + err = ipu_queue_task(&task); + if (err < 0) + printk(KERN_ERR "queue ipu task error\n"); + ipu_select_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER, buffer_num); + buffer_num = (buffer_num == 0) ? 1 : 0; +} + +static void get_disp_ipu(cam_data *cam) +{ + if (cam->output > 2) + disp_ipu = ipu_get_soc(1); /* using DISP4 */ + else + disp_ipu = ipu_get_soc(0); +} + +/*! + * csi ENC callback function. + * + * @param irq int irq line + * @param dev_id void * device id + * + * @return status IRQ_HANDLED for handled + */ +static irqreturn_t csi_enc_callback(int irq, void *dev_id) +{ + cam_data *cam = (cam_data *) dev_id; + ipu_channel_t chan = (irq == IPU_IRQ_CSI0_OUT_EOF) ? + CSI_MEM0 : CSI_MEM1; + + ipu_select_buffer(cam->ipu, chan, + IPU_OUTPUT_BUFFER, csi_buffer_num); + + if ((cam->crop_current.width != cam->win.w.width) || + (cam->crop_current.height != cam->win.w.height) || + (vf_out_format != IPU_PIX_FMT_NV12) || + (cam->rotation >= IPU_ROTATE_VERT_FLIP)) + schedule_work(&cam->csi_work_struct); + csi_buffer_num = (csi_buffer_num == 0) ? 1 : 0; + return IRQ_HANDLED; +} + +static int csi_enc_setup(cam_data *cam) +{ + ipu_channel_params_t params; + int err = 0, sensor_protocol = 0; + ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1; +#ifdef CONFIG_MXC_MIPI_CSI2 + void *mipi_csi2_info; + int ipu_id; + int csi_id; +#endif + + CAMERA_TRACE("In csi_enc_setup\n"); + if (!cam) { + printk(KERN_ERR "cam private is NULL\n"); + return -ENXIO; + } + + memset(¶ms, 0, sizeof(ipu_channel_params_t)); + params.csi_mem.csi = cam->csi; + + sensor_protocol = ipu_csi_get_sensor_protocol(cam->ipu, cam->csi); + switch (sensor_protocol) { + case IPU_CSI_CLK_MODE_GATED_CLK: + case IPU_CSI_CLK_MODE_NONGATED_CLK: + case IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE: + case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR: + case IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR: + params.csi_mem.interlaced = false; + break; + case IPU_CSI_CLK_MODE_CCIR656_INTERLACED: + case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR: + case IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR: + params.csi_mem.interlaced = true; + break; + default: + printk(KERN_ERR "sensor protocol unsupported\n"); + return -EINVAL; + } + +#ifdef CONFIG_MXC_MIPI_CSI2 + mipi_csi2_info = mipi_csi2_get_info(); + + if (mipi_csi2_info) { + if (mipi_csi2_get_status(mipi_csi2_info)) { + ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); + csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); + + if (cam->ipu == ipu_get_soc(ipu_id) + && cam->csi == csi_id) { + params.csi_mem.mipi_en = true; + params.csi_mem.mipi_vc = + mipi_csi2_get_virtual_channel(mipi_csi2_info); + params.csi_mem.mipi_id = + mipi_csi2_get_datatype(mipi_csi2_info); + + mipi_csi2_pixelclk_enable(mipi_csi2_info); + } else { + params.csi_mem.mipi_en = false; + params.csi_mem.mipi_vc = 0; + params.csi_mem.mipi_id = 0; + } + } else { + params.csi_mem.mipi_en = false; + params.csi_mem.mipi_vc = 0; + params.csi_mem.mipi_id = 0; + } + } +#endif + + if (cam->vf_bufs_vaddr[0]) { + dma_free_coherent(0, cam->vf_bufs_size[0], + cam->vf_bufs_vaddr[0], + (dma_addr_t) cam->vf_bufs[0]); + } + if (cam->vf_bufs_vaddr[1]) { + dma_free_coherent(0, cam->vf_bufs_size[1], + cam->vf_bufs_vaddr[1], + (dma_addr_t) cam->vf_bufs[1]); + } + csi_mem_bufsize = cam->crop_current.width * + cam->crop_current.height * 3/2; + cam->vf_bufs_size[0] = PAGE_ALIGN(csi_mem_bufsize); + cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0, + cam->vf_bufs_size[0], + (dma_addr_t *) & + cam->vf_bufs[0], + GFP_DMA | + GFP_KERNEL); + if (cam->vf_bufs_vaddr[0] == NULL) { + printk(KERN_ERR "Error to allocate vf buffer\n"); + err = -ENOMEM; + goto out_2; + } + cam->vf_bufs_size[1] = PAGE_ALIGN(csi_mem_bufsize); + cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0, + cam->vf_bufs_size[1], + (dma_addr_t *) & + cam->vf_bufs[1], + GFP_DMA | + GFP_KERNEL); + if (cam->vf_bufs_vaddr[1] == NULL) { + printk(KERN_ERR "Error to allocate vf buffer\n"); + err = -ENOMEM; + goto out_1; + } + pr_debug("vf_bufs %x %x\n", cam->vf_bufs[0], cam->vf_bufs[1]); + + err = ipu_init_channel(cam->ipu, chan, ¶ms); + if (err != 0) { + printk(KERN_ERR "ipu_init_channel %d\n", err); + goto out_1; + } + + if ((cam->crop_current.width == cam->win.w.width) && + (cam->crop_current.height == cam->win.w.height) && + (vf_out_format == IPU_PIX_FMT_NV12) && + (cam->rotation < IPU_ROTATE_VERT_FLIP)) { + err = ipu_init_channel_buffer(cam->ipu, chan, + IPU_OUTPUT_BUFFER, IPU_PIX_FMT_NV12, + cam->crop_current.width, + cam->crop_current.height, + cam->crop_current.width, IPU_ROTATE_NONE, + fbi->fix.smem_start + + (fbi->fix.line_length * fbvar.yres), + fbi->fix.smem_start, 0, + cam->offset.u_offset, cam->offset.u_offset); + } else { + err = ipu_init_channel_buffer(cam->ipu, chan, + IPU_OUTPUT_BUFFER, IPU_PIX_FMT_NV12, + cam->crop_current.width, + cam->crop_current.height, + cam->crop_current.width, IPU_ROTATE_NONE, + cam->vf_bufs[0], cam->vf_bufs[1], 0, + cam->offset.u_offset, cam->offset.u_offset); + } + if (err != 0) { + printk(KERN_ERR "CSI_MEM output buffer\n"); + goto out_1; + } + err = ipu_enable_channel(cam->ipu, chan); + if (err < 0) { + printk(KERN_ERR "ipu_enable_channel CSI_MEM\n"); + goto out_1; + } + + csi_buffer_num = 0; + + ipu_select_buffer(cam->ipu, chan, IPU_OUTPUT_BUFFER, 0); + ipu_select_buffer(cam->ipu, chan, IPU_OUTPUT_BUFFER, 1); + return err; +out_1: + if (cam->vf_bufs_vaddr[0]) { + dma_free_coherent(0, cam->vf_bufs_size[0], + cam->vf_bufs_vaddr[0], + (dma_addr_t) cam->vf_bufs[0]); + cam->vf_bufs_vaddr[0] = NULL; + cam->vf_bufs[0] = 0; + } + if (cam->vf_bufs_vaddr[1]) { + dma_free_coherent(0, cam->vf_bufs_size[1], + cam->vf_bufs_vaddr[1], + (dma_addr_t) cam->vf_bufs[1]); + cam->vf_bufs_vaddr[1] = NULL; + cam->vf_bufs[1] = 0; + } +out_2: + return err; +} + +/*! + * Enable encoder task + * @param private struct cam_data * mxc capture instance + * + * @return status + */ +static int csi_enc_enabling_tasks(void *private) +{ + cam_data *cam = (cam_data *) private; + int err = 0; + CAMERA_TRACE("IPU:In csi_enc_enabling_tasks\n"); + + ipu_clear_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi); + err = ipu_request_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi, + csi_enc_callback, 0, "Mxc Camera", cam); + if (err != 0) { + printk(KERN_ERR "Error registering CSI_OUT_EOF irq\n"); + return err; + } + + INIT_WORK(&cam->csi_work_struct, csi_buf_work_func); + + err = csi_enc_setup(cam); + if (err != 0) { + printk(KERN_ERR "csi_enc_setup %d\n", err); + goto out1; + } + + return err; +out1: + ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi, cam); + return err; +} + +/* + * Function definitions + */ + +/*! + * foreground_start - start the vf task + * + * @param private cam_data * mxc v4l2 main structure + * + */ +static int foreground_start(void *private) +{ + cam_data *cam = (cam_data *) private; + int err = 0, i = 0, screen_size; + char *base; + + if (!cam) { + printk(KERN_ERR "private is NULL\n"); + return -EIO; + } + + if (cam->overlay_active == true) { + pr_debug("already started.\n"); + return 0; + } + + get_disp_ipu(cam); + + for (i = 0; i < num_registered_fb; i++) { + char *idstr = registered_fb[i]->fix.id; + if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) || + ((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) { + fbi = registered_fb[i]; + break; + } + } + + if (fbi == NULL) { + printk(KERN_ERR "DISP FG fb not found\n"); + return -EPERM; + } + + fbvar = fbi->var; + + /* Store the overlay frame buffer's original std */ + cam->fb_origin_std = fbvar.nonstd; + + if (cam->devtype == IMX5_V4L2 || cam->devtype == IMX6_V4L2) { + /* Use DP to do CSC so that we can get better performance */ + vf_out_format = IPU_PIX_FMT_NV12; + fbvar.nonstd = vf_out_format; + } else { + vf_out_format = IPU_PIX_FMT_RGB565; + fbvar.nonstd = 0; + } + + fbvar.bits_per_pixel = 16; + fbvar.xres = fbvar.xres_virtual = cam->win.w.width; + fbvar.yres = cam->win.w.height; + fbvar.yres_virtual = cam->win.w.height * 2; + fbvar.yoffset = 0; + fbvar.vmode &= ~FB_VMODE_YWRAP; + fbvar.accel_flags = FB_ACCEL_DOUBLE_FLAG; + fbvar.activate |= FB_ACTIVATE_FORCE; + fb_set_var(fbi, &fbvar); + + ipu_disp_set_window_pos(disp_ipu, MEM_FG_SYNC, cam->win.w.left, + cam->win.w.top); + + /* Fill black color for framebuffer */ + base = (char *) fbi->screen_base; + screen_size = fbi->var.xres * fbi->var.yres; + if (cam->devtype == IMX5_V4L2 || cam->devtype == IMX6_V4L2) { + memset(base, 0, screen_size); + base += screen_size; + for (i = 0; i < screen_size / 2; i++, base++) + *base = 0x80; + } else { + for (i = 0; i < screen_size * 2; i++, base++) + *base = 0x00; + } + + console_lock(); + fb_blank(fbi, FB_BLANK_UNBLANK); + console_unlock(); + + /* correct display ch buffer address */ + ipu_update_channel_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER, + 0, fbi->fix.smem_start + + (fbi->fix.line_length * fbvar.yres)); + ipu_update_channel_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER, + 1, fbi->fix.smem_start); + + err = csi_enc_enabling_tasks(cam); + if (err != 0) { + printk(KERN_ERR "Error csi enc enable fail\n"); + return err; + } + + cam->overlay_active = true; + return err; + +} + +/*! + * foreground_stop - stop the vf task + * + * @param private cam_data * mxc v4l2 main structure + * + */ +static int foreground_stop(void *private) +{ + cam_data *cam = (cam_data *) private; + int err = 0, i = 0; + struct fb_info *fbi = NULL; + struct fb_var_screeninfo fbvar; + ipu_channel_t chan = (cam->csi == 0) ? CSI_MEM0 : CSI_MEM1; + +#ifdef CONFIG_MXC_MIPI_CSI2 + void *mipi_csi2_info; + int ipu_id; + int csi_id; +#endif + + if (cam->overlay_active == false) + return 0; + + err = ipu_disable_channel(cam->ipu, chan, true); + + ipu_uninit_channel(cam->ipu, chan); + + csi_buffer_num = 0; + buffer_num = 0; + + for (i = 0; i < num_registered_fb; i++) { + char *idstr = registered_fb[i]->fix.id; + if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) || + ((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) { + fbi = registered_fb[i]; + break; + } + } + + if (fbi == NULL) { + printk(KERN_ERR "DISP FG fb not found\n"); + return -EPERM; + } + + console_lock(); + fb_blank(fbi, FB_BLANK_POWERDOWN); + console_unlock(); + + /* Set the overlay frame buffer std to what it is used to be */ + fbvar = fbi->var; + fbvar.accel_flags = FB_ACCEL_TRIPLE_FLAG; + fbvar.nonstd = cam->fb_origin_std; + fbvar.activate |= FB_ACTIVATE_FORCE; + fb_set_var(fbi, &fbvar); + +#ifdef CONFIG_MXC_MIPI_CSI2 + mipi_csi2_info = mipi_csi2_get_info(); + + if (mipi_csi2_info) { + if (mipi_csi2_get_status(mipi_csi2_info)) { + ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); + csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); + + if (cam->ipu == ipu_get_soc(ipu_id) + && cam->csi == csi_id) + mipi_csi2_pixelclk_disable(mipi_csi2_info); + } + } +#endif + + flush_work(&cam->csi_work_struct); + cancel_work_sync(&cam->csi_work_struct); + + if (cam->vf_bufs_vaddr[0]) { + dma_free_coherent(0, cam->vf_bufs_size[0], + cam->vf_bufs_vaddr[0], + (dma_addr_t) cam->vf_bufs[0]); + cam->vf_bufs_vaddr[0] = NULL; + cam->vf_bufs[0] = 0; + } + if (cam->vf_bufs_vaddr[1]) { + dma_free_coherent(0, cam->vf_bufs_size[1], + cam->vf_bufs_vaddr[1], + (dma_addr_t) cam->vf_bufs[1]); + cam->vf_bufs_vaddr[1] = NULL; + cam->vf_bufs[1] = 0; + } + + cam->overlay_active = false; + return err; +} + +/*! + * Enable csi + * @param private struct cam_data * mxc capture instance + * + * @return status + */ +static int foreground_enable_csi(void *private) +{ + cam_data *cam = (cam_data *) private; + + return ipu_enable_csi(cam->ipu, cam->csi); +} + +/*! + * Disable csi + * @param private struct cam_data * mxc capture instance + * + * @return status + */ +static int foreground_disable_csi(void *private) +{ + cam_data *cam = (cam_data *) private; + + /* free csi eof irq firstly. + * when disable csi, wait for idmac eof. + * it requests eof irq again */ + ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF + cam->csi, cam); + + return ipu_disable_csi(cam->ipu, cam->csi); +} + +/*! + * function to select foreground as the working path + * + * @param private cam_data * mxc v4l2 main structure + * + * @return status + */ +int foreground_sdc_select(void *private) +{ + cam_data *cam; + int err = 0; + if (private) { + cam = (cam_data *) private; + cam->vf_start_sdc = foreground_start; + cam->vf_stop_sdc = foreground_stop; + cam->vf_enable_csi = foreground_enable_csi; + cam->vf_disable_csi = foreground_disable_csi; + cam->overlay_active = false; + } else + err = -EIO; + + return err; +} +EXPORT_SYMBOL(foreground_sdc_select); + +/*! + * function to de-select foreground as the working path + * + * @param private cam_data * mxc v4l2 main structure + * + * @return int + */ +int foreground_sdc_deselect(void *private) +{ + cam_data *cam; + + if (private) { + cam = (cam_data *) private; + cam->vf_start_sdc = NULL; + cam->vf_stop_sdc = NULL; + cam->vf_enable_csi = NULL; + cam->vf_disable_csi = NULL; + } + return 0; +} +EXPORT_SYMBOL(foreground_sdc_deselect); + +/*! + * Init viewfinder task. + * + * @return Error code indicating success or failure + */ +__init int foreground_sdc_init(void) +{ + return 0; +} + +/*! + * Deinit viewfinder task. + * + * @return Error code indicating success or failure + */ +void __exit foreground_sdc_exit(void) +{ +} + +module_init(foreground_sdc_init); +module_exit(foreground_sdc_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("IPU PRP VF SDC Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/mxc/capture/ipu_prp_enc.c b/drivers/media/platform/mxc/capture/ipu_prp_enc.c new file mode 100644 index 000000000000..1e4420b952f8 --- /dev/null +++ b/drivers/media/platform/mxc/capture/ipu_prp_enc.c @@ -0,0 +1,597 @@ +/* + * Copyright 2004-2015 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file ipu_prp_enc.c + * + * @brief IPU Use case for PRP-ENC + * + * @ingroup IPU + */ + +#include +#include +#include +#include +#include +#include "mxc_v4l2_capture.h" +#include "ipu_prp_sw.h" + +#ifdef CAMERA_DBG + #define CAMERA_TRACE(x) (printk)x +#else + #define CAMERA_TRACE(x) +#endif + +static ipu_rotate_mode_t grotation = IPU_ROTATE_NONE; + +/* + * Function definitions + */ + +/*! + * IPU ENC callback function. + * + * @param irq int irq line + * @param dev_id void * device id + * + * @return status IRQ_HANDLED for handled + */ +static irqreturn_t prp_enc_callback(int irq, void *dev_id) +{ + cam_data *cam = (cam_data *) dev_id; + + if (cam->enc_callback == NULL) + return IRQ_HANDLED; + + cam->enc_callback(irq, dev_id); + + return IRQ_HANDLED; +} + +/*! + * PrpENC enable channel setup function + * + * @param cam struct cam_data * mxc capture instance + * + * @return status + */ +static int prp_enc_setup(cam_data *cam) +{ + ipu_channel_params_t enc; + int err = 0; + dma_addr_t dummy = cam->dummy_frame.buffer.m.offset; +#ifdef CONFIG_MXC_MIPI_CSI2 + void *mipi_csi2_info; + int ipu_id; + int csi_id; +#endif + + CAMERA_TRACE("In prp_enc_setup\n"); + if (!cam) { + printk(KERN_ERR "cam private is NULL\n"); + return -ENXIO; + } + memset(&enc, 0, sizeof(ipu_channel_params_t)); + + ipu_csi_get_window_size(cam->ipu, &enc.csi_prp_enc_mem.in_width, + &enc.csi_prp_enc_mem.in_height, cam->csi); + + enc.csi_prp_enc_mem.in_pixel_fmt = IPU_PIX_FMT_UYVY; + enc.csi_prp_enc_mem.out_width = cam->v2f.fmt.pix.width; + enc.csi_prp_enc_mem.out_height = cam->v2f.fmt.pix.height; + enc.csi_prp_enc_mem.csi = cam->csi; + if (cam->rotation >= IPU_ROTATE_90_RIGHT) { + enc.csi_prp_enc_mem.out_width = cam->v2f.fmt.pix.height; + enc.csi_prp_enc_mem.out_height = cam->v2f.fmt.pix.width; + } + + if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) { + enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YUV420P; + pr_info("YUV420\n"); + } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YVU420) { + enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YVU420P; + pr_info("YVU420\n"); + } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) { + enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YUV422P; + pr_info("YUV422P\n"); + } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) { + enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_YUYV; + pr_info("YUYV\n"); + } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY) { + enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_UYVY; + pr_info("UYVY\n"); + } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12) { + enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_NV12; + pr_info("NV12\n"); + } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24) { + enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_BGR24; + pr_info("BGR24\n"); + } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) { + enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_RGB24; + pr_info("RGB24\n"); + } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) { + enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_RGB565; + pr_info("RGB565\n"); + } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32) { + enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_BGR32; + pr_info("BGR32\n"); + } else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB32) { + enc.csi_prp_enc_mem.out_pixel_fmt = IPU_PIX_FMT_RGB32; + pr_info("RGB32\n"); + } else { + printk(KERN_ERR "format not supported\n"); + return -EINVAL; + } + +#ifdef CONFIG_MXC_MIPI_CSI2 + mipi_csi2_info = mipi_csi2_get_info(); + + if (mipi_csi2_info) { + if (mipi_csi2_get_status(mipi_csi2_info)) { + ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); + csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); + + if (cam->ipu == ipu_get_soc(ipu_id) + && cam->csi == csi_id) { + enc.csi_prp_enc_mem.mipi_en = true; + enc.csi_prp_enc_mem.mipi_vc = + mipi_csi2_get_virtual_channel(mipi_csi2_info); + enc.csi_prp_enc_mem.mipi_id = + mipi_csi2_get_datatype(mipi_csi2_info); + + mipi_csi2_pixelclk_enable(mipi_csi2_info); + } else { + enc.csi_prp_enc_mem.mipi_en = false; + enc.csi_prp_enc_mem.mipi_vc = 0; + enc.csi_prp_enc_mem.mipi_id = 0; + } + } else { + enc.csi_prp_enc_mem.mipi_en = false; + enc.csi_prp_enc_mem.mipi_vc = 0; + enc.csi_prp_enc_mem.mipi_id = 0; + } + } +#endif + + err = ipu_init_channel(cam->ipu, CSI_PRP_ENC_MEM, &enc); + if (err != 0) { + printk(KERN_ERR "ipu_init_channel %d\n", err); + return err; + } + + grotation = cam->rotation; + if (cam->rotation >= IPU_ROTATE_90_RIGHT) { + if (cam->rot_enc_bufs_vaddr[0]) { + dma_free_coherent(0, cam->rot_enc_buf_size[0], + cam->rot_enc_bufs_vaddr[0], + cam->rot_enc_bufs[0]); + } + if (cam->rot_enc_bufs_vaddr[1]) { + dma_free_coherent(0, cam->rot_enc_buf_size[1], + cam->rot_enc_bufs_vaddr[1], + cam->rot_enc_bufs[1]); + } + cam->rot_enc_buf_size[0] = + PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage); + cam->rot_enc_bufs_vaddr[0] = + (void *)dma_alloc_coherent(0, cam->rot_enc_buf_size[0], + &cam->rot_enc_bufs[0], + GFP_DMA | GFP_KERNEL); + if (!cam->rot_enc_bufs_vaddr[0]) { + printk(KERN_ERR "alloc enc_bufs0\n"); + return -ENOMEM; + } + cam->rot_enc_buf_size[1] = + PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage); + cam->rot_enc_bufs_vaddr[1] = + (void *)dma_alloc_coherent(0, cam->rot_enc_buf_size[1], + &cam->rot_enc_bufs[1], + GFP_DMA | GFP_KERNEL); + if (!cam->rot_enc_bufs_vaddr[1]) { + dma_free_coherent(0, cam->rot_enc_buf_size[0], + cam->rot_enc_bufs_vaddr[0], + cam->rot_enc_bufs[0]); + cam->rot_enc_bufs_vaddr[0] = NULL; + cam->rot_enc_bufs[0] = 0; + printk(KERN_ERR "alloc enc_bufs1\n"); + return -ENOMEM; + } + + err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_ENC_MEM, + IPU_OUTPUT_BUFFER, + enc.csi_prp_enc_mem.out_pixel_fmt, + enc.csi_prp_enc_mem.out_width, + enc.csi_prp_enc_mem.out_height, + enc.csi_prp_enc_mem.out_width, + IPU_ROTATE_NONE, + cam->rot_enc_bufs[0], + cam->rot_enc_bufs[1], 0, 0, 0); + if (err != 0) { + printk(KERN_ERR "CSI_PRP_ENC_MEM err\n"); + return err; + } + + err = ipu_init_channel(cam->ipu, MEM_ROT_ENC_MEM, NULL); + if (err != 0) { + printk(KERN_ERR "MEM_ROT_ENC_MEM channel err\n"); + return err; + } + + err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_ENC_MEM, + IPU_INPUT_BUFFER, + enc.csi_prp_enc_mem.out_pixel_fmt, + enc.csi_prp_enc_mem.out_width, + enc.csi_prp_enc_mem.out_height, + enc.csi_prp_enc_mem.out_width, + cam->rotation, + cam->rot_enc_bufs[0], + cam->rot_enc_bufs[1], 0, 0, 0); + if (err != 0) { + printk(KERN_ERR "MEM_ROT_ENC_MEM input buffer\n"); + return err; + } + + err = + ipu_init_channel_buffer(cam->ipu, MEM_ROT_ENC_MEM, + IPU_OUTPUT_BUFFER, + enc.csi_prp_enc_mem.out_pixel_fmt, + enc.csi_prp_enc_mem.out_height, + enc.csi_prp_enc_mem.out_width, + cam->v2f.fmt.pix.bytesperline / + bytes_per_pixel(enc.csi_prp_enc_mem. + out_pixel_fmt), + IPU_ROTATE_NONE, + dummy, dummy, 0, + cam->offset.u_offset, + cam->offset.v_offset); + if (err != 0) { + printk(KERN_ERR "MEM_ROT_ENC_MEM output buffer\n"); + return err; + } + + err = ipu_link_channels(cam->ipu, + CSI_PRP_ENC_MEM, MEM_ROT_ENC_MEM); + if (err < 0) { + printk(KERN_ERR + "link CSI_PRP_ENC_MEM-MEM_ROT_ENC_MEM\n"); + return err; + } + + err = ipu_enable_channel(cam->ipu, CSI_PRP_ENC_MEM); + if (err < 0) { + printk(KERN_ERR "ipu_enable_channel CSI_PRP_ENC_MEM\n"); + return err; + } + err = ipu_enable_channel(cam->ipu, MEM_ROT_ENC_MEM); + if (err < 0) { + printk(KERN_ERR "ipu_enable_channel MEM_ROT_ENC_MEM\n"); + return err; + } + + ipu_select_buffer(cam->ipu, CSI_PRP_ENC_MEM, + IPU_OUTPUT_BUFFER, 0); + ipu_select_buffer(cam->ipu, CSI_PRP_ENC_MEM, + IPU_OUTPUT_BUFFER, 1); + } else { + err = + ipu_init_channel_buffer(cam->ipu, CSI_PRP_ENC_MEM, + IPU_OUTPUT_BUFFER, + enc.csi_prp_enc_mem.out_pixel_fmt, + enc.csi_prp_enc_mem.out_width, + enc.csi_prp_enc_mem.out_height, + cam->v2f.fmt.pix.bytesperline / + bytes_per_pixel(enc.csi_prp_enc_mem. + out_pixel_fmt), + cam->rotation, + dummy, dummy, 0, + cam->offset.u_offset, + cam->offset.v_offset); + if (err != 0) { + printk(KERN_ERR "CSI_PRP_ENC_MEM output buffer\n"); + return err; + } + err = ipu_enable_channel(cam->ipu, CSI_PRP_ENC_MEM); + if (err < 0) { + printk(KERN_ERR "ipu_enable_channel CSI_PRP_ENC_MEM\n"); + return err; + } + } + + return err; +} + +/*! + * function to update physical buffer address for encorder IDMA channel + * + * @param private pointer to cam_data structure + * @param eba physical buffer address for encorder IDMA channel + * + * @return status + */ +static int prp_enc_eba_update(void *private, dma_addr_t eba) +{ + int err = 0; + cam_data *cam = (cam_data *) private; + struct ipu_soc *ipu = cam->ipu; + int *buffer_num = &cam->ping_pong_csi; + + pr_debug("eba %x\n", eba); + if (grotation >= IPU_ROTATE_90_RIGHT) { + err = ipu_update_channel_buffer(ipu, MEM_ROT_ENC_MEM, + IPU_OUTPUT_BUFFER, *buffer_num, + eba); + } else { + err = ipu_update_channel_buffer(ipu, CSI_PRP_ENC_MEM, + IPU_OUTPUT_BUFFER, *buffer_num, + eba); + } + if (err != 0) { + if (grotation >= IPU_ROTATE_90_RIGHT) { + ipu_clear_buffer_ready(ipu, MEM_ROT_ENC_MEM, + IPU_OUTPUT_BUFFER, + *buffer_num); + err = ipu_update_channel_buffer(ipu, MEM_ROT_ENC_MEM, + IPU_OUTPUT_BUFFER, + *buffer_num, + eba); + } else { + ipu_clear_buffer_ready(ipu, CSI_PRP_ENC_MEM, + IPU_OUTPUT_BUFFER, + *buffer_num); + err = ipu_update_channel_buffer(ipu, CSI_PRP_ENC_MEM, + IPU_OUTPUT_BUFFER, + *buffer_num, + eba); + } + + if (err != 0) { + pr_err("ERROR: v4l2 capture: fail to update " + "buf%d\n", *buffer_num); + return err; + } + } + + if (grotation >= IPU_ROTATE_90_RIGHT) { + ipu_select_buffer(ipu, MEM_ROT_ENC_MEM, IPU_OUTPUT_BUFFER, + *buffer_num); + } else { + ipu_select_buffer(ipu, CSI_PRP_ENC_MEM, IPU_OUTPUT_BUFFER, + *buffer_num); + } + + *buffer_num = (*buffer_num == 0) ? 1 : 0; + return 0; +} + +/*! + * Enable encoder task + * @param private struct cam_data * mxc capture instance + * + * @return status + */ +static int prp_enc_enabling_tasks(void *private) +{ + cam_data *cam = (cam_data *) private; + int err = 0; + CAMERA_TRACE("IPU:In prp_enc_enabling_tasks\n"); + + cam->dummy_frame.vaddress = dma_alloc_coherent(0, + PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage), + &cam->dummy_frame.paddress, + GFP_DMA | GFP_KERNEL); + if (cam->dummy_frame.vaddress == 0) { + pr_err("ERROR: v4l2 capture: Allocate dummy frame " + "failed.\n"); + return -ENOBUFS; + } + cam->dummy_frame.buffer.type = V4L2_BUF_TYPE_PRIVATE; + cam->dummy_frame.buffer.length = + PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage); + cam->dummy_frame.buffer.m.offset = cam->dummy_frame.paddress; + + if (cam->rotation >= IPU_ROTATE_90_RIGHT) { + err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_ENC_ROT_OUT_EOF, + prp_enc_callback, 0, "Mxc Camera", cam); + } else { + err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_ENC_OUT_EOF, + prp_enc_callback, 0, "Mxc Camera", cam); + } + if (err != 0) { + printk(KERN_ERR "Error registering rot irq\n"); + return err; + } + + err = prp_enc_setup(cam); + if (err != 0) { + printk(KERN_ERR "prp_enc_setup %d\n", err); + return err; + } + + return err; +} + +/*! + * Disable encoder task + * @param private struct cam_data * mxc capture instance + * + * @return int + */ +static int prp_enc_disabling_tasks(void *private) +{ + cam_data *cam = (cam_data *) private; + int err = 0; +#ifdef CONFIG_MXC_MIPI_CSI2 + void *mipi_csi2_info; + int ipu_id; + int csi_id; +#endif + + if (cam->rotation >= IPU_ROTATE_90_RIGHT) { + ipu_free_irq(cam->ipu, IPU_IRQ_PRP_ENC_ROT_OUT_EOF, cam); + ipu_unlink_channels(cam->ipu, CSI_PRP_ENC_MEM, MEM_ROT_ENC_MEM); + } + + err = ipu_disable_channel(cam->ipu, CSI_PRP_ENC_MEM, true); + if (cam->rotation >= IPU_ROTATE_90_RIGHT) + err |= ipu_disable_channel(cam->ipu, MEM_ROT_ENC_MEM, true); + + ipu_uninit_channel(cam->ipu, CSI_PRP_ENC_MEM); + if (cam->rotation >= IPU_ROTATE_90_RIGHT) + ipu_uninit_channel(cam->ipu, MEM_ROT_ENC_MEM); + + if (cam->dummy_frame.vaddress != 0) { + dma_free_coherent(0, cam->dummy_frame.buffer.length, + cam->dummy_frame.vaddress, + cam->dummy_frame.paddress); + cam->dummy_frame.vaddress = 0; + } + +#ifdef CONFIG_MXC_MIPI_CSI2 + mipi_csi2_info = mipi_csi2_get_info(); + + if (mipi_csi2_info) { + if (mipi_csi2_get_status(mipi_csi2_info)) { + ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); + csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); + + if (cam->ipu == ipu_get_soc(ipu_id) + && cam->csi == csi_id) + mipi_csi2_pixelclk_disable(mipi_csi2_info); + } + } +#endif + + return err; +} + +/*! + * Enable csi + * @param private struct cam_data * mxc capture instance + * + * @return status + */ +static int prp_enc_enable_csi(void *private) +{ + cam_data *cam = (cam_data *) private; + + return ipu_enable_csi(cam->ipu, cam->csi); +} + +/*! + * Disable csi + * @param private struct cam_data * mxc capture instance + * + * @return status + */ +static int prp_enc_disable_csi(void *private) +{ + cam_data *cam = (cam_data *) private; + + /* free csi eof irq firstly. + * when disable csi, wait for idmac eof. + * it requests eof irq again */ + if (cam->rotation < IPU_ROTATE_90_RIGHT) + ipu_free_irq(cam->ipu, IPU_IRQ_PRP_ENC_OUT_EOF, cam); + + return ipu_disable_csi(cam->ipu, cam->csi); +} + +/*! + * function to select PRP-ENC as the working path + * + * @param private struct cam_data * mxc capture instance + * + * @return int + */ +int prp_enc_select(void *private) +{ + cam_data *cam = (cam_data *) private; + int err = 0; + + if (cam) { + cam->enc_update_eba = prp_enc_eba_update; + cam->enc_enable = prp_enc_enabling_tasks; + cam->enc_disable = prp_enc_disabling_tasks; + cam->enc_enable_csi = prp_enc_enable_csi; + cam->enc_disable_csi = prp_enc_disable_csi; + } else { + err = -EIO; + } + + return err; +} +EXPORT_SYMBOL(prp_enc_select); + +/*! + * function to de-select PRP-ENC as the working path + * + * @param private struct cam_data * mxc capture instance + * + * @return int + */ +int prp_enc_deselect(void *private) +{ + cam_data *cam = (cam_data *) private; + int err = 0; + + if (cam) { + cam->enc_update_eba = NULL; + cam->enc_enable = NULL; + cam->enc_disable = NULL; + cam->enc_enable_csi = NULL; + cam->enc_disable_csi = NULL; + if (cam->rot_enc_bufs_vaddr[0]) { + dma_free_coherent(0, cam->rot_enc_buf_size[0], + cam->rot_enc_bufs_vaddr[0], + cam->rot_enc_bufs[0]); + cam->rot_enc_bufs_vaddr[0] = NULL; + cam->rot_enc_bufs[0] = 0; + } + if (cam->rot_enc_bufs_vaddr[1]) { + dma_free_coherent(0, cam->rot_enc_buf_size[1], + cam->rot_enc_bufs_vaddr[1], + cam->rot_enc_bufs[1]); + cam->rot_enc_bufs_vaddr[1] = NULL; + cam->rot_enc_bufs[1] = 0; + } + } + + return err; +} +EXPORT_SYMBOL(prp_enc_deselect); + +/*! + * Init the Encorder channels + * + * @return Error code indicating success or failure + */ +__init int prp_enc_init(void) +{ + return 0; +} + +/*! + * Deinit the Encorder channels + * + */ +void __exit prp_enc_exit(void) +{ +} + +module_init(prp_enc_init); +module_exit(prp_enc_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("IPU PRP ENC Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/mxc/capture/ipu_prp_sw.h b/drivers/media/platform/mxc/capture/ipu_prp_sw.h new file mode 100644 index 000000000000..be02ab061e20 --- /dev/null +++ b/drivers/media/platform/mxc/capture/ipu_prp_sw.h @@ -0,0 +1,43 @@ +/* + * Copyright 2004-2014 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file ipu_prp_sw.h + * + * @brief This file contains the IPU PRP use case driver header. + * + * @ingroup IPU + */ + +#ifndef _INCLUDE_IPU__PRP_SW_H_ +#define _INCLUDE_IPU__PRP_SW_H_ + +int csi_enc_select(void *private); +int csi_enc_deselect(void *private); +int prp_enc_select(void *private); +int prp_enc_deselect(void *private); +#ifdef CONFIG_MXC_IPU_PRP_VF_SDC +int prp_vf_sdc_select(void *private); +int prp_vf_sdc_deselect(void *private); +int prp_vf_sdc_select_bg(void *private); +int prp_vf_sdc_deselect_bg(void *private); +#else +int foreground_sdc_select(void *private); +int foreground_sdc_deselect(void *private); +int bg_overlay_sdc_select(void *private); +int bg_overlay_sdc_deselect(void *private); +#endif +int prp_still_select(void *private); +int prp_still_deselect(void *private); + +#endif diff --git a/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c b/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c new file mode 100644 index 000000000000..b9610f1ed820 --- /dev/null +++ b/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc.c @@ -0,0 +1,582 @@ +/* + * Copyright 2004-2014 Freescale Semiconductor, Inc. All Rights Reserved. + */ +/* * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file ipu_prp_vf_sdc.c + * + * @brief IPU Use case for PRP-VF + * + * @ingroup IPU + */ + +#include +#include +#include +#include +#include +#include +#include +#include "mxc_v4l2_capture.h" +#include "ipu_prp_sw.h" + +static int buffer_num; +static struct ipu_soc *disp_ipu; + +static void get_disp_ipu(cam_data *cam) +{ + if (cam->output > 2) + disp_ipu = ipu_get_soc(1); /* using DISP4 */ + else + disp_ipu = ipu_get_soc(0); +} + +static irqreturn_t prpvf_rot_eof_callback(int irq, void *dev_id) +{ + cam_data *cam = dev_id; + pr_debug("buffer_num %d\n", buffer_num); + + if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) { + ipu_select_buffer(disp_ipu, MEM_FG_SYNC, + IPU_INPUT_BUFFER, buffer_num); + buffer_num = (buffer_num == 0) ? 1 : 0; + ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM, + IPU_OUTPUT_BUFFER, buffer_num); + } else { + ipu_select_buffer(disp_ipu, MEM_FG_SYNC, + IPU_INPUT_BUFFER, buffer_num); + buffer_num = (buffer_num == 0) ? 1 : 0; + ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM, + IPU_OUTPUT_BUFFER, buffer_num); + } + return IRQ_HANDLED; +} +/* + * Function definitions + */ + +/*! + * prpvf_start - start the vf task + * + * @param private cam_data * mxc v4l2 main structure + * + */ +static int prpvf_start(void *private) +{ + struct fb_var_screeninfo fbvar; + struct fb_info *fbi = NULL; + cam_data *cam = (cam_data *) private; + ipu_channel_params_t vf; + u32 vf_out_format = 0; + u32 size = 2, temp = 0; + int err = 0, i = 0; + short *tmp, color; +#ifdef CONFIG_MXC_MIPI_CSI2 + void *mipi_csi2_info; + int ipu_id; + int csi_id; +#endif + + if (!cam) { + printk(KERN_ERR "private is NULL\n"); + return -EIO; + } + + if (cam->overlay_active == true) { + pr_debug("already started.\n"); + return 0; + } + + get_disp_ipu(cam); + + for (i = 0; i < num_registered_fb; i++) { + char *idstr = registered_fb[i]->fix.id; + if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) || + ((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) { + fbi = registered_fb[i]; + break; + } + } + + if (fbi == NULL) { + printk(KERN_ERR "DISP FG fb not found\n"); + return -EPERM; + } + + fbvar = fbi->var; + + /* Store the overlay frame buffer's original std */ + cam->fb_origin_std = fbvar.nonstd; + + if (cam->devtype == IMX5_V4L2 || cam->devtype == IMX6_V4L2) { + /* Use DP to do CSC so that we can get better performance */ + vf_out_format = IPU_PIX_FMT_UYVY; + fbvar.nonstd = vf_out_format; + color = 0x80; + } else { + vf_out_format = IPU_PIX_FMT_RGB565; + fbvar.nonstd = 0; + color = 0x0; + } + + fbvar.bits_per_pixel = 16; + fbvar.xres = fbvar.xres_virtual = cam->win.w.width; + fbvar.yres = cam->win.w.height; + fbvar.yres_virtual = cam->win.w.height * 2; + fbvar.yoffset = 0; + fbvar.accel_flags = FB_ACCEL_DOUBLE_FLAG; + fbvar.activate |= FB_ACTIVATE_FORCE; + fb_set_var(fbi, &fbvar); + + ipu_disp_set_window_pos(disp_ipu, MEM_FG_SYNC, cam->win.w.left, + cam->win.w.top); + + /* Fill black color for framebuffer */ + tmp = (short *) fbi->screen_base; + for (i = 0; i < (fbi->fix.line_length * fbi->var.yres)/2; + i++, tmp++) + *tmp = color; + + console_lock(); + fb_blank(fbi, FB_BLANK_UNBLANK); + console_unlock(); + + /* correct display ch buffer address */ + ipu_update_channel_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER, + 0, fbi->fix.smem_start + + (fbi->fix.line_length * fbvar.yres)); + ipu_update_channel_buffer(disp_ipu, MEM_FG_SYNC, IPU_INPUT_BUFFER, + 1, fbi->fix.smem_start); + + memset(&vf, 0, sizeof(ipu_channel_params_t)); + ipu_csi_get_window_size(cam->ipu, &vf.csi_prp_vf_mem.in_width, + &vf.csi_prp_vf_mem.in_height, cam->csi); + vf.csi_prp_vf_mem.in_pixel_fmt = IPU_PIX_FMT_UYVY; + vf.csi_prp_vf_mem.out_width = cam->win.w.width; + vf.csi_prp_vf_mem.out_height = cam->win.w.height; + vf.csi_prp_vf_mem.csi = cam->csi; + if (cam->vf_rotation >= IPU_ROTATE_90_RIGHT) { + vf.csi_prp_vf_mem.out_width = cam->win.w.height; + vf.csi_prp_vf_mem.out_height = cam->win.w.width; + } + vf.csi_prp_vf_mem.out_pixel_fmt = vf_out_format; + size = cam->win.w.width * cam->win.w.height * size; + +#ifdef CONFIG_MXC_MIPI_CSI2 + mipi_csi2_info = mipi_csi2_get_info(); + + if (mipi_csi2_info) { + if (mipi_csi2_get_status(mipi_csi2_info)) { + ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); + csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); + + if (cam->ipu == ipu_get_soc(ipu_id) + && cam->csi == csi_id) { + vf.csi_prp_vf_mem.mipi_en = true; + vf.csi_prp_vf_mem.mipi_vc = + mipi_csi2_get_virtual_channel(mipi_csi2_info); + vf.csi_prp_vf_mem.mipi_id = + mipi_csi2_get_datatype(mipi_csi2_info); + + mipi_csi2_pixelclk_enable(mipi_csi2_info); + } else { + vf.csi_prp_vf_mem.mipi_en = false; + vf.csi_prp_vf_mem.mipi_vc = 0; + vf.csi_prp_vf_mem.mipi_id = 0; + } + } else { + vf.csi_prp_vf_mem.mipi_en = false; + vf.csi_prp_vf_mem.mipi_vc = 0; + vf.csi_prp_vf_mem.mipi_id = 0; + } + } +#endif + + err = ipu_init_channel(cam->ipu, CSI_PRP_VF_MEM, &vf); + if (err != 0) + goto out_5; + + if (cam->vf_bufs_vaddr[0]) { + dma_free_coherent(0, cam->vf_bufs_size[0], + cam->vf_bufs_vaddr[0], + (dma_addr_t) cam->vf_bufs[0]); + } + if (cam->vf_bufs_vaddr[1]) { + dma_free_coherent(0, cam->vf_bufs_size[1], + cam->vf_bufs_vaddr[1], + (dma_addr_t) cam->vf_bufs[1]); + } + cam->vf_bufs_size[0] = PAGE_ALIGN(size); + cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0, + cam->vf_bufs_size[0], + (dma_addr_t *) & + cam->vf_bufs[0], + GFP_DMA | + GFP_KERNEL); + if (cam->vf_bufs_vaddr[0] == NULL) { + printk(KERN_ERR "Error to allocate vf buffer\n"); + err = -ENOMEM; + goto out_4; + } + cam->vf_bufs_size[1] = PAGE_ALIGN(size); + cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0, + cam->vf_bufs_size[1], + (dma_addr_t *) & + cam->vf_bufs[1], + GFP_DMA | + GFP_KERNEL); + if (cam->vf_bufs_vaddr[1] == NULL) { + printk(KERN_ERR "Error to allocate vf buffer\n"); + err = -ENOMEM; + goto out_3; + } + pr_debug("vf_bufs %x %x\n", cam->vf_bufs[0], cam->vf_bufs[1]); + + if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) { + err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_VF_MEM, + IPU_OUTPUT_BUFFER, + vf_out_format, + vf.csi_prp_vf_mem.out_width, + vf.csi_prp_vf_mem.out_height, + vf.csi_prp_vf_mem.out_width, + IPU_ROTATE_NONE, + cam->vf_bufs[0], cam->vf_bufs[1], + 0, 0, 0); + if (err != 0) + goto out_3; + + err = ipu_init_channel(cam->ipu, MEM_ROT_VF_MEM, NULL); + if (err != 0) { + printk(KERN_ERR "Error MEM_ROT_VF_MEM channel\n"); + goto out_3; + } + + err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM, + IPU_INPUT_BUFFER, + vf_out_format, + vf.csi_prp_vf_mem.out_width, + vf.csi_prp_vf_mem.out_height, + vf.csi_prp_vf_mem.out_width, + cam->vf_rotation, + cam->vf_bufs[0], + cam->vf_bufs[1], + 0, 0, 0); + if (err != 0) { + printk(KERN_ERR "Error MEM_ROT_VF_MEM input buffer\n"); + goto out_2; + } + + if (cam->vf_rotation < IPU_ROTATE_90_RIGHT) { + temp = vf.csi_prp_vf_mem.out_width; + vf.csi_prp_vf_mem.out_width = + vf.csi_prp_vf_mem.out_height; + vf.csi_prp_vf_mem.out_height = temp; + } + + err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM, + IPU_OUTPUT_BUFFER, + vf_out_format, + vf.csi_prp_vf_mem.out_height, + vf.csi_prp_vf_mem.out_width, + vf.csi_prp_vf_mem.out_height, + IPU_ROTATE_NONE, + fbi->fix.smem_start + + (fbi->fix.line_length * + fbi->var.yres), + fbi->fix.smem_start, 0, 0, 0); + + if (err != 0) { + printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n"); + goto out_2; + } + + ipu_clear_irq(cam->ipu, IPU_IRQ_PRP_VF_ROT_OUT_EOF); + err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_VF_ROT_OUT_EOF, + prpvf_rot_eof_callback, + 0, "Mxc Camera", cam); + if (err < 0) { + printk(KERN_ERR "Error request irq:IPU_IRQ_PRP_VF_ROT_OUT_EOF\n"); + goto out_2; + } + + err = ipu_link_channels(cam->ipu, + CSI_PRP_VF_MEM, MEM_ROT_VF_MEM); + if (err < 0) { + printk(KERN_ERR + "Error link CSI_PRP_VF_MEM-MEM_ROT_VF_MEM\n"); + goto out_1; + } + + ipu_enable_channel(cam->ipu, CSI_PRP_VF_MEM); + ipu_enable_channel(cam->ipu, MEM_ROT_VF_MEM); + + ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM, + IPU_OUTPUT_BUFFER, 0); + ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM, + IPU_OUTPUT_BUFFER, 1); + ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM, + IPU_OUTPUT_BUFFER, 0); + } else { + err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_VF_MEM, + IPU_OUTPUT_BUFFER, + vf_out_format, cam->win.w.width, + cam->win.w.height, + cam->win.w.width, + cam->vf_rotation, + fbi->fix.smem_start + + (fbi->fix.line_length * + fbi->var.yres), + fbi->fix.smem_start, 0, 0, 0); + if (err != 0) { + printk(KERN_ERR "Error initializing CSI_PRP_VF_MEM\n"); + goto out_4; + } + ipu_clear_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF); + err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, + prpvf_rot_eof_callback, + 0, "Mxc Camera", cam); + if (err < 0) { + printk(KERN_ERR "Error request irq:IPU_IRQ_PRP_VF_OUT_EOF\n"); + goto out_4; + } + + ipu_enable_channel(cam->ipu, CSI_PRP_VF_MEM); + + ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM, + IPU_OUTPUT_BUFFER, 0); + } + + cam->overlay_active = true; + return err; + +out_1: + ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, NULL); +out_2: + if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) + ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM); +out_3: + if (cam->vf_bufs_vaddr[0]) { + dma_free_coherent(0, cam->vf_bufs_size[0], + cam->vf_bufs_vaddr[0], + (dma_addr_t) cam->vf_bufs[0]); + cam->vf_bufs_vaddr[0] = NULL; + cam->vf_bufs[0] = 0; + } + if (cam->vf_bufs_vaddr[1]) { + dma_free_coherent(0, cam->vf_bufs_size[1], + cam->vf_bufs_vaddr[1], + (dma_addr_t) cam->vf_bufs[1]); + cam->vf_bufs_vaddr[1] = NULL; + cam->vf_bufs[1] = 0; + } +out_4: + ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM); +out_5: + return err; +} + +/*! + * prpvf_stop - stop the vf task + * + * @param private cam_data * mxc v4l2 main structure + * + */ +static int prpvf_stop(void *private) +{ + cam_data *cam = (cam_data *) private; + int err = 0, i = 0; + struct fb_info *fbi = NULL; + struct fb_var_screeninfo fbvar; +#ifdef CONFIG_MXC_MIPI_CSI2 + void *mipi_csi2_info; + int ipu_id; + int csi_id; +#endif + + if (cam->overlay_active == false) + return 0; + + for (i = 0; i < num_registered_fb; i++) { + char *idstr = registered_fb[i]->fix.id; + if (((strcmp(idstr, "DISP3 FG") == 0) && (cam->output < 3)) || + ((strcmp(idstr, "DISP4 FG") == 0) && (cam->output >= 3))) { + fbi = registered_fb[i]; + break; + } + } + + if (fbi == NULL) { + printk(KERN_ERR "DISP FG fb not found\n"); + return -EPERM; + } + + if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) { + ipu_unlink_channels(cam->ipu, CSI_PRP_VF_MEM, MEM_ROT_VF_MEM); + ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_ROT_OUT_EOF, cam); + } + buffer_num = 0; + + ipu_disable_channel(cam->ipu, CSI_PRP_VF_MEM, true); + + if (cam->vf_rotation >= IPU_ROTATE_VERT_FLIP) { + ipu_disable_channel(cam->ipu, MEM_ROT_VF_MEM, true); + ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM); + } + ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM); + + console_lock(); + fb_blank(fbi, FB_BLANK_POWERDOWN); + console_unlock(); + + /* Set the overlay frame buffer std to what it is used to be */ + fbvar = fbi->var; + fbvar.accel_flags = FB_ACCEL_TRIPLE_FLAG; + fbvar.nonstd = cam->fb_origin_std; + fbvar.activate |= FB_ACTIVATE_FORCE; + fb_set_var(fbi, &fbvar); + +#ifdef CONFIG_MXC_MIPI_CSI2 + mipi_csi2_info = mipi_csi2_get_info(); + + if (mipi_csi2_info) { + if (mipi_csi2_get_status(mipi_csi2_info)) { + ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); + csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); + + if (cam->ipu == ipu_get_soc(ipu_id) + && cam->csi == csi_id) + mipi_csi2_pixelclk_disable(mipi_csi2_info); + } + } +#endif + + if (cam->vf_bufs_vaddr[0]) { + dma_free_coherent(0, cam->vf_bufs_size[0], + cam->vf_bufs_vaddr[0], + (dma_addr_t) cam->vf_bufs[0]); + cam->vf_bufs_vaddr[0] = NULL; + cam->vf_bufs[0] = 0; + } + if (cam->vf_bufs_vaddr[1]) { + dma_free_coherent(0, cam->vf_bufs_size[1], + cam->vf_bufs_vaddr[1], + (dma_addr_t) cam->vf_bufs[1]); + cam->vf_bufs_vaddr[1] = NULL; + cam->vf_bufs[1] = 0; + } + + cam->overlay_active = false; + return err; +} + +/*! + * Enable csi + * @param private struct cam_data * mxc capture instance + * + * @return status + */ +static int prp_vf_enable_csi(void *private) +{ + cam_data *cam = (cam_data *) private; + + return ipu_enable_csi(cam->ipu, cam->csi); +} + +/*! + * Disable csi + * @param private struct cam_data * mxc capture instance + * + * @return status + */ +static int prp_vf_disable_csi(void *private) +{ + cam_data *cam = (cam_data *) private; + + /* free csi eof irq firstly. + * when disable csi, wait for idmac eof. + * it requests eof irq again */ + if (cam->vf_rotation < IPU_ROTATE_VERT_FLIP) + ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, cam); + + return ipu_disable_csi(cam->ipu, cam->csi); +} + +/*! + * function to select PRP-VF as the working path + * + * @param private cam_data * mxc v4l2 main structure + * + * @return status + */ +int prp_vf_sdc_select(void *private) +{ + cam_data *cam; + int err = 0; + if (private) { + cam = (cam_data *) private; + cam->vf_start_sdc = prpvf_start; + cam->vf_stop_sdc = prpvf_stop; + cam->vf_enable_csi = prp_vf_enable_csi; + cam->vf_disable_csi = prp_vf_disable_csi; + cam->overlay_active = false; + } else + err = -EIO; + + return err; +} +EXPORT_SYMBOL(prp_vf_sdc_select); + +/*! + * function to de-select PRP-VF as the working path + * + * @param private cam_data * mxc v4l2 main structure + * + * @return int + */ +int prp_vf_sdc_deselect(void *private) +{ + cam_data *cam; + + if (private) { + cam = (cam_data *) private; + cam->vf_start_sdc = NULL; + cam->vf_stop_sdc = NULL; + cam->vf_enable_csi = NULL; + cam->vf_disable_csi = NULL; + } + return 0; +} +EXPORT_SYMBOL(prp_vf_sdc_deselect); + +/*! + * Init viewfinder task. + * + * @return Error code indicating success or failure + */ +__init int prp_vf_sdc_init(void) +{ + return 0; +} + +/*! + * Deinit viewfinder task. + * + * @return Error code indicating success or failure + */ +void __exit prp_vf_sdc_exit(void) +{ +} + +module_init(prp_vf_sdc_init); +module_exit(prp_vf_sdc_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("IPU PRP VF SDC Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c b/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c new file mode 100644 index 000000000000..a24d82dfca63 --- /dev/null +++ b/drivers/media/platform/mxc/capture/ipu_prp_vf_sdc_bg.c @@ -0,0 +1,521 @@ +/* + * Copyright 2004-2014 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file ipu_prp_vf_sdc_bg.c + * + * @brief IPU Use case for PRP-VF back-ground + * + * @ingroup IPU + */ +#include +#include +#include +#include +#include +#include "mxc_v4l2_capture.h" +#include "ipu_prp_sw.h" + +static int buffer_num; +static int buffer_ready; +static struct ipu_soc *disp_ipu; + +static void get_disp_ipu(cam_data *cam) +{ + if (cam->output > 2) + disp_ipu = ipu_get_soc(1); /* using DISP4 */ + else + disp_ipu = ipu_get_soc(0); +} + +/* + * Function definitions + */ + +/*! + * SDC V-Sync callback function. + * + * @param irq int irq line + * @param dev_id void * device id + * + * @return status IRQ_HANDLED for handled + */ +static irqreturn_t prpvf_sdc_vsync_callback(int irq, void *dev_id) +{ + cam_data *cam = dev_id; + if (buffer_ready > 0) { + ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM, + IPU_OUTPUT_BUFFER, 0); + buffer_ready--; + } + + return IRQ_HANDLED; +} + +/*! + * VF EOF callback function. + * + * @param irq int irq line + * @param dev_id void * device id + * + * @return status IRQ_HANDLED for handled + */ +static irqreturn_t prpvf_vf_eof_callback(int irq, void *dev_id) +{ + cam_data *cam = dev_id; + pr_debug("buffer_ready %d buffer_num %d\n", buffer_ready, buffer_num); + + ipu_select_buffer(cam->ipu, MEM_ROT_VF_MEM, + IPU_INPUT_BUFFER, buffer_num); + buffer_num = (buffer_num == 0) ? 1 : 0; + ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM, + IPU_OUTPUT_BUFFER, buffer_num); + buffer_ready++; + return IRQ_HANDLED; +} + +/*! + * prpvf_start - start the vf task + * + * @param private cam_data * mxc v4l2 main structure + * + */ +static int prpvf_start(void *private) +{ + cam_data *cam = (cam_data *) private; + ipu_channel_params_t vf; + u32 format; + u32 offset; + u32 bpp, size = 3; + int err = 0; +#ifdef CONFIG_MXC_MIPI_CSI2 + void *mipi_csi2_info; + int ipu_id; + int csi_id; +#endif + + if (!cam) { + printk(KERN_ERR "private is NULL\n"); + return -EIO; + } + + if (cam->overlay_active == true) { + pr_debug("already start.\n"); + return 0; + } + + get_disp_ipu(cam); + + format = cam->v4l2_fb.fmt.pixelformat; + if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR24) { + bpp = 3, size = 3; + pr_info("BGR24\n"); + } else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_RGB565) { + bpp = 2, size = 2; + pr_info("RGB565\n"); + } else if (cam->v4l2_fb.fmt.pixelformat == IPU_PIX_FMT_BGR32) { + bpp = 4, size = 4; + pr_info("BGR32\n"); + } else { + printk(KERN_ERR + "unsupported fix format from the framebuffer.\n"); + return -EINVAL; + } + + offset = cam->v4l2_fb.fmt.bytesperline * cam->win.w.top + + size * cam->win.w.left; + + if (cam->v4l2_fb.base == 0) + printk(KERN_ERR "invalid frame buffer address.\n"); + else + offset += (u32) cam->v4l2_fb.base; + + memset(&vf, 0, sizeof(ipu_channel_params_t)); + ipu_csi_get_window_size(cam->ipu, &vf.csi_prp_vf_mem.in_width, + &vf.csi_prp_vf_mem.in_height, cam->csi); + vf.csi_prp_vf_mem.in_pixel_fmt = IPU_PIX_FMT_UYVY; + vf.csi_prp_vf_mem.out_width = cam->win.w.width; + vf.csi_prp_vf_mem.out_height = cam->win.w.height; + vf.csi_prp_vf_mem.csi = cam->csi; + if (cam->vf_rotation >= IPU_ROTATE_90_RIGHT) { + vf.csi_prp_vf_mem.out_width = cam->win.w.height; + vf.csi_prp_vf_mem.out_height = cam->win.w.width; + } + vf.csi_prp_vf_mem.out_pixel_fmt = format; + size = cam->win.w.width * cam->win.w.height * size; + +#ifdef CONFIG_MXC_MIPI_CSI2 + mipi_csi2_info = mipi_csi2_get_info(); + + if (mipi_csi2_info) { + if (mipi_csi2_get_status(mipi_csi2_info)) { + ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); + csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); + + if (cam->ipu == ipu_get_soc(ipu_id) + && cam->csi == csi_id) { + vf.csi_prp_vf_mem.mipi_en = true; + vf.csi_prp_vf_mem.mipi_vc = + mipi_csi2_get_virtual_channel(mipi_csi2_info); + vf.csi_prp_vf_mem.mipi_id = + mipi_csi2_get_datatype(mipi_csi2_info); + + mipi_csi2_pixelclk_enable(mipi_csi2_info); + } else { + vf.csi_prp_vf_mem.mipi_en = false; + vf.csi_prp_vf_mem.mipi_vc = 0; + vf.csi_prp_vf_mem.mipi_id = 0; + } + } else { + vf.csi_prp_vf_mem.mipi_en = false; + vf.csi_prp_vf_mem.mipi_vc = 0; + vf.csi_prp_vf_mem.mipi_id = 0; + } + } +#endif + + err = ipu_init_channel(cam->ipu, CSI_PRP_VF_MEM, &vf); + if (err != 0) + goto out_4; + + if (cam->vf_bufs_vaddr[0]) { + dma_free_coherent(0, cam->vf_bufs_size[0], + cam->vf_bufs_vaddr[0], cam->vf_bufs[0]); + } + if (cam->vf_bufs_vaddr[1]) { + dma_free_coherent(0, cam->vf_bufs_size[1], + cam->vf_bufs_vaddr[1], cam->vf_bufs[1]); + } + cam->vf_bufs_size[0] = PAGE_ALIGN(size); + cam->vf_bufs_vaddr[0] = (void *)dma_alloc_coherent(0, + cam->vf_bufs_size[0], + &cam->vf_bufs[0], + GFP_DMA | + GFP_KERNEL); + if (cam->vf_bufs_vaddr[0] == NULL) { + printk(KERN_ERR "Error to allocate vf buffer\n"); + err = -ENOMEM; + goto out_3; + } + cam->vf_bufs_size[1] = PAGE_ALIGN(size); + cam->vf_bufs_vaddr[1] = (void *)dma_alloc_coherent(0, + cam->vf_bufs_size[1], + &cam->vf_bufs[1], + GFP_DMA | + GFP_KERNEL); + if (cam->vf_bufs_vaddr[1] == NULL) { + printk(KERN_ERR "Error to allocate vf buffer\n"); + err = -ENOMEM; + goto out_3; + } + + err = ipu_init_channel_buffer(cam->ipu, CSI_PRP_VF_MEM, + IPU_OUTPUT_BUFFER, + format, vf.csi_prp_vf_mem.out_width, + vf.csi_prp_vf_mem.out_height, + vf.csi_prp_vf_mem.out_width, + IPU_ROTATE_NONE, + cam->vf_bufs[0], + cam->vf_bufs[1], + 0, 0, 0); + if (err != 0) { + printk(KERN_ERR "Error initializing CSI_PRP_VF_MEM\n"); + goto out_3; + } + err = ipu_init_channel(cam->ipu, MEM_ROT_VF_MEM, NULL); + if (err != 0) { + printk(KERN_ERR "Error MEM_ROT_VF_MEM channel\n"); + goto out_3; + } + + err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM, + IPU_INPUT_BUFFER, + format, vf.csi_prp_vf_mem.out_width, + vf.csi_prp_vf_mem.out_height, + vf.csi_prp_vf_mem.out_width, + cam->vf_rotation, + cam->vf_bufs[0], + cam->vf_bufs[1], + 0, 0, 0); + if (err != 0) { + printk(KERN_ERR "Error MEM_ROT_VF_MEM input buffer\n"); + goto out_2; + } + + if (cam->vf_rotation >= IPU_ROTATE_90_RIGHT) { + err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM, + IPU_OUTPUT_BUFFER, + format, + vf.csi_prp_vf_mem.out_height, + vf.csi_prp_vf_mem.out_width, + cam->overlay_fb->var.xres * bpp, + IPU_ROTATE_NONE, + offset, 0, 0, 0, 0); + + if (err != 0) { + printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n"); + goto out_2; + } + } else { + err = ipu_init_channel_buffer(cam->ipu, MEM_ROT_VF_MEM, + IPU_OUTPUT_BUFFER, + format, + vf.csi_prp_vf_mem.out_width, + vf.csi_prp_vf_mem.out_height, + cam->overlay_fb->var.xres * bpp, + IPU_ROTATE_NONE, + offset, 0, 0, 0, 0); + if (err != 0) { + printk(KERN_ERR "Error MEM_ROT_VF_MEM output buffer\n"); + goto out_2; + } + } + + ipu_clear_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF); + err = ipu_request_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, + prpvf_vf_eof_callback, + 0, "Mxc Camera", cam); + if (err != 0) { + printk(KERN_ERR + "Error registering IPU_IRQ_PRP_VF_OUT_EOF irq.\n"); + goto out_2; + } + + ipu_clear_irq(disp_ipu, IPU_IRQ_BG_SF_END); + err = ipu_request_irq(disp_ipu, IPU_IRQ_BG_SF_END, + prpvf_sdc_vsync_callback, + 0, "Mxc Camera", cam); + if (err != 0) { + printk(KERN_ERR "Error registering IPU_IRQ_BG_SF_END irq.\n"); + goto out_1; + } + + ipu_enable_channel(cam->ipu, CSI_PRP_VF_MEM); + ipu_enable_channel(cam->ipu, MEM_ROT_VF_MEM); + + buffer_num = 0; + buffer_ready = 0; + ipu_select_buffer(cam->ipu, CSI_PRP_VF_MEM, IPU_OUTPUT_BUFFER, 0); + + cam->overlay_active = true; + return err; + +out_1: + ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, NULL); +out_2: + ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM); +out_3: + ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM); +out_4: + if (cam->vf_bufs_vaddr[0]) { + dma_free_coherent(0, cam->vf_bufs_size[0], + cam->vf_bufs_vaddr[0], cam->vf_bufs[0]); + cam->vf_bufs_vaddr[0] = NULL; + cam->vf_bufs[0] = 0; + } + if (cam->vf_bufs_vaddr[1]) { + dma_free_coherent(0, cam->vf_bufs_size[1], + cam->vf_bufs_vaddr[1], cam->vf_bufs[1]); + cam->vf_bufs_vaddr[1] = NULL; + cam->vf_bufs[1] = 0; + } + if (cam->rot_vf_bufs_vaddr[0]) { + dma_free_coherent(0, cam->rot_vf_buf_size[0], + cam->rot_vf_bufs_vaddr[0], + cam->rot_vf_bufs[0]); + cam->rot_vf_bufs_vaddr[0] = NULL; + cam->rot_vf_bufs[0] = 0; + } + if (cam->rot_vf_bufs_vaddr[1]) { + dma_free_coherent(0, cam->rot_vf_buf_size[1], + cam->rot_vf_bufs_vaddr[1], + cam->rot_vf_bufs[1]); + cam->rot_vf_bufs_vaddr[1] = NULL; + cam->rot_vf_bufs[1] = 0; + } + return err; +} + +/*! + * prpvf_stop - stop the vf task + * + * @param private cam_data * mxc v4l2 main structure + * + */ +static int prpvf_stop(void *private) +{ + cam_data *cam = (cam_data *) private; +#ifdef CONFIG_MXC_MIPI_CSI2 + void *mipi_csi2_info; + int ipu_id; + int csi_id; +#endif + + if (cam->overlay_active == false) + return 0; + + ipu_free_irq(disp_ipu, IPU_IRQ_BG_SF_END, cam); + + ipu_disable_channel(cam->ipu, CSI_PRP_VF_MEM, true); + ipu_disable_channel(cam->ipu, MEM_ROT_VF_MEM, true); + ipu_uninit_channel(cam->ipu, CSI_PRP_VF_MEM); + ipu_uninit_channel(cam->ipu, MEM_ROT_VF_MEM); + +#ifdef CONFIG_MXC_MIPI_CSI2 + mipi_csi2_info = mipi_csi2_get_info(); + + if (mipi_csi2_info) { + if (mipi_csi2_get_status(mipi_csi2_info)) { + ipu_id = mipi_csi2_get_bind_ipu(mipi_csi2_info); + csi_id = mipi_csi2_get_bind_csi(mipi_csi2_info); + + if (cam->ipu == ipu_get_soc(ipu_id) + && cam->csi == csi_id) + mipi_csi2_pixelclk_disable(mipi_csi2_info); + } + } +#endif + + if (cam->vf_bufs_vaddr[0]) { + dma_free_coherent(0, cam->vf_bufs_size[0], + cam->vf_bufs_vaddr[0], cam->vf_bufs[0]); + cam->vf_bufs_vaddr[0] = NULL; + cam->vf_bufs[0] = 0; + } + if (cam->vf_bufs_vaddr[1]) { + dma_free_coherent(0, cam->vf_bufs_size[1], + cam->vf_bufs_vaddr[1], cam->vf_bufs[1]); + cam->vf_bufs_vaddr[1] = NULL; + cam->vf_bufs[1] = 0; + } + if (cam->rot_vf_bufs_vaddr[0]) { + dma_free_coherent(0, cam->rot_vf_buf_size[0], + cam->rot_vf_bufs_vaddr[0], + cam->rot_vf_bufs[0]); + cam->rot_vf_bufs_vaddr[0] = NULL; + cam->rot_vf_bufs[0] = 0; + } + if (cam->rot_vf_bufs_vaddr[1]) { + dma_free_coherent(0, cam->rot_vf_buf_size[1], + cam->rot_vf_bufs_vaddr[1], + cam->rot_vf_bufs[1]); + cam->rot_vf_bufs_vaddr[1] = NULL; + cam->rot_vf_bufs[1] = 0; + } + + buffer_num = 0; + buffer_ready = 0; + cam->overlay_active = false; + return 0; +} + +/*! + * Enable csi + * @param private struct cam_data * mxc capture instance + * + * @return status + */ +static int prp_vf_enable_csi(void *private) +{ + cam_data *cam = (cam_data *) private; + + return ipu_enable_csi(cam->ipu, cam->csi); +} + +/*! + * Disable csi + * @param private struct cam_data * mxc capture instance + * + * @return status + */ +static int prp_vf_disable_csi(void *private) +{ + cam_data *cam = (cam_data *) private; + + /* free csi eof irq firstly. + * when disable csi, wait for idmac eof. + * it requests eof irq again */ + ipu_free_irq(cam->ipu, IPU_IRQ_PRP_VF_OUT_EOF, cam); + + return ipu_disable_csi(cam->ipu, cam->csi); +} + +/*! + * function to select PRP-VF as the working path + * + * @param private cam_data * mxc v4l2 main structure + * + * @return status + */ +int prp_vf_sdc_select_bg(void *private) +{ + cam_data *cam = (cam_data *) private; + + if (cam) { + cam->vf_start_sdc = prpvf_start; + cam->vf_stop_sdc = prpvf_stop; + cam->vf_enable_csi = prp_vf_enable_csi; + cam->vf_disable_csi = prp_vf_disable_csi; + cam->overlay_active = false; + } + + return 0; +} +EXPORT_SYMBOL(prp_vf_sdc_select_bg); + +/*! + * function to de-select PRP-VF as the working path + * + * @param private cam_data * mxc v4l2 main structure + * + * @return status + */ +int prp_vf_sdc_deselect_bg(void *private) +{ + cam_data *cam = (cam_data *) private; + + if (cam) { + cam->vf_start_sdc = NULL; + cam->vf_stop_sdc = NULL; + cam->vf_enable_csi = NULL; + cam->vf_disable_csi = NULL; + } + return 0; +} +EXPORT_SYMBOL(prp_vf_sdc_deselect_bg); + +/*! + * Init viewfinder task. + * + * @return Error code indicating success or failure + */ +__init int prp_vf_sdc_init_bg(void) +{ + return 0; +} + +/*! + * Deinit viewfinder task. + * + * @return Error code indicating success or failure + */ +void __exit prp_vf_sdc_exit_bg(void) +{ +} + +module_init(prp_vf_sdc_init_bg); +module_exit(prp_vf_sdc_exit_bg); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("IPU PRP VF SDC Backgroud Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/mxc/capture/ipu_still.c b/drivers/media/platform/mxc/capture/ipu_still.c new file mode 100644 index 000000000000..b18c3cf873cc --- /dev/null +++ b/drivers/media/platform/mxc/capture/ipu_still.c @@ -0,0 +1,268 @@ +/* + * Copyright 2004-2014 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file ipu_still.c + * + * @brief IPU Use case for still image capture + * + * @ingroup IPU + */ + +#include +#include +#include +#include +#include "mxc_v4l2_capture.h" +#include "ipu_prp_sw.h" + +static int callback_eof_flag; +#ifndef CONFIG_MXC_IPU_V1 +static int buffer_num; +#endif + +#ifdef CONFIG_MXC_IPU_V1 +static int callback_flag; +/* + * Function definitions + */ +/*! + * CSI EOF callback function. + * + * @param irq int irq line + * @param dev_id void * device id + * + * @return status IRQ_HANDLED for handled + */ +static irqreturn_t prp_csi_eof_callback(int irq, void *dev_id) +{ + cam_data *cam = devid; + ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, + callback_flag%2 ? 1 : 0); + if (callback_flag == 0) + ipu_enable_channel(cam->ipu, CSI_MEM); + + callback_flag++; + return IRQ_HANDLED; +} +#endif + +/*! + * CSI callback function. + * + * @param irq int irq line + * @param dev_id void * device id + * + * @return status IRQ_HANDLED for handled + */ +static irqreturn_t prp_still_callback(int irq, void *dev_id) +{ + cam_data *cam = (cam_data *) dev_id; + + callback_eof_flag++; + if (callback_eof_flag < 5) { +#ifndef CONFIG_MXC_IPU_V1 + buffer_num = (buffer_num == 0) ? 1 : 0; + ipu_select_buffer(cam->ipu, CSI_MEM, + IPU_OUTPUT_BUFFER, buffer_num); +#endif + } else { + cam->still_counter++; + wake_up_interruptible(&cam->still_queue); + } + + return IRQ_HANDLED; +} + +/*! + * start csi->mem task + * @param private struct cam_data * mxc capture instance + * + * @return status + */ +static int prp_still_start(void *private) +{ + cam_data *cam = (cam_data *) private; + u32 pixel_fmt; + int err; + ipu_channel_params_t params; + + if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) + pixel_fmt = IPU_PIX_FMT_YUV420P; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_NV12) + pixel_fmt = IPU_PIX_FMT_NV12; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) + pixel_fmt = IPU_PIX_FMT_YUV422P; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY) + pixel_fmt = IPU_PIX_FMT_UYVY; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) + pixel_fmt = IPU_PIX_FMT_YUYV; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR24) + pixel_fmt = IPU_PIX_FMT_BGR24; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) + pixel_fmt = IPU_PIX_FMT_RGB24; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) + pixel_fmt = IPU_PIX_FMT_RGB565; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32) + pixel_fmt = IPU_PIX_FMT_BGR32; + else if (cam->v2f.fmt.pix.pixelformat == V4L2_PIX_FMT_RGB32) + pixel_fmt = IPU_PIX_FMT_RGB32; + else { + printk(KERN_ERR "format not supported\n"); + return -EINVAL; + } + + memset(¶ms, 0, sizeof(params)); + err = ipu_init_channel(cam->ipu, CSI_MEM, ¶ms); + if (err != 0) + return err; + + err = ipu_init_channel_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, + pixel_fmt, cam->v2f.fmt.pix.width, + cam->v2f.fmt.pix.height, + cam->v2f.fmt.pix.width, IPU_ROTATE_NONE, + cam->still_buf[0], cam->still_buf[1], 0, + 0, 0); + if (err != 0) + return err; + +#ifdef CONFIG_MXC_IPU_V1 + ipu_clear_irq(IPU_IRQ_SENSOR_OUT_EOF); + err = ipu_request_irq(IPU_IRQ_SENSOR_OUT_EOF, prp_still_callback, + 0, "Mxc Camera", cam); + if (err != 0) { + printk(KERN_ERR "Error registering irq.\n"); + return err; + } + callback_flag = 0; + callback_eof_flag = 0; + ipu_clear_irq(IPU_IRQ_SENSOR_EOF); + err = ipu_request_irq(IPU_IRQ_SENSOR_EOF, prp_csi_eof_callback, + 0, "Mxc Camera", cam); + if (err != 0) { + printk(KERN_ERR "Error IPU_IRQ_SENSOR_EOF\n"); + return err; + } +#else + callback_eof_flag = 0; + buffer_num = 0; + + ipu_clear_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF); + err = ipu_request_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, + prp_still_callback, + 0, "Mxc Camera", cam); + if (err != 0) { + printk(KERN_ERR "Error registering irq.\n"); + return err; + } + + ipu_select_buffer(cam->ipu, CSI_MEM, IPU_OUTPUT_BUFFER, 0); + ipu_enable_channel(cam->ipu, CSI_MEM); + ipu_enable_csi(cam->ipu, cam->csi); +#endif + + return err; +} + +/*! + * stop csi->mem encoder task + * @param private struct cam_data * mxc capture instance + * + * @return status + */ +static int prp_still_stop(void *private) +{ + cam_data *cam = (cam_data *) private; + int err = 0; + +#ifdef CONFIG_MXC_IPU_V1 + ipu_free_irq(IPU_IRQ_SENSOR_EOF, NULL); + ipu_free_irq(IPU_IRQ_SENSOR_OUT_EOF, cam); +#else + ipu_free_irq(cam->ipu, IPU_IRQ_CSI0_OUT_EOF, cam); +#endif + + ipu_disable_csi(cam->ipu, cam->csi); + ipu_disable_channel(cam->ipu, CSI_MEM, true); + ipu_uninit_channel(cam->ipu, CSI_MEM); + + return err; +} + +/*! + * function to select CSI_MEM as the working path + * + * @param private struct cam_data * mxc capture instance + * + * @return status + */ +int prp_still_select(void *private) +{ + cam_data *cam = (cam_data *) private; + + if (cam) { + cam->csi_start = prp_still_start; + cam->csi_stop = prp_still_stop; + } + + return 0; +} +EXPORT_SYMBOL(prp_still_select); + +/*! + * function to de-select CSI_MEM as the working path + * + * @param private struct cam_data * mxc capture instance + * + * @return status + */ +int prp_still_deselect(void *private) +{ + cam_data *cam = (cam_data *) private; + int err = 0; + + err = prp_still_stop(cam); + + if (cam) { + cam->csi_start = NULL; + cam->csi_stop = NULL; + } + + return err; +} +EXPORT_SYMBOL(prp_still_deselect); + +/*! + * Init the Encorder channels + * + * @return Error code indicating success or failure + */ +__init int prp_still_init(void) +{ + return 0; +} + +/*! + * Deinit the Encorder channels + * + */ +void __exit prp_still_exit(void) +{ +} + +module_init(prp_still_init); +module_exit(prp_still_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("IPU PRP STILL IMAGE Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c b/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c new file mode 100644 index 000000000000..37f9dffad2d6 --- /dev/null +++ b/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c @@ -0,0 +1,3138 @@ +/* + * Copyright 2004-2015 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file drivers/media/video/mxc/capture/mxc_v4l2_capture.c + * + * @brief Mxc Video For Linux 2 driver + * + * @ingroup MXC_V4L2_CAPTURE + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "v4l2-int-device.h" +#include +#include "mxc_v4l2_capture.h" +#include "ipu_prp_sw.h" + +#define init_MUTEX(sem) sema_init(sem, 1) + +static struct platform_device_id imx_v4l2_devtype[] = { + { + .name = "v4l2-capture-imx5", + .driver_data = IMX5_V4L2, + }, { + .name = "v4l2-capture-imx6", + .driver_data = IMX6_V4L2, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(platform, imx_v4l2_devtype); + +static const struct of_device_id mxc_v4l2_dt_ids[] = { + { + .compatible = "fsl,imx6q-v4l2-capture", + .data = &imx_v4l2_devtype[IMX6_V4L2], + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, mxc_v4l2_dt_ids); + +static int video_nr = -1; + +/*! This data is used for the output to the display. */ +#define MXC_V4L2_CAPTURE_NUM_OUTPUTS 6 +#define MXC_V4L2_CAPTURE_NUM_INPUTS 2 +static struct v4l2_output mxc_capture_outputs[MXC_V4L2_CAPTURE_NUM_OUTPUTS] = { + { + .index = 0, + .name = "DISP3 BG", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .audioset = 0, + .modulator = 0, + .std = V4L2_STD_UNKNOWN, + }, + { + .index = 1, + .name = "DISP3 BG - DI1", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .audioset = 0, + .modulator = 0, + .std = V4L2_STD_UNKNOWN, + }, + { + .index = 2, + .name = "DISP3 FG", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .audioset = 0, + .modulator = 0, + .std = V4L2_STD_UNKNOWN, + }, + { + .index = 3, + .name = "DISP4 BG", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .audioset = 0, + .modulator = 0, + .std = V4L2_STD_UNKNOWN, + }, + { + .index = 4, + .name = "DISP4 BG - DI1", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .audioset = 0, + .modulator = 0, + .std = V4L2_STD_UNKNOWN, + }, + { + .index = 5, + .name = "DISP4 FG", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .audioset = 0, + .modulator = 0, + .std = V4L2_STD_UNKNOWN, + }, +}; + +static struct v4l2_input mxc_capture_inputs[MXC_V4L2_CAPTURE_NUM_INPUTS] = { + { + .index = 0, + .name = "CSI IC MEM", + .type = V4L2_INPUT_TYPE_CAMERA, + .audioset = 0, + .tuner = 0, + .std = V4L2_STD_UNKNOWN, + .status = 0, + }, + { + .index = 1, + .name = "CSI MEM", + .type = V4L2_INPUT_TYPE_CAMERA, + .audioset = 0, + .tuner = 0, + .std = V4L2_STD_UNKNOWN, + .status = V4L2_IN_ST_NO_POWER, + }, +}; + +/*! List of TV input video formats supported. The video formats is corresponding + * to the v4l2_id in video_fmt_t. + * Currently, only PAL and NTSC is supported. Needs to be expanded in the + * future. + */ +typedef enum { + TV_NTSC = 0, /*!< Locked on (M) NTSC video signal. */ + TV_PAL, /*!< (B, G, H, I, N)PAL video signal. */ + TV_NOT_LOCKED, /*!< Not locked on a signal. */ +} video_fmt_idx; + +/*! Number of video standards supported (including 'not locked' signal). */ +#define TV_STD_MAX (TV_NOT_LOCKED + 1) + +/*! Video format structure. */ +typedef struct { + int v4l2_id; /*!< Video for linux ID. */ + char name[16]; /*!< Name (e.g., "NTSC", "PAL", etc.) */ + u16 raw_width; /*!< Raw width. */ + u16 raw_height; /*!< Raw height. */ + u16 active_width; /*!< Active width. */ + u16 active_height; /*!< Active height. */ + u16 active_top; /*!< Active top. */ + u16 active_left; /*!< Active left. */ +} video_fmt_t; + +/*! + * Description of video formats supported. + * + * PAL: raw=720x625, active=720x576. + * NTSC: raw=720x525, active=720x480. + */ +static video_fmt_t video_fmts[] = { + { /*! NTSC */ + .v4l2_id = V4L2_STD_NTSC, + .name = "NTSC", + .raw_width = 720, /* SENS_FRM_WIDTH */ + .raw_height = 525, /* SENS_FRM_HEIGHT */ + .active_width = 720, /* ACT_FRM_WIDTH */ + .active_height = 480, /* ACT_FRM_HEIGHT */ + .active_top = 13, + .active_left = 0, + }, + { /*! (B, G, H, I, N) PAL */ + .v4l2_id = V4L2_STD_PAL, + .name = "PAL", + .raw_width = 720, + .raw_height = 625, + .active_width = 720, + .active_height = 576, + .active_top = 0, + .active_left = 0, + }, + { /*! Unlocked standard */ + .v4l2_id = V4L2_STD_ALL, + .name = "Autodetect", + .raw_width = 720, + .raw_height = 625, + .active_width = 720, + .active_height = 576, + .active_top = 0, + .active_left = 0, + }, +}; + +/*!* Standard index of TV. */ +static video_fmt_idx video_index = TV_NOT_LOCKED; + +static int mxc_v4l2_master_attach(struct v4l2_int_device *slave); +static void mxc_v4l2_master_detach(struct v4l2_int_device *slave); +static int start_preview(cam_data *cam); +static int stop_preview(cam_data *cam); + +/*! Information about this driver. */ +static struct v4l2_int_master mxc_v4l2_master = { + .attach = mxc_v4l2_master_attach, + .detach = mxc_v4l2_master_detach, +}; + +/*************************************************************************** + * Functions for handling Frame buffers. + **************************************************************************/ + +/*! + * Free frame buffers + * + * @param cam Structure cam_data * + * + * @return status 0 success. + */ +static int mxc_free_frame_buf(cam_data *cam) +{ + int i; + + pr_debug("MVC: In mxc_free_frame_buf\n"); + + for (i = 0; i < FRAME_NUM; i++) { + if (cam->frame[i].vaddress != 0) { + dma_free_coherent(0, cam->frame[i].buffer.length, + cam->frame[i].vaddress, + cam->frame[i].paddress); + cam->frame[i].vaddress = 0; + } + } + + return 0; +} + +/*! + * Allocate frame buffers + * + * @param cam Structure cam_data* + * @param count int number of buffer need to allocated + * + * @return status -0 Successfully allocated a buffer, -ENOBUFS failed. + */ +static int mxc_allocate_frame_buf(cam_data *cam, int count) +{ + int i; + + pr_debug("In MVC:mxc_allocate_frame_buf - size=%d\n", + cam->v2f.fmt.pix.sizeimage); + + for (i = 0; i < count; i++) { + cam->frame[i].vaddress = + dma_alloc_coherent(0, + PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage), + &cam->frame[i].paddress, + GFP_DMA | GFP_KERNEL); + if (cam->frame[i].vaddress == 0) { + pr_err("ERROR: v4l2 capture: " + "mxc_allocate_frame_buf failed.\n"); + mxc_free_frame_buf(cam); + return -ENOBUFS; + } + cam->frame[i].buffer.index = i; + cam->frame[i].buffer.flags = V4L2_BUF_FLAG_MAPPED; + cam->frame[i].buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + cam->frame[i].buffer.length = + PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage); + cam->frame[i].buffer.memory = V4L2_MEMORY_MMAP; + cam->frame[i].buffer.m.offset = cam->frame[i].paddress; + cam->frame[i].index = i; + } + + return 0; +} + +/*! + * Free frame buffers status + * + * @param cam Structure cam_data * + * + * @return none + */ +static void mxc_free_frames(cam_data *cam) +{ + int i; + + pr_debug("In MVC:mxc_free_frames\n"); + + for (i = 0; i < FRAME_NUM; i++) + cam->frame[i].buffer.flags = V4L2_BUF_FLAG_MAPPED; + + cam->enc_counter = 0; + INIT_LIST_HEAD(&cam->ready_q); + INIT_LIST_HEAD(&cam->working_q); + INIT_LIST_HEAD(&cam->done_q); +} + +/*! + * Return the buffer status + * + * @param cam Structure cam_data * + * @param buf Structure v4l2_buffer * + * + * @return status 0 success, EINVAL failed. + */ +static int mxc_v4l2_buffer_status(cam_data *cam, struct v4l2_buffer *buf) +{ + pr_debug("In MVC:mxc_v4l2_buffer_status\n"); + + if (buf->index < 0 || buf->index >= FRAME_NUM) { + pr_err("ERROR: v4l2 capture: mxc_v4l2_buffer_status buffers " + "not allocated\n"); + return -EINVAL; + } + + memcpy(buf, &(cam->frame[buf->index].buffer), sizeof(*buf)); + return 0; +} + +static int mxc_v4l2_release_bufs(cam_data *cam) +{ + pr_debug("In MVC:mxc_v4l2_release_bufs\n"); + return 0; +} + +static int mxc_v4l2_prepare_bufs(cam_data *cam, struct v4l2_buffer *buf) +{ + pr_debug("In MVC:mxc_v4l2_prepare_bufs\n"); + + if (buf->index < 0 || buf->index >= FRAME_NUM || buf->length < + PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage)) { + pr_err("ERROR: v4l2 capture: mxc_v4l2_prepare_bufs buffers " + "not allocated,index=%d, length=%d\n", buf->index, + buf->length); + return -EINVAL; + } + + cam->frame[buf->index].buffer.index = buf->index; + cam->frame[buf->index].buffer.flags = V4L2_BUF_FLAG_MAPPED; + cam->frame[buf->index].buffer.length = buf->length; + cam->frame[buf->index].buffer.m.offset = cam->frame[buf->index].paddress + = buf->m.offset; + cam->frame[buf->index].buffer.type = buf->type; + cam->frame[buf->index].buffer.memory = V4L2_MEMORY_USERPTR; + cam->frame[buf->index].index = buf->index; + + return 0; +} + +/*************************************************************************** + * Functions for handling the video stream. + **************************************************************************/ + +/*! + * Indicates whether the palette is supported. + * + * @param palette V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_BGR24 or V4L2_PIX_FMT_BGR32 + * + * @return 0 if failed + */ +static inline int valid_mode(u32 palette) +{ + return ((palette == V4L2_PIX_FMT_RGB565) || + (palette == V4L2_PIX_FMT_BGR24) || + (palette == V4L2_PIX_FMT_RGB24) || + (palette == V4L2_PIX_FMT_BGR32) || + (palette == V4L2_PIX_FMT_RGB32) || + (palette == V4L2_PIX_FMT_YUV422P) || + (palette == V4L2_PIX_FMT_UYVY) || + (palette == V4L2_PIX_FMT_YUYV) || + (palette == V4L2_PIX_FMT_YUV420) || + (palette == V4L2_PIX_FMT_YVU420) || + (palette == V4L2_PIX_FMT_NV12)); +} + +/*! + * Start the encoder job + * + * @param cam structure cam_data * + * + * @return status 0 Success + */ +static int mxc_streamon(cam_data *cam) +{ + struct mxc_v4l_frame *frame; + unsigned long lock_flags; + int err = 0; + + pr_debug("In MVC:mxc_streamon\n"); + + if (NULL == cam) { + pr_err("ERROR! cam parameter is NULL\n"); + return -1; + } + + if (cam->capture_on) { + pr_err("ERROR: v4l2 capture: Capture stream has been turned " + " on\n"); + return -1; + } + + if (list_empty(&cam->ready_q)) { + pr_err("ERROR: v4l2 capture: mxc_streamon buffer has not been " + "queued yet\n"); + return -EINVAL; + } + if (cam->enc_update_eba && + cam->ready_q.prev == cam->ready_q.next) { + pr_err("ERROR: v4l2 capture: mxc_streamon buffer need " + "ping pong at least two buffers\n"); + return -EINVAL; + } + + cam->capture_pid = current->pid; + + if (cam->overlay_on == true) + stop_preview(cam); + + if (cam->enc_enable) { + err = cam->enc_enable(cam); + if (err != 0) + return err; + } + + spin_lock_irqsave(&cam->queue_int_lock, lock_flags); + cam->ping_pong_csi = 0; + cam->local_buf_num = 0; + if (cam->enc_update_eba) { + frame = + list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue); + list_del(cam->ready_q.next); + list_add_tail(&frame->queue, &cam->working_q); + frame->ipu_buf_num = cam->ping_pong_csi; + err = cam->enc_update_eba(cam, frame->buffer.m.offset); + + frame = + list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue); + list_del(cam->ready_q.next); + list_add_tail(&frame->queue, &cam->working_q); + frame->ipu_buf_num = cam->ping_pong_csi; + err |= cam->enc_update_eba(cam, frame->buffer.m.offset); + spin_unlock_irqrestore(&cam->queue_int_lock, lock_flags); + } else { + spin_unlock_irqrestore(&cam->queue_int_lock, lock_flags); + return -EINVAL; + } + + if (cam->overlay_on == true) + start_preview(cam); + + if (cam->enc_enable_csi) { + err = cam->enc_enable_csi(cam); + if (err != 0) + return err; + } + + cam->capture_on = true; + + return err; +} + +/*! + * Shut down the encoder job + * + * @param cam structure cam_data * + * + * @return status 0 Success + */ +static int mxc_streamoff(cam_data *cam) +{ + int err = 0; + + pr_debug("In MVC:mxc_streamoff\n"); + + if (cam->capture_on == false) + return 0; + + /* For both CSI--MEM and CSI--IC--MEM + * 1. wait for idmac eof + * 2. disable csi first + * 3. disable idmac + * 4. disable smfc (CSI--MEM channel) + */ + if (mxc_capture_inputs[cam->current_input].name != NULL) { + if (cam->enc_disable_csi) { + err = cam->enc_disable_csi(cam); + if (err != 0) + return err; + } + if (cam->enc_disable) { + err = cam->enc_disable(cam); + if (err != 0) + return err; + } + } + + mxc_free_frames(cam); + mxc_capture_inputs[cam->current_input].status |= V4L2_IN_ST_NO_POWER; + cam->capture_on = false; + return err; +} + +/*! + * Valid and adjust the overlay window size, position + * + * @param cam structure cam_data * + * @param win struct v4l2_window * + * + * @return 0 + */ +static int verify_preview(cam_data *cam, struct v4l2_window *win) +{ + int i = 0, width_bound = 0, height_bound = 0; + int *width, *height; + unsigned int ipu_ch = CHAN_NONE; + struct fb_info *bg_fbi = NULL, *fbi = NULL; + bool foregound_fb = false; + mm_segment_t old_fs; + + pr_debug("In MVC: verify_preview\n"); + + do { + fbi = (struct fb_info *)registered_fb[i]; + if (fbi == NULL) { + pr_err("ERROR: verify_preview frame buffer NULL.\n"); + return -1; + } + + /* Which DI supports 2 layers? */ + if (((strncmp(fbi->fix.id, "DISP3 BG", 8) == 0) && + (cam->output < 3)) || + ((strncmp(fbi->fix.id, "DISP4 BG", 8) == 0) && + (cam->output >= 3))) { + if (fbi->fbops->fb_ioctl) { + old_fs = get_fs(); + set_fs(KERNEL_DS); + fbi->fbops->fb_ioctl(fbi, MXCFB_GET_FB_IPU_CHAN, + (unsigned long)&ipu_ch); + set_fs(old_fs); + } + if (ipu_ch == MEM_BG_SYNC) { + bg_fbi = fbi; + pr_debug("Found background frame buffer.\n"); + } + } + + /* Found the frame buffer to preview on. */ + if (strcmp(fbi->fix.id, + mxc_capture_outputs[cam->output].name) == 0) { + if (((strcmp(fbi->fix.id, "DISP3 FG") == 0) && + (cam->output < 3)) || + ((strcmp(fbi->fix.id, "DISP4 FG") == 0) && + (cam->output >= 3))) + foregound_fb = true; + + cam->overlay_fb = fbi; + break; + } + } while (++i < FB_MAX); + + if (foregound_fb) { + width_bound = bg_fbi->var.xres; + height_bound = bg_fbi->var.yres; + + if (win->w.width + win->w.left > bg_fbi->var.xres || + win->w.height + win->w.top > bg_fbi->var.yres) { + pr_err("ERROR: FG window position exceeds.\n"); + return -1; + } + } else { + /* 4 bytes alignment for BG */ + width_bound = cam->overlay_fb->var.xres; + height_bound = cam->overlay_fb->var.yres; + + if (cam->overlay_fb->var.bits_per_pixel == 24) + win->w.left -= win->w.left % 4; + else if (cam->overlay_fb->var.bits_per_pixel == 16) + win->w.left -= win->w.left % 2; + + if (win->w.width + win->w.left > cam->overlay_fb->var.xres) + win->w.width = cam->overlay_fb->var.xres - win->w.left; + if (win->w.height + win->w.top > cam->overlay_fb->var.yres) + win->w.height = cam->overlay_fb->var.yres - win->w.top; + } + + /* stride line limitation */ + win->w.height -= win->w.height % 8; + win->w.width -= win->w.width % 8; + + if (cam->rotation >= IPU_ROTATE_90_RIGHT) { + height = &win->w.width; + width = &win->w.height; + } else { + width = &win->w.width; + height = &win->w.height; + } + + if (*width == 0 || *height == 0) { + pr_err("ERROR: v4l2 capture: width or height" + " too small.\n"); + return -EINVAL; + } + + if ((cam->crop_bounds.width / *width > 8) || + ((cam->crop_bounds.width / *width == 8) && + (cam->crop_bounds.width % *width))) { + *width = cam->crop_bounds.width / 8; + if (*width % 8) + *width += 8 - *width % 8; + if (*width + win->w.left > width_bound) { + pr_err("ERROR: v4l2 capture: width exceeds " + "resize limit.\n"); + return -1; + } + pr_err("ERROR: v4l2 capture: width exceeds limit. " + "Resize to %d.\n", + *width); + } + + if ((cam->crop_bounds.height / *height > 8) || + ((cam->crop_bounds.height / *height == 8) && + (cam->crop_bounds.height % *height))) { + *height = cam->crop_bounds.height / 8; + if (*height % 8) + *height += 8 - *height % 8; + if (*height + win->w.top > height_bound) { + pr_err("ERROR: v4l2 capture: height exceeds " + "resize limit.\n"); + return -1; + } + pr_err("ERROR: v4l2 capture: height exceeds limit " + "resize to %d.\n", + *height); + } + + return 0; +} + +/*! + * start the viewfinder job + * + * @param cam structure cam_data * + * + * @return status 0 Success + */ +static int start_preview(cam_data *cam) +{ + int err = 0; + + pr_debug("MVC: start_preview\n"); + + if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) + #ifdef CONFIG_MXC_IPU_PRP_VF_SDC + err = prp_vf_sdc_select(cam); + #else + err = foreground_sdc_select(cam); + #endif + else if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_PRIMARY) + #ifdef CONFIG_MXC_IPU_PRP_VF_SDC + err = prp_vf_sdc_select_bg(cam); + #else + err = bg_overlay_sdc_select(cam); + #endif + if (err != 0) + return err; + + if (cam->vf_start_sdc) { + err = cam->vf_start_sdc(cam); + if (err != 0) + return err; + } + + if (cam->vf_enable_csi) + err = cam->vf_enable_csi(cam); + + pr_debug("End of %s: v2f pix widthxheight %d x %d\n", + __func__, + cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height); + pr_debug("End of %s: crop_bounds widthxheight %d x %d\n", + __func__, + cam->crop_bounds.width, cam->crop_bounds.height); + pr_debug("End of %s: crop_defrect widthxheight %d x %d\n", + __func__, + cam->crop_defrect.width, cam->crop_defrect.height); + pr_debug("End of %s: crop_current widthxheight %d x %d\n", + __func__, + cam->crop_current.width, cam->crop_current.height); + + return err; +} + +/*! + * shut down the viewfinder job + * + * @param cam structure cam_data * + * + * @return status 0 Success + */ +static int stop_preview(cam_data *cam) +{ + int err = 0; + + if (cam->vf_disable_csi) { + err = cam->vf_disable_csi(cam); + if (err != 0) + return err; + } + + if (cam->vf_stop_sdc) { + err = cam->vf_stop_sdc(cam); + if (err != 0) + return err; + } + + if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) + #ifdef CONFIG_MXC_IPU_PRP_VF_SDC + err = prp_vf_sdc_deselect(cam); + #else + err = foreground_sdc_deselect(cam); + #endif + else if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_PRIMARY) + #ifdef CONFIG_MXC_IPU_PRP_VF_SDC + err = prp_vf_sdc_deselect_bg(cam); + #else + err = bg_overlay_sdc_deselect(cam); + #endif + + return err; +} + +/*************************************************************************** + * VIDIOC Functions. + **************************************************************************/ + +/*! + * V4L2 - mxc_v4l2_g_fmt function + * + * @param cam structure cam_data * + * + * @param f structure v4l2_format * + * + * @return status 0 success, EINVAL failed + */ +static int mxc_v4l2_g_fmt(cam_data *cam, struct v4l2_format *f) +{ + int retval = 0; + + pr_debug("In MVC: mxc_v4l2_g_fmt type=%d\n", f->type); + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + pr_debug(" type is V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); + f->fmt.pix = cam->v2f.fmt.pix; + break; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + pr_debug(" type is V4L2_BUF_TYPE_VIDEO_OVERLAY\n"); + f->fmt.win = cam->win; + break; + default: + pr_debug(" type is invalid\n"); + retval = -EINVAL; + } + + pr_debug("End of %s: v2f pix widthxheight %d x %d\n", + __func__, + cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height); + pr_debug("End of %s: crop_bounds widthxheight %d x %d\n", + __func__, + cam->crop_bounds.width, cam->crop_bounds.height); + pr_debug("End of %s: crop_defrect widthxheight %d x %d\n", + __func__, + cam->crop_defrect.width, cam->crop_defrect.height); + pr_debug("End of %s: crop_current widthxheight %d x %d\n", + __func__, + cam->crop_current.width, cam->crop_current.height); + + return retval; +} + +/*! + * V4L2 - mxc_v4l2_s_fmt function + * + * @param cam structure cam_data * + * + * @param f structure v4l2_format * + * + * @return status 0 success, EINVAL failed + */ +static int mxc_v4l2_s_fmt(cam_data *cam, struct v4l2_format *f) +{ + int retval = 0; + int size = 0; + int bytesperline = 0; + int *width, *height; + + pr_debug("In MVC: mxc_v4l2_s_fmt\n"); + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + pr_debug(" type=V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); + if (!valid_mode(f->fmt.pix.pixelformat)) { + pr_err("ERROR: v4l2 capture: mxc_v4l2_s_fmt: format " + "not supported\n"); + return -EINVAL; + } + + /* + * Force the capture window resolution to be crop bounds + * for CSI MEM input mode. + */ + if (strcmp(mxc_capture_inputs[cam->current_input].name, + "CSI MEM") == 0) { + f->fmt.pix.width = cam->crop_current.width; + f->fmt.pix.height = cam->crop_current.height; + } + + if (cam->rotation >= IPU_ROTATE_90_RIGHT) { + height = &f->fmt.pix.width; + width = &f->fmt.pix.height; + } else { + width = &f->fmt.pix.width; + height = &f->fmt.pix.height; + } + + /* stride line limitation */ + *width -= *width % 8; + *height -= *height % 8; + + if (*width == 0 || *height == 0) { + pr_err("ERROR: v4l2 capture: width or height" + " too small.\n"); + return -EINVAL; + } + + if ((cam->crop_current.width / *width > 8) || + ((cam->crop_current.width / *width == 8) && + (cam->crop_current.width % *width))) { + *width = cam->crop_current.width / 8; + if (*width % 8) + *width += 8 - *width % 8; + pr_err("ERROR: v4l2 capture: width exceeds limit " + "resize to %d.\n", + *width); + } + + if ((cam->crop_current.height / *height > 8) || + ((cam->crop_current.height / *height == 8) && + (cam->crop_current.height % *height))) { + *height = cam->crop_current.height / 8; + if (*height % 8) + *height += 8 - *height % 8; + pr_err("ERROR: v4l2 capture: height exceeds limit " + "resize to %d.\n", + *height); + } + + switch (f->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_RGB565: + size = f->fmt.pix.width * f->fmt.pix.height * 2; + bytesperline = f->fmt.pix.width * 2; + break; + case V4L2_PIX_FMT_BGR24: + size = f->fmt.pix.width * f->fmt.pix.height * 3; + bytesperline = f->fmt.pix.width * 3; + break; + case V4L2_PIX_FMT_RGB24: + size = f->fmt.pix.width * f->fmt.pix.height * 3; + bytesperline = f->fmt.pix.width * 3; + break; + case V4L2_PIX_FMT_BGR32: + size = f->fmt.pix.width * f->fmt.pix.height * 4; + bytesperline = f->fmt.pix.width * 4; + break; + case V4L2_PIX_FMT_RGB32: + size = f->fmt.pix.width * f->fmt.pix.height * 4; + bytesperline = f->fmt.pix.width * 4; + break; + case V4L2_PIX_FMT_YUV422P: + size = f->fmt.pix.width * f->fmt.pix.height * 2; + bytesperline = f->fmt.pix.width; + break; + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YUYV: + size = f->fmt.pix.width * f->fmt.pix.height * 2; + bytesperline = f->fmt.pix.width * 2; + break; + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + size = f->fmt.pix.width * f->fmt.pix.height * 3 / 2; + bytesperline = f->fmt.pix.width; + break; + case V4L2_PIX_FMT_NV12: + size = f->fmt.pix.width * f->fmt.pix.height * 3 / 2; + bytesperline = f->fmt.pix.width; + break; + default: + break; + } + + if (f->fmt.pix.bytesperline < bytesperline) + f->fmt.pix.bytesperline = bytesperline; + else + bytesperline = f->fmt.pix.bytesperline; + + if (f->fmt.pix.sizeimage < size) + f->fmt.pix.sizeimage = size; + else + size = f->fmt.pix.sizeimage; + + cam->v2f.fmt.pix = f->fmt.pix; + break; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + pr_debug(" type=V4L2_BUF_TYPE_VIDEO_OVERLAY\n"); + retval = verify_preview(cam, &f->fmt.win); + cam->win = f->fmt.win; + break; + default: + retval = -EINVAL; + } + + pr_debug("End of %s: v2f pix widthxheight %d x %d\n", + __func__, + cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height); + pr_debug("End of %s: crop_bounds widthxheight %d x %d\n", + __func__, + cam->crop_bounds.width, cam->crop_bounds.height); + pr_debug("End of %s: crop_defrect widthxheight %d x %d\n", + __func__, + cam->crop_defrect.width, cam->crop_defrect.height); + pr_debug("End of %s: crop_current widthxheight %d x %d\n", + __func__, + cam->crop_current.width, cam->crop_current.height); + + return retval; +} + +/*! + * get control param + * + * @param cam structure cam_data * + * + * @param c structure v4l2_control * + * + * @return status 0 success, EINVAL failed + */ +static int mxc_v4l2_g_ctrl(cam_data *cam, struct v4l2_control *c) +{ + int status = 0; + + pr_debug("In MVC:mxc_v4l2_g_ctrl\n"); + + /* probably don't need to store the values that can be retrieved, + * locally, but they are for now. */ + switch (c->id) { + case V4L2_CID_HFLIP: + /* This is handled in the ipu. */ + if (cam->rotation == IPU_ROTATE_HORIZ_FLIP) + c->value = 1; + break; + case V4L2_CID_VFLIP: + /* This is handled in the ipu. */ + if (cam->rotation == IPU_ROTATE_VERT_FLIP) + c->value = 1; + break; + case V4L2_CID_MXC_ROT: + /* This is handled in the ipu. */ + c->value = cam->rotation; + break; + case V4L2_CID_BRIGHTNESS: + if (cam->sensor) { + c->value = cam->bright; + status = vidioc_int_g_ctrl(cam->sensor, c); + cam->bright = c->value; + } else { + pr_err("ERROR: v4l2 capture: slave not found!\n"); + status = -ENODEV; + } + break; + case V4L2_CID_HUE: + if (cam->sensor) { + c->value = cam->hue; + status = vidioc_int_g_ctrl(cam->sensor, c); + cam->hue = c->value; + } else { + pr_err("ERROR: v4l2 capture: slave not found!\n"); + status = -ENODEV; + } + break; + case V4L2_CID_CONTRAST: + if (cam->sensor) { + c->value = cam->contrast; + status = vidioc_int_g_ctrl(cam->sensor, c); + cam->contrast = c->value; + } else { + pr_err("ERROR: v4l2 capture: slave not found!\n"); + status = -ENODEV; + } + break; + case V4L2_CID_SATURATION: + if (cam->sensor) { + c->value = cam->saturation; + status = vidioc_int_g_ctrl(cam->sensor, c); + cam->saturation = c->value; + } else { + pr_err("ERROR: v4l2 capture: slave not found!\n"); + status = -ENODEV; + } + break; + case V4L2_CID_RED_BALANCE: + if (cam->sensor) { + c->value = cam->red; + status = vidioc_int_g_ctrl(cam->sensor, c); + cam->red = c->value; + } else { + pr_err("ERROR: v4l2 capture: slave not found!\n"); + status = -ENODEV; + } + break; + case V4L2_CID_BLUE_BALANCE: + if (cam->sensor) { + c->value = cam->blue; + status = vidioc_int_g_ctrl(cam->sensor, c); + cam->blue = c->value; + } else { + pr_err("ERROR: v4l2 capture: slave not found!\n"); + status = -ENODEV; + } + break; + case V4L2_CID_BLACK_LEVEL: + if (cam->sensor) { + c->value = cam->ae_mode; + status = vidioc_int_g_ctrl(cam->sensor, c); + cam->ae_mode = c->value; + } else { + pr_err("ERROR: v4l2 capture: slave not found!\n"); + status = -ENODEV; + } + break; + default: + pr_err("ERROR: v4l2 capture: unsupported ioctrl!\n"); + } + + return status; +} + +/*! + * V4L2 - set_control function + * V4L2_CID_PRIVATE_BASE is the extention for IPU preprocessing. + * 0 for normal operation + * 1 for vertical flip + * 2 for horizontal flip + * 3 for horizontal and vertical flip + * 4 for 90 degree rotation + * @param cam structure cam_data * + * + * @param c structure v4l2_control * + * + * @return status 0 success, EINVAL failed + */ +static int mxc_v4l2_s_ctrl(cam_data *cam, struct v4l2_control *c) +{ + int i, ret = 0; + int tmp_rotation = IPU_ROTATE_NONE; + struct sensor_data *sensor_data; + + pr_debug("In MVC:mxc_v4l2_s_ctrl\n"); + + switch (c->id) { + case V4L2_CID_HFLIP: + /* This is done by the IPU */ + if (c->value == 1) { + if ((cam->rotation != IPU_ROTATE_VERT_FLIP) && + (cam->rotation != IPU_ROTATE_180)) + cam->rotation = IPU_ROTATE_HORIZ_FLIP; + else + cam->rotation = IPU_ROTATE_180; + } else { + if (cam->rotation == IPU_ROTATE_HORIZ_FLIP) + cam->rotation = IPU_ROTATE_NONE; + if (cam->rotation == IPU_ROTATE_180) + cam->rotation = IPU_ROTATE_VERT_FLIP; + } + break; + case V4L2_CID_VFLIP: + /* This is done by the IPU */ + if (c->value == 1) { + if ((cam->rotation != IPU_ROTATE_HORIZ_FLIP) && + (cam->rotation != IPU_ROTATE_180)) + cam->rotation = IPU_ROTATE_VERT_FLIP; + else + cam->rotation = IPU_ROTATE_180; + } else { + if (cam->rotation == IPU_ROTATE_VERT_FLIP) + cam->rotation = IPU_ROTATE_NONE; + if (cam->rotation == IPU_ROTATE_180) + cam->rotation = IPU_ROTATE_HORIZ_FLIP; + } + break; + case V4L2_CID_MXC_ROT: + case V4L2_CID_MXC_VF_ROT: + /* This is done by the IPU */ + switch (c->value) { + case V4L2_MXC_ROTATE_NONE: + tmp_rotation = IPU_ROTATE_NONE; + break; + case V4L2_MXC_ROTATE_VERT_FLIP: + tmp_rotation = IPU_ROTATE_VERT_FLIP; + break; + case V4L2_MXC_ROTATE_HORIZ_FLIP: + tmp_rotation = IPU_ROTATE_HORIZ_FLIP; + break; + case V4L2_MXC_ROTATE_180: + tmp_rotation = IPU_ROTATE_180; + break; + case V4L2_MXC_ROTATE_90_RIGHT: + tmp_rotation = IPU_ROTATE_90_RIGHT; + break; + case V4L2_MXC_ROTATE_90_RIGHT_VFLIP: + tmp_rotation = IPU_ROTATE_90_RIGHT_VFLIP; + break; + case V4L2_MXC_ROTATE_90_RIGHT_HFLIP: + tmp_rotation = IPU_ROTATE_90_RIGHT_HFLIP; + break; + case V4L2_MXC_ROTATE_90_LEFT: + tmp_rotation = IPU_ROTATE_90_LEFT; + break; + default: + ret = -EINVAL; + } + #ifdef CONFIG_MXC_IPU_PRP_VF_SDC + if (c->id == V4L2_CID_MXC_VF_ROT) + cam->vf_rotation = tmp_rotation; + else + cam->rotation = tmp_rotation; + #else + cam->rotation = tmp_rotation; + #endif + + break; + case V4L2_CID_HUE: + if (cam->sensor) { + cam->hue = c->value; + ret = vidioc_int_s_ctrl(cam->sensor, c); + } else { + pr_err("ERROR: v4l2 capture: slave not found!\n"); + ret = -ENODEV; + } + break; + case V4L2_CID_CONTRAST: + if (cam->sensor) { + cam->contrast = c->value; + ret = vidioc_int_s_ctrl(cam->sensor, c); + } else { + pr_err("ERROR: v4l2 capture: slave not found!\n"); + ret = -ENODEV; + } + break; + case V4L2_CID_BRIGHTNESS: + if (cam->sensor) { + cam->bright = c->value; + ret = vidioc_int_s_ctrl(cam->sensor, c); + } else { + pr_err("ERROR: v4l2 capture: slave not found!\n"); + ret = -ENODEV; + } + break; + case V4L2_CID_SATURATION: + if (cam->sensor) { + cam->saturation = c->value; + ret = vidioc_int_s_ctrl(cam->sensor, c); + } else { + pr_err("ERROR: v4l2 capture: slave not found!\n"); + ret = -ENODEV; + } + break; + case V4L2_CID_RED_BALANCE: + if (cam->sensor) { + cam->red = c->value; + ret = vidioc_int_s_ctrl(cam->sensor, c); + } else { + pr_err("ERROR: v4l2 capture: slave not found!\n"); + ret = -ENODEV; + } + break; + case V4L2_CID_BLUE_BALANCE: + if (cam->sensor) { + cam->blue = c->value; + ret = vidioc_int_s_ctrl(cam->sensor, c); + } else { + pr_err("ERROR: v4l2 capture: slave not found!\n"); + ret = -ENODEV; + } + break; + case V4L2_CID_EXPOSURE: + if (cam->sensor) { + cam->ae_mode = c->value; + ret = vidioc_int_s_ctrl(cam->sensor, c); + } else { + pr_err("ERROR: v4l2 capture: slave not found!\n"); + ret = -ENODEV; + } + break; + case V4L2_CID_MXC_FLASH: +#ifdef CONFIG_MXC_IPU_V1 + ipu_csi_flash_strobe(true); +#endif + break; + case V4L2_CID_MXC_SWITCH_CAM: + if (cam->sensor == cam->all_sensors[c->value]) + break; + + /* power down other cameraes before enable new one */ + for (i = 0; i < cam->sensor_index; i++) { + if (i != c->value) { + vidioc_int_dev_exit(cam->all_sensors[i]); + vidioc_int_s_power(cam->all_sensors[i], 0); + if (cam->mclk_on[cam->mclk_source]) { + ipu_csi_enable_mclk_if(cam->ipu, + CSI_MCLK_I2C, + cam->mclk_source, + false, false); + cam->mclk_on[cam->mclk_source] = + false; + } + } + } + sensor_data = cam->all_sensors[c->value]->priv; + if (sensor_data->io_init) + sensor_data->io_init(); + cam->sensor = cam->all_sensors[c->value]; + cam->mclk_source = sensor_data->mclk_source; + ipu_csi_enable_mclk_if(cam->ipu, CSI_MCLK_I2C, + cam->mclk_source, true, true); + cam->mclk_on[cam->mclk_source] = true; + vidioc_int_s_power(cam->sensor, 1); + vidioc_int_dev_init(cam->sensor); + break; + default: + pr_debug(" default case\n"); + ret = -EINVAL; + break; + } + + return ret; +} + +/*! + * V4L2 - mxc_v4l2_s_param function + * Allows setting of capturemode and frame rate. + * + * @param cam structure cam_data * + * @param parm structure v4l2_streamparm * + * + * @return status 0 success, EINVAL failed + */ +static int mxc_v4l2_s_param(cam_data *cam, struct v4l2_streamparm *parm) +{ + struct v4l2_ifparm ifparm; + struct v4l2_format cam_fmt; + struct v4l2_streamparm currentparm; + ipu_csi_signal_cfg_t csi_param; + u32 current_fps, parm_fps; + int err = 0; + + pr_debug("In mxc_v4l2_s_param\n"); + + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + pr_err(KERN_ERR "mxc_v4l2_s_param invalid type\n"); + return -EINVAL; + } + + /* Stop the viewfinder */ + if (cam->overlay_on == true) + stop_preview(cam); + + currentparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + /* First check that this device can support the changes requested. */ + err = vidioc_int_g_parm(cam->sensor, ¤tparm); + if (err) { + pr_err("%s: vidioc_int_g_parm returned an error %d\n", + __func__, err); + goto exit; + } + + current_fps = currentparm.parm.capture.timeperframe.denominator + / currentparm.parm.capture.timeperframe.numerator; + parm_fps = parm->parm.capture.timeperframe.denominator + / parm->parm.capture.timeperframe.numerator; + + pr_debug(" Current capabilities are %x\n", + currentparm.parm.capture.capability); + pr_debug(" Current capturemode is %d change to %d\n", + currentparm.parm.capture.capturemode, + parm->parm.capture.capturemode); + pr_debug(" Current framerate is %d change to %d\n", + current_fps, parm_fps); + + /* This will change any camera settings needed. */ + err = vidioc_int_s_parm(cam->sensor, parm); + if (err) { + pr_err("%s: vidioc_int_s_parm returned an error %d\n", + __func__, err); + goto exit; + } + + /* If resolution changed, need to re-program the CSI */ + /* Get new values. */ + vidioc_int_g_ifparm(cam->sensor, &ifparm); + + csi_param.data_width = 0; + csi_param.clk_mode = 0; + csi_param.ext_vsync = 0; + csi_param.Vsync_pol = 0; + csi_param.Hsync_pol = 0; + csi_param.pixclk_pol = 0; + csi_param.data_pol = 0; + csi_param.sens_clksrc = 0; + csi_param.pack_tight = 0; + csi_param.force_eof = 0; + csi_param.data_en_pol = 0; + csi_param.data_fmt = 0; + csi_param.csi = cam->csi; + csi_param.mclk = 0; + + pr_debug(" clock_curr=mclk=%d\n", ifparm.u.bt656.clock_curr); + if (ifparm.u.bt656.clock_curr == 0) + csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED; + else + csi_param.clk_mode = IPU_CSI_CLK_MODE_GATED_CLK; + + csi_param.pixclk_pol = ifparm.u.bt656.latch_clk_inv; + + if (ifparm.u.bt656.mode == V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT) { + csi_param.data_width = IPU_CSI_DATA_WIDTH_8; + } else if (ifparm.u.bt656.mode + == V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT) { + csi_param.data_width = IPU_CSI_DATA_WIDTH_10; + } else { + csi_param.data_width = IPU_CSI_DATA_WIDTH_8; + } + + csi_param.Vsync_pol = ifparm.u.bt656.nobt_vs_inv; + csi_param.Hsync_pol = ifparm.u.bt656.nobt_hs_inv; + csi_param.ext_vsync = ifparm.u.bt656.bt_sync_correct; + + /* if the capturemode changed, the size bounds will have changed. */ + cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vidioc_int_g_fmt_cap(cam->sensor, &cam_fmt); + pr_debug(" g_fmt_cap returns widthxheight of input as %d x %d\n", + cam_fmt.fmt.pix.width, cam_fmt.fmt.pix.height); + + csi_param.data_fmt = cam_fmt.fmt.pix.pixelformat; + + cam->crop_bounds.top = cam->crop_bounds.left = 0; + cam->crop_bounds.width = cam_fmt.fmt.pix.width; + cam->crop_bounds.height = cam_fmt.fmt.pix.height; + + /* + * Set the default current cropped resolution to be the same with + * the cropping boundary(except for tvin module). + */ + if (cam->device_type != 1) { + cam->crop_current.width = cam->crop_bounds.width; + cam->crop_current.height = cam->crop_bounds.height; + } + + /* This essentially loses the data at the left and bottom of the image + * giving a digital zoom image, if crop_current is less than the full + * size of the image. */ + ipu_csi_set_window_size(cam->ipu, cam->crop_current.width, + cam->crop_current.height, cam->csi); + ipu_csi_set_window_pos(cam->ipu, cam->crop_current.left, + cam->crop_current.top, + cam->csi); + ipu_csi_init_interface(cam->ipu, cam->crop_bounds.width, + cam->crop_bounds.height, + cam_fmt.fmt.pix.pixelformat, csi_param); + + +exit: + if (cam->overlay_on == true) + start_preview(cam); + + return err; +} + +/*! + * V4L2 - mxc_v4l2_s_std function + * + * Sets the TV standard to be used. + * + * @param cam structure cam_data * + * @param parm structure v4l2_streamparm * + * + * @return status 0 success, EINVAL failed + */ +static int mxc_v4l2_s_std(cam_data *cam, v4l2_std_id e) +{ + pr_debug("In mxc_v4l2_s_std %Lx\n", e); + + if (e == V4L2_STD_PAL) { + pr_debug(" Setting standard to PAL %Lx\n", V4L2_STD_PAL); + cam->standard.id = V4L2_STD_PAL; + video_index = TV_PAL; + } else if (e == V4L2_STD_NTSC) { + pr_debug(" Setting standard to NTSC %Lx\n", + V4L2_STD_NTSC); + /* Get rid of the white dot line in NTSC signal input */ + cam->standard.id = V4L2_STD_NTSC; + video_index = TV_NTSC; + } else { + cam->standard.id = V4L2_STD_ALL; + video_index = TV_NOT_LOCKED; + pr_err("ERROR: unrecognized std! %Lx (PAL=%Lx, NTSC=%Lx\n", + e, V4L2_STD_PAL, V4L2_STD_NTSC); + } + + cam->standard.index = video_index; + strcpy(cam->standard.name, video_fmts[video_index].name); + cam->crop_bounds.width = video_fmts[video_index].raw_width; + cam->crop_bounds.height = video_fmts[video_index].raw_height; + cam->crop_current.width = video_fmts[video_index].active_width; + cam->crop_current.height = video_fmts[video_index].active_height; + cam->crop_current.top = video_fmts[video_index].active_top; + cam->crop_current.left = video_fmts[video_index].active_left; + + return 0; +} + +/*! + * V4L2 - mxc_v4l2_g_std function + * + * Gets the TV standard from the TV input device. + * + * @param cam structure cam_data * + * + * @param e structure v4l2_streamparm * + * + * @return status 0 success, EINVAL failed + */ +static int mxc_v4l2_g_std(cam_data *cam, v4l2_std_id *e) +{ + struct v4l2_format tv_fmt; + + pr_debug("In mxc_v4l2_g_std\n"); + + if (cam->device_type == 1) { + /* Use this function to get what the TV-In device detects the + * format to be. pixelformat is used to return the std value + * since the interface has no vidioc_g_std.*/ + tv_fmt.type = V4L2_BUF_TYPE_PRIVATE; + vidioc_int_g_fmt_cap(cam->sensor, &tv_fmt); + + /* If the TV-in automatically detects the standard, then if it + * changes, the settings need to change. */ + if (cam->standard_autodetect) { + if (cam->standard.id != tv_fmt.fmt.pix.pixelformat) { + pr_debug("MVC: mxc_v4l2_g_std: " + "Changing standard\n"); + mxc_v4l2_s_std(cam, tv_fmt.fmt.pix.pixelformat); + } + } + + *e = tv_fmt.fmt.pix.pixelformat; + } + + return 0; +} + +/*! + * Dequeue one V4L capture buffer + * + * @param cam structure cam_data * + * @param buf structure v4l2_buffer * + * + * @return status 0 success, EINVAL invalid frame number, + * ETIME timeout, ERESTARTSYS interrupted by user + */ +static int mxc_v4l_dqueue(cam_data *cam, struct v4l2_buffer *buf) +{ + int retval = 0; + struct mxc_v4l_frame *frame; + unsigned long lock_flags; + + pr_debug("In MVC:mxc_v4l_dqueue\n"); + + if (!wait_event_interruptible_timeout(cam->enc_queue, + cam->enc_counter != 0, + 10 * HZ)) { + pr_err("ERROR: v4l2 capture: mxc_v4l_dqueue timeout " + "enc_counter %x\n", + cam->enc_counter); + return -ETIME; + } else if (signal_pending(current)) { + pr_err("ERROR: v4l2 capture: mxc_v4l_dqueue() " + "interrupt received\n"); + return -ERESTARTSYS; + } + + if (down_interruptible(&cam->busy_lock)) + return -EBUSY; + + spin_lock_irqsave(&cam->dqueue_int_lock, lock_flags); + cam->enc_counter--; + + frame = list_entry(cam->done_q.next, struct mxc_v4l_frame, queue); + list_del(cam->done_q.next); + if (frame->buffer.flags & V4L2_BUF_FLAG_DONE) { + frame->buffer.flags &= ~V4L2_BUF_FLAG_DONE; + } else if (frame->buffer.flags & V4L2_BUF_FLAG_QUEUED) { + pr_err("ERROR: v4l2 capture: VIDIOC_DQBUF: " + "Buffer not filled.\n"); + frame->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED; + retval = -EINVAL; + } else if ((frame->buffer.flags & 0x7) == V4L2_BUF_FLAG_MAPPED) { + pr_err("ERROR: v4l2 capture: VIDIOC_DQBUF: " + "Buffer not queued.\n"); + retval = -EINVAL; + } + + cam->frame[frame->index].buffer.field = cam->device_type ? + V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE; + + buf->bytesused = cam->v2f.fmt.pix.sizeimage; + buf->index = frame->index; + buf->flags = frame->buffer.flags; + buf->m = cam->frame[frame->index].buffer.m; + buf->timestamp = cam->frame[frame->index].buffer.timestamp; + buf->field = cam->frame[frame->index].buffer.field; + spin_unlock_irqrestore(&cam->dqueue_int_lock, lock_flags); + + up(&cam->busy_lock); + return retval; +} + +/*! + * V4L interface - open function + * + * @param file structure file * + * + * @return status 0 success, ENODEV invalid device instance, + * ENODEV timeout, ERESTARTSYS interrupted by user + */ +static int mxc_v4l_open(struct file *file) +{ + struct v4l2_ifparm ifparm; + struct v4l2_format cam_fmt; + ipu_csi_signal_cfg_t csi_param; + struct video_device *dev = video_devdata(file); + cam_data *cam = video_get_drvdata(dev); + int err = 0; + struct sensor_data *sensor; + + pr_debug("\nIn MVC: mxc_v4l_open\n"); + pr_debug(" device name is %s\n", dev->name); + + if (!cam) { + pr_err("ERROR: v4l2 capture: Internal error, " + "cam_data not found!\n"); + return -EBADF; + } + + if (cam->sensor == NULL || + cam->sensor->type != v4l2_int_type_slave) { + pr_err("ERROR: v4l2 capture: slave not found!\n"); + return -EAGAIN; + } + + sensor = cam->sensor->priv; + if (!sensor) { + pr_err("%s: Internal error, sensor_data is not found!\n", + __func__); + return -EBADF; + } + + down(&cam->busy_lock); + err = 0; + if (signal_pending(current)) + goto oops; + + if (cam->open_count++ == 0) { + wait_event_interruptible(cam->power_queue, + cam->low_power == false); + + if (strcmp(mxc_capture_inputs[cam->current_input].name, + "CSI MEM") == 0) { +#if defined(CONFIG_MXC_IPU_CSI_ENC) || defined(CONFIG_MXC_IPU_CSI_ENC_MODULE) + err = csi_enc_select(cam); +#endif + } else if (strcmp(mxc_capture_inputs[cam->current_input].name, + "CSI IC MEM") == 0) { +#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_PRP_ENC_MODULE) + err = prp_enc_select(cam); +#endif + } + + cam->enc_counter = 0; + INIT_LIST_HEAD(&cam->ready_q); + INIT_LIST_HEAD(&cam->working_q); + INIT_LIST_HEAD(&cam->done_q); + + vidioc_int_g_ifparm(cam->sensor, &ifparm); + + csi_param.sens_clksrc = 0; + + csi_param.clk_mode = 0; + csi_param.data_pol = 0; + csi_param.ext_vsync = 0; + + csi_param.pack_tight = 0; + csi_param.force_eof = 0; + csi_param.data_en_pol = 0; + + csi_param.mclk = ifparm.u.bt656.clock_curr; + + csi_param.pixclk_pol = ifparm.u.bt656.latch_clk_inv; + + if (ifparm.u.bt656.mode + == V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT) + csi_param.data_width = IPU_CSI_DATA_WIDTH_8; + else if (ifparm.u.bt656.mode + == V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT) + csi_param.data_width = IPU_CSI_DATA_WIDTH_10; + else + csi_param.data_width = IPU_CSI_DATA_WIDTH_8; + + + csi_param.Vsync_pol = ifparm.u.bt656.nobt_vs_inv; + csi_param.Hsync_pol = ifparm.u.bt656.nobt_hs_inv; + + csi_param.csi = cam->csi; + + cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vidioc_int_g_fmt_cap(cam->sensor, &cam_fmt); + + /* Reset the sizes. Needed to prevent carryover of last + * operation.*/ + cam->crop_bounds.top = cam->crop_bounds.left = 0; + cam->crop_bounds.width = cam_fmt.fmt.pix.width; + cam->crop_bounds.height = cam_fmt.fmt.pix.height; + + /* This also is the max crop size for this device. */ + cam->crop_defrect.top = cam->crop_defrect.left = 0; + cam->crop_defrect.width = cam_fmt.fmt.pix.width; + cam->crop_defrect.height = cam_fmt.fmt.pix.height; + + /* At this point, this is also the current image size. */ + cam->crop_current.top = cam->crop_current.left = 0; + cam->crop_current.width = cam_fmt.fmt.pix.width; + cam->crop_current.height = cam_fmt.fmt.pix.height; + + pr_debug("End of %s: v2f pix widthxheight %d x %d\n", + __func__, + cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height); + pr_debug("End of %s: crop_bounds widthxheight %d x %d\n", + __func__, + cam->crop_bounds.width, cam->crop_bounds.height); + pr_debug("End of %s: crop_defrect widthxheight %d x %d\n", + __func__, + cam->crop_defrect.width, cam->crop_defrect.height); + pr_debug("End of %s: crop_current widthxheight %d x %d\n", + __func__, + cam->crop_current.width, cam->crop_current.height); + + csi_param.data_fmt = cam_fmt.fmt.pix.pixelformat; + pr_debug("On Open: Input to ipu size is %d x %d\n", + cam_fmt.fmt.pix.width, cam_fmt.fmt.pix.height); + ipu_csi_set_window_size(cam->ipu, cam->crop_current.width, + cam->crop_current.height, + cam->csi); + ipu_csi_set_window_pos(cam->ipu, cam->crop_current.left, + cam->crop_current.top, + cam->csi); + ipu_csi_init_interface(cam->ipu, cam->crop_bounds.width, + cam->crop_bounds.height, + cam_fmt.fmt.pix.pixelformat, + csi_param); + clk_prepare_enable(sensor->sensor_clk); + vidioc_int_s_power(cam->sensor, 1); + vidioc_int_init(cam->sensor); + vidioc_int_dev_init(cam->sensor); + } + + file->private_data = dev; + +oops: + up(&cam->busy_lock); + return err; +} + +/*! + * V4L interface - close function + * + * @param file struct file * + * + * @return 0 success + */ +static int mxc_v4l_close(struct file *file) +{ + struct video_device *dev = video_devdata(file); + int err = 0; + cam_data *cam = video_get_drvdata(dev); + struct sensor_data *sensor; + pr_debug("In MVC:mxc_v4l_close\n"); + + if (!cam) { + pr_err("ERROR: v4l2 capture: Internal error, " + "cam_data not found!\n"); + return -EBADF; + } + + if (!cam->sensor) { + pr_err("%s: Internal error, camera is not found!\n", + __func__); + return -EBADF; + } + + sensor = cam->sensor->priv; + if (!sensor) { + pr_err("%s: Internal error, sensor_data is not found!\n", + __func__); + return -EBADF; + } + + down(&cam->busy_lock); + + /* for the case somebody hit the ctrl C */ + if (cam->overlay_pid == current->pid && cam->overlay_on) { + err = stop_preview(cam); + cam->overlay_on = false; + } + if (cam->capture_pid == current->pid) { + err |= mxc_streamoff(cam); + wake_up_interruptible(&cam->enc_queue); + } + + if (--cam->open_count == 0) { + vidioc_int_s_power(cam->sensor, 0); + clk_disable_unprepare(sensor->sensor_clk); + wait_event_interruptible(cam->power_queue, + cam->low_power == false); + pr_debug("mxc_v4l_close: release resource\n"); + + if (strcmp(mxc_capture_inputs[cam->current_input].name, + "CSI MEM") == 0) { +#if defined(CONFIG_MXC_IPU_CSI_ENC) || defined(CONFIG_MXC_IPU_CSI_ENC_MODULE) + err |= csi_enc_deselect(cam); +#endif + } else if (strcmp(mxc_capture_inputs[cam->current_input].name, + "CSI IC MEM") == 0) { +#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_PRP_ENC_MODULE) + err |= prp_enc_deselect(cam); +#endif + } + + mxc_free_frame_buf(cam); + file->private_data = NULL; + + /* capture off */ + wake_up_interruptible(&cam->enc_queue); + mxc_free_frames(cam); + cam->enc_counter++; + } + + up(&cam->busy_lock); + + return err; +} + +#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_CSI_ENC) || \ + defined(CONFIG_MXC_IPU_PRP_ENC_MODULE) || \ + defined(CONFIG_MXC_IPU_CSI_ENC_MODULE) +/* + * V4L interface - read function + * + * @param file struct file * + * @param read buf char * + * @param count size_t + * @param ppos structure loff_t * + * + * @return bytes read + */ +static ssize_t mxc_v4l_read(struct file *file, char *buf, size_t count, + loff_t *ppos) +{ + int err = 0; + u8 *v_address[2]; + struct video_device *dev = video_devdata(file); + cam_data *cam = video_get_drvdata(dev); + + if (down_interruptible(&cam->busy_lock)) + return -EINTR; + + /* Stop the viewfinder */ + if (cam->overlay_on == true) + stop_preview(cam); + + v_address[0] = dma_alloc_coherent(0, + PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage), + &cam->still_buf[0], + GFP_DMA | GFP_KERNEL); + + v_address[1] = dma_alloc_coherent(0, + PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage), + &cam->still_buf[1], + GFP_DMA | GFP_KERNEL); + + if (!v_address[0] || !v_address[1]) { + err = -ENOBUFS; + goto exit0; + } + + err = prp_still_select(cam); + if (err != 0) { + err = -EIO; + goto exit0; + } + + cam->still_counter = 0; + err = cam->csi_start(cam); + if (err != 0) { + err = -EIO; + goto exit1; + } + + if (!wait_event_interruptible_timeout(cam->still_queue, + cam->still_counter != 0, + 10 * HZ)) { + pr_err("ERROR: v4l2 capture: mxc_v4l_read timeout counter %x\n", + cam->still_counter); + err = -ETIME; + goto exit1; + } + err = copy_to_user(buf, v_address[1], cam->v2f.fmt.pix.sizeimage); + +exit1: + prp_still_deselect(cam); + +exit0: + if (v_address[0] != 0) + dma_free_coherent(0, cam->v2f.fmt.pix.sizeimage, v_address[0], + cam->still_buf[0]); + if (v_address[1] != 0) + dma_free_coherent(0, cam->v2f.fmt.pix.sizeimage, v_address[1], + cam->still_buf[1]); + + cam->still_buf[0] = cam->still_buf[1] = 0; + + if (cam->overlay_on == true) + start_preview(cam); + + up(&cam->busy_lock); + if (err < 0) + return err; + + return cam->v2f.fmt.pix.sizeimage - err; +} +#endif + +/*! + * V4L interface - ioctl function + * + * @param file struct file* + * + * @param ioctlnr unsigned int + * + * @param arg void* + * + * @return 0 success, ENODEV for invalid device instance, + * -1 for other errors. + */ +static long mxc_v4l_do_ioctl(struct file *file, + unsigned int ioctlnr, void *arg) +{ + struct video_device *dev = video_devdata(file); + cam_data *cam = video_get_drvdata(dev); + int retval = 0; + unsigned long lock_flags; + + pr_debug("In MVC: mxc_v4l_do_ioctl %x\n", ioctlnr); + wait_event_interruptible(cam->power_queue, cam->low_power == false); + /* make this _really_ smp-safe */ + if (ioctlnr != VIDIOC_DQBUF) + if (down_interruptible(&cam->busy_lock)) + return -EBUSY; + + switch (ioctlnr) { + /*! + * V4l2 VIDIOC_QUERYCAP ioctl + */ + case VIDIOC_QUERYCAP: { + struct v4l2_capability *cap = arg; + pr_debug(" case VIDIOC_QUERYCAP\n"); + strcpy(cap->driver, "mxc_v4l2"); + cap->version = KERNEL_VERSION(0, 1, 11); + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VIDEO_OVERLAY | + V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE; + cap->card[0] = '\0'; + cap->bus_info[0] = '\0'; + break; + } + + /*! + * V4l2 VIDIOC_G_FMT ioctl + */ + case VIDIOC_G_FMT: { + struct v4l2_format *gf = arg; + pr_debug(" case VIDIOC_G_FMT\n"); + retval = mxc_v4l2_g_fmt(cam, gf); + break; + } + + /*! + * V4l2 VIDIOC_S_DEST_CROP ioctl + */ + case VIDIOC_S_DEST_CROP: { + struct v4l2_mxc_dest_crop *of = arg; + pr_debug(" case VIDIOC_S_DEST_CROP\n"); + cam->offset.u_offset = of->offset.u_offset; + cam->offset.v_offset = of->offset.v_offset; + break; + } + + /*! + * V4l2 VIDIOC_S_FMT ioctl + */ + case VIDIOC_S_FMT: { + struct v4l2_format *sf = arg; + pr_debug(" case VIDIOC_S_FMT\n"); + retval = mxc_v4l2_s_fmt(cam, sf); + break; + } + + /*! + * V4l2 VIDIOC_REQBUFS ioctl + */ + case VIDIOC_REQBUFS: { + struct v4l2_requestbuffers *req = arg; + pr_debug(" case VIDIOC_REQBUFS\n"); + + if (req->count > FRAME_NUM) { + pr_err("ERROR: v4l2 capture: VIDIOC_REQBUFS: " + "not enough buffers\n"); + req->count = FRAME_NUM; + } + + if ((req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) { + pr_err("ERROR: v4l2 capture: VIDIOC_REQBUFS: " + "wrong buffer type\n"); + retval = -EINVAL; + break; + } + + mxc_streamoff(cam); + if (req->memory & V4L2_MEMORY_MMAP) { + mxc_free_frame_buf(cam); + retval = mxc_allocate_frame_buf(cam, req->count); + } + break; + } + + /*! + * V4l2 VIDIOC_QUERYBUF ioctl + */ + case VIDIOC_QUERYBUF: { + struct v4l2_buffer *buf = arg; + int index = buf->index; + pr_debug(" case VIDIOC_QUERYBUF\n"); + + if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + pr_err("ERROR: v4l2 capture: " + "VIDIOC_QUERYBUFS: " + "wrong buffer type\n"); + retval = -EINVAL; + break; + } + + if (buf->memory & V4L2_MEMORY_MMAP) { + memset(buf, 0, sizeof(buf)); + buf->index = index; + } + + down(&cam->param_lock); + if (buf->memory & V4L2_MEMORY_USERPTR) { + mxc_v4l2_release_bufs(cam); + retval = mxc_v4l2_prepare_bufs(cam, buf); + } + + if (buf->memory & V4L2_MEMORY_MMAP) + retval = mxc_v4l2_buffer_status(cam, buf); + up(&cam->param_lock); + break; + } + + /*! + * V4l2 VIDIOC_QBUF ioctl + */ + case VIDIOC_QBUF: { + struct v4l2_buffer *buf = arg; + int index = buf->index; + pr_debug(" case VIDIOC_QBUF\n"); + + spin_lock_irqsave(&cam->queue_int_lock, lock_flags); + if ((cam->frame[index].buffer.flags & 0x7) == + V4L2_BUF_FLAG_MAPPED) { + cam->frame[index].buffer.flags |= + V4L2_BUF_FLAG_QUEUED; + list_add_tail(&cam->frame[index].queue, + &cam->ready_q); + } else if (cam->frame[index].buffer. + flags & V4L2_BUF_FLAG_QUEUED) { + pr_err("ERROR: v4l2 capture: VIDIOC_QBUF: " + "buffer already queued\n"); + retval = -EINVAL; + } else if (cam->frame[index].buffer. + flags & V4L2_BUF_FLAG_DONE) { + pr_err("ERROR: v4l2 capture: VIDIOC_QBUF: " + "overwrite done buffer.\n"); + cam->frame[index].buffer.flags &= + ~V4L2_BUF_FLAG_DONE; + cam->frame[index].buffer.flags |= + V4L2_BUF_FLAG_QUEUED; + retval = -EINVAL; + } + + buf->flags = cam->frame[index].buffer.flags; + spin_unlock_irqrestore(&cam->queue_int_lock, lock_flags); + break; + } + + /*! + * V4l2 VIDIOC_DQBUF ioctl + */ + case VIDIOC_DQBUF: { + struct v4l2_buffer *buf = arg; + pr_debug(" case VIDIOC_DQBUF\n"); + + if ((cam->enc_counter == 0) && + (file->f_flags & O_NONBLOCK)) { + retval = -EAGAIN; + break; + } + + retval = mxc_v4l_dqueue(cam, buf); + break; + } + + /*! + * V4l2 VIDIOC_STREAMON ioctl + */ + case VIDIOC_STREAMON: { + pr_debug(" case VIDIOC_STREAMON\n"); + retval = mxc_streamon(cam); + break; + } + + /*! + * V4l2 VIDIOC_STREAMOFF ioctl + */ + case VIDIOC_STREAMOFF: { + pr_debug(" case VIDIOC_STREAMOFF\n"); + retval = mxc_streamoff(cam); + break; + } + + /*! + * V4l2 VIDIOC_G_CTRL ioctl + */ + case VIDIOC_G_CTRL: { + pr_debug(" case VIDIOC_G_CTRL\n"); + retval = mxc_v4l2_g_ctrl(cam, arg); + break; + } + + /*! + * V4l2 VIDIOC_S_CTRL ioctl + */ + case VIDIOC_S_CTRL: { + pr_debug(" case VIDIOC_S_CTRL\n"); + retval = mxc_v4l2_s_ctrl(cam, arg); + break; + } + + /*! + * V4l2 VIDIOC_CROPCAP ioctl + */ + case VIDIOC_CROPCAP: { + struct v4l2_cropcap *cap = arg; + pr_debug(" case VIDIOC_CROPCAP\n"); + if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) { + retval = -EINVAL; + break; + } + cap->bounds = cam->crop_bounds; + cap->defrect = cam->crop_defrect; + break; + } + + /*! + * V4l2 VIDIOC_G_CROP ioctl + */ + case VIDIOC_G_CROP: { + struct v4l2_crop *crop = arg; + pr_debug(" case VIDIOC_G_CROP\n"); + + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) { + retval = -EINVAL; + break; + } + crop->c = cam->crop_current; + break; + } + + /*! + * V4l2 VIDIOC_S_CROP ioctl + */ + case VIDIOC_S_CROP: { + struct v4l2_crop *crop = arg; + struct v4l2_rect *b = &cam->crop_bounds; + pr_debug(" case VIDIOC_S_CROP\n"); + + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) { + retval = -EINVAL; + break; + } + + crop->c.top = (crop->c.top < b->top) ? b->top + : crop->c.top; + if (crop->c.top > b->top + b->height) + crop->c.top = b->top + b->height - 1; + if (crop->c.height > b->top + b->height - crop->c.top) + crop->c.height = + b->top + b->height - crop->c.top; + + crop->c.left = (crop->c.left < b->left) ? b->left + : crop->c.left; + if (crop->c.left > b->left + b->width) + crop->c.left = b->left + b->width - 1; + if (crop->c.width > b->left - crop->c.left + b->width) + crop->c.width = + b->left - crop->c.left + b->width; + + crop->c.width -= crop->c.width % 8; + crop->c.left -= crop->c.left % 4; + cam->crop_current = crop->c; + + pr_debug(" Cropping Input to ipu size %d x %d\n", + cam->crop_current.width, + cam->crop_current.height); + ipu_csi_set_window_size(cam->ipu, cam->crop_current.width, + cam->crop_current.height, + cam->csi); + ipu_csi_set_window_pos(cam->ipu, cam->crop_current.left, + cam->crop_current.top, + cam->csi); + break; + } + + /*! + * V4l2 VIDIOC_OVERLAY ioctl + */ + case VIDIOC_OVERLAY: { + int *on = arg; + pr_debug(" VIDIOC_OVERLAY on=%d\n", *on); + if (*on) { + cam->overlay_on = true; + cam->overlay_pid = current->pid; + retval = start_preview(cam); + } + if (!*on) { + retval = stop_preview(cam); + cam->overlay_on = false; + } + break; + } + + /*! + * V4l2 VIDIOC_G_FBUF ioctl + */ + case VIDIOC_G_FBUF: { + struct v4l2_framebuffer *fb = arg; + pr_debug(" case VIDIOC_G_FBUF\n"); + *fb = cam->v4l2_fb; + fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY; + break; + } + + /*! + * V4l2 VIDIOC_S_FBUF ioctl + */ + case VIDIOC_S_FBUF: { + struct v4l2_framebuffer *fb = arg; + pr_debug(" case VIDIOC_S_FBUF\n"); + cam->v4l2_fb = *fb; + break; + } + + case VIDIOC_G_PARM: { + struct v4l2_streamparm *parm = arg; + pr_debug(" case VIDIOC_G_PARM\n"); + if (cam->sensor) + retval = vidioc_int_g_parm(cam->sensor, parm); + else { + pr_err("ERROR: v4l2 capture: slave not found!\n"); + retval = -ENODEV; + } + break; + } + + case VIDIOC_S_PARM: { + struct v4l2_streamparm *parm = arg; + pr_debug(" case VIDIOC_S_PARM\n"); + if (cam->sensor) + retval = mxc_v4l2_s_param(cam, parm); + else { + pr_err("ERROR: v4l2 capture: slave not found!\n"); + retval = -ENODEV; + } + break; + } + + /* linux v4l2 bug, kernel c0485619 user c0405619 */ + case VIDIOC_ENUMSTD: { + struct v4l2_standard *e = arg; + pr_debug(" case VIDIOC_ENUMSTD\n"); + *e = cam->standard; + break; + } + + case VIDIOC_G_STD: { + v4l2_std_id *e = arg; + pr_debug(" case VIDIOC_G_STD\n"); + if (cam->sensor) + retval = mxc_v4l2_g_std(cam, e); + else { + pr_err("ERROR: v4l2 capture: slave not found!\n"); + retval = -ENODEV; + } + break; + } + + case VIDIOC_S_STD: { + v4l2_std_id *e = arg; + pr_debug(" case VIDIOC_S_STD\n"); + retval = mxc_v4l2_s_std(cam, *e); + + break; + } + + case VIDIOC_ENUMOUTPUT: { + struct v4l2_output *output = arg; + pr_debug(" case VIDIOC_ENUMOUTPUT\n"); + if (output->index >= MXC_V4L2_CAPTURE_NUM_OUTPUTS) { + retval = -EINVAL; + break; + } + *output = mxc_capture_outputs[output->index]; + + break; + } + case VIDIOC_G_OUTPUT: { + int *p_output_num = arg; + pr_debug(" case VIDIOC_G_OUTPUT\n"); + *p_output_num = cam->output; + break; + } + + case VIDIOC_S_OUTPUT: { + int *p_output_num = arg; + pr_debug(" case VIDIOC_S_OUTPUT\n"); + if (*p_output_num >= MXC_V4L2_CAPTURE_NUM_OUTPUTS) { + retval = -EINVAL; + break; + } + cam->output = *p_output_num; + break; + } + + case VIDIOC_ENUMINPUT: { + struct v4l2_input *input = arg; + pr_debug(" case VIDIOC_ENUMINPUT\n"); + if (input->index >= MXC_V4L2_CAPTURE_NUM_INPUTS) { + retval = -EINVAL; + break; + } + *input = mxc_capture_inputs[input->index]; + break; + } + + case VIDIOC_G_INPUT: { + int *index = arg; + pr_debug(" case VIDIOC_G_INPUT\n"); + *index = cam->current_input; + break; + } + + case VIDIOC_S_INPUT: { + int *index = arg; + pr_debug(" case VIDIOC_S_INPUT\n"); + if (*index >= MXC_V4L2_CAPTURE_NUM_INPUTS) { + retval = -EINVAL; + break; + } + + if (*index == cam->current_input) + break; + + if ((mxc_capture_inputs[cam->current_input].status & + V4L2_IN_ST_NO_POWER) == 0) { + retval = mxc_streamoff(cam); + if (retval) + break; + mxc_capture_inputs[cam->current_input].status |= + V4L2_IN_ST_NO_POWER; + } + + if (strcmp(mxc_capture_inputs[*index].name, "CSI MEM") == 0) { +#if defined(CONFIG_MXC_IPU_CSI_ENC) || defined(CONFIG_MXC_IPU_CSI_ENC_MODULE) + retval = csi_enc_select(cam); + if (retval) + break; +#endif + } else if (strcmp(mxc_capture_inputs[*index].name, + "CSI IC MEM") == 0) { +#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_PRP_ENC_MODULE) + retval = prp_enc_select(cam); + if (retval) + break; +#endif + } + + mxc_capture_inputs[*index].status &= ~V4L2_IN_ST_NO_POWER; + cam->current_input = *index; + break; + } + case VIDIOC_ENUM_FMT: { + struct v4l2_fmtdesc *f = arg; + if (cam->sensor) + retval = vidioc_int_enum_fmt_cap(cam->sensor, f); + else { + pr_err("ERROR: v4l2 capture: slave not found!\n"); + retval = -ENODEV; + } + break; + } + case VIDIOC_ENUM_FRAMESIZES: { + struct v4l2_frmsizeenum *fsize = arg; + if (cam->sensor) + retval = vidioc_int_enum_framesizes(cam->sensor, fsize); + else { + pr_err("ERROR: v4l2 capture: slave not found!\n"); + retval = -ENODEV; + } + break; + } + case VIDIOC_ENUM_FRAMEINTERVALS: { + struct v4l2_frmivalenum *fival = arg; + if (cam->sensor) { + retval = vidioc_int_enum_frameintervals(cam->sensor, + fival); + } else { + pr_err("ERROR: v4l2 capture: slave not found!\n"); + retval = -ENODEV; + } + break; + } + case VIDIOC_DBG_G_CHIP_IDENT: { + struct v4l2_dbg_chip_ident *p = arg; + p->ident = V4L2_IDENT_NONE; + p->revision = 0; + if (cam->sensor) + retval = vidioc_int_g_chip_ident(cam->sensor, (int *)p); + else { + pr_err("ERROR: v4l2 capture: slave not found!\n"); + retval = -ENODEV; + } + break; + } + case VIDIOC_TRY_FMT: + case VIDIOC_QUERYCTRL: + case VIDIOC_G_TUNER: + case VIDIOC_S_TUNER: + case VIDIOC_G_FREQUENCY: + case VIDIOC_S_FREQUENCY: + default: + pr_debug(" case default or not supported\n"); + retval = -EINVAL; + break; + } + + if (ioctlnr != VIDIOC_DQBUF) + up(&cam->busy_lock); + return retval; +} + +/* + * V4L interface - ioctl function + * + * @return None + */ +static long mxc_v4l_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + pr_debug("In MVC:mxc_v4l_ioctl\n"); + return video_usercopy(file, cmd, arg, mxc_v4l_do_ioctl); +} + +/*! + * V4L interface - mmap function + * + * @param file structure file * + * + * @param vma structure vm_area_struct * + * + * @return status 0 Success, EINTR busy lock error, ENOBUFS remap_page error + */ +static int mxc_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct video_device *dev = video_devdata(file); + unsigned long size; + int res = 0; + cam_data *cam = video_get_drvdata(dev); + + pr_debug("In MVC:mxc_mmap\n"); + pr_debug(" pgoff=0x%lx, start=0x%lx, end=0x%lx\n", + vma->vm_pgoff, vma->vm_start, vma->vm_end); + + /* make this _really_ smp-safe */ + if (down_interruptible(&cam->busy_lock)) + return -EINTR; + + size = vma->vm_end - vma->vm_start; + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + + if (remap_pfn_range(vma, vma->vm_start, + vma->vm_pgoff, size, vma->vm_page_prot)) { + pr_err("ERROR: v4l2 capture: mxc_mmap: " + "remap_pfn_range failed\n"); + res = -ENOBUFS; + goto mxc_mmap_exit; + } + + vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */ + +mxc_mmap_exit: + up(&cam->busy_lock); + return res; +} + +/*! + * V4L interface - poll function + * + * @param file structure file * + * + * @param wait structure poll_table_struct * + * + * @return status POLLIN | POLLRDNORM + */ +static unsigned int mxc_poll(struct file *file, struct poll_table_struct *wait) +{ + struct video_device *dev = video_devdata(file); + cam_data *cam = video_get_drvdata(dev); + wait_queue_head_t *queue = NULL; + int res = POLLIN | POLLRDNORM; + + pr_debug("In MVC:mxc_poll\n"); + + if (down_interruptible(&cam->busy_lock)) + return -EINTR; + + queue = &cam->enc_queue; + poll_wait(file, queue, wait); + + up(&cam->busy_lock); + + return res; +} + +/*! + * This structure defines the functions to be called in this driver. + */ +static struct v4l2_file_operations mxc_v4l_fops = { + .owner = THIS_MODULE, + .open = mxc_v4l_open, + .release = mxc_v4l_close, + .read = mxc_v4l_read, + .unlocked_ioctl = mxc_v4l_ioctl, + .mmap = mxc_mmap, + .poll = mxc_poll, +}; + +static struct video_device mxc_v4l_template = { + .name = "Mxc Camera", + .fops = &mxc_v4l_fops, + .release = video_device_release, +}; + +/*! + * This function can be used to release any platform data on closing. + */ +static void camera_platform_release(struct device *device) +{ +} + +/*! + * Camera V4l2 callback function. + * + * @param mask u32 + * + * @param dev void device structure + * + * @return status + */ +static void camera_callback(u32 mask, void *dev) +{ + struct mxc_v4l_frame *done_frame; + struct mxc_v4l_frame *ready_frame; + struct timeval cur_time; + + cam_data *cam = (cam_data *) dev; + if (cam == NULL) + return; + + pr_debug("In MVC:camera_callback\n"); + + spin_lock(&cam->queue_int_lock); + spin_lock(&cam->dqueue_int_lock); + if (!list_empty(&cam->working_q)) { + do_gettimeofday(&cur_time); + + done_frame = list_entry(cam->working_q.next, + struct mxc_v4l_frame, + queue); + + if (done_frame->ipu_buf_num != cam->local_buf_num) + goto next; + + /* + * Set the current time to done frame buffer's + * timestamp. Users can use this information to judge + * the frame's usage. + */ + done_frame->buffer.timestamp = cur_time; + + if (done_frame->buffer.flags & V4L2_BUF_FLAG_QUEUED) { + done_frame->buffer.flags |= V4L2_BUF_FLAG_DONE; + done_frame->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED; + + /* Added to the done queue */ + list_del(cam->working_q.next); + list_add_tail(&done_frame->queue, &cam->done_q); + + /* Wake up the queue */ + cam->enc_counter++; + wake_up_interruptible(&cam->enc_queue); + } else + pr_err("ERROR: v4l2 capture: camera_callback: " + "buffer not queued\n"); + } + +next: + if (!list_empty(&cam->ready_q)) { + ready_frame = list_entry(cam->ready_q.next, + struct mxc_v4l_frame, + queue); + if (cam->enc_update_eba) + if (cam->enc_update_eba( + cam, + ready_frame->buffer.m.offset) == 0) { + list_del(cam->ready_q.next); + list_add_tail(&ready_frame->queue, + &cam->working_q); + ready_frame->ipu_buf_num = cam->local_buf_num; + } + } else { + if (cam->enc_update_eba) + cam->enc_update_eba( + cam, cam->dummy_frame.buffer.m.offset); + } + + cam->local_buf_num = (cam->local_buf_num == 0) ? 1 : 0; + spin_unlock(&cam->dqueue_int_lock); + spin_unlock(&cam->queue_int_lock); + + return; +} + +/*! + * initialize cam_data structure + * + * @param cam structure cam_data * + * + * @return status 0 Success + */ +static int init_camera_struct(cam_data *cam, struct platform_device *pdev) +{ + const struct of_device_id *of_id = + of_match_device(mxc_v4l2_dt_ids, &pdev->dev); + struct device_node *np = pdev->dev.of_node; + int ipu_id, csi_id, mclk_source; + int ret = 0; + struct v4l2_device *v4l2_dev; + + pr_debug("In MVC: init_camera_struct\n"); + + ret = of_property_read_u32(np, "ipu_id", &ipu_id); + if (ret) { + dev_err(&pdev->dev, "ipu_id missing or invalid\n"); + return ret; + } + + ret = of_property_read_u32(np, "csi_id", &csi_id); + if (ret) { + dev_err(&pdev->dev, "csi_id missing or invalid\n"); + return ret; + } + + ret = of_property_read_u32(np, "mclk_source", &mclk_source); + if (ret) { + dev_err(&pdev->dev, "sensor mclk missing or invalid\n"); + return ret; + } + + /* Default everything to 0 */ + memset(cam, 0, sizeof(cam_data)); + + /* get devtype to distinguish if the cpu is imx5 or imx6 + * IMX5_V4L2 specify the cpu is imx5 + * IMX6_V4L2 specify the cpu is imx6q or imx6sdl + */ + if (of_id) + pdev->id_entry = of_id->data; + cam->devtype = pdev->id_entry->driver_data; + + cam->ipu = ipu_get_soc(ipu_id); + if (cam->ipu == NULL) { + pr_err("ERROR: v4l2 capture: failed to get ipu\n"); + return -EINVAL; + } else if (cam->ipu == ERR_PTR(-ENODEV)) { + pr_err("ERROR: v4l2 capture: get invalid ipu\n"); + return -ENODEV; + } + + init_MUTEX(&cam->param_lock); + init_MUTEX(&cam->busy_lock); + + cam->video_dev = video_device_alloc(); + if (cam->video_dev == NULL) + return -ENODEV; + + *(cam->video_dev) = mxc_v4l_template; + + video_set_drvdata(cam->video_dev, cam); + dev_set_drvdata(&pdev->dev, (void *)cam); + cam->video_dev->minor = -1; + + v4l2_dev = kzalloc(sizeof(*v4l2_dev), GFP_KERNEL); + if (!v4l2_dev) { + dev_err(&pdev->dev, "failed to allocate v4l2_dev structure\n"); + video_device_release(cam->video_dev); + return -ENOMEM; + } + + if (v4l2_device_register(&pdev->dev, v4l2_dev) < 0) { + dev_err(&pdev->dev, "register v4l2 device failed\n"); + video_device_release(cam->video_dev); + kfree(v4l2_dev); + return -ENODEV; + } + cam->video_dev->v4l2_dev = v4l2_dev; + + init_waitqueue_head(&cam->enc_queue); + init_waitqueue_head(&cam->still_queue); + + /* setup cropping */ + cam->crop_bounds.left = 0; + cam->crop_bounds.width = 640; + cam->crop_bounds.top = 0; + cam->crop_bounds.height = 480; + cam->crop_current = cam->crop_defrect = cam->crop_bounds; + ipu_csi_set_window_size(cam->ipu, cam->crop_current.width, + cam->crop_current.height, cam->csi); + ipu_csi_set_window_pos(cam->ipu, cam->crop_current.left, + cam->crop_current.top, cam->csi); + cam->streamparm.parm.capture.capturemode = 0; + + cam->standard.index = 0; + cam->standard.id = V4L2_STD_UNKNOWN; + cam->standard.frameperiod.denominator = 30; + cam->standard.frameperiod.numerator = 1; + cam->standard.framelines = 480; + cam->standard_autodetect = true; + cam->streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + cam->streamparm.parm.capture.timeperframe = cam->standard.frameperiod; + cam->streamparm.parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + cam->overlay_on = false; + cam->capture_on = false; + cam->v4l2_fb.flags = V4L2_FBUF_FLAG_OVERLAY; + + cam->v2f.fmt.pix.sizeimage = 352 * 288 * 3 / 2; + cam->v2f.fmt.pix.bytesperline = 288 * 3 / 2; + cam->v2f.fmt.pix.width = 288; + cam->v2f.fmt.pix.height = 352; + cam->v2f.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; + cam->win.w.width = 160; + cam->win.w.height = 160; + cam->win.w.left = 0; + cam->win.w.top = 0; + + cam->ipu_id = ipu_id; + cam->csi = csi_id; + cam->mclk_source = mclk_source; + cam->mclk_on[cam->mclk_source] = false; + + cam->enc_callback = camera_callback; + init_waitqueue_head(&cam->power_queue); + spin_lock_init(&cam->queue_int_lock); + spin_lock_init(&cam->dqueue_int_lock); + + cam->self = kmalloc(sizeof(struct v4l2_int_device), GFP_KERNEL); + cam->self->module = THIS_MODULE; + sprintf(cam->self->name, "mxc_v4l2_cap%d", cam->csi); + cam->self->type = v4l2_int_type_master; + cam->self->u.master = &mxc_v4l2_master; + + return 0; +} + +static ssize_t show_streaming(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *video_dev = container_of(dev, + struct video_device, dev); + cam_data *cam = video_get_drvdata(video_dev); + + if (cam->capture_on) + return sprintf(buf, "stream on\n"); + else + return sprintf(buf, "stream off\n"); +} +static DEVICE_ATTR(fsl_v4l2_capture_property, S_IRUGO, show_streaming, NULL); + +static ssize_t show_overlay(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *video_dev = container_of(dev, + struct video_device, dev); + cam_data *cam = video_get_drvdata(video_dev); + + if (cam->overlay_on) + return sprintf(buf, "overlay on\n"); + else + return sprintf(buf, "overlay off\n"); +} +static DEVICE_ATTR(fsl_v4l2_overlay_property, S_IRUGO, show_overlay, NULL); + +static ssize_t show_csi(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct video_device *video_dev = container_of(dev, + struct video_device, dev); + cam_data *cam = video_get_drvdata(video_dev); + + return sprintf(buf, "ipu%d_csi%d\n", cam->ipu_id, cam->csi); +} +static DEVICE_ATTR(fsl_csi_property, S_IRUGO, show_csi, NULL); + +/*! + * This function is called to probe the devices if registered. + * + * @param pdev the device structure used to give information on which device + * to probe + * + * @return The function returns 0 on success and -1 on failure. + */ +static int mxc_v4l2_probe(struct platform_device *pdev) +{ + /* Create cam and initialize it. */ + cam_data *cam = kmalloc(sizeof(cam_data), GFP_KERNEL); + if (cam == NULL) { + pr_err("ERROR: v4l2 capture: failed to register camera\n"); + return -1; + } + + init_camera_struct(cam, pdev); + pdev->dev.release = camera_platform_release; + + /* Set up the v4l2 device and register it*/ + cam->self->priv = cam; + v4l2_int_device_register(cam->self); + + /* register v4l video device */ + if (video_register_device(cam->video_dev, VFL_TYPE_GRABBER, video_nr) + < 0) { + kfree(cam); + cam = NULL; + pr_err("ERROR: v4l2 capture: video_register_device failed\n"); + return -1; + } + pr_debug(" Video device registered: %s #%d\n", + cam->video_dev->name, cam->video_dev->minor); + + if (device_create_file(&cam->video_dev->dev, + &dev_attr_fsl_v4l2_capture_property)) + dev_err(&pdev->dev, "Error on creating sysfs file" + " for capture\n"); + + if (device_create_file(&cam->video_dev->dev, + &dev_attr_fsl_v4l2_overlay_property)) + dev_err(&pdev->dev, "Error on creating sysfs file" + " for overlay\n"); + + if (device_create_file(&cam->video_dev->dev, + &dev_attr_fsl_csi_property)) + dev_err(&pdev->dev, "Error on creating sysfs file" + " for csi number\n"); + + return 0; +} + +/*! + * This function is called to remove the devices when device unregistered. + * + * @param pdev the device structure used to give information on which device + * to remove + * + * @return The function returns 0 on success and -1 on failure. + */ +static int mxc_v4l2_remove(struct platform_device *pdev) +{ + cam_data *cam = (cam_data *)platform_get_drvdata(pdev); + if (cam->open_count) { + pr_err("ERROR: v4l2 capture:camera open " + "-- setting ops to NULL\n"); + return -EBUSY; + } else { + struct v4l2_device *v4l2_dev = cam->video_dev->v4l2_dev; + device_remove_file(&cam->video_dev->dev, + &dev_attr_fsl_v4l2_capture_property); + device_remove_file(&cam->video_dev->dev, + &dev_attr_fsl_v4l2_overlay_property); + device_remove_file(&cam->video_dev->dev, + &dev_attr_fsl_csi_property); + + pr_info("V4L2 freeing image input device\n"); + v4l2_int_device_unregister(cam->self); + video_unregister_device(cam->video_dev); + + mxc_free_frame_buf(cam); + kfree(cam); + + v4l2_device_unregister(v4l2_dev); + kfree(v4l2_dev); + } + + pr_info("V4L2 unregistering video\n"); + return 0; +} + +/*! + * This function is called to put the sensor in a low power state. + * Refer to the document driver-model/driver.txt in the kernel source tree + * for more information. + * + * @param pdev the device structure used to give information on which I2C + * to suspend + * @param state the power state the device is entering + * + * @return The function returns 0 on success and -1 on failure. + */ +static int mxc_v4l2_suspend(struct platform_device *pdev, pm_message_t state) +{ + cam_data *cam = platform_get_drvdata(pdev); + + pr_debug("In MVC:mxc_v4l2_suspend\n"); + + if (cam == NULL) + return -1; + + down(&cam->busy_lock); + + cam->low_power = true; + + if (cam->overlay_on == true) + stop_preview(cam); + if ((cam->capture_on == true) && cam->enc_disable) + cam->enc_disable(cam); + + if (cam->sensor && cam->open_count) { + if (cam->mclk_on[cam->mclk_source]) { + ipu_csi_enable_mclk_if(cam->ipu, CSI_MCLK_I2C, + cam->mclk_source, + false, false); + cam->mclk_on[cam->mclk_source] = false; + } + vidioc_int_s_power(cam->sensor, 0); + } + + up(&cam->busy_lock); + + return 0; +} + +/*! + * This function is called to bring the sensor back from a low power state. + * Refer to the document driver-model/driver.txt in the kernel source tree + * for more information. + * + * @param pdev the device structure + * + * @return The function returns 0 on success and -1 on failure + */ +static int mxc_v4l2_resume(struct platform_device *pdev) +{ + cam_data *cam = platform_get_drvdata(pdev); + + pr_debug("In MVC:mxc_v4l2_resume\n"); + + if (cam == NULL) + return -1; + + down(&cam->busy_lock); + + cam->low_power = false; + wake_up_interruptible(&cam->power_queue); + + if (cam->sensor && cam->open_count) { + vidioc_int_s_power(cam->sensor, 1); + + if (!cam->mclk_on[cam->mclk_source]) { + ipu_csi_enable_mclk_if(cam->ipu, CSI_MCLK_I2C, + cam->mclk_source, + true, true); + cam->mclk_on[cam->mclk_source] = true; + } + } + + if (cam->overlay_on == true) + start_preview(cam); + if (cam->capture_on == true) + mxc_streamon(cam); + + up(&cam->busy_lock); + + return 0; +} + +/*! + * This structure contains pointers to the power management callback functions. + */ +static struct platform_driver mxc_v4l2_driver = { + .driver = { + .name = "mxc_v4l2_capture", + .owner = THIS_MODULE, + .of_match_table = mxc_v4l2_dt_ids, + }, + .id_table = imx_v4l2_devtype, + .probe = mxc_v4l2_probe, + .remove = mxc_v4l2_remove, + .suspend = mxc_v4l2_suspend, + .resume = mxc_v4l2_resume, + .shutdown = NULL, +}; + +/*! + * Initializes the camera driver. + */ +static int mxc_v4l2_master_attach(struct v4l2_int_device *slave) +{ + cam_data *cam = slave->u.slave->master->priv; + struct v4l2_format cam_fmt; + int i; + struct sensor_data *sdata = slave->priv; + + pr_debug("In MVC: mxc_v4l2_master_attach\n"); + pr_debug(" slave.name = %s\n", slave->name); + pr_debug(" master.name = %s\n", slave->u.slave->master->name); + + if (slave == NULL) { + pr_err("ERROR: v4l2 capture: slave parameter not valid.\n"); + return -1; + } + + if (sdata->csi != cam->csi) { + pr_debug("%s: csi doesn't match\n", __func__); + return -1; + } + + cam->sensor = slave; + + if (cam->sensor_index < MXC_SENSOR_NUM) { + cam->all_sensors[cam->sensor_index] = slave; + cam->sensor_index++; + } else { + pr_err("ERROR: v4l2 capture: slave number exceeds " + "the maximum.\n"); + return -1; + } + + for (i = 0; i < cam->sensor_index; i++) { + vidioc_int_dev_exit(cam->all_sensors[i]); + vidioc_int_s_power(cam->all_sensors[i], 0); + } + + cam_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vidioc_int_g_fmt_cap(cam->sensor, &cam_fmt); + + /* Used to detect TV in (type 1) vs. camera (type 0)*/ + cam->device_type = cam_fmt.fmt.pix.priv; + + /* Set the input size to the ipu for this device */ + cam->crop_bounds.top = cam->crop_bounds.left = 0; + cam->crop_bounds.width = cam_fmt.fmt.pix.width; + cam->crop_bounds.height = cam_fmt.fmt.pix.height; + + /* This also is the max crop size for this device. */ + cam->crop_defrect.top = cam->crop_defrect.left = 0; + cam->crop_defrect.width = cam_fmt.fmt.pix.width; + cam->crop_defrect.height = cam_fmt.fmt.pix.height; + + /* At this point, this is also the current image size. */ + cam->crop_current.top = cam->crop_current.left = 0; + cam->crop_current.width = cam_fmt.fmt.pix.width; + cam->crop_current.height = cam_fmt.fmt.pix.height; + + pr_debug("End of %s: v2f pix widthxheight %d x %d\n", + __func__, + cam->v2f.fmt.pix.width, cam->v2f.fmt.pix.height); + pr_debug("End of %s: crop_bounds widthxheight %d x %d\n", + __func__, + cam->crop_bounds.width, cam->crop_bounds.height); + pr_debug("End of %s: crop_defrect widthxheight %d x %d\n", + __func__, + cam->crop_defrect.width, cam->crop_defrect.height); + pr_debug("End of %s: crop_current widthxheight %d x %d\n", + __func__, + cam->crop_current.width, cam->crop_current.height); + + return 0; +} + +/*! + * Disconnects the camera driver. + */ +static void mxc_v4l2_master_detach(struct v4l2_int_device *slave) +{ + unsigned int i; + cam_data *cam = slave->u.slave->master->priv; + + pr_debug("In MVC:mxc_v4l2_master_detach\n"); + + if (cam->sensor_index > 1) { + for (i = 0; i < cam->sensor_index; i++) { + if (cam->all_sensors[i] != slave) + continue; + /* Move all the sensors behind this + * sensor one step forward + */ + for (; i <= MXC_SENSOR_NUM - 2; i++) + cam->all_sensors[i] = cam->all_sensors[i+1]; + break; + } + /* Point current sensor to the last one */ + cam->sensor = cam->all_sensors[cam->sensor_index - 2]; + } else + cam->sensor = NULL; + + cam->sensor_index--; + vidioc_int_dev_exit(slave); +} + +/*! + * Entry point for the V4L2 + * + * @return Error code indicating success or failure + */ +static __init int camera_init(void) +{ + u8 err = 0; + + pr_debug("In MVC:camera_init\n"); + + /* Register the device driver structure. */ + err = platform_driver_register(&mxc_v4l2_driver); + if (err != 0) { + pr_err("ERROR: v4l2 capture:camera_init: " + "platform_driver_register failed.\n"); + return err; + } + + return err; +} + +/*! + * Exit and cleanup for the V4L2 + */ +static void __exit camera_exit(void) +{ + pr_debug("In MVC: camera_exit\n"); + + platform_driver_unregister(&mxc_v4l2_driver); +} + +module_init(camera_init); +module_exit(camera_exit); + +module_param(video_nr, int, 0444); +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("V4L2 capture driver for Mxc based cameras"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("video"); diff --git a/drivers/media/platform/mxc/capture/mxc_v4l2_capture.h b/drivers/media/platform/mxc/capture/mxc_v4l2_capture.h new file mode 100644 index 000000000000..f6717752d4b9 --- /dev/null +++ b/drivers/media/platform/mxc/capture/mxc_v4l2_capture.h @@ -0,0 +1,262 @@ +/* + * Copyright 2004-2015 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @defgroup MXC_V4L2_CAPTURE MXC V4L2 Video Capture Driver + */ +/*! + * @file mxc_v4l2_capture.h + * + * @brief mxc V4L2 capture device API Header file + * + * It include all the defines for frame operations, also three structure defines + * use case ops structure, common v4l2 driver structure and frame structure. + * + * @ingroup MXC_V4L2_CAPTURE + */ +#ifndef __MXC_V4L2_CAPTURE_H__ +#define __MXC_V4L2_CAPTURE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "v4l2-int-device.h" + + +#define FRAME_NUM 10 +#define MXC_SENSOR_NUM 2 + +enum imx_v4l2_devtype { + IMX5_V4L2, + IMX6_V4L2, +}; + +/*! + * v4l2 frame structure. + */ +struct mxc_v4l_frame { + u32 paddress; + void *vaddress; + int count; + int width; + int height; + + struct v4l2_buffer buffer; + struct list_head queue; + int index; + union { + int ipu_buf_num; + int csi_buf_num; + }; +}; + +/* Only for old version. Will go away soon. */ +typedef struct { + u8 clk_mode; + u8 ext_vsync; + u8 Vsync_pol; + u8 Hsync_pol; + u8 pixclk_pol; + u8 data_pol; + u8 data_width; + u8 pack_tight; + u8 force_eof; + u8 data_en_pol; + u16 width; + u16 height; + u32 pixel_fmt; + u32 mclk; + u16 active_width; + u16 active_height; +} sensor_interface; + +/* Sensor control function */ +/* Only for old version. Will go away soon. */ +struct camera_sensor { + void (*set_color) (int bright, int saturation, int red, int green, + int blue); + void (*get_color) (int *bright, int *saturation, int *red, int *green, + int *blue); + void (*set_ae_mode) (int ae_mode); + void (*get_ae_mode) (int *ae_mode); + sensor_interface *(*config) (int *frame_rate, int high_quality); + sensor_interface *(*reset) (void); + void (*get_std) (v4l2_std_id *std); + void (*set_std) (v4l2_std_id std); + unsigned int csi; +}; + +/*! + * common v4l2 driver structure. + */ +typedef struct _cam_data { + struct video_device *video_dev; + int device_type; + + /* semaphore guard against SMP multithreading */ + struct semaphore busy_lock; + + int open_count; + + /* params lock for this camera */ + struct semaphore param_lock; + + /* Encoder */ + struct list_head ready_q; + struct list_head done_q; + struct list_head working_q; + int ping_pong_csi; + spinlock_t queue_int_lock; + spinlock_t dqueue_int_lock; + struct mxc_v4l_frame frame[FRAME_NUM]; + struct mxc_v4l_frame dummy_frame; + wait_queue_head_t enc_queue; + int enc_counter; + dma_addr_t rot_enc_bufs[2]; + void *rot_enc_bufs_vaddr[2]; + int rot_enc_buf_size[2]; + enum v4l2_buf_type type; + + /* still image capture */ + wait_queue_head_t still_queue; + int still_counter; + dma_addr_t still_buf[2]; + void *still_buf_vaddr; + + /* overlay */ + struct v4l2_window win; + struct v4l2_framebuffer v4l2_fb; + dma_addr_t vf_bufs[2]; + void *vf_bufs_vaddr[2]; + int vf_bufs_size[2]; + dma_addr_t rot_vf_bufs[2]; + void *rot_vf_bufs_vaddr[2]; + int rot_vf_buf_size[2]; + bool overlay_active; + int output; + struct fb_info *overlay_fb; + int fb_origin_std; + struct work_struct csi_work_struct; + + /* v4l2 format */ + struct v4l2_format v2f; + struct v4l2_format input_fmt; /* camera in */ + bool bswapenable; + int rotation; /* for IPUv1 and IPUv3, this means encoder rotation */ + int vf_rotation; /* viewfinder rotation only for IPUv1 and IPUv3 */ + struct v4l2_mxc_offset offset; + + /* V4l2 control bit */ + int bright; + int hue; + int contrast; + int saturation; + int red; + int green; + int blue; + int ae_mode; + + /* standard */ + struct v4l2_streamparm streamparm; + struct v4l2_standard standard; + bool standard_autodetect; + + /* crop */ + struct v4l2_rect crop_bounds; + struct v4l2_rect crop_defrect; + struct v4l2_rect crop_current; + + int (*enc_update_eba) (void *private, dma_addr_t eba); + int (*enc_enable) (void *private); + int (*enc_disable) (void *private); + int (*enc_enable_csi) (void *private); + int (*enc_disable_csi) (void *private); + void (*enc_callback) (u32 mask, void *dev); + int (*vf_start_adc) (void *private); + int (*vf_stop_adc) (void *private); + int (*vf_start_sdc) (void *private); + int (*vf_stop_sdc) (void *private); + int (*vf_enable_csi) (void *private); + int (*vf_disable_csi) (void *private); + int (*csi_start) (void *private); + int (*csi_stop) (void *private); + + /* misc status flag */ + bool overlay_on; + bool capture_on; + int overlay_pid; + int capture_pid; + bool low_power; + wait_queue_head_t power_queue; + unsigned int ipu_id; + unsigned int csi; + u8 mclk_source; + bool mclk_on[2]; /* two mclk sources at most now */ + int current_input; + + int local_buf_num; + + /* camera sensor interface */ + struct camera_sensor *cam_sensor; /* old version */ + struct v4l2_int_device *all_sensors[MXC_SENSOR_NUM]; + struct v4l2_int_device *sensor; + struct v4l2_int_device *self; + int sensor_index; + void *ipu; + void *csi_soc; + enum imx_v4l2_devtype devtype; + + /* v4l2 buf elements related to PxP DMA */ + struct completion pxp_tx_cmpl; + struct pxp_channel *pxp_chan; + struct pxp_config_data pxp_conf; + struct dma_async_tx_descriptor *txd; + dma_cookie_t cookie; + struct scatterlist sg[2]; +} cam_data; + +struct sensor_data { + const struct ov5642_platform_data *platform_data; + struct v4l2_int_device *v4l2_int_device; + struct i2c_client *i2c_client; + struct v4l2_pix_format pix; + struct v4l2_captureparm streamcap; + bool on; + + /* control settings */ + int brightness; + int hue; + int contrast; + int saturation; + int red; + int green; + int blue; + int ae_mode; + + u32 mclk; + u8 mclk_source; + struct clk *sensor_clk; + int csi; + + void (*io_init)(void); +}; + +void set_mclk_rate(uint32_t *p_mclk_freq, uint32_t csi); +#endif /* __MXC_V4L2_CAPTURE_H__ */ diff --git a/drivers/media/platform/mxc/capture/ov5640.c b/drivers/media/platform/mxc/capture/ov5640.c new file mode 100644 index 000000000000..ec8b8090201d --- /dev/null +++ b/drivers/media/platform/mxc/capture/ov5640.c @@ -0,0 +1,1950 @@ +/* + * Copyright (C) 2012-2015 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "v4l2-int-device.h" +#include "mxc_v4l2_capture.h" + +#define OV5640_VOLTAGE_ANALOG 2800000 +#define OV5640_VOLTAGE_DIGITAL_CORE 1500000 +#define OV5640_VOLTAGE_DIGITAL_IO 1800000 + +#define MIN_FPS 15 +#define MAX_FPS 30 +#define DEFAULT_FPS 30 + +#define OV5640_XCLK_MIN 6000000 +#define OV5640_XCLK_MAX 24000000 + +#define OV5640_CHIP_ID_HIGH_BYTE 0x300A +#define OV5640_CHIP_ID_LOW_BYTE 0x300B + +enum ov5640_mode { + ov5640_mode_MIN = 0, + ov5640_mode_VGA_640_480 = 0, + ov5640_mode_QVGA_320_240 = 1, + ov5640_mode_NTSC_720_480 = 2, + ov5640_mode_PAL_720_576 = 3, + ov5640_mode_720P_1280_720 = 4, + ov5640_mode_1080P_1920_1080 = 5, + ov5640_mode_QSXGA_2592_1944 = 6, + ov5640_mode_QCIF_176_144 = 7, + ov5640_mode_XGA_1024_768 = 8, + ov5640_mode_MAX = 8 +}; + +enum ov5640_frame_rate { + ov5640_15_fps, + ov5640_30_fps +}; + +static int ov5640_framerates[] = { + [ov5640_15_fps] = 15, + [ov5640_30_fps] = 30, +}; + +struct reg_value { + u16 u16RegAddr; + u8 u8Val; + u8 u8Mask; + u32 u32Delay_ms; +}; + +struct ov5640_mode_info { + enum ov5640_mode mode; + u32 width; + u32 height; + struct reg_value *init_data_ptr; + u32 init_data_size; +}; + +/*! + * Maintains the information on the current state of the sesor. + */ +static struct sensor_data ov5640_data; +static int pwn_gpio, rst_gpio; +static int prev_sysclk; +static int AE_Target = 52, night_mode; +static int prev_HTS; +static int AE_high, AE_low; + +static struct reg_value ov5640_global_init_setting[] = { + {0x3008, 0x42, 0, 0}, + {0x3103, 0x03, 0, 0}, {0x3017, 0xff, 0, 0}, {0x3018, 0xff, 0, 0}, + {0x3034, 0x1a, 0, 0}, {0x3037, 0x13, 0, 0}, {0x3108, 0x01, 0, 0}, + {0x3630, 0x36, 0, 0}, {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, + {0x3633, 0x12, 0, 0}, {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, + {0x3703, 0x5a, 0, 0}, {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, + {0x370b, 0x60, 0, 0}, {0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, + {0x3906, 0x10, 0, 0}, {0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, + {0x3600, 0x08, 0, 0}, {0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, + {0x3620, 0x52, 0, 0}, {0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, + {0x3a13, 0x43, 0, 0}, {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0}, + {0x3635, 0x13, 0, 0}, {0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, + {0x3622, 0x01, 0, 0}, {0x3c01, 0x34, 0, 0}, {0x3c04, 0x28, 0, 0}, + {0x3c05, 0x98, 0, 0}, {0x3c06, 0x00, 0, 0}, {0x3c07, 0x07, 0, 0}, + {0x3c08, 0x00, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, + {0x3c0b, 0x40, 0, 0}, {0x3810, 0x00, 0, 0}, {0x3811, 0x10, 0, 0}, + {0x3812, 0x00, 0, 0}, {0x3708, 0x64, 0, 0}, {0x4001, 0x02, 0, 0}, + {0x4005, 0x1a, 0, 0}, {0x3000, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, + {0x300e, 0x58, 0, 0}, {0x302e, 0x00, 0, 0}, {0x4300, 0x30, 0, 0}, + {0x501f, 0x00, 0, 0}, {0x440e, 0x00, 0, 0}, {0x5000, 0xa7, 0, 0}, + {0x3008, 0x02, 0, 0}, +}; + +static struct reg_value ov5640_init_setting_30fps_VGA[] = { + {0x3008, 0x42, 0, 0}, + {0x3103, 0x03, 0, 0}, {0x3017, 0xff, 0, 0}, {0x3018, 0xff, 0, 0}, + {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, {0x3036, 0x46, 0, 0}, + {0x3037, 0x13, 0, 0}, {0x3108, 0x01, 0, 0}, {0x3630, 0x36, 0, 0}, + {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0}, + {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0}, + {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0}, + {0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0}, + {0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0}, + {0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0}, + {0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0}, + {0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0}, + {0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0}, + {0x3c01, 0x34, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0}, + {0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, + {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0}, + {0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x300e, 0x58, 0, 0}, {0x302e, 0x00, 0, 0}, {0x4300, 0x30, 0, 0}, + {0x501f, 0x00, 0, 0}, {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, + {0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, {0x5000, 0xa7, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0xf2, 0, 0}, + {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, + {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0}, {0x5187, 0x09, 0, 0}, + {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0}, {0x518a, 0x54, 0, 0}, + {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x50, 0, 0}, + {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0}, {0x5190, 0x46, 0, 0}, + {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, + {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, + {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x6c, 0, 0}, + {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x09, 0, 0}, + {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0}, {0x5381, 0x1e, 0, 0}, + {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0}, {0x5384, 0x0a, 0, 0}, + {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0}, {0x5387, 0x7c, 0, 0}, + {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0}, {0x538a, 0x01, 0, 0}, + {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0}, {0x5301, 0x30, 0, 0}, + {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0}, {0x5304, 0x08, 0, 0}, + {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0}, {0x5307, 0x16, 0, 0}, + {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0}, {0x530b, 0x04, 0, 0}, + {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0}, {0x5481, 0x08, 0, 0}, + {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0}, {0x5484, 0x51, 0, 0}, + {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0}, {0x5487, 0x7d, 0, 0}, + {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0}, {0x548a, 0x9a, 0, 0}, + {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0}, {0x548d, 0xcd, 0, 0}, + {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0}, {0x5490, 0x1d, 0, 0}, + {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0}, {0x5584, 0x10, 0, 0}, + {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0}, {0x558b, 0xf8, 0, 0}, + {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0}, {0x5802, 0x0f, 0, 0}, + {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0}, {0x5805, 0x26, 0, 0}, + {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0}, {0x5808, 0x05, 0, 0}, + {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0}, {0x580b, 0x0d, 0, 0}, + {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0}, {0x580e, 0x00, 0, 0}, + {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0}, {0x5811, 0x09, 0, 0}, + {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x00, 0, 0}, + {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0}, {0x5817, 0x08, 0, 0}, + {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0}, {0x581a, 0x05, 0, 0}, + {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0}, {0x581d, 0x0e, 0, 0}, + {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0}, {0x5820, 0x11, 0, 0}, + {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0}, {0x5823, 0x28, 0, 0}, + {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0}, {0x5826, 0x08, 0, 0}, + {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0}, {0x5829, 0x26, 0, 0}, + {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0}, {0x582c, 0x24, 0, 0}, + {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0}, {0x582f, 0x22, 0, 0}, + {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0}, {0x5832, 0x24, 0, 0}, + {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0}, {0x5835, 0x22, 0, 0}, + {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0}, {0x5838, 0x44, 0, 0}, + {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0}, {0x583b, 0x28, 0, 0}, + {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0}, {0x5025, 0x00, 0, 0}, + {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0}, {0x3a1b, 0x30, 0, 0}, + {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x14, 0, 0}, + {0x3008, 0x02, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_VGA_640_480[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, + {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, {0x3503, 0x00, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_VGA_640_480[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, + {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, {0x3503, 0x00, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_QVGA_320_240[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, + {0x380a, 0x00, 0, 0}, {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_QVGA_320_240[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, + {0x380a, 0x00, 0, 0}, {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_NTSC_720_480[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, + {0x3807, 0xd4, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, + {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_NTSC_720_480[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, + {0x3807, 0xd4, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, + {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_PAL_720_576[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x60, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x09, 0, 0}, {0x3805, 0x7e, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, + {0x380a, 0x02, 0, 0}, {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_PAL_720_576[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x60, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x09, 0, 0}, {0x3805, 0x7e, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, + {0x380a, 0x02, 0, 0}, {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_720P_1280_720[] = { + {0x3035, 0x21, 0, 0}, {0x3036, 0x69, 0, 0}, {0x3c07, 0x07, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0}, + {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0}, + {0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0}, + {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3813, 0x04, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3709, 0x52, 0, 0}, + {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, {0x3a03, 0xe0, 0, 0}, + {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe0, 0, 0}, {0x4004, 0x02, 0, 0}, + {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, + {0x4837, 0x16, 0, 0}, {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, + {0x3503, 0x00, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_720P_1280_720[] = { + {0x3035, 0x41, 0, 0}, {0x3036, 0x69, 0, 0}, {0x3c07, 0x07, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0}, + {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0}, + {0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0}, + {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3813, 0x04, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3709, 0x52, 0, 0}, + {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, {0x3a03, 0xe0, 0, 0}, + {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe0, 0, 0}, {0x4004, 0x02, 0, 0}, + {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, + {0x4837, 0x16, 0, 0}, {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, + {0x3503, 0x00, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_QCIF_176_144[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, + {0x380a, 0x00, 0, 0}, {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_QCIF_176_144[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, + {0x380a, 0x00, 0, 0}, {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_XGA_1024_768[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0}, + {0x380a, 0x03, 0, 0}, {0x380b, 0x00, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x20, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x01, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x69, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_XGA_1024_768[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0}, + {0x380a, 0x03, 0, 0}, {0x380b, 0x00, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x20, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x01, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + + +static struct reg_value ov5640_setting_15fps_1080P_1920_1080[] = { + {0x3c07, 0x07, 0, 0}, {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, + {0x3814, 0x11, 0, 0}, {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0xee, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x05, 0, 0}, + {0x3807, 0xc3, 0, 0}, {0x3808, 0x07, 0, 0}, {0x3809, 0x80, 0, 0}, + {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0}, {0x380c, 0x0b, 0, 0}, + {0x380d, 0x1c, 0, 0}, {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, + {0x3813, 0x04, 0, 0}, {0x3618, 0x04, 0, 0}, {0x3612, 0x2b, 0, 0}, + {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x07, 0, 0}, + {0x3a03, 0xae, 0, 0}, {0x3a14, 0x07, 0, 0}, {0x3a15, 0xae, 0, 0}, + {0x4004, 0x06, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x02, 0, 0}, {0x4407, 0x0c, 0, 0}, {0x460b, 0x37, 0, 0}, + {0x460c, 0x20, 0, 0}, {0x4837, 0x2c, 0, 0}, {0x3824, 0x01, 0, 0}, + {0x5001, 0x83, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x69, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = { + {0x3c07, 0x07, 0, 0}, {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, + {0x3814, 0x11, 0, 0}, {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9f, 0, 0}, {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, + {0x380a, 0x07, 0, 0}, {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, + {0x380d, 0x1c, 0, 0}, {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, + {0x3813, 0x04, 0, 0}, {0x3618, 0x04, 0, 0}, {0x3612, 0x2b, 0, 0}, + {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x07, 0, 0}, + {0x3a03, 0xae, 0, 0}, {0x3a14, 0x07, 0, 0}, {0x3a15, 0xae, 0, 0}, + {0x4004, 0x06, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x02, 0, 0}, {0x4407, 0x0c, 0, 0}, {0x460b, 0x37, 0, 0}, + {0x460c, 0x20, 0, 0}, {0x4837, 0x2c, 0, 0}, {0x3824, 0x01, 0, 0}, + {0x5001, 0x83, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x69, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct ov5640_mode_info ov5640_mode_info_data[2][ov5640_mode_MAX + 1] = { + { + {ov5640_mode_VGA_640_480, 640, 480, + ov5640_setting_15fps_VGA_640_480, + ARRAY_SIZE(ov5640_setting_15fps_VGA_640_480)}, + {ov5640_mode_QVGA_320_240, 320, 240, + ov5640_setting_15fps_QVGA_320_240, + ARRAY_SIZE(ov5640_setting_15fps_QVGA_320_240)}, + {ov5640_mode_NTSC_720_480, 720, 480, + ov5640_setting_15fps_NTSC_720_480, + ARRAY_SIZE(ov5640_setting_15fps_NTSC_720_480)}, + {ov5640_mode_PAL_720_576, 720, 576, + ov5640_setting_15fps_PAL_720_576, + ARRAY_SIZE(ov5640_setting_15fps_PAL_720_576)}, + {ov5640_mode_720P_1280_720, 1280, 720, + ov5640_setting_15fps_720P_1280_720, + ARRAY_SIZE(ov5640_setting_15fps_720P_1280_720)}, + {ov5640_mode_1080P_1920_1080, 1920, 1080, + ov5640_setting_15fps_1080P_1920_1080, + ARRAY_SIZE(ov5640_setting_15fps_1080P_1920_1080)}, + {ov5640_mode_QSXGA_2592_1944, 2592, 1944, + ov5640_setting_15fps_QSXGA_2592_1944, + ARRAY_SIZE(ov5640_setting_15fps_QSXGA_2592_1944)}, + {ov5640_mode_QCIF_176_144, 176, 144, + ov5640_setting_15fps_QCIF_176_144, + ARRAY_SIZE(ov5640_setting_15fps_QCIF_176_144)}, + {ov5640_mode_XGA_1024_768, 1024, 768, + ov5640_setting_15fps_XGA_1024_768, + ARRAY_SIZE(ov5640_setting_15fps_XGA_1024_768)}, + }, + { + {ov5640_mode_VGA_640_480, 640, 480, + ov5640_setting_30fps_VGA_640_480, + ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480)}, + {ov5640_mode_QVGA_320_240, 320, 240, + ov5640_setting_30fps_QVGA_320_240, + ARRAY_SIZE(ov5640_setting_30fps_QVGA_320_240)}, + {ov5640_mode_NTSC_720_480, 720, 480, + ov5640_setting_30fps_NTSC_720_480, + ARRAY_SIZE(ov5640_setting_30fps_NTSC_720_480)}, + {ov5640_mode_PAL_720_576, 720, 576, + ov5640_setting_30fps_PAL_720_576, + ARRAY_SIZE(ov5640_setting_30fps_PAL_720_576)}, + {ov5640_mode_720P_1280_720, 1280, 720, + ov5640_setting_30fps_720P_1280_720, + ARRAY_SIZE(ov5640_setting_30fps_720P_1280_720)}, + {ov5640_mode_1080P_1920_1080, 0, 0, NULL, 0}, + {ov5640_mode_QSXGA_2592_1944, 0, 0, NULL, 0}, + {ov5640_mode_QCIF_176_144, 176, 144, + ov5640_setting_30fps_QCIF_176_144, + ARRAY_SIZE(ov5640_setting_30fps_QCIF_176_144)}, + {ov5640_mode_XGA_1024_768, 1024, 768, + ov5640_setting_30fps_XGA_1024_768, + ARRAY_SIZE(ov5640_setting_30fps_XGA_1024_768)}, + }, +}; + +static struct regulator *io_regulator; +static struct regulator *core_regulator; +static struct regulator *analog_regulator; + +static int ov5640_probe(struct i2c_client *adapter, + const struct i2c_device_id *device_id); +static int ov5640_remove(struct i2c_client *client); + +static s32 ov5640_read_reg(u16 reg, u8 *val); +static s32 ov5640_write_reg(u16 reg, u8 val); + +static const struct i2c_device_id ov5640_id[] = { + {"ov564x", 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, ov5640_id); + +static struct i2c_driver ov5640_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "ov564x", + }, + .probe = ov5640_probe, + .remove = ov5640_remove, + .id_table = ov5640_id, +}; + +static inline void ov5640_power_down(int enable) +{ + gpio_set_value(pwn_gpio, enable); + + msleep(2); +} + +static inline void ov5640_reset(void) +{ + /* camera reset */ + gpio_set_value(rst_gpio, 1); + + /* camera power down */ + gpio_set_value(pwn_gpio, 1); + msleep(5); + gpio_set_value(pwn_gpio, 0); + msleep(5); + gpio_set_value(rst_gpio, 0); + msleep(1); + gpio_set_value(rst_gpio, 1); + msleep(5); + gpio_set_value(pwn_gpio, 1); +} + +static int ov5640_regulator_enable(struct device *dev) +{ + int ret = 0; + + io_regulator = devm_regulator_get(dev, "DOVDD"); + if (!IS_ERR(io_regulator)) { + regulator_set_voltage(io_regulator, + OV5640_VOLTAGE_DIGITAL_IO, + OV5640_VOLTAGE_DIGITAL_IO); + ret = regulator_enable(io_regulator); + if (ret) { + dev_err(dev, "set io voltage failed\n"); + return ret; + } else { + dev_dbg(dev, "set io voltage ok\n"); + } + } else { + io_regulator = NULL; + dev_warn(dev, "cannot get io voltage\n"); + } + + core_regulator = devm_regulator_get(dev, "DVDD"); + if (!IS_ERR(core_regulator)) { + regulator_set_voltage(core_regulator, + OV5640_VOLTAGE_DIGITAL_CORE, + OV5640_VOLTAGE_DIGITAL_CORE); + ret = regulator_enable(core_regulator); + if (ret) { + dev_err(dev, "set core voltage failed\n"); + return ret; + } else { + dev_dbg(dev, "set core voltage ok\n"); + } + } else { + core_regulator = NULL; + dev_warn(dev, "cannot get core voltage\n"); + } + + analog_regulator = devm_regulator_get(dev, "AVDD"); + if (!IS_ERR(analog_regulator)) { + regulator_set_voltage(analog_regulator, + OV5640_VOLTAGE_ANALOG, + OV5640_VOLTAGE_ANALOG); + ret = regulator_enable(analog_regulator); + if (ret) { + dev_err(dev, "set analog voltage failed\n"); + return ret; + } else { + dev_dbg(dev, "set analog voltage ok\n"); + } + } else { + analog_regulator = NULL; + dev_warn(dev, "cannot get analog voltage\n"); + } + + return ret; +} + +static s32 ov5640_write_reg(u16 reg, u8 val) +{ + u8 au8Buf[3] = {0}; + + au8Buf[0] = reg >> 8; + au8Buf[1] = reg & 0xff; + au8Buf[2] = val; + + if (i2c_master_send(ov5640_data.i2c_client, au8Buf, 3) < 0) { + pr_err("%s:write reg error:reg=%x,val=%x\n", + __func__, reg, val); + return -1; + } + + return 0; +} + +static s32 ov5640_read_reg(u16 reg, u8 *val) +{ + u8 au8RegBuf[2] = {0}; + u8 u8RdVal = 0; + + au8RegBuf[0] = reg >> 8; + au8RegBuf[1] = reg & 0xff; + + if (2 != i2c_master_send(ov5640_data.i2c_client, au8RegBuf, 2)) { + pr_err("%s:write reg error:reg=%x\n", + __func__, reg); + return -1; + } + + if (1 != i2c_master_recv(ov5640_data.i2c_client, &u8RdVal, 1)) { + pr_err("%s:read reg error:reg=%x,val=%x\n", + __func__, reg, u8RdVal); + return -1; + } + + *val = u8RdVal; + + return u8RdVal; +} + +static void ov5640_soft_reset(void) +{ + /* sysclk from pad */ + ov5640_write_reg(0x3103, 0x11); + + /* software reset */ + ov5640_write_reg(0x3008, 0x82); + + /* delay at least 5ms */ + msleep(10); +} + +/* set sensor driver capability + * 0x302c[7:6] - strength + 00 - 1x + 01 - 2x + 10 - 3x + 11 - 4x + */ +static int ov5640_driver_capability(int strength) +{ + u8 temp = 0; + + if (strength > 4 || strength < 1) { + pr_err("The valid driver capability of ov5640 is 1x~4x\n"); + return -EINVAL; + } + + ov5640_read_reg(0x302c, &temp); + + temp &= ~0xc0; /* clear [7:6] */ + temp |= ((strength - 1) << 6); /* set [7:6] */ + + ov5640_write_reg(0x302c, temp); + + return 0; +} + +/* calculate sysclk */ +static int ov5640_get_sysclk(void) +{ + int xvclk = ov5640_data.mclk / 10000; + int sysclk; + int temp1, temp2; + int Multiplier, PreDiv, VCO, SysDiv, Pll_rdiv, Bit_div2x, sclk_rdiv; + int sclk_rdiv_map[] = {1, 2, 4, 8}; + u8 regval = 0; + + temp1 = ov5640_read_reg(0x3034, ®val); + temp2 = temp1 & 0x0f; + if (temp2 == 8 || temp2 == 10) { + Bit_div2x = temp2 / 2; + } else { + pr_err("ov5640: unsupported bit mode %d\n", temp2); + return -1; + } + + temp1 = ov5640_read_reg(0x3035, ®val); + SysDiv = temp1 >> 4; + if (SysDiv == 0) + SysDiv = 16; + + temp1 = ov5640_read_reg(0x3036, ®val); + Multiplier = temp1; + temp1 = ov5640_read_reg(0x3037, ®val); + PreDiv = temp1 & 0x0f; + Pll_rdiv = ((temp1 >> 4) & 0x01) + 1; + + temp1 = ov5640_read_reg(0x3108, ®val); + temp2 = temp1 & 0x03; + + sclk_rdiv = sclk_rdiv_map[temp2]; + VCO = xvclk * Multiplier / PreDiv; + sysclk = VCO / SysDiv / Pll_rdiv * 2 / Bit_div2x / sclk_rdiv; + + return sysclk; +} + +/* read HTS from register settings */ +static int ov5640_get_HTS(void) +{ + int HTS; + u8 temp = 0; + + HTS = ov5640_read_reg(0x380c, &temp); + HTS = (HTS<<8) + ov5640_read_reg(0x380d, &temp); + return HTS; +} + +/* read VTS from register settings */ +static int ov5640_get_VTS(void) +{ + int VTS; + u8 temp = 0; + + VTS = ov5640_read_reg(0x380e, &temp); + VTS = (VTS<<8) + ov5640_read_reg(0x380f, &temp); + + return VTS; +} + +/* write VTS to registers */ +static int ov5640_set_VTS(int VTS) +{ + int temp; + + temp = VTS & 0xff; + ov5640_write_reg(0x380f, temp); + + temp = VTS>>8; + ov5640_write_reg(0x380e, temp); + return 0; +} + +/* read shutter, in number of line period */ +static int ov5640_get_shutter(void) +{ + int shutter; + u8 regval; + + shutter = (ov5640_read_reg(0x03500, ®val) & 0x0f); + + shutter = (shutter<<8) + ov5640_read_reg(0x3501, ®val); + shutter = (shutter<<4) + (ov5640_read_reg(0x3502, ®val)>>4); + + return shutter; +} + +/* write shutter, in number of line period */ +static int ov5640_set_shutter(int shutter) +{ + int temp; + + shutter = shutter & 0xffff; + temp = shutter & 0x0f; + temp = temp<<4; + ov5640_write_reg(0x3502, temp); + + temp = shutter & 0xfff; + temp = temp>>4; + ov5640_write_reg(0x3501, temp); + + temp = shutter>>12; + ov5640_write_reg(0x3500, temp); + + return 0; +} + +/* read gain, 16 = 1x */ +static int ov5640_get_gain16(void) +{ + int gain16; + u8 regval; + + gain16 = ov5640_read_reg(0x350a, ®val) & 0x03; + gain16 = (gain16<<8) + ov5640_read_reg(0x350b, ®val); + + return gain16; +} + +/* write gain, 16 = 1x */ +static int ov5640_set_gain16(int gain16) +{ + int temp; + + gain16 = gain16 & 0x3ff; + temp = gain16 & 0xff; + + ov5640_write_reg(0x350b, temp); + temp = gain16>>8; + + ov5640_write_reg(0x350a, temp); + return 0; +} + +/* get banding filter value */ +static int ov5640_get_light_freq(void) +{ + int temp, temp1, light_frequency; + u8 regval; + + temp = ov5640_read_reg(0x3c01, ®val); + if (temp & 0x80) { + /* manual */ + temp1 = ov5640_read_reg(0x3c00, ®val); + if (temp1 & 0x04) { + /* 50Hz */ + light_frequency = 50; + } else { + /* 60Hz */ + light_frequency = 60; + } + } else { + /* auto */ + temp1 = ov5640_read_reg(0x3c0c, ®val); + if (temp1 & 0x01) { + /* 50Hz */ + light_frequency = 50; + } else { + /* 60Hz */ + light_frequency = 60; + } + } + + return light_frequency; +} + +static void ov5640_set_bandingfilter(void) +{ + int prev_VTS; + int band_step60, max_band60, band_step50, max_band50; + + /* read preview PCLK */ + prev_sysclk = ov5640_get_sysclk(); + + /* read preview HTS */ + prev_HTS = ov5640_get_HTS(); + + /* read preview VTS */ + prev_VTS = ov5640_get_VTS(); + + /* calculate banding filter */ + /* 60Hz */ + band_step60 = prev_sysclk * 100/prev_HTS * 100/120; + ov5640_write_reg(0x3a0a, (band_step60 >> 8)); + ov5640_write_reg(0x3a0b, (band_step60 & 0xff)); + + max_band60 = (int)((prev_VTS-4)/band_step60); + ov5640_write_reg(0x3a0d, max_band60); + + /* 50Hz */ + band_step50 = prev_sysclk * 100/prev_HTS; + ov5640_write_reg(0x3a08, (band_step50 >> 8)); + ov5640_write_reg(0x3a09, (band_step50 & 0xff)); + + max_band50 = (int)((prev_VTS-4)/band_step50); + ov5640_write_reg(0x3a0e, max_band50); +} + +/* stable in high */ +static int ov5640_set_AE_target(int target) +{ + int fast_high, fast_low; + + AE_low = target * 23 / 25; /* 0.92 */ + AE_high = target * 27 / 25; /* 1.08 */ + fast_high = AE_high << 1; + + if (fast_high > 255) + fast_high = 255; + fast_low = AE_low >> 1; + + ov5640_write_reg(0x3a0f, AE_high); + ov5640_write_reg(0x3a10, AE_low); + ov5640_write_reg(0x3a1b, AE_high); + ov5640_write_reg(0x3a1e, AE_low); + ov5640_write_reg(0x3a11, fast_high); + ov5640_write_reg(0x3a1f, fast_low); + + return 0; +} + +/* enable = 0 to turn off night mode + enable = 1 to turn on night mode */ +static int ov5640_set_night_mode(int enable) +{ + u8 mode; + + ov5640_read_reg(0x3a00, &mode); + + if (enable) { + /* night mode on */ + mode |= 0x04; + ov5640_write_reg(0x3a00, mode); + } else { + /* night mode off */ + mode &= 0xfb; + ov5640_write_reg(0x3a00, mode); + } + + return 0; +} + +/* enable = 0 to turn off AEC/AGC + enable = 1 to turn on AEC/AGC */ +static void ov5640_turn_on_AE_AG(int enable) +{ + u8 ae_ag_ctrl; + + ov5640_read_reg(0x3503, &ae_ag_ctrl); + if (enable) { + /* turn on auto AE/AG */ + ae_ag_ctrl = ae_ag_ctrl & ~(0x03); + } else { + /* turn off AE/AG */ + ae_ag_ctrl = ae_ag_ctrl | 0x03; + } + ov5640_write_reg(0x3503, ae_ag_ctrl); +} + +/* download ov5640 settings to sensor through i2c */ +static int ov5640_download_firmware(struct reg_value *pModeSetting, s32 ArySize) +{ + register u32 Delay_ms = 0; + register u16 RegAddr = 0; + register u8 Mask = 0; + register u8 Val = 0; + u8 RegVal = 0; + int i, retval = 0; + + for (i = 0; i < ArySize; ++i, ++pModeSetting) { + Delay_ms = pModeSetting->u32Delay_ms; + RegAddr = pModeSetting->u16RegAddr; + Val = pModeSetting->u8Val; + Mask = pModeSetting->u8Mask; + + if (Mask) { + retval = ov5640_read_reg(RegAddr, &RegVal); + if (retval < 0) + goto err; + + RegVal &= ~(u8)Mask; + Val &= Mask; + Val |= RegVal; + } + + retval = ov5640_write_reg(RegAddr, Val); + if (retval < 0) + goto err; + + if (Delay_ms) + msleep(Delay_ms); + } +err: + return retval; +} + +static int ov5640_init_mode(void) +{ + struct reg_value *pModeSetting = NULL; + int ArySize = 0, retval = 0; + + ov5640_soft_reset(); + + pModeSetting = ov5640_global_init_setting; + ArySize = ARRAY_SIZE(ov5640_global_init_setting); + retval = ov5640_download_firmware(pModeSetting, ArySize); + if (retval < 0) + goto err; + + pModeSetting = ov5640_init_setting_30fps_VGA; + ArySize = ARRAY_SIZE(ov5640_init_setting_30fps_VGA); + retval = ov5640_download_firmware(pModeSetting, ArySize); + if (retval < 0) + goto err; + + /* change driver capability to 2x according to validation board. + * if the image is not stable, please increase the driver strength. + */ + ov5640_driver_capability(2); + ov5640_set_bandingfilter(); + ov5640_set_AE_target(AE_Target); + ov5640_set_night_mode(night_mode); + + /* skip 9 vysnc: start capture at 10th vsync */ + msleep(300); + + /* turn off night mode */ + night_mode = 0; + ov5640_data.pix.width = 640; + ov5640_data.pix.height = 480; +err: + return retval; +} + +/* change to or back to subsampling mode set the mode directly + * image size below 1280 * 960 is subsampling mode */ +static int ov5640_change_mode_direct(enum ov5640_frame_rate frame_rate, + enum ov5640_mode mode) +{ + struct reg_value *pModeSetting = NULL; + s32 ArySize = 0; + int retval = 0; + + if (mode > ov5640_mode_MAX || mode < ov5640_mode_MIN) { + pr_err("Wrong ov5640 mode detected!\n"); + return -1; + } + + pModeSetting = ov5640_mode_info_data[frame_rate][mode].init_data_ptr; + ArySize = + ov5640_mode_info_data[frame_rate][mode].init_data_size; + + ov5640_data.pix.width = ov5640_mode_info_data[frame_rate][mode].width; + ov5640_data.pix.height = ov5640_mode_info_data[frame_rate][mode].height; + + if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 || + pModeSetting == NULL || ArySize == 0) + return -EINVAL; + + /* set ov5640 to subsampling mode */ + retval = ov5640_download_firmware(pModeSetting, ArySize); + + /* turn on AE AG for subsampling mode, in case the firmware didn't */ + ov5640_turn_on_AE_AG(1); + + /* calculate banding filter */ + ov5640_set_bandingfilter(); + + /* set AE target */ + ov5640_set_AE_target(AE_Target); + + /* update night mode setting */ + ov5640_set_night_mode(night_mode); + + /* skip 9 vysnc: start capture at 10th vsync */ + if (mode == ov5640_mode_XGA_1024_768 && frame_rate == ov5640_30_fps) { + pr_warning("ov5640: actual frame rate of XGA is 22.5fps\n"); + /* 1/22.5 * 9*/ + msleep(400); + return retval; + } + + if (frame_rate == ov5640_15_fps) { + /* 1/15 * 9*/ + msleep(600); + } else if (frame_rate == ov5640_30_fps) { + /* 1/30 * 9*/ + msleep(300); + } + + return retval; +} + +/* change to scaling mode go through exposure calucation + * image size above 1280 * 960 is scaling mode */ +static int ov5640_change_mode_exposure_calc(enum ov5640_frame_rate frame_rate, + enum ov5640_mode mode) +{ + int prev_shutter, prev_gain16, average; + int cap_shutter, cap_gain16; + int cap_sysclk, cap_HTS, cap_VTS; + int light_freq, cap_bandfilt, cap_maxband; + long cap_gain16_shutter; + u8 temp; + struct reg_value *pModeSetting = NULL; + s32 ArySize = 0; + int retval = 0; + + /* check if the input mode and frame rate is valid */ + pModeSetting = + ov5640_mode_info_data[frame_rate][mode].init_data_ptr; + ArySize = + ov5640_mode_info_data[frame_rate][mode].init_data_size; + + ov5640_data.pix.width = + ov5640_mode_info_data[frame_rate][mode].width; + ov5640_data.pix.height = + ov5640_mode_info_data[frame_rate][mode].height; + + if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 || + pModeSetting == NULL || ArySize == 0) + return -EINVAL; + + /* read preview shutter */ + prev_shutter = ov5640_get_shutter(); + + /* read preview gain */ + prev_gain16 = ov5640_get_gain16(); + + /* get average */ + average = ov5640_read_reg(0x56a1, &temp); + + /* turn off night mode for capture */ + ov5640_set_night_mode(0); + + /* turn off overlay */ + ov5640_write_reg(0x3022, 0x06); + + /* Write capture setting */ + retval = ov5640_download_firmware(pModeSetting, ArySize); + if (retval < 0) + goto err; + + /* turn off AE AG when capture image. */ + ov5640_turn_on_AE_AG(0); + + /* read capture VTS */ + cap_VTS = ov5640_get_VTS(); + cap_HTS = ov5640_get_HTS(); + cap_sysclk = ov5640_get_sysclk(); + + /* calculate capture banding filter */ + light_freq = ov5640_get_light_freq(); + if (light_freq == 60) { + /* 60Hz */ + cap_bandfilt = cap_sysclk * 100 / cap_HTS * 100 / 120; + } else { + /* 50Hz */ + cap_bandfilt = cap_sysclk * 100 / cap_HTS; + } + cap_maxband = (int)((cap_VTS - 4)/cap_bandfilt); + /* calculate capture shutter/gain16 */ + if (average > AE_low && average < AE_high) { + /* in stable range */ + cap_gain16_shutter = + prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk * + prev_HTS/cap_HTS * AE_Target / average; + } else { + cap_gain16_shutter = + prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk * + prev_HTS/cap_HTS; + } + + /* gain to shutter */ + if (cap_gain16_shutter < (cap_bandfilt * 16)) { + /* shutter < 1/100 */ + cap_shutter = cap_gain16_shutter/16; + if (cap_shutter < 1) + cap_shutter = 1; + cap_gain16 = cap_gain16_shutter/cap_shutter; + if (cap_gain16 < 16) + cap_gain16 = 16; + } else { + if (cap_gain16_shutter > (cap_bandfilt*cap_maxband*16)) { + /* exposure reach max */ + cap_shutter = cap_bandfilt*cap_maxband; + cap_gain16 = cap_gain16_shutter / cap_shutter; + } else { + /* 1/100 < cap_shutter =< max, cap_shutter = n/100 */ + cap_shutter = + ((int)(cap_gain16_shutter/16/cap_bandfilt)) + * cap_bandfilt; + cap_gain16 = cap_gain16_shutter / cap_shutter; + } + } + + /* write capture gain */ + ov5640_set_gain16(cap_gain16); + + /* write capture shutter */ + if (cap_shutter > (cap_VTS - 4)) { + cap_VTS = cap_shutter + 4; + ov5640_set_VTS(cap_VTS); + } + + ov5640_set_shutter(cap_shutter); + + /* skip 2 vysnc: start capture at 3rd vsync + * frame rate of QSXGA and 1080P is 7.5fps: 1/7.5 * 2 + */ + pr_warning("ov5640: the actual frame rate of %s is 7.5fps\n", + mode == ov5640_mode_1080P_1920_1080 ? "1080P" : "QSXGA"); + msleep(267); +err: + return retval; +} + +static int ov5640_change_mode(enum ov5640_frame_rate frame_rate, + enum ov5640_mode mode) +{ + int retval = 0; + + if (mode > ov5640_mode_MAX || mode < ov5640_mode_MIN) { + pr_err("Wrong ov5640 mode detected!\n"); + return -1; + } + + if (mode == ov5640_mode_1080P_1920_1080 || + mode == ov5640_mode_QSXGA_2592_1944) { + /* change to scaling mode go through exposure calucation + * image size above 1280 * 960 is scaling mode */ + retval = ov5640_change_mode_exposure_calc(frame_rate, mode); + } else { + /* change back to subsampling modem download firmware directly + * image size below 1280 * 960 is subsampling mode */ + retval = ov5640_change_mode_direct(frame_rate, mode); + } + + return retval; +} + +/* --------------- IOCTL functions from v4l2_int_ioctl_desc --------------- */ + +static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p) +{ + if (s == NULL) { + pr_err(" ERROR!! no slave device set!\n"); + return -1; + } + + memset(p, 0, sizeof(*p)); + p->u.bt656.clock_curr = ov5640_data.mclk; + pr_debug(" clock_curr=mclk=%d\n", ov5640_data.mclk); + p->if_type = V4L2_IF_TYPE_BT656; + p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT; + p->u.bt656.clock_min = OV5640_XCLK_MIN; + p->u.bt656.clock_max = OV5640_XCLK_MAX; + p->u.bt656.bt_sync_correct = 1; /* Indicate external vsync */ + + return 0; +} + +/*! + * ioctl_s_power - V4L2 sensor interface handler for VIDIOC_S_POWER ioctl + * @s: pointer to standard V4L2 device structure + * @on: indicates power mode (on or off) + * + * Turns the power on or off, depending on the value of on and returns the + * appropriate error code. + */ +static int ioctl_s_power(struct v4l2_int_device *s, int on) +{ + struct sensor_data *sensor = s->priv; + + if (on && !sensor->on) { + if (io_regulator) + if (regulator_enable(io_regulator) != 0) + return -EIO; + if (core_regulator) + if (regulator_enable(core_regulator) != 0) + return -EIO; + if (analog_regulator) + if (regulator_enable(analog_regulator) != 0) + return -EIO; + /* Make sure power on */ + ov5640_power_down(0); + } else if (!on && sensor->on) { + if (analog_regulator) + regulator_disable(analog_regulator); + if (core_regulator) + regulator_disable(core_regulator); + if (io_regulator) + regulator_disable(io_regulator); + + ov5640_power_down(1); +} + + sensor->on = on; + + return 0; +} + +/*! + * ioctl_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl + * @s: pointer to standard V4L2 device structure + * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure + * + * Returns the sensor's video CAPTURE parameters. + */ +static int ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) +{ + struct sensor_data *sensor = s->priv; + struct v4l2_captureparm *cparm = &a->parm.capture; + int ret = 0; + + switch (a->type) { + /* This is the only case currently handled. */ + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + memset(a, 0, sizeof(*a)); + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + cparm->capability = sensor->streamcap.capability; + cparm->timeperframe = sensor->streamcap.timeperframe; + cparm->capturemode = sensor->streamcap.capturemode; + ret = 0; + break; + + /* These are all the possible cases. */ + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + ret = -EINVAL; + break; + + default: + pr_debug(" type is unknown - %d\n", a->type); + ret = -EINVAL; + break; + } + + return ret; +} + +/*! + * ioctl_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl + * @s: pointer to standard V4L2 device structure + * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure + * + * Configures the sensor to use the input parameters, if possible. If + * not possible, reverts to the old parameters and returns the + * appropriate error code. + */ +static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) +{ + struct sensor_data *sensor = s->priv; + struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe; + u32 tgt_fps; /* target frames per secound */ + enum ov5640_frame_rate frame_rate; + int ret = 0; + + /* Make sure power on */ + ov5640_power_down(0); + + switch (a->type) { + /* This is the only case currently handled. */ + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + /* Check that the new frame rate is allowed. */ + if ((timeperframe->numerator == 0) || + (timeperframe->denominator == 0)) { + timeperframe->denominator = DEFAULT_FPS; + timeperframe->numerator = 1; + } + + tgt_fps = timeperframe->denominator / + timeperframe->numerator; + + if (tgt_fps > MAX_FPS) { + timeperframe->denominator = MAX_FPS; + timeperframe->numerator = 1; + } else if (tgt_fps < MIN_FPS) { + timeperframe->denominator = MIN_FPS; + timeperframe->numerator = 1; + } + + /* Actual frame rate we use */ + tgt_fps = timeperframe->denominator / + timeperframe->numerator; + + if (tgt_fps == 15) + frame_rate = ov5640_15_fps; + else if (tgt_fps == 30) + frame_rate = ov5640_30_fps; + else { + pr_err(" The camera frame rate is not supported!\n"); + return -EINVAL; + } + + ret = ov5640_change_mode(frame_rate, + a->parm.capture.capturemode); + if (ret < 0) + return ret; + + sensor->streamcap.timeperframe = *timeperframe; + sensor->streamcap.capturemode = a->parm.capture.capturemode; + + break; + + /* These are all the possible cases. */ + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + pr_debug(" type is not " \ + "V4L2_BUF_TYPE_VIDEO_CAPTURE but %d\n", + a->type); + ret = -EINVAL; + break; + + default: + pr_debug(" type is unknown - %d\n", a->type); + ret = -EINVAL; + break; + } + + return ret; +} + +/*! + * ioctl_g_fmt_cap - V4L2 sensor interface handler for ioctl_g_fmt_cap + * @s: pointer to standard V4L2 device structure + * @f: pointer to standard V4L2 v4l2_format structure + * + * Returns the sensor's current pixel format in the v4l2_format + * parameter. + */ +static int ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) +{ + struct sensor_data *sensor = s->priv; + + f->fmt.pix = sensor->pix; + + return 0; +} + +/*! + * ioctl_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl + * @s: pointer to standard V4L2 device structure + * @vc: standard V4L2 VIDIOC_G_CTRL ioctl structure + * + * If the requested control is supported, returns the control's current + * value from the video_control[] array. Otherwise, returns -EINVAL + * if the control is not supported. + */ +static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) +{ + int ret = 0; + + switch (vc->id) { + case V4L2_CID_BRIGHTNESS: + vc->value = ov5640_data.brightness; + break; + case V4L2_CID_HUE: + vc->value = ov5640_data.hue; + break; + case V4L2_CID_CONTRAST: + vc->value = ov5640_data.contrast; + break; + case V4L2_CID_SATURATION: + vc->value = ov5640_data.saturation; + break; + case V4L2_CID_RED_BALANCE: + vc->value = ov5640_data.red; + break; + case V4L2_CID_BLUE_BALANCE: + vc->value = ov5640_data.blue; + break; + case V4L2_CID_EXPOSURE: + vc->value = ov5640_data.ae_mode; + break; + default: + ret = -EINVAL; + } + + return ret; +} + +/*! + * ioctl_s_ctrl - V4L2 sensor interface handler for VIDIOC_S_CTRL ioctl + * @s: pointer to standard V4L2 device structure + * @vc: standard V4L2 VIDIOC_S_CTRL ioctl structure + * + * If the requested control is supported, sets the control's current + * value in HW (and updates the video_control[] array). Otherwise, + * returns -EINVAL if the control is not supported. + */ +static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) +{ + int retval = 0; + + pr_debug("In ov5640:ioctl_s_ctrl %d\n", + vc->id); + + switch (vc->id) { + case V4L2_CID_BRIGHTNESS: + break; + case V4L2_CID_CONTRAST: + break; + case V4L2_CID_SATURATION: + break; + case V4L2_CID_HUE: + break; + case V4L2_CID_AUTO_WHITE_BALANCE: + break; + case V4L2_CID_DO_WHITE_BALANCE: + break; + case V4L2_CID_RED_BALANCE: + break; + case V4L2_CID_BLUE_BALANCE: + break; + case V4L2_CID_GAMMA: + break; + case V4L2_CID_EXPOSURE: + break; + case V4L2_CID_AUTOGAIN: + break; + case V4L2_CID_GAIN: + break; + case V4L2_CID_HFLIP: + break; + case V4L2_CID_VFLIP: + break; + default: + retval = -EPERM; + break; + } + + return retval; +} + +/*! + * ioctl_enum_framesizes - V4L2 sensor interface handler for + * VIDIOC_ENUM_FRAMESIZES ioctl + * @s: pointer to standard V4L2 device structure + * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure + * + * Return 0 if successful, otherwise -EINVAL. + */ +static int ioctl_enum_framesizes(struct v4l2_int_device *s, + struct v4l2_frmsizeenum *fsize) +{ + if (fsize->index > ov5640_mode_MAX) + return -EINVAL; + + fsize->pixel_format = ov5640_data.pix.pixelformat; + fsize->discrete.width = + max(ov5640_mode_info_data[0][fsize->index].width, + ov5640_mode_info_data[1][fsize->index].width); + fsize->discrete.height = + max(ov5640_mode_info_data[0][fsize->index].height, + ov5640_mode_info_data[1][fsize->index].height); + return 0; +} + +/*! + * ioctl_enum_frameintervals - V4L2 sensor interface handler for + * VIDIOC_ENUM_FRAMEINTERVALS ioctl + * @s: pointer to standard V4L2 device structure + * @fival: standard V4L2 VIDIOC_ENUM_FRAMEINTERVALS ioctl structure + * + * Return 0 if successful, otherwise -EINVAL. + */ +static int ioctl_enum_frameintervals(struct v4l2_int_device *s, + struct v4l2_frmivalenum *fival) +{ + int i, j, count; + + if (fival->index < 0 || fival->index > ov5640_mode_MAX) + return -EINVAL; + + if (fival->width == 0 || fival->height == 0 || + fival->pixel_format == 0) { + pr_warning("Please assign pixelformat, width and height.\n"); + return -EINVAL; + } + + fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; + fival->discrete.numerator = 1; + + count = 0; + for (i = 0; i < ARRAY_SIZE(ov5640_mode_info_data); i++) { + for (j = 0; j < (ov5640_mode_MAX + 1); j++) { + if (fival->pixel_format == ov5640_data.pix.pixelformat + && fival->width == ov5640_mode_info_data[i][j].width + && fival->height == ov5640_mode_info_data[i][j].height + && ov5640_mode_info_data[i][j].init_data_ptr != NULL) { + count++; + } + if (fival->index == (count - 1)) { + fival->discrete.denominator = + ov5640_framerates[i]; + return 0; + } + } + } + + return -EINVAL; +} + +/*! + * ioctl_g_chip_ident - V4L2 sensor interface handler for + * VIDIOC_DBG_G_CHIP_IDENT ioctl + * @s: pointer to standard V4L2 device structure + * @id: pointer to int + * + * Return 0. + */ +static int ioctl_g_chip_ident(struct v4l2_int_device *s, int *id) +{ + ((struct v4l2_dbg_chip_ident *)id)->match.type = + V4L2_CHIP_MATCH_I2C_DRIVER; + strcpy(((struct v4l2_dbg_chip_ident *)id)->match.name, "ov5640_camera"); + + return 0; +} + +/*! + * ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT + * @s: pointer to standard V4L2 device structure + */ +static int ioctl_init(struct v4l2_int_device *s) +{ + + return 0; +} + +/*! + * ioctl_enum_fmt_cap - V4L2 sensor interface handler for VIDIOC_ENUM_FMT + * @s: pointer to standard V4L2 device structure + * @fmt: pointer to standard V4L2 fmt description structure + * + * Return 0. + */ +static int ioctl_enum_fmt_cap(struct v4l2_int_device *s, + struct v4l2_fmtdesc *fmt) +{ + if (fmt->index > ov5640_mode_MAX) + return -EINVAL; + + fmt->pixelformat = ov5640_data.pix.pixelformat; + + return 0; +} + +/*! + * ioctl_dev_init - V4L2 sensor interface handler for vidioc_int_dev_init_num + * @s: pointer to standard V4L2 device structure + * + * Initialise the device when slave attaches to the master. + */ +static int ioctl_dev_init(struct v4l2_int_device *s) +{ + struct sensor_data *sensor = s->priv; + u32 tgt_xclk; /* target xclk */ + u32 tgt_fps; /* target frames per secound */ + enum ov5640_frame_rate frame_rate; + int ret; + + ov5640_data.on = true; + + /* mclk */ + tgt_xclk = ov5640_data.mclk; + tgt_xclk = min(tgt_xclk, (u32)OV5640_XCLK_MAX); + tgt_xclk = max(tgt_xclk, (u32)OV5640_XCLK_MIN); + ov5640_data.mclk = tgt_xclk; + + pr_debug(" Setting mclk to %d MHz\n", tgt_xclk / 1000000); + clk_set_rate(ov5640_data.sensor_clk, ov5640_data.mclk); + + /* Default camera frame rate is set in probe */ + tgt_fps = sensor->streamcap.timeperframe.denominator / + sensor->streamcap.timeperframe.numerator; + + if (tgt_fps == 15) + frame_rate = ov5640_15_fps; + else if (tgt_fps == 30) + frame_rate = ov5640_30_fps; + else + return -EINVAL; /* Only support 15fps or 30fps now. */ + + ret = ov5640_init_mode(); + return ret; +} + +/*! + * ioctl_dev_exit - V4L2 sensor interface handler for vidioc_int_dev_exit_num + * @s: pointer to standard V4L2 device structure + * + * Delinitialise the device when slave detaches to the master. + */ +static int ioctl_dev_exit(struct v4l2_int_device *s) +{ + return 0; +} + +/*! + * This structure defines all the ioctls for this module and links them to the + * enumeration. + */ +static struct v4l2_int_ioctl_desc ov5640_ioctl_desc[] = { + { vidioc_int_dev_init_num, + (v4l2_int_ioctl_func *)ioctl_dev_init }, + { vidioc_int_dev_exit_num, + ioctl_dev_exit}, + { vidioc_int_s_power_num, + (v4l2_int_ioctl_func *)ioctl_s_power }, + { vidioc_int_g_ifparm_num, + (v4l2_int_ioctl_func *)ioctl_g_ifparm }, + { vidioc_int_init_num, + (v4l2_int_ioctl_func *)ioctl_init }, + { vidioc_int_enum_fmt_cap_num, + (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap }, + { vidioc_int_g_fmt_cap_num, + (v4l2_int_ioctl_func *)ioctl_g_fmt_cap }, + { vidioc_int_g_parm_num, + (v4l2_int_ioctl_func *)ioctl_g_parm }, + { vidioc_int_s_parm_num, + (v4l2_int_ioctl_func *)ioctl_s_parm }, + { vidioc_int_g_ctrl_num, + (v4l2_int_ioctl_func *)ioctl_g_ctrl }, + { vidioc_int_s_ctrl_num, + (v4l2_int_ioctl_func *)ioctl_s_ctrl }, + { vidioc_int_enum_framesizes_num, + (v4l2_int_ioctl_func *)ioctl_enum_framesizes }, + { vidioc_int_enum_frameintervals_num, + (v4l2_int_ioctl_func *)ioctl_enum_frameintervals }, + { vidioc_int_g_chip_ident_num, + (v4l2_int_ioctl_func *)ioctl_g_chip_ident }, +}; + +static struct v4l2_int_slave ov5640_slave = { + .ioctls = ov5640_ioctl_desc, + .num_ioctls = ARRAY_SIZE(ov5640_ioctl_desc), +}; + +static struct v4l2_int_device ov5640_int_device = { + .module = THIS_MODULE, + .name = "ov564x", + .type = v4l2_int_type_slave, + .u = { + .slave = &ov5640_slave, + }, +}; + +/*! + * ov5640 I2C probe function + * + * @param adapter struct i2c_adapter * + * @return Error code indicating success or failure + */ +static int ov5640_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pinctrl *pinctrl; + struct device *dev = &client->dev; + int retval; + u8 chip_id_high, chip_id_low; + + /* ov5640 pinctrl */ + pinctrl = devm_pinctrl_get_select_default(dev); + if (IS_ERR(pinctrl)) { + dev_err(dev, "setup pinctrl failed\n"); + return PTR_ERR(pinctrl); + } + + /* request power down pin */ + pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0); + if (!gpio_is_valid(pwn_gpio)) { + dev_err(dev, "no sensor pwdn pin available\n"); + return -ENODEV; + } + retval = devm_gpio_request_one(dev, pwn_gpio, GPIOF_OUT_INIT_HIGH, + "ov5640_pwdn"); + if (retval < 0) + return retval; + + /* request reset pin */ + rst_gpio = of_get_named_gpio(dev->of_node, "rst-gpios", 0); + if (!gpio_is_valid(rst_gpio)) { + dev_err(dev, "no sensor reset pin available\n"); + return -EINVAL; + } + retval = devm_gpio_request_one(dev, rst_gpio, GPIOF_OUT_INIT_HIGH, + "ov5640_reset"); + if (retval < 0) + return retval; + + /* Set initial values for the sensor struct. */ + memset(&ov5640_data, 0, sizeof(ov5640_data)); + ov5640_data.sensor_clk = devm_clk_get(dev, "csi_mclk"); + if (IS_ERR(ov5640_data.sensor_clk)) { + dev_err(dev, "get mclk failed\n"); + return PTR_ERR(ov5640_data.sensor_clk); + } + + retval = of_property_read_u32(dev->of_node, "mclk", + &ov5640_data.mclk); + if (retval) { + dev_err(dev, "mclk frequency is invalid\n"); + return retval; + } + + retval = of_property_read_u32(dev->of_node, "mclk_source", + (u32 *) &(ov5640_data.mclk_source)); + if (retval) { + dev_err(dev, "mclk_source invalid\n"); + return retval; + } + + retval = of_property_read_u32(dev->of_node, "csi_id", + &(ov5640_data.csi)); + if (retval) { + dev_err(dev, "csi_id invalid\n"); + return retval; + } + + clk_prepare_enable(ov5640_data.sensor_clk); + + ov5640_data.io_init = ov5640_reset; + ov5640_data.i2c_client = client; + ov5640_data.pix.pixelformat = V4L2_PIX_FMT_YUYV; + ov5640_data.pix.width = 640; + ov5640_data.pix.height = 480; + ov5640_data.streamcap.capability = V4L2_MODE_HIGHQUALITY | + V4L2_CAP_TIMEPERFRAME; + ov5640_data.streamcap.capturemode = 0; + ov5640_data.streamcap.timeperframe.denominator = DEFAULT_FPS; + ov5640_data.streamcap.timeperframe.numerator = 1; + + ov5640_regulator_enable(&client->dev); + + ov5640_reset(); + + ov5640_power_down(0); + + retval = ov5640_read_reg(OV5640_CHIP_ID_HIGH_BYTE, &chip_id_high); + if (retval < 0 || chip_id_high != 0x56) { + clk_disable_unprepare(ov5640_data.sensor_clk); + pr_warning("camera ov5640 is not found\n"); + return -ENODEV; + } + retval = ov5640_read_reg(OV5640_CHIP_ID_LOW_BYTE, &chip_id_low); + if (retval < 0 || chip_id_low != 0x40) { + clk_disable_unprepare(ov5640_data.sensor_clk); + pr_warning("camera ov5640 is not found\n"); + return -ENODEV; + } + + ov5640_power_down(1); + + clk_disable_unprepare(ov5640_data.sensor_clk); + + ov5640_int_device.priv = &ov5640_data; + retval = v4l2_int_device_register(&ov5640_int_device); + + pr_info("camera ov5640 is found\n"); + return retval; +} + +/*! + * ov5640 I2C detach function + * + * @param client struct i2c_client * + * @return Error code indicating success or failure + */ +static int ov5640_remove(struct i2c_client *client) +{ + v4l2_int_device_unregister(&ov5640_int_device); + + if (analog_regulator) + regulator_disable(analog_regulator); + + if (core_regulator) + regulator_disable(core_regulator); + + if (io_regulator) + regulator_disable(io_regulator); + + return 0; +} + +module_i2c_driver(ov5640_i2c_driver); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("OV5640 Camera Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("1.0"); +MODULE_ALIAS("CSI"); diff --git a/drivers/media/platform/mxc/capture/ov5640_mipi.c b/drivers/media/platform/mxc/capture/ov5640_mipi.c new file mode 100644 index 000000000000..ec813a6268ce --- /dev/null +++ b/drivers/media/platform/mxc/capture/ov5640_mipi.c @@ -0,0 +1,2142 @@ +/* + * Copyright (C) 2011-2015 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "v4l2-int-device.h" +#include "mxc_v4l2_capture.h" + +#define OV5640_VOLTAGE_ANALOG 2800000 +#define OV5640_VOLTAGE_DIGITAL_CORE 1500000 +#define OV5640_VOLTAGE_DIGITAL_IO 1800000 + +#define MIN_FPS 15 +#define MAX_FPS 30 +#define DEFAULT_FPS 30 + +#define OV5640_XCLK_MIN 6000000 +#define OV5640_XCLK_MAX 24000000 + +#define OV5640_CHIP_ID_HIGH_BYTE 0x300A +#define OV5640_CHIP_ID_LOW_BYTE 0x300B + +enum ov5640_mode { + ov5640_mode_MIN = 0, + ov5640_mode_VGA_640_480 = 0, + ov5640_mode_QVGA_320_240 = 1, + ov5640_mode_NTSC_720_480 = 2, + ov5640_mode_PAL_720_576 = 3, + ov5640_mode_720P_1280_720 = 4, + ov5640_mode_1080P_1920_1080 = 5, + ov5640_mode_QSXGA_2592_1944 = 6, + ov5640_mode_QCIF_176_144 = 7, + ov5640_mode_XGA_1024_768 = 8, + ov5640_mode_MAX = 8, + ov5640_mode_INIT = 0xff, /*only for sensor init*/ +}; + +enum ov5640_frame_rate { + ov5640_15_fps, + ov5640_30_fps +}; + +static int ov5640_framerates[] = { + [ov5640_15_fps] = 15, + [ov5640_30_fps] = 30, +}; + +/* image size under 1280 * 960 are SUBSAMPLING + * image size upper 1280 * 960 are SCALING + */ +enum ov5640_downsize_mode { + SUBSAMPLING, + SCALING, +}; + +struct reg_value { + u16 u16RegAddr; + u8 u8Val; + u8 u8Mask; + u32 u32Delay_ms; +}; + +struct ov5640_mode_info { + enum ov5640_mode mode; + enum ov5640_downsize_mode dn_mode; + u32 width; + u32 height; + struct reg_value *init_data_ptr; + u32 init_data_size; +}; + +/*! + * Maintains the information on the current state of the sesor. + */ +static struct sensor_data ov5640_data; +static int pwn_gpio, rst_gpio; + +static struct reg_value ov5640_init_setting_30fps_VGA[] = { + + {0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0}, + {0x3103, 0x03, 0, 0}, {0x3017, 0x00, 0, 0}, {0x3018, 0x00, 0, 0}, + {0x3034, 0x18, 0, 0}, {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, + {0x3037, 0x13, 0, 0}, {0x3108, 0x01, 0, 0}, {0x3630, 0x36, 0, 0}, + {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0}, + {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0}, + {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0}, + {0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0}, + {0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0}, + {0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0}, + {0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0}, + {0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0}, + {0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0}, + {0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0}, + {0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, + {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0}, + {0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x300e, 0x45, 0, 0}, {0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0}, + {0x501f, 0x00, 0, 0}, {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, + {0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x4837, 0x0a, 0, 0}, {0x4800, 0x04, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0}, + {0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0}, + {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0}, + {0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0}, + {0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0}, + {0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0}, + {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, + {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, + {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, + {0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, + {0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0}, + {0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0}, + {0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0}, + {0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0}, + {0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0}, + {0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0}, + {0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0}, + {0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0}, + {0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0}, + {0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0}, + {0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0}, + {0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0}, + {0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0}, + {0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0}, + {0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0}, + {0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0}, + {0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0}, + {0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0}, + {0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0}, + {0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0}, + {0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0}, + {0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0}, + {0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0}, + {0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0}, + {0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0}, + {0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0}, + {0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0}, + {0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0}, + {0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0}, + {0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0}, + {0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0}, + {0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0}, + {0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0}, + {0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0}, + {0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0}, + {0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0}, + {0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0}, + {0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0}, + {0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0}, + {0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300}, +}; + +static struct reg_value ov5640_setting_30fps_VGA_640_480[] = { + + {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, + {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x04, 0, 0}, {0x380f, 0x38, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x0e, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3503, 0x00, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_VGA_640_480[] = { + {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, + {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_XGA_1024_768[] = { + + {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, + {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x04, 0, 0}, {0x380f, 0x38, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x0e, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3503, 0x00, 0, 0}, + {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x03, 0, 0}, + {0x380b, 0x00, 0, 0}, {0x3035, 0x12, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_XGA_1024_768[] = { + {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, + {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3808, 0x04, 0, 0}, + {0x3809, 0x00, 0, 0}, {0x380a, 0x03, 0, 0}, {0x380b, 0x00, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_QVGA_320_240[] = { + {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0}, + {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_QVGA_320_240[] = { + {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0}, + {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_QCIF_176_144[] = { + {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, {0x380a, 0x00, 0, 0}, + {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; +static struct reg_value ov5640_setting_15fps_QCIF_176_144[] = { + {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, {0x380a, 0x00, 0, 0}, + {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_NTSC_720_480[] = { + {0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x01, 0, 0}, + {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_NTSC_720_480[] = { + {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x01, 0, 0}, + {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_PAL_720_576[] = { + {0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x02, 0, 0}, + {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_PAL_720_576[] = { + {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x02, 0, 0}, + {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_720P_1280_720[] = { + {0x3008, 0x42, 0, 0}, + {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0}, + {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0}, + {0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0}, + {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, + {0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0}, + {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0}, + {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x02, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, + {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, {0x4005, 0x1a, 0, 0}, + {0x3008, 0x02, 0, 0}, {0x3503, 0, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_720P_1280_720[] = { + {0x3035, 0x41, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0}, + {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0}, + {0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0}, + {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, + {0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0}, + {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0}, + {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x02, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, + {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_1080P_1920_1080[] = { + {0x3008, 0x42, 0, 0}, + {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, {0x3814, 0x11, 0, 0}, + {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0}, + {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, + {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0}, + {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, + {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, + {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, {0x3035, 0x11, 0, 0}, + {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0}, + {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0}, + {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, {0x3808, 0x07, 0, 0}, + {0x3809, 0x80, 0, 0}, {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0}, + {0x380c, 0x09, 0, 0}, {0x380d, 0xc4, 0, 0}, {0x380e, 0x04, 0, 0}, + {0x380f, 0x60, 0, 0}, {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0}, + {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0}, + {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0}, + {0x3a15, 0x60, 0, 0}, {0x4713, 0x02, 0, 0}, {0x4407, 0x04, 0, 0}, + {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0}, + {0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0}, + {0x3503, 0, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_1080P_1920_1080[] = { + {0x3008, 0x42, 0, 0}, + {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, {0x3814, 0x11, 0, 0}, + {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0}, + {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, + {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0}, + {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, + {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, + {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x54, 0, 1}, {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0}, + {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0}, + {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, {0x3808, 0x07, 0, 0}, + {0x3809, 0x80, 0, 0}, {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0}, + {0x380c, 0x09, 0, 0}, {0x380d, 0xc4, 0, 0}, {0x380e, 0x04, 0, 0}, + {0x380f, 0x60, 0, 0}, {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0}, + {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0}, + {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0}, + {0x3a15, 0x60, 0, 0}, {0x4713, 0x02, 0, 0}, {0x4407, 0x04, 0, 0}, + {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0}, + {0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3503, 0, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = { + {0x4202, 0x0f, 0, 0}, /* stream off the sensor */ + {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, /*disable flip*/ + {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, {0x3814, 0x11, 0, 0}, + {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0}, + {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, + {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0}, + {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, + {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, + {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70}, + {0x4202, 0x00, 0, 0}, /* stream on the sensor */ +}; + +static struct ov5640_mode_info ov5640_mode_info_data[2][ov5640_mode_MAX + 1] = { + { + {ov5640_mode_VGA_640_480, SUBSAMPLING, 640, 480, + ov5640_setting_15fps_VGA_640_480, + ARRAY_SIZE(ov5640_setting_15fps_VGA_640_480)}, + {ov5640_mode_QVGA_320_240, SUBSAMPLING, 320, 240, + ov5640_setting_15fps_QVGA_320_240, + ARRAY_SIZE(ov5640_setting_15fps_QVGA_320_240)}, + {ov5640_mode_NTSC_720_480, SUBSAMPLING, 720, 480, + ov5640_setting_15fps_NTSC_720_480, + ARRAY_SIZE(ov5640_setting_15fps_NTSC_720_480)}, + {ov5640_mode_PAL_720_576, SUBSAMPLING, 720, 576, + ov5640_setting_15fps_PAL_720_576, + ARRAY_SIZE(ov5640_setting_15fps_PAL_720_576)}, + {ov5640_mode_720P_1280_720, SUBSAMPLING, 1280, 720, + ov5640_setting_15fps_720P_1280_720, + ARRAY_SIZE(ov5640_setting_15fps_720P_1280_720)}, + {ov5640_mode_1080P_1920_1080, SCALING, 1920, 1080, + ov5640_setting_15fps_1080P_1920_1080, + ARRAY_SIZE(ov5640_setting_15fps_1080P_1920_1080)}, + {ov5640_mode_QSXGA_2592_1944, SCALING, 2592, 1944, + ov5640_setting_15fps_QSXGA_2592_1944, + ARRAY_SIZE(ov5640_setting_15fps_QSXGA_2592_1944)}, + {ov5640_mode_QCIF_176_144, SUBSAMPLING, 176, 144, + ov5640_setting_15fps_QCIF_176_144, + ARRAY_SIZE(ov5640_setting_15fps_QCIF_176_144)}, + {ov5640_mode_XGA_1024_768, SUBSAMPLING, 1024, 768, + ov5640_setting_15fps_XGA_1024_768, + ARRAY_SIZE(ov5640_setting_15fps_XGA_1024_768)}, + }, + { + {ov5640_mode_VGA_640_480, SUBSAMPLING, 640, 480, + ov5640_setting_30fps_VGA_640_480, + ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480)}, + {ov5640_mode_QVGA_320_240, SUBSAMPLING, 320, 240, + ov5640_setting_30fps_QVGA_320_240, + ARRAY_SIZE(ov5640_setting_30fps_QVGA_320_240)}, + {ov5640_mode_NTSC_720_480, SUBSAMPLING, 720, 480, + ov5640_setting_30fps_NTSC_720_480, + ARRAY_SIZE(ov5640_setting_30fps_NTSC_720_480)}, + {ov5640_mode_PAL_720_576, SUBSAMPLING, 720, 576, + ov5640_setting_30fps_PAL_720_576, + ARRAY_SIZE(ov5640_setting_30fps_PAL_720_576)}, + {ov5640_mode_720P_1280_720, SUBSAMPLING, 1280, 720, + ov5640_setting_30fps_720P_1280_720, + ARRAY_SIZE(ov5640_setting_30fps_720P_1280_720)}, + {ov5640_mode_1080P_1920_1080, SCALING, 1920, 1080, + ov5640_setting_30fps_1080P_1920_1080, + ARRAY_SIZE(ov5640_setting_30fps_1080P_1920_1080)}, + {ov5640_mode_QSXGA_2592_1944, -1, 0, 0, NULL, 0}, + {ov5640_mode_QCIF_176_144, SUBSAMPLING, 176, 144, + ov5640_setting_30fps_QCIF_176_144, + ARRAY_SIZE(ov5640_setting_30fps_QCIF_176_144)}, + {ov5640_mode_XGA_1024_768, SUBSAMPLING, 1024, 768, + ov5640_setting_30fps_XGA_1024_768, + ARRAY_SIZE(ov5640_setting_30fps_XGA_1024_768)}, + }, +}; + +static struct regulator *io_regulator; +static struct regulator *core_regulator; +static struct regulator *analog_regulator; +static struct regulator *gpo_regulator; + +static int ov5640_probe(struct i2c_client *adapter, + const struct i2c_device_id *device_id); +static int ov5640_remove(struct i2c_client *client); + +static s32 ov5640_read_reg(u16 reg, u8 *val); +static s32 ov5640_write_reg(u16 reg, u8 val); + +static const struct i2c_device_id ov5640_id[] = { + {"ov564x_mipi", 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, ov5640_id); + +static struct i2c_driver ov5640_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "ov564x_mipi", + }, + .probe = ov5640_probe, + .remove = ov5640_remove, + .id_table = ov5640_id, +}; + +static void ov5640_standby(s32 enable) +{ + if (enable) + gpio_set_value(pwn_gpio, 1); + else + gpio_set_value(pwn_gpio, 0); + + msleep(2); +} + +static void ov5640_reset(void) +{ + /* camera reset */ + gpio_set_value(rst_gpio, 1); + + /* camera power dowmn */ + gpio_set_value(pwn_gpio, 1); + msleep(5); + + gpio_set_value(pwn_gpio, 0); + msleep(5); + + gpio_set_value(rst_gpio, 0); + msleep(1); + + gpio_set_value(rst_gpio, 1); + msleep(5); + + gpio_set_value(pwn_gpio, 1); +} + +static int ov5640_power_on(struct device *dev) +{ + int ret = 0; + + io_regulator = devm_regulator_get(dev, "DOVDD"); + if (!IS_ERR(io_regulator)) { + regulator_set_voltage(io_regulator, + OV5640_VOLTAGE_DIGITAL_IO, + OV5640_VOLTAGE_DIGITAL_IO); + ret = regulator_enable(io_regulator); + if (ret) { + pr_err("%s:io set voltage error\n", __func__); + return ret; + } else { + dev_dbg(dev, + "%s:io set voltage ok\n", __func__); + } + } else { + pr_err("%s: cannot get io voltage error\n", __func__); + io_regulator = NULL; + } + + core_regulator = devm_regulator_get(dev, "DVDD"); + if (!IS_ERR(core_regulator)) { + regulator_set_voltage(core_regulator, + OV5640_VOLTAGE_DIGITAL_CORE, + OV5640_VOLTAGE_DIGITAL_CORE); + ret = regulator_enable(core_regulator); + if (ret) { + pr_err("%s:core set voltage error\n", __func__); + return ret; + } else { + dev_dbg(dev, + "%s:core set voltage ok\n", __func__); + } + } else { + core_regulator = NULL; + pr_err("%s: cannot get core voltage error\n", __func__); + } + + analog_regulator = devm_regulator_get(dev, "AVDD"); + if (!IS_ERR(analog_regulator)) { + regulator_set_voltage(analog_regulator, + OV5640_VOLTAGE_ANALOG, + OV5640_VOLTAGE_ANALOG); + ret = regulator_enable(analog_regulator); + if (ret) { + pr_err("%s:analog set voltage error\n", + __func__); + return ret; + } else { + dev_dbg(dev, + "%s:analog set voltage ok\n", __func__); + } + } else { + analog_regulator = NULL; + pr_err("%s: cannot get analog voltage error\n", __func__); + } + + return ret; +} + +static s32 ov5640_write_reg(u16 reg, u8 val) +{ + u8 au8Buf[3] = {0}; + + au8Buf[0] = reg >> 8; + au8Buf[1] = reg & 0xff; + au8Buf[2] = val; + + if (i2c_master_send(ov5640_data.i2c_client, au8Buf, 3) < 0) { + pr_err("%s:write reg error:reg=%x,val=%x\n", + __func__, reg, val); + return -1; + } + + return 0; +} + +static s32 ov5640_read_reg(u16 reg, u8 *val) +{ + u8 au8RegBuf[2] = {0}; + u8 u8RdVal = 0; + + au8RegBuf[0] = reg >> 8; + au8RegBuf[1] = reg & 0xff; + + if (2 != i2c_master_send(ov5640_data.i2c_client, au8RegBuf, 2)) { + pr_err("%s:write reg error:reg=%x\n", + __func__, reg); + return -1; + } + + if (1 != i2c_master_recv(ov5640_data.i2c_client, &u8RdVal, 1)) { + pr_err("%s:read reg error:reg=%x,val=%x\n", + __func__, reg, u8RdVal); + return -1; + } + + *val = u8RdVal; + + return u8RdVal; +} + +static int prev_sysclk, prev_HTS; +static int AE_low, AE_high, AE_Target = 52; + +static void OV5640_stream_on(void) +{ + ov5640_write_reg(0x4202, 0x00); +} + +static void OV5640_stream_off(void) +{ + ov5640_write_reg(0x4202, 0x0f); +} + + +static int OV5640_get_sysclk(void) +{ + /* calculate sysclk */ + int xvclk = ov5640_data.mclk / 10000; + int temp1, temp2; + int Multiplier, PreDiv, VCO, SysDiv, Pll_rdiv; + int Bit_div2x = 1, sclk_rdiv, sysclk; + u8 temp; + + int sclk_rdiv_map[] = {1, 2, 4, 8}; + + temp1 = ov5640_read_reg(0x3034, &temp); + temp2 = temp1 & 0x0f; + if (temp2 == 8 || temp2 == 10) + Bit_div2x = temp2 / 2; + + temp1 = ov5640_read_reg(0x3035, &temp); + SysDiv = temp1>>4; + if (SysDiv == 0) + SysDiv = 16; + + temp1 = ov5640_read_reg(0x3036, &temp); + Multiplier = temp1; + + temp1 = ov5640_read_reg(0x3037, &temp); + PreDiv = temp1 & 0x0f; + Pll_rdiv = ((temp1 >> 4) & 0x01) + 1; + + temp1 = ov5640_read_reg(0x3108, &temp); + temp2 = temp1 & 0x03; + sclk_rdiv = sclk_rdiv_map[temp2]; + + VCO = xvclk * Multiplier / PreDiv; + + sysclk = VCO / SysDiv / Pll_rdiv * 2 / Bit_div2x / sclk_rdiv; + + return sysclk; +} + +static void OV5640_set_night_mode(void) +{ + /* read HTS from register settings */ + u8 mode; + + ov5640_read_reg(0x3a00, &mode); + mode &= 0xfb; + ov5640_write_reg(0x3a00, mode); +} + +static int OV5640_get_HTS(void) +{ + /* read HTS from register settings */ + int HTS; + u8 temp; + + HTS = ov5640_read_reg(0x380c, &temp); + HTS = (HTS<<8) + ov5640_read_reg(0x380d, &temp); + + return HTS; +} + +static int OV5640_get_VTS(void) +{ + /* read VTS from register settings */ + int VTS; + u8 temp; + + /* total vertical size[15:8] high byte */ + VTS = ov5640_read_reg(0x380e, &temp); + + VTS = (VTS<<8) + ov5640_read_reg(0x380f, &temp); + + return VTS; +} + +static int OV5640_set_VTS(int VTS) +{ + /* write VTS to registers */ + int temp; + + temp = VTS & 0xff; + ov5640_write_reg(0x380f, temp); + + temp = VTS>>8; + ov5640_write_reg(0x380e, temp); + + return 0; +} + +static int OV5640_get_shutter(void) +{ + /* read shutter, in number of line period */ + int shutter; + u8 temp; + + shutter = (ov5640_read_reg(0x03500, &temp) & 0x0f); + shutter = (shutter<<8) + ov5640_read_reg(0x3501, &temp); + shutter = (shutter<<4) + (ov5640_read_reg(0x3502, &temp)>>4); + + return shutter; +} + +static int OV5640_set_shutter(int shutter) +{ + /* write shutter, in number of line period */ + int temp; + + shutter = shutter & 0xffff; + + temp = shutter & 0x0f; + temp = temp<<4; + ov5640_write_reg(0x3502, temp); + + temp = shutter & 0xfff; + temp = temp>>4; + ov5640_write_reg(0x3501, temp); + + temp = shutter>>12; + ov5640_write_reg(0x3500, temp); + + return 0; +} + +static int OV5640_get_gain16(void) +{ + /* read gain, 16 = 1x */ + int gain16; + u8 temp; + + gain16 = ov5640_read_reg(0x350a, &temp) & 0x03; + gain16 = (gain16<<8) + ov5640_read_reg(0x350b, &temp); + + return gain16; +} + +static int OV5640_set_gain16(int gain16) +{ + /* write gain, 16 = 1x */ + u8 temp; + gain16 = gain16 & 0x3ff; + + temp = gain16 & 0xff; + ov5640_write_reg(0x350b, temp); + + temp = gain16>>8; + ov5640_write_reg(0x350a, temp); + + return 0; +} + +static int OV5640_get_light_freq(void) +{ + /* get banding filter value */ + int temp, temp1, light_freq = 0; + u8 tmp; + + temp = ov5640_read_reg(0x3c01, &tmp); + + if (temp & 0x80) { + /* manual */ + temp1 = ov5640_read_reg(0x3c00, &tmp); + if (temp1 & 0x04) { + /* 50Hz */ + light_freq = 50; + } else { + /* 60Hz */ + light_freq = 60; + } + } else { + /* auto */ + temp1 = ov5640_read_reg(0x3c0c, &tmp); + if (temp1 & 0x01) { + /* 50Hz */ + light_freq = 50; + } else { + /* 60Hz */ + } + } + return light_freq; +} + +static void OV5640_set_bandingfilter(void) +{ + int prev_VTS; + int band_step60, max_band60, band_step50, max_band50; + + /* read preview PCLK */ + prev_sysclk = OV5640_get_sysclk(); + /* read preview HTS */ + prev_HTS = OV5640_get_HTS(); + + /* read preview VTS */ + prev_VTS = OV5640_get_VTS(); + + /* calculate banding filter */ + /* 60Hz */ + band_step60 = prev_sysclk * 100/prev_HTS * 100/120; + ov5640_write_reg(0x3a0a, (band_step60 >> 8)); + ov5640_write_reg(0x3a0b, (band_step60 & 0xff)); + + max_band60 = (int)((prev_VTS-4)/band_step60); + ov5640_write_reg(0x3a0d, max_band60); + + /* 50Hz */ + band_step50 = prev_sysclk * 100/prev_HTS; + ov5640_write_reg(0x3a08, (band_step50 >> 8)); + ov5640_write_reg(0x3a09, (band_step50 & 0xff)); + + max_band50 = (int)((prev_VTS-4)/band_step50); + ov5640_write_reg(0x3a0e, max_band50); +} + +static int OV5640_set_AE_target(int target) +{ + /* stable in high */ + int fast_high, fast_low; + AE_low = target * 23 / 25; /* 0.92 */ + AE_high = target * 27 / 25; /* 1.08 */ + + fast_high = AE_high<<1; + if (fast_high > 255) + fast_high = 255; + + fast_low = AE_low >> 1; + + ov5640_write_reg(0x3a0f, AE_high); + ov5640_write_reg(0x3a10, AE_low); + ov5640_write_reg(0x3a1b, AE_high); + ov5640_write_reg(0x3a1e, AE_low); + ov5640_write_reg(0x3a11, fast_high); + ov5640_write_reg(0x3a1f, fast_low); + + return 0; +} + +static void OV5640_turn_on_AE_AG(int enable) +{ + u8 ae_ag_ctrl; + + ov5640_read_reg(0x3503, &ae_ag_ctrl); + if (enable) { + /* turn on auto AE/AG */ + ae_ag_ctrl = ae_ag_ctrl & ~(0x03); + } else { + /* turn off AE/AG */ + ae_ag_ctrl = ae_ag_ctrl | 0x03; + } + ov5640_write_reg(0x3503, ae_ag_ctrl); +} + +static bool binning_on(void) +{ + u8 temp; + ov5640_read_reg(0x3821, &temp); + temp &= 0xfe; + if (temp) + return true; + else + return false; +} + +static void ov5640_set_virtual_channel(int channel) +{ + u8 channel_id; + + ov5640_read_reg(0x4814, &channel_id); + channel_id &= ~(3 << 6); + ov5640_write_reg(0x4814, channel_id | (channel << 6)); +} + +/* download ov5640 settings to sensor through i2c */ +static int ov5640_download_firmware(struct reg_value *pModeSetting, s32 ArySize) +{ + register u32 Delay_ms = 0; + register u16 RegAddr = 0; + register u8 Mask = 0; + register u8 Val = 0; + u8 RegVal = 0; + int i, retval = 0; + + for (i = 0; i < ArySize; ++i, ++pModeSetting) { + Delay_ms = pModeSetting->u32Delay_ms; + RegAddr = pModeSetting->u16RegAddr; + Val = pModeSetting->u8Val; + Mask = pModeSetting->u8Mask; + + if (Mask) { + retval = ov5640_read_reg(RegAddr, &RegVal); + if (retval < 0) + goto err; + + RegVal &= ~(u8)Mask; + Val &= Mask; + Val |= RegVal; + } + + retval = ov5640_write_reg(RegAddr, Val); + if (retval < 0) + goto err; + + if (Delay_ms) + msleep(Delay_ms); + } +err: + return retval; +} + +/* sensor changes between scaling and subsampling + * go through exposure calcualtion + */ +static int ov5640_change_mode_exposure_calc(enum ov5640_frame_rate frame_rate, + enum ov5640_mode mode) +{ + struct reg_value *pModeSetting = NULL; + s32 ArySize = 0; + u8 average; + int prev_shutter, prev_gain16; + int cap_shutter, cap_gain16; + int cap_sysclk, cap_HTS, cap_VTS; + int light_freq, cap_bandfilt, cap_maxband; + long cap_gain16_shutter; + int retval = 0; + + /* check if the input mode and frame rate is valid */ + pModeSetting = + ov5640_mode_info_data[frame_rate][mode].init_data_ptr; + ArySize = + ov5640_mode_info_data[frame_rate][mode].init_data_size; + + ov5640_data.pix.width = + ov5640_mode_info_data[frame_rate][mode].width; + ov5640_data.pix.height = + ov5640_mode_info_data[frame_rate][mode].height; + + if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 || + pModeSetting == NULL || ArySize == 0) + return -EINVAL; + + /* auto focus */ + /* OV5640_auto_focus();//if no af function, just skip it */ + + /* turn off AE/AG */ + OV5640_turn_on_AE_AG(0); + + /* read preview shutter */ + prev_shutter = OV5640_get_shutter(); + if ((binning_on()) && (mode != ov5640_mode_720P_1280_720) + && (mode != ov5640_mode_1080P_1920_1080)) + prev_shutter *= 2; + + /* read preview gain */ + prev_gain16 = OV5640_get_gain16(); + + /* get average */ + ov5640_read_reg(0x56a1, &average); + + /* turn off night mode for capture */ + OV5640_set_night_mode(); + + /* turn off overlay */ + /* ov5640_write_reg(0x3022, 0x06);//if no af function, just skip it */ + + OV5640_stream_off(); + + /* Write capture setting */ + retval = ov5640_download_firmware(pModeSetting, ArySize); + if (retval < 0) + goto err; + + /* read capture VTS */ + cap_VTS = OV5640_get_VTS(); + cap_HTS = OV5640_get_HTS(); + cap_sysclk = OV5640_get_sysclk(); + + /* calculate capture banding filter */ + light_freq = OV5640_get_light_freq(); + if (light_freq == 60) { + /* 60Hz */ + cap_bandfilt = cap_sysclk * 100 / cap_HTS * 100 / 120; + } else { + /* 50Hz */ + cap_bandfilt = cap_sysclk * 100 / cap_HTS; + } + cap_maxband = (int)((cap_VTS - 4)/cap_bandfilt); + + /* calculate capture shutter/gain16 */ + if (average > AE_low && average < AE_high) { + /* in stable range */ + cap_gain16_shutter = + prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk + * prev_HTS/cap_HTS * AE_Target / average; + } else { + cap_gain16_shutter = + prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk + * prev_HTS/cap_HTS; + } + + /* gain to shutter */ + if (cap_gain16_shutter < (cap_bandfilt * 16)) { + /* shutter < 1/100 */ + cap_shutter = cap_gain16_shutter/16; + if (cap_shutter < 1) + cap_shutter = 1; + + cap_gain16 = cap_gain16_shutter/cap_shutter; + if (cap_gain16 < 16) + cap_gain16 = 16; + } else { + if (cap_gain16_shutter > + (cap_bandfilt * cap_maxband * 16)) { + /* exposure reach max */ + cap_shutter = cap_bandfilt * cap_maxband; + cap_gain16 = cap_gain16_shutter / cap_shutter; + } else { + /* 1/100 < (cap_shutter = n/100) =< max */ + cap_shutter = + ((int) (cap_gain16_shutter/16 / cap_bandfilt)) + *cap_bandfilt; + cap_gain16 = cap_gain16_shutter / cap_shutter; + } + } + + /* write capture gain */ + OV5640_set_gain16(cap_gain16); + + /* write capture shutter */ + if (cap_shutter > (cap_VTS - 4)) { + cap_VTS = cap_shutter + 4; + OV5640_set_VTS(cap_VTS); + } + OV5640_set_shutter(cap_shutter); + + OV5640_stream_on(); + +err: + return retval; +} + +/* if sensor changes inside scaling or subsampling + * change mode directly + * */ +static int ov5640_change_mode_direct(enum ov5640_frame_rate frame_rate, + enum ov5640_mode mode) +{ + struct reg_value *pModeSetting = NULL; + s32 ArySize = 0; + int retval = 0; + + /* check if the input mode and frame rate is valid */ + pModeSetting = + ov5640_mode_info_data[frame_rate][mode].init_data_ptr; + ArySize = + ov5640_mode_info_data[frame_rate][mode].init_data_size; + + ov5640_data.pix.width = + ov5640_mode_info_data[frame_rate][mode].width; + ov5640_data.pix.height = + ov5640_mode_info_data[frame_rate][mode].height; + + if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 || + pModeSetting == NULL || ArySize == 0) + return -EINVAL; + + /* turn off AE/AG */ + OV5640_turn_on_AE_AG(0); + + OV5640_stream_off(); + + /* Write capture setting */ + retval = ov5640_download_firmware(pModeSetting, ArySize); + if (retval < 0) + goto err; + + OV5640_stream_on(); + + OV5640_turn_on_AE_AG(1); + +err: + return retval; +} + +static int ov5640_init_mode(enum ov5640_frame_rate frame_rate, + enum ov5640_mode mode, enum ov5640_mode orig_mode) +{ + struct reg_value *pModeSetting = NULL; + s32 ArySize = 0; + int retval = 0; + void *mipi_csi2_info; + u32 mipi_reg, msec_wait4stable = 0; + enum ov5640_downsize_mode dn_mode, orig_dn_mode; + + if ((mode > ov5640_mode_MAX || mode < ov5640_mode_MIN) + && (mode != ov5640_mode_INIT)) { + pr_err("Wrong ov5640 mode detected!\n"); + return -1; + } + + mipi_csi2_info = mipi_csi2_get_info(); + + /* initial mipi dphy */ + if (!mipi_csi2_info) { + printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n", + __func__, __FILE__); + return -1; + } + + if (!mipi_csi2_get_status(mipi_csi2_info)) + mipi_csi2_enable(mipi_csi2_info); + + if (!mipi_csi2_get_status(mipi_csi2_info)) { + pr_err("Can not enable mipi csi2 driver!\n"); + return -1; + } + + mipi_csi2_set_lanes(mipi_csi2_info); + + /*Only reset MIPI CSI2 HW at sensor initialize*/ + if (mode == ov5640_mode_INIT) + mipi_csi2_reset(mipi_csi2_info); + + if (ov5640_data.pix.pixelformat == V4L2_PIX_FMT_UYVY) + mipi_csi2_set_datatype(mipi_csi2_info, MIPI_DT_YUV422); + else if (ov5640_data.pix.pixelformat == V4L2_PIX_FMT_RGB565) + mipi_csi2_set_datatype(mipi_csi2_info, MIPI_DT_RGB565); + else + pr_err("currently this sensor format can not be supported!\n"); + + dn_mode = ov5640_mode_info_data[frame_rate][mode].dn_mode; + orig_dn_mode = ov5640_mode_info_data[frame_rate][orig_mode].dn_mode; + if (mode == ov5640_mode_INIT) { + pModeSetting = ov5640_init_setting_30fps_VGA; + ArySize = ARRAY_SIZE(ov5640_init_setting_30fps_VGA); + + ov5640_data.pix.width = 640; + ov5640_data.pix.height = 480; + retval = ov5640_download_firmware(pModeSetting, ArySize); + if (retval < 0) + goto err; + + pModeSetting = ov5640_setting_30fps_VGA_640_480; + ArySize = ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480); + retval = ov5640_download_firmware(pModeSetting, ArySize); + } else if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) || + (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) { + /* change between subsampling and scaling + * go through exposure calucation */ + retval = ov5640_change_mode_exposure_calc(frame_rate, mode); + } else { + /* change inside subsampling or scaling + * download firmware directly */ + retval = ov5640_change_mode_direct(frame_rate, mode); + } + + if (retval < 0) + goto err; + + OV5640_set_AE_target(AE_Target); + OV5640_get_light_freq(); + OV5640_set_bandingfilter(); + ov5640_set_virtual_channel(ov5640_data.csi); + + /* add delay to wait for sensor stable */ + if (mode == ov5640_mode_QSXGA_2592_1944) { + /* dump the first two frames: 1/7.5*2 + * the frame rate of QSXGA is 7.5fps */ + msec_wait4stable = 267; + } else if (frame_rate == ov5640_15_fps) { + /* dump the first nine frames: 1/15*9 */ + msec_wait4stable = 600; + } else if (frame_rate == ov5640_30_fps) { + /* dump the first nine frames: 1/30*9 */ + msec_wait4stable = 300; + } + msleep(msec_wait4stable); + + if (mipi_csi2_info) { + unsigned int i; + + i = 0; + + /* wait for mipi sensor ready */ + mipi_reg = mipi_csi2_dphy_status(mipi_csi2_info); + while ((mipi_reg == 0x200) && (i < 10)) { + mipi_reg = mipi_csi2_dphy_status(mipi_csi2_info); + i++; + msleep(10); + } + + if (i >= 10) { + pr_err("mipi csi2 can not receive sensor clk!\n"); + return -1; + } + + i = 0; + + /* wait for mipi stable */ + mipi_reg = mipi_csi2_get_error1(mipi_csi2_info); + while ((mipi_reg != 0x0) && (i < 10)) { + mipi_reg = mipi_csi2_get_error1(mipi_csi2_info); + i++; + msleep(10); + } + + if (i >= 10) { + pr_err("mipi csi2 can not reveive data correctly!\n"); + return -1; + } + } +err: + return retval; +} + +/* --------------- IOCTL functions from v4l2_int_ioctl_desc --------------- */ + +static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p) +{ + if (s == NULL) { + pr_err(" ERROR!! no slave device set!\n"); + return -1; + } + + memset(p, 0, sizeof(*p)); + p->u.bt656.clock_curr = ov5640_data.mclk; + pr_debug(" clock_curr=mclk=%d\n", ov5640_data.mclk); + p->if_type = V4L2_IF_TYPE_BT656; + p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT; + p->u.bt656.clock_min = OV5640_XCLK_MIN; + p->u.bt656.clock_max = OV5640_XCLK_MAX; + p->u.bt656.bt_sync_correct = 1; /* Indicate external vsync */ + + return 0; +} + +/*! + * ioctl_s_power - V4L2 sensor interface handler for VIDIOC_S_POWER ioctl + * @s: pointer to standard V4L2 device structure + * @on: indicates power mode (on or off) + * + * Turns the power on or off, depending on the value of on and returns the + * appropriate error code. + */ +static int ioctl_s_power(struct v4l2_int_device *s, int on) +{ + struct sensor_data *sensor = s->priv; + + if (on && !sensor->on) { + if (io_regulator) + if (regulator_enable(io_regulator) != 0) + return -EIO; + if (core_regulator) + if (regulator_enable(core_regulator) != 0) + return -EIO; + if (gpo_regulator) + if (regulator_enable(gpo_regulator) != 0) + return -EIO; + if (analog_regulator) + if (regulator_enable(analog_regulator) != 0) + return -EIO; + /* Make sure power on */ + ov5640_standby(0); + } else if (!on && sensor->on) { + if (analog_regulator) + regulator_disable(analog_regulator); + if (core_regulator) + regulator_disable(core_regulator); + if (io_regulator) + regulator_disable(io_regulator); + if (gpo_regulator) + regulator_disable(gpo_regulator); + + ov5640_standby(1); + } + + sensor->on = on; + + return 0; +} + +/*! + * ioctl_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl + * @s: pointer to standard V4L2 device structure + * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure + * + * Returns the sensor's video CAPTURE parameters. + */ +static int ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) +{ + struct sensor_data *sensor = s->priv; + struct v4l2_captureparm *cparm = &a->parm.capture; + int ret = 0; + + switch (a->type) { + /* This is the only case currently handled. */ + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + memset(a, 0, sizeof(*a)); + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + cparm->capability = sensor->streamcap.capability; + cparm->timeperframe = sensor->streamcap.timeperframe; + cparm->capturemode = sensor->streamcap.capturemode; + ret = 0; + break; + + /* These are all the possible cases. */ + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + ret = -EINVAL; + break; + + default: + pr_debug(" type is unknown - %d\n", a->type); + ret = -EINVAL; + break; + } + + return ret; +} + +/*! + * ioctl_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl + * @s: pointer to standard V4L2 device structure + * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure + * + * Configures the sensor to use the input parameters, if possible. If + * not possible, reverts to the old parameters and returns the + * appropriate error code. + */ +static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) +{ + struct sensor_data *sensor = s->priv; + struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe; + u32 tgt_fps; /* target frames per secound */ + enum ov5640_frame_rate frame_rate; + enum ov5640_mode orig_mode; + int ret = 0; + + /* Make sure power on */ + ov5640_standby(0); + + switch (a->type) { + /* This is the only case currently handled. */ + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + /* Check that the new frame rate is allowed. */ + if ((timeperframe->numerator == 0) || + (timeperframe->denominator == 0)) { + timeperframe->denominator = DEFAULT_FPS; + timeperframe->numerator = 1; + } + + tgt_fps = timeperframe->denominator / + timeperframe->numerator; + + if (tgt_fps > MAX_FPS) { + timeperframe->denominator = MAX_FPS; + timeperframe->numerator = 1; + } else if (tgt_fps < MIN_FPS) { + timeperframe->denominator = MIN_FPS; + timeperframe->numerator = 1; + } + + /* Actual frame rate we use */ + tgt_fps = timeperframe->denominator / + timeperframe->numerator; + + if (tgt_fps == 15) + frame_rate = ov5640_15_fps; + else if (tgt_fps == 30) + frame_rate = ov5640_30_fps; + else { + pr_err(" The camera frame rate is not supported!\n"); + return -EINVAL; + } + + orig_mode = sensor->streamcap.capturemode; + ret = ov5640_init_mode(frame_rate, + (u32)a->parm.capture.capturemode, orig_mode); + if (ret < 0) + return ret; + + sensor->streamcap.timeperframe = *timeperframe; + sensor->streamcap.capturemode = + (u32)a->parm.capture.capturemode; + + break; + + /* These are all the possible cases. */ + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + pr_debug(" type is not " \ + "V4L2_BUF_TYPE_VIDEO_CAPTURE but %d\n", + a->type); + ret = -EINVAL; + break; + + default: + pr_debug(" type is unknown - %d\n", a->type); + ret = -EINVAL; + break; + } + + return ret; +} + +/*! + * ioctl_g_fmt_cap - V4L2 sensor interface handler for ioctl_g_fmt_cap + * @s: pointer to standard V4L2 device structure + * @f: pointer to standard V4L2 v4l2_format structure + * + * Returns the sensor's current pixel format in the v4l2_format + * parameter. + */ +static int ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) +{ + struct sensor_data *sensor = s->priv; + + f->fmt.pix = sensor->pix; + + return 0; +} + +/*! + * ioctl_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl + * @s: pointer to standard V4L2 device structure + * @vc: standard V4L2 VIDIOC_G_CTRL ioctl structure + * + * If the requested control is supported, returns the control's current + * value from the video_control[] array. Otherwise, returns -EINVAL + * if the control is not supported. + */ +static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) +{ + int ret = 0; + + switch (vc->id) { + case V4L2_CID_BRIGHTNESS: + vc->value = ov5640_data.brightness; + break; + case V4L2_CID_HUE: + vc->value = ov5640_data.hue; + break; + case V4L2_CID_CONTRAST: + vc->value = ov5640_data.contrast; + break; + case V4L2_CID_SATURATION: + vc->value = ov5640_data.saturation; + break; + case V4L2_CID_RED_BALANCE: + vc->value = ov5640_data.red; + break; + case V4L2_CID_BLUE_BALANCE: + vc->value = ov5640_data.blue; + break; + case V4L2_CID_EXPOSURE: + vc->value = ov5640_data.ae_mode; + break; + default: + ret = -EINVAL; + } + + return ret; +} + +/*! + * ioctl_s_ctrl - V4L2 sensor interface handler for VIDIOC_S_CTRL ioctl + * @s: pointer to standard V4L2 device structure + * @vc: standard V4L2 VIDIOC_S_CTRL ioctl structure + * + * If the requested control is supported, sets the control's current + * value in HW (and updates the video_control[] array). Otherwise, + * returns -EINVAL if the control is not supported. + */ +static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) +{ + int retval = 0; + + pr_debug("In ov5640:ioctl_s_ctrl %d\n", + vc->id); + + switch (vc->id) { + case V4L2_CID_BRIGHTNESS: + break; + case V4L2_CID_CONTRAST: + break; + case V4L2_CID_SATURATION: + break; + case V4L2_CID_HUE: + break; + case V4L2_CID_AUTO_WHITE_BALANCE: + break; + case V4L2_CID_DO_WHITE_BALANCE: + break; + case V4L2_CID_RED_BALANCE: + break; + case V4L2_CID_BLUE_BALANCE: + break; + case V4L2_CID_GAMMA: + break; + case V4L2_CID_EXPOSURE: + break; + case V4L2_CID_AUTOGAIN: + break; + case V4L2_CID_GAIN: + break; + case V4L2_CID_HFLIP: + break; + case V4L2_CID_VFLIP: + break; + default: + retval = -EPERM; + break; + } + + return retval; +} + +/*! + * ioctl_enum_framesizes - V4L2 sensor interface handler for + * VIDIOC_ENUM_FRAMESIZES ioctl + * @s: pointer to standard V4L2 device structure + * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure + * + * Return 0 if successful, otherwise -EINVAL. + */ +static int ioctl_enum_framesizes(struct v4l2_int_device *s, + struct v4l2_frmsizeenum *fsize) +{ + if (fsize->index > ov5640_mode_MAX) + return -EINVAL; + + fsize->pixel_format = ov5640_data.pix.pixelformat; + fsize->discrete.width = + max(ov5640_mode_info_data[0][fsize->index].width, + ov5640_mode_info_data[1][fsize->index].width); + fsize->discrete.height = + max(ov5640_mode_info_data[0][fsize->index].height, + ov5640_mode_info_data[1][fsize->index].height); + return 0; +} + +/*! + * ioctl_enum_frameintervals - V4L2 sensor interface handler for + * VIDIOC_ENUM_FRAMEINTERVALS ioctl + * @s: pointer to standard V4L2 device structure + * @fival: standard V4L2 VIDIOC_ENUM_FRAMEINTERVALS ioctl structure + * + * Return 0 if successful, otherwise -EINVAL. + */ +static int ioctl_enum_frameintervals(struct v4l2_int_device *s, + struct v4l2_frmivalenum *fival) +{ + int i, j, count = 0; + + fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; + fival->discrete.numerator = 1; + + for (i = 0; i < ARRAY_SIZE(ov5640_mode_info_data); i++) + for (j = 0; j < (ov5640_mode_MAX + 1); j++) + if (fival->pixel_format == ov5640_data.pix.pixelformat + && fival->width == ov5640_mode_info_data[i][j].width + && fival->height == ov5640_mode_info_data[i][j].height + && ov5640_mode_info_data[i][j].init_data_ptr != NULL + && fival->index == count++) { + fival->discrete.denominator = + ov5640_framerates[i]; + return 0; + } + + return -EINVAL; +} + +/*! + * ioctl_g_chip_ident - V4L2 sensor interface handler for + * VIDIOC_DBG_G_CHIP_IDENT ioctl + * @s: pointer to standard V4L2 device structure + * @id: pointer to int + * + * Return 0. + */ +static int ioctl_g_chip_ident(struct v4l2_int_device *s, int *id) +{ + ((struct v4l2_dbg_chip_ident *)id)->match.type = + V4L2_CHIP_MATCH_I2C_DRIVER; + strcpy(((struct v4l2_dbg_chip_ident *)id)->match.name, + "ov5640_mipi_camera"); + + return 0; +} + +/*! + * ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT + * @s: pointer to standard V4L2 device structure + */ +static int ioctl_init(struct v4l2_int_device *s) +{ + + return 0; +} + +/*! + * ioctl_enum_fmt_cap - V4L2 sensor interface handler for VIDIOC_ENUM_FMT + * @s: pointer to standard V4L2 device structure + * @fmt: pointer to standard V4L2 fmt description structure + * + * Return 0. + */ +static int ioctl_enum_fmt_cap(struct v4l2_int_device *s, + struct v4l2_fmtdesc *fmt) +{ + if (fmt->index > ov5640_mode_MAX) + return -EINVAL; + + fmt->pixelformat = ov5640_data.pix.pixelformat; + + return 0; +} + +/*! + * ioctl_dev_init - V4L2 sensor interface handler for vidioc_int_dev_init_num + * @s: pointer to standard V4L2 device structure + * + * Initialise the device when slave attaches to the master. + */ +static int ioctl_dev_init(struct v4l2_int_device *s) +{ + struct sensor_data *sensor = s->priv; + u32 tgt_xclk; /* target xclk */ + u32 tgt_fps; /* target frames per secound */ + int ret; + enum ov5640_frame_rate frame_rate; + void *mipi_csi2_info; + + ov5640_data.on = true; + + /* mclk */ + tgt_xclk = ov5640_data.mclk; + tgt_xclk = min(tgt_xclk, (u32)OV5640_XCLK_MAX); + tgt_xclk = max(tgt_xclk, (u32)OV5640_XCLK_MIN); + ov5640_data.mclk = tgt_xclk; + + pr_debug(" Setting mclk to %d MHz\n", tgt_xclk / 1000000); + + /* Default camera frame rate is set in probe */ + tgt_fps = sensor->streamcap.timeperframe.denominator / + sensor->streamcap.timeperframe.numerator; + + if (tgt_fps == 15) + frame_rate = ov5640_15_fps; + else if (tgt_fps == 30) + frame_rate = ov5640_30_fps; + else + return -EINVAL; /* Only support 15fps or 30fps now. */ + + mipi_csi2_info = mipi_csi2_get_info(); + + /* enable mipi csi2 */ + if (mipi_csi2_info) + mipi_csi2_enable(mipi_csi2_info); + else { + printk(KERN_ERR "%s() in %s: Fail to get mipi_csi2_info!\n", + __func__, __FILE__); + return -EPERM; + } + + ret = ov5640_init_mode(frame_rate, ov5640_mode_INIT, ov5640_mode_INIT); + + return ret; +} + +/*! + * ioctl_dev_exit - V4L2 sensor interface handler for vidioc_int_dev_exit_num + * @s: pointer to standard V4L2 device structure + * + * Delinitialise the device when slave detaches to the master. + */ +static int ioctl_dev_exit(struct v4l2_int_device *s) +{ + void *mipi_csi2_info; + + mipi_csi2_info = mipi_csi2_get_info(); + + /* disable mipi csi2 */ + if (mipi_csi2_info) + if (mipi_csi2_get_status(mipi_csi2_info)) + mipi_csi2_disable(mipi_csi2_info); + + return 0; +} + +/*! + * This structure defines all the ioctls for this module and links them to the + * enumeration. + */ +static struct v4l2_int_ioctl_desc ov5640_ioctl_desc[] = { + {vidioc_int_dev_init_num, (v4l2_int_ioctl_func *) ioctl_dev_init}, + {vidioc_int_dev_exit_num, ioctl_dev_exit}, + {vidioc_int_s_power_num, (v4l2_int_ioctl_func *) ioctl_s_power}, + {vidioc_int_g_ifparm_num, (v4l2_int_ioctl_func *) ioctl_g_ifparm}, +/* {vidioc_int_g_needs_reset_num, + (v4l2_int_ioctl_func *)ioctl_g_needs_reset}, */ +/* {vidioc_int_reset_num, (v4l2_int_ioctl_func *)ioctl_reset}, */ + {vidioc_int_init_num, (v4l2_int_ioctl_func *) ioctl_init}, + {vidioc_int_enum_fmt_cap_num, + (v4l2_int_ioctl_func *) ioctl_enum_fmt_cap}, +/* {vidioc_int_try_fmt_cap_num, + (v4l2_int_ioctl_func *)ioctl_try_fmt_cap}, */ + {vidioc_int_g_fmt_cap_num, (v4l2_int_ioctl_func *) ioctl_g_fmt_cap}, +/* {vidioc_int_s_fmt_cap_num, (v4l2_int_ioctl_func *) ioctl_s_fmt_cap}, */ + {vidioc_int_g_parm_num, (v4l2_int_ioctl_func *) ioctl_g_parm}, + {vidioc_int_s_parm_num, (v4l2_int_ioctl_func *) ioctl_s_parm}, +/* {vidioc_int_queryctrl_num, (v4l2_int_ioctl_func *)ioctl_queryctrl}, */ + {vidioc_int_g_ctrl_num, (v4l2_int_ioctl_func *) ioctl_g_ctrl}, + {vidioc_int_s_ctrl_num, (v4l2_int_ioctl_func *) ioctl_s_ctrl}, + {vidioc_int_enum_framesizes_num, + (v4l2_int_ioctl_func *) ioctl_enum_framesizes}, + {vidioc_int_enum_frameintervals_num, + (v4l2_int_ioctl_func *) ioctl_enum_frameintervals}, + {vidioc_int_g_chip_ident_num, + (v4l2_int_ioctl_func *) ioctl_g_chip_ident}, +}; + +static struct v4l2_int_slave ov5640_slave = { + .ioctls = ov5640_ioctl_desc, + .num_ioctls = ARRAY_SIZE(ov5640_ioctl_desc), +}; + +static struct v4l2_int_device ov5640_int_device = { + .module = THIS_MODULE, + .name = "ov564x", + .type = v4l2_int_type_slave, + .u = { + .slave = &ov5640_slave, + }, +}; + +/*! + * ov5640 I2C probe function + * + * @param adapter struct i2c_adapter * + * @return Error code indicating success or failure + */ +static int ov5640_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + int retval; + u8 chip_id_high, chip_id_low; + + /* request power down pin */ + pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0); + if (!gpio_is_valid(pwn_gpio)) { + dev_warn(dev, "no sensor pwdn pin available"); + return -EINVAL; + } + retval = devm_gpio_request_one(dev, pwn_gpio, GPIOF_OUT_INIT_HIGH, + "ov5640_mipi_pwdn"); + if (retval < 0) + return retval; + + /* request reset pin */ + rst_gpio = of_get_named_gpio(dev->of_node, "rst-gpios", 0); + if (!gpio_is_valid(rst_gpio)) { + dev_warn(dev, "no sensor reset pin available"); + return -EINVAL; + } + retval = devm_gpio_request_one(dev, rst_gpio, GPIOF_OUT_INIT_HIGH, + "ov5640_mipi_reset"); + if (retval < 0) + return retval; + + /* Set initial values for the sensor struct. */ + memset(&ov5640_data, 0, sizeof(ov5640_data)); + ov5640_data.sensor_clk = devm_clk_get(dev, "csi_mclk"); + if (IS_ERR(ov5640_data.sensor_clk)) { + /* assuming clock enabled by default */ + ov5640_data.sensor_clk = NULL; + dev_err(dev, "clock-frequency missing or invalid\n"); + return PTR_ERR(ov5640_data.sensor_clk); + } + + retval = of_property_read_u32(dev->of_node, "mclk", + &(ov5640_data.mclk)); + if (retval) { + dev_err(dev, "mclk missing or invalid\n"); + return retval; + } + + retval = of_property_read_u32(dev->of_node, "mclk_source", + (u32 *) &(ov5640_data.mclk_source)); + if (retval) { + dev_err(dev, "mclk_source missing or invalid\n"); + return retval; + } + + retval = of_property_read_u32(dev->of_node, "csi_id", + &(ov5640_data.csi)); + if (retval) { + dev_err(dev, "csi id missing or invalid\n"); + return retval; + } + + clk_prepare_enable(ov5640_data.sensor_clk); + + ov5640_data.io_init = ov5640_reset; + ov5640_data.i2c_client = client; + ov5640_data.pix.pixelformat = V4L2_PIX_FMT_UYVY; + ov5640_data.pix.width = 640; + ov5640_data.pix.height = 480; + ov5640_data.streamcap.capability = V4L2_MODE_HIGHQUALITY | + V4L2_CAP_TIMEPERFRAME; + ov5640_data.streamcap.capturemode = 0; + ov5640_data.streamcap.timeperframe.denominator = DEFAULT_FPS; + ov5640_data.streamcap.timeperframe.numerator = 1; + + ov5640_power_on(dev); + + ov5640_reset(); + + ov5640_standby(0); + + retval = ov5640_read_reg(OV5640_CHIP_ID_HIGH_BYTE, &chip_id_high); + if (retval < 0 || chip_id_high != 0x56) { + pr_warning("camera ov5640_mipi is not found\n"); + clk_disable_unprepare(ov5640_data.sensor_clk); + return -ENODEV; + } + retval = ov5640_read_reg(OV5640_CHIP_ID_LOW_BYTE, &chip_id_low); + if (retval < 0 || chip_id_low != 0x40) { + pr_warning("camera ov5640_mipi is not found\n"); + clk_disable_unprepare(ov5640_data.sensor_clk); + return -ENODEV; + } + + ov5640_standby(1); + + ov5640_int_device.priv = &ov5640_data; + retval = v4l2_int_device_register(&ov5640_int_device); + + clk_disable_unprepare(ov5640_data.sensor_clk); + + pr_info("camera ov5640_mipi is found\n"); + return retval; +} + +/*! + * ov5640 I2C detach function + * + * @param client struct i2c_client * + * @return Error code indicating success or failure + */ +static int ov5640_remove(struct i2c_client *client) +{ + v4l2_int_device_unregister(&ov5640_int_device); + + if (gpo_regulator) + regulator_disable(gpo_regulator); + + if (analog_regulator) + regulator_disable(analog_regulator); + + if (core_regulator) + regulator_disable(core_regulator); + + if (io_regulator) + regulator_disable(io_regulator); + + return 0; +} + +/*! + * ov5640 init function + * Called by insmod ov5640_camera.ko. + * + * @return Error code indicating success or failure + */ +static __init int ov5640_init(void) +{ + u8 err; + + err = i2c_add_driver(&ov5640_i2c_driver); + if (err != 0) + pr_err("%s:driver registration failed, error=%d\n", + __func__, err); + + return err; +} + +/*! + * OV5640 cleanup function + * Called on rmmod ov5640_camera.ko + * + * @return Error code indicating success or failure + */ +static void __exit ov5640_clean(void) +{ + i2c_del_driver(&ov5640_i2c_driver); +} + +module_init(ov5640_init); +module_exit(ov5640_clean); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("OV5640 MIPI Camera Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("1.0"); +MODULE_ALIAS("CSI"); diff --git a/drivers/media/platform/mxc/capture/ov5642.c b/drivers/media/platform/mxc/capture/ov5642.c new file mode 100644 index 000000000000..be6122205c18 --- /dev/null +++ b/drivers/media/platform/mxc/capture/ov5642.c @@ -0,0 +1,4252 @@ +/* + * Copyright (C) 2012-2014 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "v4l2-int-device.h" +#include "mxc_v4l2_capture.h" + +#define OV5642_VOLTAGE_ANALOG 2800000 +#define OV5642_VOLTAGE_DIGITAL_CORE 1500000 +#define OV5642_VOLTAGE_DIGITAL_IO 1800000 + +#define MIN_FPS 15 +#define MAX_FPS 30 +#define DEFAULT_FPS 30 + +#define OV5642_XCLK_MIN 6000000 +#define OV5642_XCLK_MAX 24000000 + +#define OV5642_CHIP_ID_HIGH_BYTE 0x300A +#define OV5642_CHIP_ID_LOW_BYTE 0x300B + +enum ov5642_mode { + ov5642_mode_MIN = 0, + ov5642_mode_VGA_640_480 = 0, + ov5642_mode_QVGA_320_240 = 1, + ov5642_mode_NTSC_720_480 = 2, + ov5642_mode_PAL_720_576 = 3, + ov5642_mode_720P_1280_720 = 4, + ov5642_mode_1080P_1920_1080 = 5, + ov5642_mode_QSXGA_2592_1944 = 6, + ov5642_mode_QCIF_176_144 = 7, + ov5642_mode_XGA_1024_768 = 8, + ov5642_mode_MAX = 8 +}; + +enum ov5642_frame_rate { + ov5642_15_fps, + ov5642_30_fps +}; + +static int ov5642_framerates[] = { + [ov5642_15_fps] = 15, + [ov5642_30_fps] = 30, +}; + +struct reg_value { + u16 u16RegAddr; + u8 u8Val; + u8 u8Mask; + u32 u32Delay_ms; +}; + +struct ov5642_mode_info { + enum ov5642_mode mode; + u32 width; + u32 height; + struct reg_value *init_data_ptr; + u32 init_data_size; +}; + +/*! + * Maintains the information on the current state of the sesor. + */ +static struct sensor_data ov5642_data; +static int pwn_gpio, rst_gpio; + +static struct reg_value ov5642_rot_none_VGA[] = { + {0x3818, 0xc1, 0x00, 0x00}, {0x3621, 0x87, 0x00, 0x00}, +}; + +static struct reg_value ov5642_rot_vert_flip_VGA[] = { + {0x3818, 0x20, 0xbf, 0x00}, {0x3621, 0x20, 0xff, 0x00}, +}; + +static struct reg_value ov5642_rot_horiz_flip_VGA[] = { + {0x3818, 0x81, 0x00, 0x01}, {0x3621, 0xa7, 0x00, 0x00}, +}; + +static struct reg_value ov5642_rot_180_VGA[] = { + {0x3818, 0x60, 0xff, 0x00}, {0x3621, 0x00, 0xdf, 0x00}, +}; + + +static struct reg_value ov5642_rot_none_FULL[] = { + {0x3818, 0xc0, 0x00, 0x00}, {0x3621, 0x09, 0x00, 0x00}, +}; + +static struct reg_value ov5642_rot_vert_flip_FULL[] = { + {0x3818, 0x20, 0xbf, 0x01}, {0x3621, 0x20, 0xff, 0x00}, +}; + +static struct reg_value ov5642_rot_horiz_flip_FULL[] = { + {0x3818, 0x80, 0x00, 0x01}, {0x3621, 0x29, 0x00, 0x00}, +}; + +static struct reg_value ov5642_rot_180_FULL[] = { + {0x3818, 0x60, 0xff, 0x00}, {0x3621, 0x00, 0xdf, 0x00}, +}; + + +static struct reg_value ov5642_initial_setting[] = { + {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, + {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0}, + {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, + {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, + {0x3006, 0x43, 0, 0}, {0x3007, 0x37, 0, 0}, {0x3011, 0x08, 0, 0}, + {0x3010, 0x00, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3815, 0x04, 0, 0}, + {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0}, + {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0}, + {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0}, + {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0}, + {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0}, + {0x3606, 0x3f, 0, 0}, {0x3c00, 0x04, 0, 0}, {0x3c01, 0x80, 0, 0}, + {0x5000, 0x4f, 0, 0}, {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, + {0x5182, 0x00, 0, 0}, {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, + {0x5001, 0xff, 0, 0}, {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, + {0x5505, 0x7f, 0, 0}, {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, + {0x4610, 0x00, 0, 0}, {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, + {0x380b, 0xe0, 0, 0}, {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, + {0x501f, 0x00, 0, 0}, {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, + {0x3503, 0x07, 0, 0}, {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, + {0x350b, 0x00, 0, 0}, {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, + {0x3501, 0x1e, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, + {0x380c, 0x0c, 0, 0}, {0x380d, 0x80, 0, 0}, {0x380e, 0x03, 0, 0}, + {0x380f, 0xe8, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3818, 0xc1, 0, 0}, {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, + {0x3801, 0x80, 0, 0}, {0x3621, 0x87, 0, 0}, {0x3801, 0x50, 0, 0}, + {0x3803, 0x08, 0, 0}, {0x3827, 0x08, 0, 0}, {0x3810, 0x40, 0, 0}, + {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, + {0x5683, 0x00, 0, 0}, {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, + {0x5686, 0x03, 0, 0}, {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, + {0x3a1a, 0x05, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, + {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, + {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, + {0x350d, 0xd0, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, + {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, + {0x3503, 0x00, 0, 0}, {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, + {0x528c, 0x08, 0, 0}, {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, + {0x528f, 0x10, 0, 0}, {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, + {0x5293, 0x02, 0, 0}, {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, + {0x5296, 0x00, 0, 0}, {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, + {0x5299, 0x02, 0, 0}, {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, + {0x529c, 0x00, 0, 0}, {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, + {0x529f, 0x02, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, + {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, + {0x3a1f, 0x10, 0, 0}, {0x3030, 0x0b, 0, 0}, {0x3a02, 0x00, 0, 0}, + {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, + {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, + {0x5193, 0x70, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, + {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, + {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, + {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, + {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, + {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, + {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, + {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, + {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, + {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, + {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, + {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, + {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, + {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, + {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, + {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, + {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, + {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, + {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, + {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, + {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, + {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, + {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, + {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, + {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, + {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, + {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, + {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, + {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, + {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, + {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, + {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, + {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, + {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, + {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, + {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, + {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, + {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, + {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, + {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, + {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, + {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, + {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, + {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, + {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, + {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, + {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, + {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, + {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, + {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, + {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, + {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, + {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, + {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, + {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, + {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, + {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, + {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, + {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, + {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, + {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, + {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, + {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, + {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, + {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, + {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, + {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, + {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, + {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, + {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, + {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, + {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, + {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, + {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, + {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, + {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, + {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, + {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, + {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, + {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, + {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, + {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, + {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, + {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, + {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, + {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, + {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, + {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, + {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, + {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, + {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, + {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, + {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, + {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, + {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, + {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, + {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, + {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, + {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, + {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, + {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, + {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, + {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, + {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, + {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, + {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, + {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, + {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, + {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, + {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, + {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, + {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, + {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, + {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, + {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, + {0x302b, 0x00, 0, 300}, +}; + +static struct reg_value ov5642_setting_15fps_QCIF_176_144[] = { + {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, + {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0}, + {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, + {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, + {0x3006, 0x43, 0, 0}, {0x3007, 0x37, 0, 0}, {0x3011, 0x08, 0, 0}, + {0x3010, 0x10, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3815, 0x04, 0, 0}, + {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0}, + {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0}, + {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0}, + {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0}, + {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0}, + {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0}, + {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, + {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0}, + {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, + {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, + {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0}, + {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, + {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0}, + {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0}, + {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, + {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3501, 0x1e, 0, 0}, + {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, {0x380c, 0x0c, 0, 0}, + {0x380d, 0x80, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xe8, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3818, 0xc1, 0, 0}, + {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, {0x3801, 0x80, 0, 0}, + {0x3621, 0x87, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3803, 0x08, 0, 0}, + {0x3827, 0x08, 0, 0}, {0x3810, 0x40, 0, 0}, {0x3804, 0x05, 0, 0}, + {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, {0x5683, 0x00, 0, 0}, + {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, {0x5686, 0x03, 0, 0}, + {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a1a, 0x05, 0, 0}, + {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0}, + {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, + {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0}, + {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, {0x3502, 0x00, 0, 0}, + {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, {0x3503, 0x00, 0, 0}, + {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, + {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, {0x528f, 0x10, 0, 0}, + {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x02, 0, 0}, + {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, {0x5296, 0x00, 0, 0}, + {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x02, 0, 0}, + {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, {0x529c, 0x00, 0, 0}, + {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x02, 0, 0}, + {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3c, 0, 0}, + {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, {0x3a1f, 0x10, 0, 0}, + {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, {0x3a03, 0x7d, 0, 0}, + {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, {0x3a15, 0x7d, 0, 0}, + {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a08, 0x09, 0, 0}, + {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x07, 0, 0}, {0x3a0b, 0xd0, 0, 0}, + {0x3a0d, 0x08, 0, 0}, {0x3a0e, 0x06, 0, 0}, {0x5193, 0x70, 0, 0}, + {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, {0x401e, 0x20, 0, 0}, + {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, {0x528a, 0x01, 0, 0}, + {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, {0x528d, 0x10, 0, 0}, + {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, {0x5290, 0x30, 0, 0}, + {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, {0x5294, 0x00, 0, 0}, + {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, {0x5297, 0x08, 0, 0}, + {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, {0x529a, 0x00, 0, 0}, + {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, {0x529d, 0x28, 0, 0}, + {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, {0x5282, 0x00, 0, 0}, + {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, {0x5302, 0x00, 0, 0}, + {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, {0x530d, 0x0c, 0, 0}, + {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, {0x5310, 0x20, 0, 0}, + {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, {0x5309, 0x40, 0, 0}, + {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x00, 0, 0}, + {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, {0x5315, 0x20, 0, 0}, + {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, {0x5317, 0x00, 0, 0}, + {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, {0x5381, 0x00, 0, 0}, + {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, {0x5384, 0x00, 0, 0}, + {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, {0x5387, 0x00, 0, 0}, + {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, {0x538a, 0x00, 0, 0}, + {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, {0x538d, 0x00, 0, 0}, + {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, {0x5390, 0x00, 0, 0}, + {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, {0x5393, 0xa2, 0, 0}, + {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, {0x5481, 0x21, 0, 0}, + {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, {0x5484, 0x65, 0, 0}, + {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, {0x5487, 0x87, 0, 0}, + {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, {0x548a, 0xaa, 0, 0}, + {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, {0x548d, 0xdd, 0, 0}, + {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, {0x5490, 0x05, 0, 0}, + {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, {0x5493, 0x20, 0, 0}, + {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, {0x5496, 0x02, 0, 0}, + {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, {0x5499, 0x86, 0, 0}, + {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, {0x549c, 0x02, 0, 0}, + {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, {0x549f, 0x1c, 0, 0}, + {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, {0x54a2, 0x01, 0, 0}, + {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, {0x54a5, 0xc5, 0, 0}, + {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, {0x54a8, 0x01, 0, 0}, + {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, {0x54ab, 0x41, 0, 0}, + {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, {0x54ae, 0x00, 0, 0}, + {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, {0x54b1, 0x20, 0, 0}, + {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, {0x54b4, 0x00, 0, 0}, + {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, {0x54b7, 0xdf, 0, 0}, + {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, {0x3406, 0x00, 0, 0}, + {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, {0x5182, 0x11, 0, 0}, + {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, + {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, {0x5188, 0x08, 0, 0}, + {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, {0x518b, 0xb2, 0, 0}, + {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, {0x518e, 0x3d, 0, 0}, + {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, + {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, + {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, + {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, {0x519a, 0x04, 0, 0}, + {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, {0x519d, 0x82, 0, 0}, + {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, {0x3a0f, 0x38, 0, 0}, + {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, {0x3a1e, 0x2e, 0, 0}, + {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, {0x5688, 0xa6, 0, 0}, + {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, {0x568b, 0xae, 0, 0}, + {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, {0x568e, 0x62, 0, 0}, + {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, {0x5584, 0x40, 0, 0}, + {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, {0x5800, 0x27, 0, 0}, + {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, {0x5803, 0x0f, 0, 0}, + {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, {0x5806, 0x1e, 0, 0}, + {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, {0x5809, 0x0d, 0, 0}, + {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, {0x580c, 0x0a, 0, 0}, + {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, {0x580f, 0x19, 0, 0}, + {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, {0x5812, 0x04, 0, 0}, + {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, {0x5815, 0x06, 0, 0}, + {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, {0x5818, 0x0a, 0, 0}, + {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, {0x581b, 0x00, 0, 0}, + {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, {0x581e, 0x08, 0, 0}, + {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, {0x5821, 0x05, 0, 0}, + {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, {0x5824, 0x00, 0, 0}, + {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, {0x5827, 0x0c, 0, 0}, + {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, {0x582a, 0x06, 0, 0}, + {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, {0x582d, 0x07, 0, 0}, + {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, {0x5830, 0x18, 0, 0}, + {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, {0x5833, 0x0a, 0, 0}, + {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, {0x5836, 0x15, 0, 0}, + {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, {0x5839, 0x1f, 0, 0}, + {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, {0x583c, 0x17, 0, 0}, + {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, {0x583f, 0x53, 0, 0}, + {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, {0x5842, 0x0d, 0, 0}, + {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, {0x5845, 0x09, 0, 0}, + {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, {0x5848, 0x10, 0, 0}, + {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, {0x584b, 0x0e, 0, 0}, + {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, {0x584e, 0x11, 0, 0}, + {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, {0x5851, 0x0c, 0, 0}, + {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, {0x5854, 0x10, 0, 0}, + {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, {0x5857, 0x0b, 0, 0}, + {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, {0x585a, 0x0d, 0, 0}, + {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, {0x585d, 0x0c, 0, 0}, + {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, {0x5860, 0x0c, 0, 0}, + {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, {0x5863, 0x08, 0, 0}, + {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, {0x5866, 0x18, 0, 0}, + {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, {0x5869, 0x19, 0, 0}, + {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, {0x586c, 0x13, 0, 0}, + {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, {0x586f, 0x16, 0, 0}, + {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, {0x5872, 0x10, 0, 0}, + {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, {0x5875, 0x16, 0, 0}, + {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, {0x5878, 0x10, 0, 0}, + {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, {0x587b, 0x14, 0, 0}, + {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, {0x587e, 0x11, 0, 0}, + {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, {0x5881, 0x15, 0, 0}, + {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, {0x5884, 0x15, 0, 0}, + {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, {0x5887, 0x17, 0, 0}, + {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, {0x3702, 0x10, 0, 0}, + {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, {0x370b, 0x40, 0, 0}, + {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, {0x3632, 0x52, 0, 0}, + {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, {0x5785, 0x07, 0, 0}, + {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, {0x3604, 0x48, 0, 0}, + {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, {0x370f, 0xc0, 0, 0}, + {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, {0x5007, 0x00, 0, 0}, + {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, {0x5013, 0x00, 0, 0}, + {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, {0x5087, 0x00, 0, 0}, + {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, {0x302b, 0x00, 0, 0}, + {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, {0x380a, 0x00, 0, 0}, + {0x380b, 0x90, 0, 0}, {0x3a00, 0x78, 0, 0}, +}; + +static struct reg_value ov5642_setting_30fps_QCIF_176_144[] = { + {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, + {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0}, + {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, + {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, + {0x3006, 0x43, 0, 0}, {0x3007, 0x37, 0, 0}, {0x3011, 0x10, 0, 0}, + {0x3010, 0x10, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3815, 0x04, 0, 0}, + {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0}, + {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0}, + {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0}, + {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0}, + {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0}, + {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0}, + {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, + {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0}, + {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, + {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, + {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0}, + {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, + {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0}, + {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0}, + {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, + {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3501, 0x1e, 0, 0}, + {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, {0x380c, 0x0c, 0, 0}, + {0x380d, 0x80, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xe8, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3818, 0xc1, 0, 0}, + {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, {0x3801, 0x80, 0, 0}, + {0x3621, 0x87, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3803, 0x08, 0, 0}, + {0x3827, 0x08, 0, 0}, {0x3810, 0x40, 0, 0}, {0x3804, 0x05, 0, 0}, + {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, {0x5683, 0x00, 0, 0}, + {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, {0x5686, 0x03, 0, 0}, + {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a1a, 0x05, 0, 0}, + {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0}, + {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, + {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0}, + {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, {0x3502, 0x00, 0, 0}, + {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, {0x3503, 0x00, 0, 0}, + {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, + {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, {0x528f, 0x10, 0, 0}, + {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x02, 0, 0}, + {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, {0x5296, 0x00, 0, 0}, + {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x02, 0, 0}, + {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, {0x529c, 0x00, 0, 0}, + {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x02, 0, 0}, + {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3c, 0, 0}, + {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, {0x3a1f, 0x10, 0, 0}, + {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, {0x3a03, 0x7d, 0, 0}, + {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, {0x3a15, 0x7d, 0, 0}, + {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a08, 0x09, 0, 0}, + {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x07, 0, 0}, {0x3a0b, 0xd0, 0, 0}, + {0x3a0d, 0x08, 0, 0}, {0x3a0e, 0x06, 0, 0}, {0x5193, 0x70, 0, 0}, + {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, {0x401e, 0x20, 0, 0}, + {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, {0x528a, 0x01, 0, 0}, + {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, {0x528d, 0x10, 0, 0}, + {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, {0x5290, 0x30, 0, 0}, + {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, {0x5294, 0x00, 0, 0}, + {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, {0x5297, 0x08, 0, 0}, + {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, {0x529a, 0x00, 0, 0}, + {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, {0x529d, 0x28, 0, 0}, + {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, {0x5282, 0x00, 0, 0}, + {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, {0x5302, 0x00, 0, 0}, + {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, {0x530d, 0x0c, 0, 0}, + {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, {0x5310, 0x20, 0, 0}, + {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, {0x5309, 0x40, 0, 0}, + {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x00, 0, 0}, + {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, {0x5315, 0x20, 0, 0}, + {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, {0x5317, 0x00, 0, 0}, + {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, {0x5381, 0x00, 0, 0}, + {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, {0x5384, 0x00, 0, 0}, + {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, {0x5387, 0x00, 0, 0}, + {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, {0x538a, 0x00, 0, 0}, + {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, {0x538d, 0x00, 0, 0}, + {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, {0x5390, 0x00, 0, 0}, + {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, {0x5393, 0xa2, 0, 0}, + {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, {0x5481, 0x21, 0, 0}, + {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, {0x5484, 0x65, 0, 0}, + {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, {0x5487, 0x87, 0, 0}, + {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, {0x548a, 0xaa, 0, 0}, + {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, {0x548d, 0xdd, 0, 0}, + {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, {0x5490, 0x05, 0, 0}, + {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, {0x5493, 0x20, 0, 0}, + {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, {0x5496, 0x02, 0, 0}, + {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, {0x5499, 0x86, 0, 0}, + {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, {0x549c, 0x02, 0, 0}, + {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, {0x549f, 0x1c, 0, 0}, + {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, {0x54a2, 0x01, 0, 0}, + {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, {0x54a5, 0xc5, 0, 0}, + {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, {0x54a8, 0x01, 0, 0}, + {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, {0x54ab, 0x41, 0, 0}, + {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, {0x54ae, 0x00, 0, 0}, + {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, {0x54b1, 0x20, 0, 0}, + {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, {0x54b4, 0x00, 0, 0}, + {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, {0x54b7, 0xdf, 0, 0}, + {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, {0x3406, 0x00, 0, 0}, + {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, {0x5182, 0x11, 0, 0}, + {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, + {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, {0x5188, 0x08, 0, 0}, + {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, {0x518b, 0xb2, 0, 0}, + {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, {0x518e, 0x3d, 0, 0}, + {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, + {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, + {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, + {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, {0x519a, 0x04, 0, 0}, + {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, {0x519d, 0x82, 0, 0}, + {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, {0x3a0f, 0x38, 0, 0}, + {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, {0x3a1e, 0x2e, 0, 0}, + {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, {0x5688, 0xa6, 0, 0}, + {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, {0x568b, 0xae, 0, 0}, + {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, {0x568e, 0x62, 0, 0}, + {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, {0x5584, 0x40, 0, 0}, + {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, {0x5800, 0x27, 0, 0}, + {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, {0x5803, 0x0f, 0, 0}, + {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, {0x5806, 0x1e, 0, 0}, + {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, {0x5809, 0x0d, 0, 0}, + {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, {0x580c, 0x0a, 0, 0}, + {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, {0x580f, 0x19, 0, 0}, + {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, {0x5812, 0x04, 0, 0}, + {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, {0x5815, 0x06, 0, 0}, + {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, {0x5818, 0x0a, 0, 0}, + {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, {0x581b, 0x00, 0, 0}, + {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, {0x581e, 0x08, 0, 0}, + {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, {0x5821, 0x05, 0, 0}, + {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, {0x5824, 0x00, 0, 0}, + {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, {0x5827, 0x0c, 0, 0}, + {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, {0x582a, 0x06, 0, 0}, + {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, {0x582d, 0x07, 0, 0}, + {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, {0x5830, 0x18, 0, 0}, + {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, {0x5833, 0x0a, 0, 0}, + {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, {0x5836, 0x15, 0, 0}, + {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, {0x5839, 0x1f, 0, 0}, + {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, {0x583c, 0x17, 0, 0}, + {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, {0x583f, 0x53, 0, 0}, + {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, {0x5842, 0x0d, 0, 0}, + {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, {0x5845, 0x09, 0, 0}, + {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, {0x5848, 0x10, 0, 0}, + {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, {0x584b, 0x0e, 0, 0}, + {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, {0x584e, 0x11, 0, 0}, + {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, {0x5851, 0x0c, 0, 0}, + {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, {0x5854, 0x10, 0, 0}, + {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, {0x5857, 0x0b, 0, 0}, + {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, {0x585a, 0x0d, 0, 0}, + {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, {0x585d, 0x0c, 0, 0}, + {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, {0x5860, 0x0c, 0, 0}, + {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, {0x5863, 0x08, 0, 0}, + {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, {0x5866, 0x18, 0, 0}, + {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, {0x5869, 0x19, 0, 0}, + {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, {0x586c, 0x13, 0, 0}, + {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, {0x586f, 0x16, 0, 0}, + {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, {0x5872, 0x10, 0, 0}, + {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, {0x5875, 0x16, 0, 0}, + {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, {0x5878, 0x10, 0, 0}, + {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, {0x587b, 0x14, 0, 0}, + {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, {0x587e, 0x11, 0, 0}, + {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, {0x5881, 0x15, 0, 0}, + {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, {0x5884, 0x15, 0, 0}, + {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, {0x5887, 0x17, 0, 0}, + {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, {0x3702, 0x10, 0, 0}, + {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, {0x370b, 0x40, 0, 0}, + {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, {0x3632, 0x52, 0, 0}, + {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, {0x5785, 0x07, 0, 0}, + {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, {0x3604, 0x48, 0, 0}, + {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, {0x370f, 0xc0, 0, 0}, + {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, {0x5007, 0x00, 0, 0}, + {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, {0x5013, 0x00, 0, 0}, + {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, {0x5087, 0x00, 0, 0}, + {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, {0x302b, 0x00, 0, 0}, + {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, {0x380a, 0x00, 0, 0}, + {0x380b, 0x90, 0, 0}, {0x3a00, 0x78, 0, 0}, +}; + +static struct reg_value ov5642_setting_15fps_QSXGA_2592_1944[] = { + {0x3503, 0x07, 0, 0}, {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, + {0x3002, 0x00, 0, 0}, {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, + {0x3005, 0xff, 0, 0}, {0x3006, 0xff, 0, 0}, {0x3007, 0x3f, 0, 0}, + {0x3011, 0x08, 0, 0}, {0x3010, 0x10, 0, 0}, {0x3818, 0xc0, 0, 0}, + {0x3621, 0x09, 0, 0}, {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0}, + {0x3602, 0xe4, 0, 0}, {0x3612, 0xac, 0, 0}, {0x3613, 0x44, 0, 0}, + {0x3622, 0x60, 0, 0}, {0x3623, 0x22, 0, 0}, {0x3604, 0x48, 0, 0}, + {0x3705, 0xda, 0, 0}, {0x370a, 0x80, 0, 0}, {0x3801, 0x95, 0, 0}, + {0x3803, 0x0e, 0, 0}, {0x3804, 0x0a, 0, 0}, {0x3805, 0x20, 0, 0}, + {0x3806, 0x07, 0, 0}, {0x3807, 0x98, 0, 0}, {0x3808, 0x0a, 0, 0}, + {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, {0x380b, 0x98, 0, 0}, + {0x380c, 0x0c, 0, 0}, {0x380d, 0x80, 0, 0}, {0x380e, 0x07, 0, 0}, + {0x380f, 0xd0, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3815, 0x44, 0, 0}, + {0x3824, 0x11, 0, 0}, {0x3825, 0xac, 0, 0}, {0x3827, 0x0c, 0, 0}, + {0x3a00, 0x78, 0, 0}, {0x3a0d, 0x10, 0, 0}, {0x3a0e, 0x0d, 0, 0}, + {0x5682, 0x0a, 0, 0}, {0x5683, 0x20, 0, 0}, {0x5686, 0x07, 0, 0}, + {0x5687, 0x98, 0, 0}, {0x5001, 0xff, 0, 0}, {0x589b, 0x00, 0, 0}, + {0x589a, 0xc0, 0, 0}, {0x4407, 0x04, 0, 0}, {0x3008, 0x02, 0, 0}, + {0x460b, 0x37, 0, 0}, {0x460c, 0x22, 0, 0}, {0x471d, 0x05, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x471c, 0xd0, 0, 0}, {0x3815, 0x01, 0, 0}, + {0x501f, 0x00, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3819, 0x80, 0, 0}, + {0x5002, 0xe0, 0, 0}, {0x530a, 0x01, 0, 0}, {0x530d, 0x10, 0, 0}, + {0x530c, 0x04, 0, 0}, {0x5312, 0x20, 0, 0}, {0x5282, 0x01, 0, 0}, + {0x3010, 0x10, 0, 0}, {0x3012, 0x00, 0, 0}, +}; + + +static struct reg_value ov5642_setting_VGA_2_QVGA[] = { + {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0}, + {0x380b, 0xf0, 0, 0}, {0x3815, 0x04, 0, 0}, +}; + +static struct reg_value ov5642_setting_QSXGA_2_VGA[] = { + {0x3503, 0x00, 0, 0}, {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, + {0x3002, 0x5c, 0, 0}, {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, + {0x3005, 0xff, 0, 0}, {0x3006, 0x43, 0, 0}, {0x3007, 0x37, 0, 0}, + {0x3010, 0x00, 0, 0}, {0x3818, 0xc1, 0, 0}, {0x3621, 0x87, 0, 0}, + {0x350c, 0x03, 0, 0}, {0x350d, 0xe8, 0, 0}, {0x3602, 0xfc, 0, 0}, + {0x3612, 0xff, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3622, 0x60, 0, 0}, + {0x3623, 0x01, 0, 0}, {0x3604, 0x48, 0, 0}, {0x3705, 0xdb, 0, 0}, + {0x370a, 0x81, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3803, 0x08, 0, 0}, + {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x3806, 0x03, 0, 0}, + {0x3807, 0xc0, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, + {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x0c, 0, 0}, + {0x380d, 0x80, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xe8, 0, 0}, + {0x3810, 0x40, 0, 0}, {0x3815, 0x04, 0, 0}, {0x3824, 0x11, 0, 0}, + {0x3825, 0xb4, 0, 0}, {0x3827, 0x08, 0, 0}, {0x3a00, 0x78, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x5682, 0x05, 0, 0}, + {0x5683, 0x00, 0, 0}, {0x5686, 0x03, 0, 0}, {0x5687, 0xbc, 0, 0}, + {0x5001, 0xff, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, + {0x4407, 0x0c, 0, 0}, {0x3008, 0x02, 0, 0}, {0x460b, 0x37, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x471d, 0x05, 0, 0}, {0x4713, 0x02, 0, 0}, + {0x471c, 0xd0, 0, 0}, {0x3815, 0x04, 0, 0}, {0x501f, 0x00, 0, 0}, + {0x3002, 0x5c, 0, 0}, {0x3819, 0x80, 0, 0}, {0x5002, 0xe0, 0, 0}, + {0x530a, 0x01, 0, 0}, {0x530d, 0x0c, 0, 0}, {0x530c, 0x00, 0, 0}, + {0x5312, 0x40, 0, 0}, {0x5282, 0x00, 0, 0}, + {0x3012, 0x02, 0, 0}, {0x3010, 0x00, 0, 0}, +}; + +static struct reg_value ov5642_setting_30fps_VGA_640_480[] = { + {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, + {0x3018, 0xfc, 0, 0}, {0x3615, 0xf0, 0, 0}, {0x3000, 0x00, 0, 0}, + {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, {0x3003, 0x00, 0, 0}, + {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, {0x3006, 0x43, 0, 0}, + {0x3007, 0x37, 0, 0}, {0x3011, 0x09, 0, 0}, {0x3012, 0x02, 0, 0}, + {0x3010, 0x00, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3815, 0x04, 0, 0}, + {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0}, + {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0}, + {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0}, + {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0}, + {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0}, + {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0}, + {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, + {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0}, + {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, + {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, + {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0}, + {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, + {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0}, + {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0}, + {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, + {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3825, 0xb0, 0, 0}, + {0x3501, 0x1e, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, + {0x380c, 0x07, 0, 0}, {0x380d, 0x2a, 0, 0}, {0x380e, 0x03, 0, 0}, + {0x380f, 0xe8, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3818, 0xc1, 0, 0}, {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, + {0x3801, 0x80, 0, 0}, {0x3621, 0xc7, 0, 0}, {0x3801, 0x50, 0, 0}, + {0x3803, 0x08, 0, 0}, {0x3827, 0x08, 0, 0}, {0x3810, 0x80, 0, 0}, + {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, + {0x5683, 0x00, 0, 0}, {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, + {0x5686, 0x03, 0, 0}, {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, + {0x3a1a, 0x05, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, + {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, + {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, + {0x350d, 0xd0, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, + {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, + {0x3503, 0x00, 0, 0}, {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, + {0x528c, 0x08, 0, 0}, {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, + {0x528f, 0x10, 0, 0}, {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, + {0x5293, 0x02, 0, 0}, {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, + {0x5296, 0x00, 0, 0}, {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, + {0x5299, 0x02, 0, 0}, {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, + {0x529c, 0x00, 0, 0}, {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, + {0x529f, 0x02, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, + {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, + {0x3a1f, 0x10, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, + {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, + {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, + {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, + {0x3a0b, 0xa0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x5193, 0x70, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, + {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, + {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, + {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, + {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, + {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, + {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, + {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, + {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, + {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, + {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, + {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, + {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, + {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, + {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, + {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, + {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, + {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, + {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, + {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, + {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, + {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, + {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, + {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, + {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, + {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, + {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, + {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, + {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, + {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, + {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, + {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, + {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, + {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, + {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, + {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, + {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, + {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, + {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, + {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, + {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, + {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, + {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, + {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, + {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, + {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, + {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, + {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, + {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, + {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, + {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, + {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, + {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, + {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, + {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, + {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, + {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, + {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, + {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, + {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, + {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, + {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, + {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, + {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, + {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, + {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, + {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, + {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, + {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, + {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, + {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, + {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, + {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, + {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, + {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, + {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, + {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, + {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, + {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, + {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, + {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, + {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, + {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, + {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, + {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, + {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, + {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, + {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, + {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, + {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, + {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, + {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, + {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, + {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, + {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, + {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, + {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, + {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, + {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, + {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, + {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, + {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, + {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, + {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, + {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, + {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, + {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, + {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, + {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, + {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, + {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, + {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, + {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, + {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, + {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, + {0x302b, 0x00, 0, 0}, {0x3621, 0x87, 0, 0}, {0x3a00, 0x78, 0, 0}, +}; + +static struct reg_value ov5642_setting_15fps_VGA_640_480[] = { + {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, + {0x3018, 0xfc, 0, 0}, {0x3615, 0xf0, 0, 0}, {0x3000, 0x00, 0, 0}, + {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, {0x3003, 0x00, 0, 0}, + {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, {0x3006, 0x43, 0, 0}, + {0x3007, 0x37, 0, 0}, {0x3011, 0x09, 0, 0}, {0x3012, 0x02, 0, 0}, + {0x3010, 0x00, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3815, 0x04, 0, 0}, + {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0}, + {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0}, + {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0}, + {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0}, + {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0}, + {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0}, + {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, + {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0}, + {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, + {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, + {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0}, + {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, + {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0}, + {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0}, + {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, + {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3825, 0xb0, 0, 0}, + {0x3501, 0x1e, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, + {0x380c, 0x07, 0, 0}, {0x380d, 0x2a, 0, 0}, {0x380e, 0x07, 0, 0}, + {0x380f, 0xd0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3818, 0xc1, 0, 0}, {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, + {0x3801, 0x80, 0, 0}, {0x3621, 0xc7, 0, 0}, {0x3801, 0x50, 0, 0}, + {0x3803, 0x08, 0, 0}, {0x3827, 0x08, 0, 0}, {0x3810, 0x80, 0, 0}, + {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, + {0x5683, 0x00, 0, 0}, {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, + {0x5686, 0x03, 0, 0}, {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, + {0x3a1a, 0x05, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, + {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, + {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, + {0x350d, 0xd0, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, + {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, + {0x3503, 0x00, 0, 0}, {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, + {0x528c, 0x08, 0, 0}, {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, + {0x528f, 0x10, 0, 0}, {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, + {0x5293, 0x02, 0, 0}, {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, + {0x5296, 0x00, 0, 0}, {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, + {0x5299, 0x02, 0, 0}, {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, + {0x529c, 0x00, 0, 0}, {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, + {0x529f, 0x02, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, + {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, + {0x3a1f, 0x10, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, + {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, + {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, + {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, + {0x3a0b, 0xa0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x5193, 0x70, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, + {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, + {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, + {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, + {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, + {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, + {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, + {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, + {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, + {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, + {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, + {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, + {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, + {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, + {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, + {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, + {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, + {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, + {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, + {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, + {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, + {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, + {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, + {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, + {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, + {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, + {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, + {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, + {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, + {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, + {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, + {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, + {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, + {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, + {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, + {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, + {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, + {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, + {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, + {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, + {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, + {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, + {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, + {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, + {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, + {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, + {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, + {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, + {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, + {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, + {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, + {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, + {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, + {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, + {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, + {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, + {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, + {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, + {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, + {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, + {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, + {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, + {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, + {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, + {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, + {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, + {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, + {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, + {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, + {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, + {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, + {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, + {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, + {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, + {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, + {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, + {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, + {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, + {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, + {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, + {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, + {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, + {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, + {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, + {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, + {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, + {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, + {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, + {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, + {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, + {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, + {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, + {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, + {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, + {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, + {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, + {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, + {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, + {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, + {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, + {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, + {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, + {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, + {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, + {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, + {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, + {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, + {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, + {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, + {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, + {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, + {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, + {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, + {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, + {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, + {0x302b, 0x00, 0, 0}, {0x3621, 0x87, 0, 0}, {0x3a00, 0x78, 0, 0}, +}; + + +static struct reg_value ov5642_setting_30fps_XGA_1024_768[] = { + {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, + {0x3018, 0xfc, 0, 0}, {0x3615, 0xf0, 0, 0}, {0x3000, 0x00, 0, 0}, + {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, {0x3003, 0x00, 0, 0}, + {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, {0x3006, 0x43, 0, 0}, + {0x3007, 0x37, 0, 0}, {0x3011, 0x09, 0, 0}, {0x3012, 0x02, 0, 0}, + {0x3010, 0x00, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3815, 0x04, 0, 0}, + {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0}, + {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0}, + {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0}, + {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0}, + {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0}, + {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0}, + {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, + {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0}, + {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, + {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, + {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0}, + {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, + {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0}, + {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0}, + {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, + {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3825, 0xb0, 0, 0}, + {0x3501, 0x1e, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, + {0x380c, 0x07, 0, 0}, {0x380d, 0x2a, 0, 0}, {0x380e, 0x03, 0, 0}, + {0x380f, 0xe8, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3818, 0xc1, 0, 0}, {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, + {0x3801, 0x80, 0, 0}, {0x3621, 0xc7, 0, 0}, {0x3801, 0x50, 0, 0}, + {0x3803, 0x08, 0, 0}, {0x3827, 0x08, 0, 0}, {0x3810, 0x80, 0, 0}, + {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, + {0x5683, 0x00, 0, 0}, {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, + {0x5686, 0x03, 0, 0}, {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, + {0x3a1a, 0x05, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, + {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, + {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, + {0x350d, 0xd0, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, + {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, + {0x3503, 0x00, 0, 0}, {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, + {0x528c, 0x08, 0, 0}, {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, + {0x528f, 0x10, 0, 0}, {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, + {0x5293, 0x02, 0, 0}, {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, + {0x5296, 0x00, 0, 0}, {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, + {0x5299, 0x02, 0, 0}, {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, + {0x529c, 0x00, 0, 0}, {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, + {0x529f, 0x02, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, + {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, + {0x3a1f, 0x10, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, + {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, + {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, + {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, + {0x3a0b, 0xa0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x5193, 0x70, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, + {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, + {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, + {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, + {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, + {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, + {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, + {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, + {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, + {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, + {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, + {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, + {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, + {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, + {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, + {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, + {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, + {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, + {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, + {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, + {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, + {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, + {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, + {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, + {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, + {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, + {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, + {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, + {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, + {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, + {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, + {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, + {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, + {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, + {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, + {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, + {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, + {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, + {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, + {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, + {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, + {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, + {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, + {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, + {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, + {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, + {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, + {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, + {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, + {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, + {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, + {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, + {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, + {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, + {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, + {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, + {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, + {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, + {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, + {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, + {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, + {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, + {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, + {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, + {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, + {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, + {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, + {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, + {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, + {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, + {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, + {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, + {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, + {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, + {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, + {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, + {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, + {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, + {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, + {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, + {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, + {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, + {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, + {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, + {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, + {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, + {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, + {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, + {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, + {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, + {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, + {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, + {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, + {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, + {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, + {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, + {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, + {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, + {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, + {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, + {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, + {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, + {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, + {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, + {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, + {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, + {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, + {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, + {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, + {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, + {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, + {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, + {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, + {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, + {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, + {0x302b, 0x00, 0, 0}, {0x3621, 0x87, 0, 0}, {0x3a00, 0x78, 0, 0}, + {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x03, 0, 0}, + {0x380b, 0x00, 0, 0}, {0x3815, 0x02, 0, 0}, {0x302c, 0x60, 0x60, 0}, +}; + +static struct reg_value ov5642_setting_15fps_XGA_1024_768[] = { + {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, + {0x3018, 0xfc, 0, 0}, {0x3615, 0xf0, 0, 0}, {0x3000, 0x00, 0, 0}, + {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, {0x3003, 0x00, 0, 0}, + {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, {0x3006, 0x43, 0, 0}, + {0x3007, 0x37, 0, 0}, {0x3011, 0x09, 0, 0}, {0x3012, 0x02, 0, 0}, + {0x3010, 0x00, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3815, 0x04, 0, 0}, + {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0}, + {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0}, + {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0}, + {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0}, + {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0}, + {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0}, + {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, + {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0}, + {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, + {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, + {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0}, + {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, + {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0}, + {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0}, + {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, + {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3825, 0xb0, 0, 0}, + {0x3501, 0x1e, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, + {0x380c, 0x07, 0, 0}, {0x380d, 0x2a, 0, 0}, {0x380e, 0x07, 0, 0}, + {0x380f, 0xd0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3818, 0xc1, 0, 0}, {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, + {0x3801, 0x80, 0, 0}, {0x3621, 0xc7, 0, 0}, {0x3801, 0x50, 0, 0}, + {0x3803, 0x08, 0, 0}, {0x3827, 0x08, 0, 0}, {0x3810, 0x80, 0, 0}, + {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, + {0x5683, 0x00, 0, 0}, {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, + {0x5686, 0x03, 0, 0}, {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, + {0x3a1a, 0x05, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, + {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, + {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, + {0x350d, 0xd0, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, + {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, + {0x3503, 0x00, 0, 0}, {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, + {0x528c, 0x08, 0, 0}, {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, + {0x528f, 0x10, 0, 0}, {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, + {0x5293, 0x02, 0, 0}, {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, + {0x5296, 0x00, 0, 0}, {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, + {0x5299, 0x02, 0, 0}, {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, + {0x529c, 0x00, 0, 0}, {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, + {0x529f, 0x02, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, + {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, + {0x3a1f, 0x10, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, + {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, + {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, + {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, + {0x3a0b, 0xa0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x5193, 0x70, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, + {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, + {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, + {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, + {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, + {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, + {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, + {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, + {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, + {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, + {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, + {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, + {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, + {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, + {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, + {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, + {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, + {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, + {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, + {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, + {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, + {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, + {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, + {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, + {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, + {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, + {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, + {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, + {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, + {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, + {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, + {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, + {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, + {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, + {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, + {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, + {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, + {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, + {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, + {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, + {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, + {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, + {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, + {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, + {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, + {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, + {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, + {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, + {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, + {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, + {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, + {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, + {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, + {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, + {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, + {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, + {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, + {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, + {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, + {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, + {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, + {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, + {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, + {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, + {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, + {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, + {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, + {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, + {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, + {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, + {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, + {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, + {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, + {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, + {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, + {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, + {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, + {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, + {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, + {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, + {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, + {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, + {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, + {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, + {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, + {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, + {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, + {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, + {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, + {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, + {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, + {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, + {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, + {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, + {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, + {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, + {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, + {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, + {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, + {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, + {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, + {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, + {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, + {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, + {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, + {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, + {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, + {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, + {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, + {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, + {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, + {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, + {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, + {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, + {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, + {0x302b, 0x00, 0, 0}, {0x3621, 0x87, 0, 0}, {0x3a00, 0x78, 0, 0}, + {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x03, 0, 0}, + {0x380b, 0x00, 0, 0}, {0x3815, 0x02, 0, 0}, {0x302c, 0x60, 0x60, 0}, +}; + +static struct reg_value ov5642_setting_30fps_QVGA_320_240[] = { + {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, + {0x3018, 0xfc, 0, 0}, {0x3615, 0xf0, 0, 0}, {0x3000, 0x00, 0, 0}, + {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, {0x3003, 0x00, 0, 0}, + {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, {0x3006, 0x43, 0, 0}, + {0x3007, 0x37, 0, 0}, {0x3011, 0x09, 0, 0}, {0x3012, 0x02, 0, 0}, + {0x3010, 0x00, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3815, 0x04, 0, 0}, + {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0}, + {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0}, + {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0}, + {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0}, + {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0}, + {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0}, + {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, + {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0}, + {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, + {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, + {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0}, + {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, + {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0}, + {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0}, + {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, + {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3825, 0xb0, 0, 0}, + {0x3501, 0x1e, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, + {0x380c, 0x07, 0, 0}, {0x380d, 0x2a, 0, 0}, {0x380e, 0x03, 0, 0}, + {0x380f, 0xe8, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3818, 0xc1, 0, 0}, {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, + {0x3801, 0x80, 0, 0}, {0x3621, 0xc7, 0, 0}, {0x3801, 0x50, 0, 0}, + {0x3803, 0x08, 0, 0}, {0x3827, 0x08, 0, 0}, {0x3810, 0x80, 0, 0}, + {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, + {0x5683, 0x00, 0, 0}, {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, + {0x5686, 0x03, 0, 0}, {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, + {0x3a1a, 0x05, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, + {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, + {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, + {0x350d, 0xd0, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, + {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, + {0x3503, 0x00, 0, 0}, {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, + {0x528c, 0x08, 0, 0}, {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, + {0x528f, 0x10, 0, 0}, {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, + {0x5293, 0x02, 0, 0}, {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, + {0x5296, 0x00, 0, 0}, {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, + {0x5299, 0x02, 0, 0}, {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, + {0x529c, 0x00, 0, 0}, {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, + {0x529f, 0x02, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, + {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, + {0x3a1f, 0x10, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, + {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, + {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, + {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, + {0x3a0b, 0xa0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x5193, 0x70, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, + {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, + {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, + {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, + {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, + {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, + {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, + {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, + {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, + {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, + {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, + {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, + {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, + {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, + {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, + {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, + {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, + {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, + {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, + {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, + {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, + {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, + {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, + {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, + {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, + {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, + {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, + {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, + {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, + {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, + {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, + {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, + {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, + {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, + {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, + {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, + {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, + {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, + {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, + {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, + {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, + {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, + {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, + {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, + {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, + {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, + {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, + {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, + {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, + {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, + {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, + {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, + {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, + {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, + {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, + {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, + {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, + {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, + {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, + {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, + {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, + {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, + {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, + {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, + {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, + {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, + {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, + {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, + {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, + {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, + {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, + {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, + {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, + {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, + {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, + {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, + {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, + {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, + {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, + {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, + {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, + {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, + {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, + {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, + {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, + {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, + {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, + {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, + {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, + {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, + {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, + {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, + {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, + {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, + {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, + {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, + {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, + {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, + {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, + {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, + {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, + {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, + {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, + {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, + {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, + {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, + {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, + {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, + {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, + {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, + {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, + {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, + {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, + {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, + {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, + {0x302b, 0x00, 0, 0}, {0x3621, 0x87, 0, 0}, {0x3808, 0x01, 0, 0}, + {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0}, {0x380b, 0xf0, 0, 0}, +}; + +static struct reg_value ov5642_setting_30fps_NTSC_720_480[] = { + {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, + {0x3018, 0xfc, 0, 0}, {0x3615, 0xf0, 0, 0}, {0x3000, 0x00, 0, 0}, + {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, {0x3003, 0x00, 0, 0}, + {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, {0x3006, 0x43, 0, 0}, + {0x3007, 0x37, 0, 0}, {0x3011, 0x09, 0, 0}, {0x3012, 0x02, 0, 0}, + {0x3010, 0x00, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3815, 0x04, 0, 0}, + {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0}, + {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0}, + {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0}, + {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0}, + {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0}, + {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0}, + {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, + {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0}, + {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, + {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, + {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0}, + {0x3809, 0xd0, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, + {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0}, + {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0}, + {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, + {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3825, 0xb0, 0, 0}, + {0x3501, 0x1e, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, + {0x380c, 0x07, 0, 0}, {0x380d, 0x2a, 0, 0}, {0x380e, 0x03, 0, 0}, + {0x380f, 0xe8, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3818, 0xc1, 0, 0}, {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, + {0x3801, 0x80, 0, 0}, {0x3621, 0xc7, 0, 0}, {0x3801, 0x50, 0, 0}, + {0x3803, 0x08, 0, 0}, {0x3827, 0x3c, 0, 0}, {0x3810, 0x80, 0, 0}, + {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, + {0x5683, 0x00, 0, 0}, {0x3806, 0x03, 0, 0}, {0x3807, 0x58, 0, 0}, + {0x5686, 0x03, 0, 0}, {0x5687, 0x58, 0, 0}, {0x3a00, 0x78, 0, 0}, + {0x3a1a, 0x05, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, + {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, + {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, + {0x350d, 0xd0, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, + {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, + {0x3503, 0x00, 0, 0}, {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, + {0x528c, 0x08, 0, 0}, {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, + {0x528f, 0x10, 0, 0}, {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, + {0x5293, 0x02, 0, 0}, {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, + {0x5296, 0x00, 0, 0}, {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, + {0x5299, 0x02, 0, 0}, {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, + {0x529c, 0x00, 0, 0}, {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, + {0x529f, 0x02, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, + {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, + {0x3a1f, 0x10, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, + {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, + {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, + {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, + {0x3a0b, 0xa0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x5193, 0x70, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, + {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, + {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, + {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, + {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, + {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, + {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, + {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, + {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, + {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, + {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, + {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, + {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, + {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, + {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, + {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, + {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, + {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, + {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, + {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, + {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, + {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, + {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, + {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, + {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, + {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, + {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, + {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, + {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, + {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, + {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, + {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, + {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, + {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, + {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, + {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, + {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, + {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, + {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, + {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, + {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, + {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, + {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, + {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, + {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, + {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, + {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, + {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, + {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, + {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, + {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, + {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, + {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, + {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, + {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, + {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, + {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, + {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, + {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, + {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, + {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, + {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, + {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, + {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, + {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, + {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, + {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, + {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, + {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, + {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, + {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, + {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, + {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, + {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, + {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, + {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, + {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, + {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, + {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, + {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, + {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, + {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, + {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, + {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, + {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, + {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, + {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, + {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, + {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, + {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, + {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, + {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, + {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, + {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, + {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, + {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, + {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, + {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, + {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, + {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, + {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, + {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, + {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, + {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, + {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, + {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, + {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, + {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, + {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, + {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, + {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, + {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, + {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, + {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, + {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, + {0x302b, 0x00, 0, 0}, {0x3621, 0x87, 0, 0}, {0x3a00, 0x78, 0, 0}, + {0x302c, 0x60, 0x60, 0}, +}; + +static struct reg_value ov5642_setting_30fps_PAL_720_576[] = { + {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, + {0x3018, 0xfc, 0, 0}, {0x3615, 0xf0, 0, 0}, {0x3000, 0x00, 0, 0}, + {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, {0x3003, 0x00, 0, 0}, + {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, {0x3006, 0x43, 0, 0}, + {0x3007, 0x37, 0, 0}, {0x3011, 0x09, 0, 0}, {0x3012, 0x02, 0, 0}, + {0x3010, 0x00, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3815, 0x04, 0, 0}, + {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0}, + {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0}, + {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0}, + {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0}, + {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0}, + {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0}, + {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, + {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0}, + {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, + {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, + {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0}, + {0x3809, 0xd0, 0, 0}, {0x380a, 0x02, 0, 0}, {0x380b, 0x40, 0, 0}, + {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0}, + {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0}, + {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, + {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3825, 0xd8, 0, 0}, + {0x3501, 0x1e, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, + {0x380c, 0x07, 0, 0}, {0x380d, 0x2a, 0, 0}, {0x380e, 0x03, 0, 0}, + {0x380f, 0xe8, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3818, 0xc1, 0, 0}, {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, + {0x3801, 0x80, 0, 0}, {0x3621, 0xc7, 0, 0}, {0x3801, 0x50, 0, 0}, + {0x3803, 0x08, 0, 0}, {0x3827, 0x3c, 0, 0}, {0x3810, 0x80, 0, 0}, + {0x3804, 0x04, 0, 0}, {0x3805, 0xb0, 0, 0}, {0x5682, 0x04, 0, 0}, + {0x5683, 0xb0, 0, 0}, {0x3806, 0x03, 0, 0}, {0x3807, 0x58, 0, 0}, + {0x5686, 0x03, 0, 0}, {0x5687, 0x58, 0, 0}, {0x3a00, 0x78, 0, 0}, + {0x3a1a, 0x05, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, + {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, + {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, + {0x350d, 0xd0, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, + {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, + {0x3503, 0x00, 0, 0}, {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, + {0x528c, 0x08, 0, 0}, {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, + {0x528f, 0x10, 0, 0}, {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, + {0x5293, 0x02, 0, 0}, {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, + {0x5296, 0x00, 0, 0}, {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, + {0x5299, 0x02, 0, 0}, {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, + {0x529c, 0x00, 0, 0}, {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, + {0x529f, 0x02, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, + {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, + {0x3a1f, 0x10, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, + {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, + {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, + {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, + {0x3a0b, 0xa0, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x5193, 0x70, 0, 0}, {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, + {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, + {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, + {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, + {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, + {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, + {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, + {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, + {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, + {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, + {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, + {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, + {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, + {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, + {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, + {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, + {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, + {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, + {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, + {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, + {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, + {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, + {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, + {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, + {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, + {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, + {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, + {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, + {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, + {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, + {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, + {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, + {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, + {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, + {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, + {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, + {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, + {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, + {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, + {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, + {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, + {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, + {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, + {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, + {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, + {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, + {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, + {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, + {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, + {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, + {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, + {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, + {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, + {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, + {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, + {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, + {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, + {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, + {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, + {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, + {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, + {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, + {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, + {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, + {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, + {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, + {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, + {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, + {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, + {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, + {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, + {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, + {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, + {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, + {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, + {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, + {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, + {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, + {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, + {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, + {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, + {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, + {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, + {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, + {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, + {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, + {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, + {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, + {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, + {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, + {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, + {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, + {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, + {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, + {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, + {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, + {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, + {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, + {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, + {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, + {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, + {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, + {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, + {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, + {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, + {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, + {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, + {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, + {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, + {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, + {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, + {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, + {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, + {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, + {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, + {0x302b, 0x00, 0, 0}, {0x3621, 0x87, 0, 0}, {0x3a00, 0x78, 0, 0}, + {0x302c, 0x60, 0x60, 0}, +}; + +static struct reg_value ov5642_setting_15fps_720P_1280_720[] = { + {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, + {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0}, + {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x00, 0, 0}, + {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3030, 0x2b, 0, 0}, + {0x3011, 0x08, 0, 0}, {0x3010, 0x10, 0, 0}, {0x3604, 0x60, 0, 0}, + {0x3622, 0x60, 0, 0}, {0x3621, 0x09, 0, 0}, {0x3709, 0x00, 0, 0}, + {0x4000, 0x21, 0, 0}, {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, + {0x3605, 0x04, 0, 0}, {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, + {0x300d, 0x22, 0, 0}, {0x3623, 0x22, 0, 0}, {0x5000, 0x4f, 0, 0}, + {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, + {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5500, 0x0a, 0, 0}, + {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, {0x5080, 0x08, 0, 0}, + {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, {0x471d, 0x05, 0, 0}, + {0x4708, 0x06, 0, 0}, {0x370c, 0xa0, 0, 0}, {0x3808, 0x0a, 0, 0}, + {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, {0x380b, 0x98, 0, 0}, + {0x380c, 0x0c, 0, 0}, {0x380d, 0x80, 0, 0}, {0x380e, 0x07, 0, 0}, + {0x380f, 0xd0, 0, 0}, {0x5687, 0x94, 0, 0}, {0x501f, 0x00, 0, 0}, + {0x5000, 0x4f, 0, 0}, {0x5001, 0xcf, 0, 0}, {0x4300, 0x30, 0, 0}, + {0x4300, 0x30, 0, 0}, {0x460b, 0x35, 0, 0}, {0x471d, 0x00, 0, 0}, + {0x3002, 0x0c, 0, 0}, {0x3002, 0x00, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x471c, 0x50, 0, 0}, {0x4721, 0x02, 0, 0}, {0x4402, 0x90, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x3815, 0x44, 0, 0}, {0x3503, 0x07, 0, 0}, + {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, + {0x3818, 0xc8, 0, 0}, {0x3801, 0x88, 0, 0}, {0x3824, 0x11, 0, 0}, + {0x3a00, 0x78, 0, 0}, {0x3a1a, 0x04, 0, 0}, {0x3a13, 0x30, 0, 0}, + {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, + {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, + {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0}, {0x3a0d, 0x08, 0, 0}, + {0x3a0e, 0x06, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, + {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, + {0x3503, 0x00, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x32, 0, 0}, + {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x32, 0, 0}, {0x3a11, 0x80, 0, 0}, + {0x3a1f, 0x20, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, + {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, + {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, + {0x3a08, 0x09, 0, 0}, {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x07, 0, 0}, + {0x3a0b, 0xd0, 0, 0}, {0x3a0d, 0x10, 0, 0}, {0x3a0e, 0x0d, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, {0x589b, 0x00, 0, 0}, + {0x589a, 0xc0, 0, 0}, {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, + {0x401c, 0x06, 0, 0}, {0x3825, 0xac, 0, 0}, {0x3827, 0x0c, 0, 0}, + {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, + {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, + {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, + {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, + {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, + {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, + {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, + {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, + {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, + {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, + {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, + {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, + {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, + {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, + {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, + {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, + {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, + {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, + {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, + {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, + {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, + {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, + {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, + {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, + {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, + {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, + {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, + {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, + {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, + {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, + {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, + {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, + {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, + {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, + {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, + {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, + {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, + {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, + {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, + {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, + {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, + {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, + {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, + {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, + {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, + {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, + {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, + {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, + {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, + {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, + {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, + {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, + {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, + {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, + {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, + {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, + {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, + {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, + {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, + {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, + {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, + {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, + {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, + {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, + {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, + {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, + {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, + {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, + {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, + {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, + {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, + {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, + {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, + {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, + {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, + {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, + {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, + {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, + {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, + {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, + {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, + {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, + {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, + {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, + {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, + {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, + {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, + {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, + {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, + {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, + {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, + {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, + {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, + {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, + {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, + {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, + {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, + {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, + {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, + {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, + {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, + {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, + {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, + {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, + {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, + {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, + {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, + {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, + {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, + {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, + {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, + {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, + {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, + {0x302b, 0x00, 0, 0}, {0x3503, 0x07, 0, 0}, {0x3011, 0x08, 0, 0}, + {0x350c, 0x02, 0, 0}, {0x350d, 0xe4, 0, 0}, {0x3621, 0xc9, 0, 0}, + {0x370a, 0x81, 0, 0}, {0x3803, 0x08, 0, 0}, {0x3804, 0x05, 0, 0}, + {0x3805, 0x00, 0, 0}, {0x3806, 0x02, 0, 0}, {0x3807, 0xd0, 0, 0}, + {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0}, + {0x380b, 0xd0, 0, 0}, {0x380c, 0x08, 0, 0}, {0x380d, 0x72, 0, 0}, + {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3810, 0xc0, 0, 0}, + {0x3818, 0xc9, 0, 0}, {0x381c, 0x10, 0, 0}, {0x381d, 0xa0, 0, 0}, + {0x381e, 0x05, 0, 0}, {0x381f, 0xb0, 0, 0}, {0x3820, 0x00, 0, 0}, + {0x3821, 0x00, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3a08, 0x1b, 0, 0}, + {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x17, 0, 0}, {0x3a0b, 0x20, 0, 0}, + {0x3a0d, 0x02, 0, 0}, {0x3a0e, 0x01, 0, 0}, {0x401c, 0x04, 0, 0}, + {0x5682, 0x05, 0, 0}, {0x5683, 0x00, 0, 0}, {0x5686, 0x02, 0, 0}, + {0x5687, 0xcc, 0, 0}, {0x5001, 0x7f, 0, 0}, {0x589b, 0x06, 0, 0}, + {0x589a, 0xc5, 0, 0}, {0x3503, 0x00, 0, 0}, {0x3010, 0x10, 0, 0}, + {0x460c, 0x20, 0, 0}, {0x460b, 0x37, 0, 0}, {0x471c, 0xd0, 0, 0}, + {0x471d, 0x05, 0, 0}, {0x3815, 0x01, 0, 0}, {0x3818, 0x00, 0x08, 0}, + {0x501f, 0x00, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3002, 0x1c, 0, 0}, + {0x3819, 0x80, 0, 0}, {0x5002, 0xe0, 0, 0}, {0x3010, 0x30, 0, 0}, + {0x3a08, 0x06, 0, 0}, {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x05, 0, 0}, + {0x3a0b, 0x50, 0, 0}, {0x3a0d, 0x08, 0, 0}, {0x3a0e, 0x07, 0, 0}, +}; + +static struct reg_value ov5642_setting_30fps_720P_1280_720[] = { + {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, + {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0}, + {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x00, 0, 0}, + {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3030, 0x2b, 0, 0}, + {0x3011, 0x08, 0, 0}, {0x3010, 0x10, 0, 0}, {0x3604, 0x60, 0, 0}, + {0x3622, 0x60, 0, 0}, {0x3621, 0x09, 0, 0}, {0x3709, 0x00, 0, 0}, + {0x4000, 0x21, 0, 0}, {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, + {0x3605, 0x04, 0, 0}, {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, + {0x300d, 0x22, 0, 0}, {0x3623, 0x22, 0, 0}, {0x5000, 0x4f, 0, 0}, + {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, + {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5500, 0x0a, 0, 0}, + {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, {0x5080, 0x08, 0, 0}, + {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, {0x471d, 0x05, 0, 0}, + {0x4708, 0x06, 0, 0}, {0x370c, 0xa0, 0, 0}, {0x3808, 0x0a, 0, 0}, + {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, {0x380b, 0x98, 0, 0}, + {0x380c, 0x0c, 0, 0}, {0x380d, 0x80, 0, 0}, {0x380e, 0x07, 0, 0}, + {0x380f, 0xd0, 0, 0}, {0x5687, 0x94, 0, 0}, {0x501f, 0x00, 0, 0}, + {0x5000, 0x4f, 0, 0}, {0x5001, 0xcf, 0, 0}, {0x4300, 0x30, 0, 0}, + {0x4300, 0x30, 0, 0}, {0x460b, 0x35, 0, 0}, {0x471d, 0x00, 0, 0}, + {0x3002, 0x0c, 0, 0}, {0x3002, 0x00, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x471c, 0x50, 0, 0}, {0x4721, 0x02, 0, 0}, {0x4402, 0x90, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x3815, 0x44, 0, 0}, {0x3503, 0x07, 0, 0}, + {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, + {0x3818, 0xc8, 0, 0}, {0x3801, 0x88, 0, 0}, {0x3824, 0x11, 0, 0}, + {0x3a00, 0x78, 0, 0}, {0x3a1a, 0x04, 0, 0}, {0x3a13, 0x30, 0, 0}, + {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, + {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, + {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0}, {0x3a0d, 0x08, 0, 0}, + {0x3a0e, 0x06, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, + {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, + {0x3503, 0x00, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x32, 0, 0}, + {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x32, 0, 0}, {0x3a11, 0x80, 0, 0}, + {0x3a1f, 0x20, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, + {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, + {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, + {0x3a08, 0x09, 0, 0}, {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x07, 0, 0}, + {0x3a0b, 0xd0, 0, 0}, {0x3a0d, 0x10, 0, 0}, {0x3a0e, 0x0d, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, {0x589b, 0x00, 0, 0}, + {0x589a, 0xc0, 0, 0}, {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, + {0x401c, 0x06, 0, 0}, {0x3825, 0xac, 0, 0}, {0x3827, 0x0c, 0, 0}, + {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, + {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, + {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, + {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, + {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, + {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, + {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, + {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, + {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, + {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, + {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, + {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, + {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, + {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, + {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, + {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, + {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, + {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, + {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, + {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, + {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, + {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, + {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, + {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, + {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, + {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, + {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, + {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, + {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, + {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, + {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, + {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, + {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, + {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, + {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, + {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, + {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, + {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, + {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, + {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, + {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, + {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, + {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, + {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, + {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, + {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, + {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, + {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, + {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, + {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, + {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, + {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, + {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, + {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, + {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, + {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, + {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, + {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, + {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, + {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, + {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, + {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, + {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, + {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, + {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, + {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, + {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, + {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, + {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, + {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, + {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, + {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, + {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, + {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, + {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, + {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, + {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, + {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, + {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, + {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, + {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, + {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, + {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, + {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, + {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, + {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, + {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, + {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, + {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, + {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, + {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, + {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, + {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, + {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, + {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, + {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, + {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, + {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, + {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, + {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, + {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, + {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, + {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, + {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, + {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, + {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, + {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, + {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, + {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, + {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, + {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, + {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, + {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, + {0x302b, 0x00, 0, 0}, {0x3503, 0x07, 0, 0}, {0x3011, 0x08, 0, 0}, + {0x350c, 0x02, 0, 0}, {0x350d, 0xe4, 0, 0}, {0x3621, 0xc9, 0, 0}, + {0x370a, 0x81, 0, 0}, {0x3803, 0x08, 0, 0}, {0x3804, 0x05, 0, 0}, + {0x3805, 0x00, 0, 0}, {0x3806, 0x02, 0, 0}, {0x3807, 0xd0, 0, 0}, + {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0}, + {0x380b, 0xd0, 0, 0}, {0x380c, 0x08, 0, 0}, {0x380d, 0x72, 0, 0}, + {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3810, 0xc0, 0, 0}, + {0x3818, 0xc9, 0, 0}, {0x381c, 0x10, 0, 0}, {0x381d, 0xa0, 0, 0}, + {0x381e, 0x05, 0, 0}, {0x381f, 0xb0, 0, 0}, {0x3820, 0x00, 0, 0}, + {0x3821, 0x00, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3a08, 0x1b, 0, 0}, + {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x17, 0, 0}, {0x3a0b, 0x20, 0, 0}, + {0x3a0d, 0x02, 0, 0}, {0x3a0e, 0x01, 0, 0}, {0x401c, 0x04, 0, 0}, + {0x5682, 0x05, 0, 0}, {0x5683, 0x00, 0, 0}, {0x5686, 0x02, 0, 0}, + {0x5687, 0xcc, 0, 0}, {0x5001, 0x7f, 0, 0}, {0x589b, 0x06, 0, 0}, + {0x589a, 0xc5, 0, 0}, {0x3503, 0x00, 0, 0}, {0x3010, 0x10, 0, 0}, + {0x460c, 0x20, 0, 0}, {0x460b, 0x37, 0, 0}, {0x471c, 0xd0, 0, 0}, + {0x471d, 0x05, 0, 0}, {0x3815, 0x01, 0, 0}, {0x3818, 0x00, 0x08, 0}, + {0x501f, 0x00, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3002, 0x1c, 0, 0}, + {0x3819, 0x80, 0, 0}, {0x5002, 0xe0, 0, 0}, +}; + +static struct reg_value ov5642_setting_15fps_1080P_1920_1080[] = { + {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, + {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0}, + {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x00, 0, 0}, + {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3030, 0x2b, 0, 0}, + {0x3011, 0x08, 0, 0}, {0x3010, 0x10, 0, 0}, {0x3604, 0x60, 0, 0}, + {0x3622, 0x60, 0, 0}, {0x3621, 0x09, 0, 0}, {0x3709, 0x00, 0, 0}, + {0x4000, 0x21, 0, 0}, {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, + {0x3605, 0x04, 0, 0}, {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, + {0x300d, 0x22, 0, 0}, {0x3623, 0x22, 0, 0}, {0x5000, 0x4f, 0, 0}, + {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, + {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5500, 0x0a, 0, 0}, + {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, {0x5080, 0x08, 0, 0}, + {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, {0x471d, 0x05, 0, 0}, + {0x4708, 0x06, 0, 0}, {0x370c, 0xa0, 0, 0}, {0x3808, 0x0a, 0, 0}, + {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, {0x380b, 0x98, 0, 0}, + {0x380c, 0x0c, 0, 0}, {0x380d, 0x80, 0, 0}, {0x380e, 0x07, 0, 0}, + {0x380f, 0xd0, 0, 0}, {0x5687, 0x94, 0, 0}, {0x501f, 0x00, 0, 0}, + {0x5000, 0x4f, 0, 0}, {0x5001, 0xcf, 0, 0}, {0x4300, 0x30, 0, 0}, + {0x4300, 0x30, 0, 0}, {0x460b, 0x35, 0, 0}, {0x471d, 0x00, 0, 0}, + {0x3002, 0x0c, 0, 0}, {0x3002, 0x00, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x471c, 0x50, 0, 0}, {0x4721, 0x02, 0, 0}, {0x4402, 0x90, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x3815, 0x44, 0, 0}, {0x3503, 0x07, 0, 0}, + {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, + {0x3818, 0xc8, 0, 0}, {0x3801, 0x88, 0, 0}, {0x3824, 0x11, 0, 0}, + {0x3a00, 0x78, 0, 0}, {0x3a1a, 0x04, 0, 0}, {0x3a13, 0x30, 0, 0}, + {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0}, {0x3a08, 0x12, 0, 0}, + {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, {0x3a0b, 0xa0, 0, 0}, + {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0}, {0x3a0d, 0x08, 0, 0}, + {0x3a0e, 0x06, 0, 0}, {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, + {0x3502, 0x00, 0, 0}, {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, + {0x3503, 0x00, 0, 0}, {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x32, 0, 0}, + {0x3a1b, 0x3c, 0, 0}, {0x3a1e, 0x32, 0, 0}, {0x3a11, 0x80, 0, 0}, + {0x3a1f, 0x20, 0, 0}, {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, + {0x3a03, 0x7d, 0, 0}, {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, + {0x3a15, 0x7d, 0, 0}, {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, + {0x3a08, 0x09, 0, 0}, {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x07, 0, 0}, + {0x3a0b, 0xd0, 0, 0}, {0x3a0d, 0x10, 0, 0}, {0x3a0e, 0x0d, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, {0x589b, 0x00, 0, 0}, + {0x589a, 0xc0, 0, 0}, {0x401e, 0x20, 0, 0}, {0x4001, 0x42, 0, 0}, + {0x401c, 0x06, 0, 0}, {0x3825, 0xac, 0, 0}, {0x3827, 0x0c, 0, 0}, + {0x528a, 0x01, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, + {0x528d, 0x10, 0, 0}, {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, + {0x5290, 0x30, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, + {0x5294, 0x00, 0, 0}, {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, + {0x5297, 0x08, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, + {0x529a, 0x00, 0, 0}, {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, + {0x529d, 0x28, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, + {0x5282, 0x00, 0, 0}, {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, + {0x5302, 0x00, 0, 0}, {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, + {0x530d, 0x0c, 0, 0}, {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, + {0x5310, 0x20, 0, 0}, {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, + {0x5309, 0x40, 0, 0}, {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, + {0x5306, 0x00, 0, 0}, {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, + {0x5315, 0x20, 0, 0}, {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, + {0x5317, 0x00, 0, 0}, {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, + {0x5381, 0x00, 0, 0}, {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, + {0x5384, 0x00, 0, 0}, {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, + {0x5387, 0x00, 0, 0}, {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, + {0x538a, 0x00, 0, 0}, {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, + {0x538d, 0x00, 0, 0}, {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, + {0x5390, 0x00, 0, 0}, {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, + {0x5393, 0xa2, 0, 0}, {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, + {0x5481, 0x21, 0, 0}, {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, + {0x5484, 0x65, 0, 0}, {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, + {0x5487, 0x87, 0, 0}, {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, + {0x548a, 0xaa, 0, 0}, {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, + {0x548d, 0xdd, 0, 0}, {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, + {0x5490, 0x05, 0, 0}, {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, + {0x5493, 0x20, 0, 0}, {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, + {0x5496, 0x02, 0, 0}, {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, + {0x5499, 0x86, 0, 0}, {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, + {0x549c, 0x02, 0, 0}, {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, + {0x549f, 0x1c, 0, 0}, {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, + {0x54a2, 0x01, 0, 0}, {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, + {0x54a5, 0xc5, 0, 0}, {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, + {0x54a8, 0x01, 0, 0}, {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, + {0x54ab, 0x41, 0, 0}, {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, + {0x54ae, 0x00, 0, 0}, {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, + {0x54b1, 0x20, 0, 0}, {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, + {0x54b4, 0x00, 0, 0}, {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, + {0x54b7, 0xdf, 0, 0}, {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, + {0x3406, 0x00, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, + {0x5182, 0x11, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, + {0x5185, 0x24, 0, 0}, {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, + {0x5188, 0x08, 0, 0}, {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, + {0x518b, 0xb2, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, + {0x518e, 0x3d, 0, 0}, {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, + {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, + {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, + {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, + {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, + {0x519d, 0x82, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, + {0x3a0f, 0x38, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, + {0x3a1e, 0x2e, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, + {0x5688, 0xa6, 0, 0}, {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, + {0x568b, 0xae, 0, 0}, {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, + {0x568e, 0x62, 0, 0}, {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, + {0x5584, 0x40, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, + {0x5800, 0x27, 0, 0}, {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, + {0x5803, 0x0f, 0, 0}, {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, + {0x5806, 0x1e, 0, 0}, {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, + {0x5809, 0x0d, 0, 0}, {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, + {0x580c, 0x0a, 0, 0}, {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, + {0x580f, 0x19, 0, 0}, {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, + {0x5812, 0x04, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, + {0x5815, 0x06, 0, 0}, {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, + {0x5818, 0x0a, 0, 0}, {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, + {0x581b, 0x00, 0, 0}, {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, + {0x581e, 0x08, 0, 0}, {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, + {0x5821, 0x05, 0, 0}, {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, + {0x5824, 0x00, 0, 0}, {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, + {0x5827, 0x0c, 0, 0}, {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, + {0x582a, 0x06, 0, 0}, {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, + {0x582d, 0x07, 0, 0}, {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, + {0x5830, 0x18, 0, 0}, {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, + {0x5833, 0x0a, 0, 0}, {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, + {0x5836, 0x15, 0, 0}, {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, + {0x5839, 0x1f, 0, 0}, {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, + {0x583c, 0x17, 0, 0}, {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, + {0x583f, 0x53, 0, 0}, {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, + {0x5842, 0x0d, 0, 0}, {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, + {0x5845, 0x09, 0, 0}, {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, + {0x5848, 0x10, 0, 0}, {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, + {0x584b, 0x0e, 0, 0}, {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, + {0x584e, 0x11, 0, 0}, {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, + {0x5851, 0x0c, 0, 0}, {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, + {0x5854, 0x10, 0, 0}, {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, + {0x5857, 0x0b, 0, 0}, {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, + {0x585a, 0x0d, 0, 0}, {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, + {0x585d, 0x0c, 0, 0}, {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, + {0x5860, 0x0c, 0, 0}, {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, + {0x5863, 0x08, 0, 0}, {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, + {0x5866, 0x18, 0, 0}, {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, + {0x5869, 0x19, 0, 0}, {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, + {0x586c, 0x13, 0, 0}, {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, + {0x586f, 0x16, 0, 0}, {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, + {0x5872, 0x10, 0, 0}, {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, + {0x5875, 0x16, 0, 0}, {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, + {0x5878, 0x10, 0, 0}, {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, + {0x587b, 0x14, 0, 0}, {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, + {0x587e, 0x11, 0, 0}, {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, + {0x5881, 0x15, 0, 0}, {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, + {0x5884, 0x15, 0, 0}, {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, + {0x5887, 0x17, 0, 0}, {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, + {0x3702, 0x10, 0, 0}, {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, + {0x370b, 0x40, 0, 0}, {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, + {0x3632, 0x52, 0, 0}, {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, + {0x5785, 0x07, 0, 0}, {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, + {0x3604, 0x48, 0, 0}, {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, + {0x370f, 0xc0, 0, 0}, {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, + {0x5007, 0x00, 0, 0}, {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, + {0x5013, 0x00, 0, 0}, {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, + {0x5087, 0x00, 0, 0}, {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, + {0x302b, 0x00, 0, 0}, {0x3503, 0x07, 0, 0}, {0x3011, 0x07, 0, 0}, + {0x350c, 0x04, 0, 0}, {0x350d, 0x58, 0, 0}, {0x3801, 0x8a, 0, 0}, + {0x3803, 0x0a, 0, 0}, {0x3804, 0x07, 0, 0}, {0x3805, 0x80, 0, 0}, + {0x3806, 0x04, 0, 0}, {0x3807, 0x39, 0, 0}, {0x3808, 0x07, 0, 0}, + {0x3809, 0x80, 0, 0}, {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0}, + {0x380c, 0x09, 0, 0}, {0x380d, 0xd6, 0, 0}, {0x380e, 0x04, 0, 0}, + {0x380f, 0x58, 0, 0}, {0x381c, 0x11, 0, 0}, {0x381d, 0xba, 0, 0}, + {0x381e, 0x04, 0, 0}, {0x381f, 0x48, 0, 0}, {0x3820, 0x04, 0, 0}, + {0x3821, 0x18, 0, 0}, {0x3a08, 0x14, 0, 0}, {0x3a09, 0xe0, 0, 0}, + {0x3a0a, 0x11, 0, 0}, {0x3a0b, 0x60, 0, 0}, {0x3a0d, 0x04, 0, 0}, + {0x3a0e, 0x03, 0, 0}, {0x5682, 0x07, 0, 0}, {0x5683, 0x60, 0, 0}, + {0x5686, 0x04, 0, 0}, {0x5687, 0x1c, 0, 0}, {0x5001, 0x7f, 0, 0}, + {0x3503, 0x00, 0, 0}, {0x3010, 0x10, 0, 0}, {0x460c, 0x20, 0, 0}, + {0x460b, 0x37, 0, 0}, {0x471c, 0xd0, 0, 0}, {0x471d, 0x05, 0, 0}, + {0x3815, 0x01, 0, 0}, {0x3818, 0x00, 0x08, 0}, {0x501f, 0x00, 0, 0}, + {0x4300, 0x30, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3819, 0x80, 0, 0}, + {0x5002, 0xe0, 0, 0}, +}; + +static struct reg_value ov5642_setting_15fps_QVGA_320_240[] = { + {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, + {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0}, + {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, + {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, + {0x3006, 0x43, 0, 0}, {0x3007, 0x37, 0, 0}, {0x3011, 0x08, 0, 0}, + {0x3010, 0x10, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3815, 0x04, 0, 0}, + {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0}, + {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0}, + {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0}, + {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0}, + {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0}, + {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0}, + {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, + {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0}, + {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, + {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, + {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0}, + {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, + {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0}, + {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0}, + {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, + {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3501, 0x1e, 0, 0}, + {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, {0x380c, 0x0c, 0, 0}, + {0x380d, 0x80, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xe8, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3818, 0xc1, 0, 0}, + {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, {0x3801, 0x80, 0, 0}, + {0x3621, 0x87, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3803, 0x08, 0, 0}, + {0x3827, 0x08, 0, 0}, {0x3810, 0x40, 0, 0}, {0x3804, 0x05, 0, 0}, + {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, {0x5683, 0x00, 0, 0}, + {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, {0x5686, 0x03, 0, 0}, + {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a1a, 0x05, 0, 0}, + {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0}, + {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, + {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0}, + {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, {0x3502, 0x00, 0, 0}, + {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, {0x3503, 0x00, 0, 0}, + {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, + {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, {0x528f, 0x10, 0, 0}, + {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x02, 0, 0}, + {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, {0x5296, 0x00, 0, 0}, + {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x02, 0, 0}, + {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, {0x529c, 0x00, 0, 0}, + {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x02, 0, 0}, + {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3c, 0, 0}, + {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, {0x3a1f, 0x10, 0, 0}, + {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, {0x3a03, 0x7d, 0, 0}, + {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, {0x3a15, 0x7d, 0, 0}, + {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a08, 0x09, 0, 0}, + {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x07, 0, 0}, {0x3a0b, 0xd0, 0, 0}, + {0x3a0d, 0x08, 0, 0}, {0x3a0e, 0x06, 0, 0}, {0x5193, 0x70, 0, 0}, + {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, {0x401e, 0x20, 0, 0}, + {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, {0x528a, 0x01, 0, 0}, + {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, {0x528d, 0x10, 0, 0}, + {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, {0x5290, 0x30, 0, 0}, + {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, {0x5294, 0x00, 0, 0}, + {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, {0x5297, 0x08, 0, 0}, + {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, {0x529a, 0x00, 0, 0}, + {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, {0x529d, 0x28, 0, 0}, + {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, {0x5282, 0x00, 0, 0}, + {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, {0x5302, 0x00, 0, 0}, + {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, {0x530d, 0x0c, 0, 0}, + {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, {0x5310, 0x20, 0, 0}, + {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, {0x5309, 0x40, 0, 0}, + {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x00, 0, 0}, + {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, {0x5315, 0x20, 0, 0}, + {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, {0x5317, 0x00, 0, 0}, + {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, {0x5381, 0x00, 0, 0}, + {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, {0x5384, 0x00, 0, 0}, + {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, {0x5387, 0x00, 0, 0}, + {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, {0x538a, 0x00, 0, 0}, + {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, {0x538d, 0x00, 0, 0}, + {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, {0x5390, 0x00, 0, 0}, + {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, {0x5393, 0xa2, 0, 0}, + {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, {0x5481, 0x21, 0, 0}, + {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, {0x5484, 0x65, 0, 0}, + {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, {0x5487, 0x87, 0, 0}, + {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, {0x548a, 0xaa, 0, 0}, + {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, {0x548d, 0xdd, 0, 0}, + {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, {0x5490, 0x05, 0, 0}, + {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, {0x5493, 0x20, 0, 0}, + {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, {0x5496, 0x02, 0, 0}, + {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, {0x5499, 0x86, 0, 0}, + {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, {0x549c, 0x02, 0, 0}, + {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, {0x549f, 0x1c, 0, 0}, + {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, {0x54a2, 0x01, 0, 0}, + {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, {0x54a5, 0xc5, 0, 0}, + {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, {0x54a8, 0x01, 0, 0}, + {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, {0x54ab, 0x41, 0, 0}, + {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, {0x54ae, 0x00, 0, 0}, + {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, {0x54b1, 0x20, 0, 0}, + {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, {0x54b4, 0x00, 0, 0}, + {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, {0x54b7, 0xdf, 0, 0}, + {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, {0x3406, 0x00, 0, 0}, + {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, {0x5182, 0x11, 0, 0}, + {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, + {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, {0x5188, 0x08, 0, 0}, + {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, {0x518b, 0xb2, 0, 0}, + {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, {0x518e, 0x3d, 0, 0}, + {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, + {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, + {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, + {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, {0x519a, 0x04, 0, 0}, + {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, {0x519d, 0x82, 0, 0}, + {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, {0x3a0f, 0x38, 0, 0}, + {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, {0x3a1e, 0x2e, 0, 0}, + {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, {0x5688, 0xa6, 0, 0}, + {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, {0x568b, 0xae, 0, 0}, + {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, {0x568e, 0x62, 0, 0}, + {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, {0x5584, 0x40, 0, 0}, + {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, {0x5800, 0x27, 0, 0}, + {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, {0x5803, 0x0f, 0, 0}, + {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, {0x5806, 0x1e, 0, 0}, + {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, {0x5809, 0x0d, 0, 0}, + {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, {0x580c, 0x0a, 0, 0}, + {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, {0x580f, 0x19, 0, 0}, + {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, {0x5812, 0x04, 0, 0}, + {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, {0x5815, 0x06, 0, 0}, + {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, {0x5818, 0x0a, 0, 0}, + {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, {0x581b, 0x00, 0, 0}, + {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, {0x581e, 0x08, 0, 0}, + {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, {0x5821, 0x05, 0, 0}, + {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, {0x5824, 0x00, 0, 0}, + {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, {0x5827, 0x0c, 0, 0}, + {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, {0x582a, 0x06, 0, 0}, + {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, {0x582d, 0x07, 0, 0}, + {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, {0x5830, 0x18, 0, 0}, + {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, {0x5833, 0x0a, 0, 0}, + {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, {0x5836, 0x15, 0, 0}, + {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, {0x5839, 0x1f, 0, 0}, + {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, {0x583c, 0x17, 0, 0}, + {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, {0x583f, 0x53, 0, 0}, + {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, {0x5842, 0x0d, 0, 0}, + {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, {0x5845, 0x09, 0, 0}, + {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, {0x5848, 0x10, 0, 0}, + {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, {0x584b, 0x0e, 0, 0}, + {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, {0x584e, 0x11, 0, 0}, + {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, {0x5851, 0x0c, 0, 0}, + {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, {0x5854, 0x10, 0, 0}, + {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, {0x5857, 0x0b, 0, 0}, + {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, {0x585a, 0x0d, 0, 0}, + {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, {0x585d, 0x0c, 0, 0}, + {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, {0x5860, 0x0c, 0, 0}, + {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, {0x5863, 0x08, 0, 0}, + {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, {0x5866, 0x18, 0, 0}, + {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, {0x5869, 0x19, 0, 0}, + {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, {0x586c, 0x13, 0, 0}, + {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, {0x586f, 0x16, 0, 0}, + {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, {0x5872, 0x10, 0, 0}, + {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, {0x5875, 0x16, 0, 0}, + {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, {0x5878, 0x10, 0, 0}, + {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, {0x587b, 0x14, 0, 0}, + {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, {0x587e, 0x11, 0, 0}, + {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, {0x5881, 0x15, 0, 0}, + {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, {0x5884, 0x15, 0, 0}, + {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, {0x5887, 0x17, 0, 0}, + {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, {0x3702, 0x10, 0, 0}, + {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, {0x370b, 0x40, 0, 0}, + {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, {0x3632, 0x52, 0, 0}, + {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, {0x5785, 0x07, 0, 0}, + {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, {0x3604, 0x48, 0, 0}, + {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, {0x370f, 0xc0, 0, 0}, + {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, {0x5007, 0x00, 0, 0}, + {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, {0x5013, 0x00, 0, 0}, + {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, {0x5087, 0x00, 0, 0}, + {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, {0x302b, 0x00, 0, 0}, + {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0}, + {0x380b, 0xf0, 0, 0}, {0x3a00, 0x78, 0, 0}, +}; + +static struct reg_value ov5642_setting_15fps_NTSC_720_480[] = { + {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, + {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0}, + {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, + {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, + {0x3006, 0x43, 0, 0}, {0x3007, 0x37, 0, 0}, {0x3011, 0x08, 0, 0}, + {0x3010, 0x10, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3815, 0x04, 0, 0}, + {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0}, + {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0}, + {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0}, + {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0}, + {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0}, + {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0}, + {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, + {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0}, + {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, + {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, + {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0}, + {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, + {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0}, + {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0}, + {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, + {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3501, 0x1e, 0, 0}, + {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, {0x380c, 0x0c, 0, 0}, + {0x380d, 0x80, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xe8, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3818, 0xc1, 0, 0}, + {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, {0x3801, 0x80, 0, 0}, + {0x3621, 0x87, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3803, 0x08, 0, 0}, + {0x3827, 0x08, 0, 0}, {0x3810, 0x40, 0, 0}, {0x3804, 0x05, 0, 0}, + {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, {0x5683, 0x00, 0, 0}, + {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, {0x5686, 0x03, 0, 0}, + {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a1a, 0x05, 0, 0}, + {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0}, + {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, + {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0}, + {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, {0x3502, 0x00, 0, 0}, + {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, {0x3503, 0x00, 0, 0}, + {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, + {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, {0x528f, 0x10, 0, 0}, + {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x02, 0, 0}, + {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, {0x5296, 0x00, 0, 0}, + {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x02, 0, 0}, + {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, {0x529c, 0x00, 0, 0}, + {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x02, 0, 0}, + {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3c, 0, 0}, + {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, {0x3a1f, 0x10, 0, 0}, + {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, {0x3a03, 0x7d, 0, 0}, + {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, {0x3a15, 0x7d, 0, 0}, + {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a08, 0x09, 0, 0}, + {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x07, 0, 0}, {0x3a0b, 0xd0, 0, 0}, + {0x3a0d, 0x08, 0, 0}, {0x3a0e, 0x06, 0, 0}, {0x5193, 0x70, 0, 0}, + {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, {0x401e, 0x20, 0, 0}, + {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, {0x528a, 0x01, 0, 0}, + {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, {0x528d, 0x10, 0, 0}, + {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, {0x5290, 0x30, 0, 0}, + {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, {0x5294, 0x00, 0, 0}, + {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, {0x5297, 0x08, 0, 0}, + {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, {0x529a, 0x00, 0, 0}, + {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, {0x529d, 0x28, 0, 0}, + {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, {0x5282, 0x00, 0, 0}, + {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, {0x5302, 0x00, 0, 0}, + {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, {0x530d, 0x0c, 0, 0}, + {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, {0x5310, 0x20, 0, 0}, + {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, {0x5309, 0x40, 0, 0}, + {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x00, 0, 0}, + {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, {0x5315, 0x20, 0, 0}, + {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, {0x5317, 0x00, 0, 0}, + {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, {0x5381, 0x00, 0, 0}, + {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, {0x5384, 0x00, 0, 0}, + {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, {0x5387, 0x00, 0, 0}, + {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, {0x538a, 0x00, 0, 0}, + {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, {0x538d, 0x00, 0, 0}, + {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, {0x5390, 0x00, 0, 0}, + {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, {0x5393, 0xa2, 0, 0}, + {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, {0x5481, 0x21, 0, 0}, + {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, {0x5484, 0x65, 0, 0}, + {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, {0x5487, 0x87, 0, 0}, + {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, {0x548a, 0xaa, 0, 0}, + {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, {0x548d, 0xdd, 0, 0}, + {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, {0x5490, 0x05, 0, 0}, + {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, {0x5493, 0x20, 0, 0}, + {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, {0x5496, 0x02, 0, 0}, + {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, {0x5499, 0x86, 0, 0}, + {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, {0x549c, 0x02, 0, 0}, + {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, {0x549f, 0x1c, 0, 0}, + {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, {0x54a2, 0x01, 0, 0}, + {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, {0x54a5, 0xc5, 0, 0}, + {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, {0x54a8, 0x01, 0, 0}, + {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, {0x54ab, 0x41, 0, 0}, + {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, {0x54ae, 0x00, 0, 0}, + {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, {0x54b1, 0x20, 0, 0}, + {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, {0x54b4, 0x00, 0, 0}, + {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, {0x54b7, 0xdf, 0, 0}, + {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, {0x3406, 0x00, 0, 0}, + {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, {0x5182, 0x11, 0, 0}, + {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, + {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, {0x5188, 0x08, 0, 0}, + {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, {0x518b, 0xb2, 0, 0}, + {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, {0x518e, 0x3d, 0, 0}, + {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, + {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, + {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, + {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, {0x519a, 0x04, 0, 0}, + {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, {0x519d, 0x82, 0, 0}, + {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, {0x3a0f, 0x38, 0, 0}, + {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, {0x3a1e, 0x2e, 0, 0}, + {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, {0x5688, 0xa6, 0, 0}, + {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, {0x568b, 0xae, 0, 0}, + {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, {0x568e, 0x62, 0, 0}, + {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, {0x5584, 0x40, 0, 0}, + {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, {0x5800, 0x27, 0, 0}, + {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, {0x5803, 0x0f, 0, 0}, + {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, {0x5806, 0x1e, 0, 0}, + {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, {0x5809, 0x0d, 0, 0}, + {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, {0x580c, 0x0a, 0, 0}, + {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, {0x580f, 0x19, 0, 0}, + {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, {0x5812, 0x04, 0, 0}, + {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, {0x5815, 0x06, 0, 0}, + {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, {0x5818, 0x0a, 0, 0}, + {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, {0x581b, 0x00, 0, 0}, + {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, {0x581e, 0x08, 0, 0}, + {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, {0x5821, 0x05, 0, 0}, + {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, {0x5824, 0x00, 0, 0}, + {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, {0x5827, 0x0c, 0, 0}, + {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, {0x582a, 0x06, 0, 0}, + {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, {0x582d, 0x07, 0, 0}, + {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, {0x5830, 0x18, 0, 0}, + {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, {0x5833, 0x0a, 0, 0}, + {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, {0x5836, 0x15, 0, 0}, + {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, {0x5839, 0x1f, 0, 0}, + {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, {0x583c, 0x17, 0, 0}, + {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, {0x583f, 0x53, 0, 0}, + {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, {0x5842, 0x0d, 0, 0}, + {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, {0x5845, 0x09, 0, 0}, + {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, {0x5848, 0x10, 0, 0}, + {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, {0x584b, 0x0e, 0, 0}, + {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, {0x584e, 0x11, 0, 0}, + {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, {0x5851, 0x0c, 0, 0}, + {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, {0x5854, 0x10, 0, 0}, + {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, {0x5857, 0x0b, 0, 0}, + {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, {0x585a, 0x0d, 0, 0}, + {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, {0x585d, 0x0c, 0, 0}, + {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, {0x5860, 0x0c, 0, 0}, + {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, {0x5863, 0x08, 0, 0}, + {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, {0x5866, 0x18, 0, 0}, + {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, {0x5869, 0x19, 0, 0}, + {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, {0x586c, 0x13, 0, 0}, + {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, {0x586f, 0x16, 0, 0}, + {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, {0x5872, 0x10, 0, 0}, + {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, {0x5875, 0x16, 0, 0}, + {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, {0x5878, 0x10, 0, 0}, + {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, {0x587b, 0x14, 0, 0}, + {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, {0x587e, 0x11, 0, 0}, + {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, {0x5881, 0x15, 0, 0}, + {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, {0x5884, 0x15, 0, 0}, + {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, {0x5887, 0x17, 0, 0}, + {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, {0x3702, 0x10, 0, 0}, + {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, {0x370b, 0x40, 0, 0}, + {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, {0x3632, 0x52, 0, 0}, + {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, {0x5785, 0x07, 0, 0}, + {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, {0x3604, 0x48, 0, 0}, + {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, {0x370f, 0xc0, 0, 0}, + {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, {0x5007, 0x00, 0, 0}, + {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, {0x5013, 0x00, 0, 0}, + {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, {0x5087, 0x00, 0, 0}, + {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, {0x302b, 0x00, 0, 0}, + {0x3824, 0x11, 0, 0}, {0x3825, 0xb4, 0, 0}, {0x3826, 0x00, 0, 0}, + {0x3827, 0x3d, 0, 0}, {0x380c, 0x0c, 0, 0}, {0x380d, 0x80, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xe8, 0, 0}, {0x3808, 0x02, 0, 0}, + {0x3809, 0xd0, 0, 0}, {0x380A, 0x01, 0, 0}, {0x380B, 0xe0, 0, 0}, + {0x3804, 0x05, 0, 0}, {0x3805, 0x00, 0, 0}, {0x3806, 0x03, 0, 0}, + {0x3807, 0x55, 0, 0}, {0x5686, 0x03, 0, 0}, {0x5687, 0x55, 0, 0}, + {0x5682, 0x05, 0, 0}, {0x5683, 0x00, 0, 0}, +}; + +static struct reg_value ov5642_setting_15fps_PAL_720_576[] = { + {0x3103, 0x93, 0, 0}, {0x3008, 0x82, 0, 0}, {0x3017, 0x7f, 0, 0}, + {0x3018, 0xfc, 0, 0}, {0x3810, 0xc2, 0, 0}, {0x3615, 0xf0, 0, 0}, + {0x3000, 0x00, 0, 0}, {0x3001, 0x00, 0, 0}, {0x3002, 0x5c, 0, 0}, + {0x3003, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3005, 0xff, 0, 0}, + {0x3006, 0x43, 0, 0}, {0x3007, 0x37, 0, 0}, {0x3011, 0x08, 0, 0}, + {0x3010, 0x10, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3815, 0x04, 0, 0}, + {0x370c, 0xa0, 0, 0}, {0x3602, 0xfc, 0, 0}, {0x3612, 0xff, 0, 0}, + {0x3634, 0xc0, 0, 0}, {0x3613, 0x00, 0, 0}, {0x3605, 0x7c, 0, 0}, + {0x3621, 0x09, 0, 0}, {0x3622, 0x60, 0, 0}, {0x3604, 0x40, 0, 0}, + {0x3603, 0xa7, 0, 0}, {0x3603, 0x27, 0, 0}, {0x4000, 0x21, 0, 0}, + {0x401d, 0x22, 0, 0}, {0x3600, 0x54, 0, 0}, {0x3605, 0x04, 0, 0}, + {0x3606, 0x3f, 0, 0}, {0x3c01, 0x80, 0, 0}, {0x5000, 0x4f, 0, 0}, + {0x5020, 0x04, 0, 0}, {0x5181, 0x79, 0, 0}, {0x5182, 0x00, 0, 0}, + {0x5185, 0x22, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5001, 0xff, 0, 0}, + {0x5500, 0x0a, 0, 0}, {0x5504, 0x00, 0, 0}, {0x5505, 0x7f, 0, 0}, + {0x5080, 0x08, 0, 0}, {0x300e, 0x18, 0, 0}, {0x4610, 0x00, 0, 0}, + {0x471d, 0x05, 0, 0}, {0x4708, 0x06, 0, 0}, {0x3808, 0x02, 0, 0}, + {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, + {0x380e, 0x07, 0, 0}, {0x380f, 0xd0, 0, 0}, {0x501f, 0x00, 0, 0}, + {0x5000, 0x4f, 0, 0}, {0x4300, 0x30, 0, 0}, {0x3503, 0x07, 0, 0}, + {0x3501, 0x73, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350b, 0x00, 0, 0}, + {0x3503, 0x07, 0, 0}, {0x3824, 0x11, 0, 0}, {0x3501, 0x1e, 0, 0}, + {0x3502, 0x80, 0, 0}, {0x350b, 0x7f, 0, 0}, {0x380c, 0x0c, 0, 0}, + {0x380d, 0x80, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xe8, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3818, 0xc1, 0, 0}, + {0x3705, 0xdb, 0, 0}, {0x370a, 0x81, 0, 0}, {0x3801, 0x80, 0, 0}, + {0x3621, 0x87, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3803, 0x08, 0, 0}, + {0x3827, 0x08, 0, 0}, {0x3810, 0x40, 0, 0}, {0x3804, 0x05, 0, 0}, + {0x3805, 0x00, 0, 0}, {0x5682, 0x05, 0, 0}, {0x5683, 0x00, 0, 0}, + {0x3806, 0x03, 0, 0}, {0x3807, 0xc0, 0, 0}, {0x5686, 0x03, 0, 0}, + {0x5687, 0xbc, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a1a, 0x05, 0, 0}, + {0x3a13, 0x30, 0, 0}, {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0}, + {0x3a08, 0x12, 0, 0}, {0x3a09, 0xc0, 0, 0}, {0x3a0a, 0x0f, 0, 0}, + {0x3a0b, 0xa0, 0, 0}, {0x350c, 0x07, 0, 0}, {0x350d, 0xd0, 0, 0}, + {0x3500, 0x00, 0, 0}, {0x3501, 0x00, 0, 0}, {0x3502, 0x00, 0, 0}, + {0x350a, 0x00, 0, 0}, {0x350b, 0x00, 0, 0}, {0x3503, 0x00, 0, 0}, + {0x528a, 0x02, 0, 0}, {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, + {0x528d, 0x08, 0, 0}, {0x528e, 0x08, 0, 0}, {0x528f, 0x10, 0, 0}, + {0x5290, 0x10, 0, 0}, {0x5292, 0x00, 0, 0}, {0x5293, 0x02, 0, 0}, + {0x5294, 0x00, 0, 0}, {0x5295, 0x02, 0, 0}, {0x5296, 0x00, 0, 0}, + {0x5297, 0x02, 0, 0}, {0x5298, 0x00, 0, 0}, {0x5299, 0x02, 0, 0}, + {0x529a, 0x00, 0, 0}, {0x529b, 0x02, 0, 0}, {0x529c, 0x00, 0, 0}, + {0x529d, 0x02, 0, 0}, {0x529e, 0x00, 0, 0}, {0x529f, 0x02, 0, 0}, + {0x3a0f, 0x3c, 0, 0}, {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3c, 0, 0}, + {0x3a1e, 0x30, 0, 0}, {0x3a11, 0x70, 0, 0}, {0x3a1f, 0x10, 0, 0}, + {0x3030, 0x2b, 0, 0}, {0x3a02, 0x00, 0, 0}, {0x3a03, 0x7d, 0, 0}, + {0x3a04, 0x00, 0, 0}, {0x3a14, 0x00, 0, 0}, {0x3a15, 0x7d, 0, 0}, + {0x3a16, 0x00, 0, 0}, {0x3a00, 0x78, 0, 0}, {0x3a08, 0x09, 0, 0}, + {0x3a09, 0x60, 0, 0}, {0x3a0a, 0x07, 0, 0}, {0x3a0b, 0xd0, 0, 0}, + {0x3a0d, 0x08, 0, 0}, {0x3a0e, 0x06, 0, 0}, {0x5193, 0x70, 0, 0}, + {0x589b, 0x04, 0, 0}, {0x589a, 0xc5, 0, 0}, {0x401e, 0x20, 0, 0}, + {0x4001, 0x42, 0, 0}, {0x401c, 0x04, 0, 0}, {0x528a, 0x01, 0, 0}, + {0x528b, 0x04, 0, 0}, {0x528c, 0x08, 0, 0}, {0x528d, 0x10, 0, 0}, + {0x528e, 0x20, 0, 0}, {0x528f, 0x28, 0, 0}, {0x5290, 0x30, 0, 0}, + {0x5292, 0x00, 0, 0}, {0x5293, 0x01, 0, 0}, {0x5294, 0x00, 0, 0}, + {0x5295, 0x04, 0, 0}, {0x5296, 0x00, 0, 0}, {0x5297, 0x08, 0, 0}, + {0x5298, 0x00, 0, 0}, {0x5299, 0x10, 0, 0}, {0x529a, 0x00, 0, 0}, + {0x529b, 0x20, 0, 0}, {0x529c, 0x00, 0, 0}, {0x529d, 0x28, 0, 0}, + {0x529e, 0x00, 0, 0}, {0x529f, 0x30, 0, 0}, {0x5282, 0x00, 0, 0}, + {0x5300, 0x00, 0, 0}, {0x5301, 0x20, 0, 0}, {0x5302, 0x00, 0, 0}, + {0x5303, 0x7c, 0, 0}, {0x530c, 0x00, 0, 0}, {0x530d, 0x0c, 0, 0}, + {0x530e, 0x20, 0, 0}, {0x530f, 0x80, 0, 0}, {0x5310, 0x20, 0, 0}, + {0x5311, 0x80, 0, 0}, {0x5308, 0x20, 0, 0}, {0x5309, 0x40, 0, 0}, + {0x5304, 0x00, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x00, 0, 0}, + {0x5307, 0x80, 0, 0}, {0x5314, 0x08, 0, 0}, {0x5315, 0x20, 0, 0}, + {0x5319, 0x30, 0, 0}, {0x5316, 0x10, 0, 0}, {0x5317, 0x00, 0, 0}, + {0x5318, 0x02, 0, 0}, {0x5380, 0x01, 0, 0}, {0x5381, 0x00, 0, 0}, + {0x5382, 0x00, 0, 0}, {0x5383, 0x4e, 0, 0}, {0x5384, 0x00, 0, 0}, + {0x5385, 0x0f, 0, 0}, {0x5386, 0x00, 0, 0}, {0x5387, 0x00, 0, 0}, + {0x5388, 0x01, 0, 0}, {0x5389, 0x15, 0, 0}, {0x538a, 0x00, 0, 0}, + {0x538b, 0x31, 0, 0}, {0x538c, 0x00, 0, 0}, {0x538d, 0x00, 0, 0}, + {0x538e, 0x00, 0, 0}, {0x538f, 0x0f, 0, 0}, {0x5390, 0x00, 0, 0}, + {0x5391, 0xab, 0, 0}, {0x5392, 0x00, 0, 0}, {0x5393, 0xa2, 0, 0}, + {0x5394, 0x08, 0, 0}, {0x5480, 0x14, 0, 0}, {0x5481, 0x21, 0, 0}, + {0x5482, 0x36, 0, 0}, {0x5483, 0x57, 0, 0}, {0x5484, 0x65, 0, 0}, + {0x5485, 0x71, 0, 0}, {0x5486, 0x7d, 0, 0}, {0x5487, 0x87, 0, 0}, + {0x5488, 0x91, 0, 0}, {0x5489, 0x9a, 0, 0}, {0x548a, 0xaa, 0, 0}, + {0x548b, 0xb8, 0, 0}, {0x548c, 0xcd, 0, 0}, {0x548d, 0xdd, 0, 0}, + {0x548e, 0xea, 0, 0}, {0x548f, 0x1d, 0, 0}, {0x5490, 0x05, 0, 0}, + {0x5491, 0x00, 0, 0}, {0x5492, 0x04, 0, 0}, {0x5493, 0x20, 0, 0}, + {0x5494, 0x03, 0, 0}, {0x5495, 0x60, 0, 0}, {0x5496, 0x02, 0, 0}, + {0x5497, 0xb8, 0, 0}, {0x5498, 0x02, 0, 0}, {0x5499, 0x86, 0, 0}, + {0x549a, 0x02, 0, 0}, {0x549b, 0x5b, 0, 0}, {0x549c, 0x02, 0, 0}, + {0x549d, 0x3b, 0, 0}, {0x549e, 0x02, 0, 0}, {0x549f, 0x1c, 0, 0}, + {0x54a0, 0x02, 0, 0}, {0x54a1, 0x04, 0, 0}, {0x54a2, 0x01, 0, 0}, + {0x54a3, 0xed, 0, 0}, {0x54a4, 0x01, 0, 0}, {0x54a5, 0xc5, 0, 0}, + {0x54a6, 0x01, 0, 0}, {0x54a7, 0xa5, 0, 0}, {0x54a8, 0x01, 0, 0}, + {0x54a9, 0x6c, 0, 0}, {0x54aa, 0x01, 0, 0}, {0x54ab, 0x41, 0, 0}, + {0x54ac, 0x01, 0, 0}, {0x54ad, 0x20, 0, 0}, {0x54ae, 0x00, 0, 0}, + {0x54af, 0x16, 0, 0}, {0x54b0, 0x01, 0, 0}, {0x54b1, 0x20, 0, 0}, + {0x54b2, 0x00, 0, 0}, {0x54b3, 0x10, 0, 0}, {0x54b4, 0x00, 0, 0}, + {0x54b5, 0xf0, 0, 0}, {0x54b6, 0x00, 0, 0}, {0x54b7, 0xdf, 0, 0}, + {0x5402, 0x3f, 0, 0}, {0x5403, 0x00, 0, 0}, {0x3406, 0x00, 0, 0}, + {0x5180, 0xff, 0, 0}, {0x5181, 0x52, 0, 0}, {0x5182, 0x11, 0, 0}, + {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, + {0x5186, 0x06, 0, 0}, {0x5187, 0x08, 0, 0}, {0x5188, 0x08, 0, 0}, + {0x5189, 0x7c, 0, 0}, {0x518a, 0x60, 0, 0}, {0x518b, 0xb2, 0, 0}, + {0x518c, 0xb2, 0, 0}, {0x518d, 0x44, 0, 0}, {0x518e, 0x3d, 0, 0}, + {0x518f, 0x58, 0, 0}, {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, + {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, + {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, + {0x5198, 0x04, 0, 0}, {0x5199, 0x12, 0, 0}, {0x519a, 0x04, 0, 0}, + {0x519b, 0x00, 0, 0}, {0x519c, 0x06, 0, 0}, {0x519d, 0x82, 0, 0}, + {0x519e, 0x00, 0, 0}, {0x5025, 0x80, 0, 0}, {0x3a0f, 0x38, 0, 0}, + {0x3a10, 0x30, 0, 0}, {0x3a1b, 0x3a, 0, 0}, {0x3a1e, 0x2e, 0, 0}, + {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x10, 0, 0}, {0x5688, 0xa6, 0, 0}, + {0x5689, 0x6a, 0, 0}, {0x568a, 0xea, 0, 0}, {0x568b, 0xae, 0, 0}, + {0x568c, 0xa6, 0, 0}, {0x568d, 0x6a, 0, 0}, {0x568e, 0x62, 0, 0}, + {0x568f, 0x26, 0, 0}, {0x5583, 0x40, 0, 0}, {0x5584, 0x40, 0, 0}, + {0x5580, 0x02, 0, 0}, {0x5000, 0xcf, 0, 0}, {0x5800, 0x27, 0, 0}, + {0x5801, 0x19, 0, 0}, {0x5802, 0x12, 0, 0}, {0x5803, 0x0f, 0, 0}, + {0x5804, 0x10, 0, 0}, {0x5805, 0x15, 0, 0}, {0x5806, 0x1e, 0, 0}, + {0x5807, 0x2f, 0, 0}, {0x5808, 0x15, 0, 0}, {0x5809, 0x0d, 0, 0}, + {0x580a, 0x0a, 0, 0}, {0x580b, 0x09, 0, 0}, {0x580c, 0x0a, 0, 0}, + {0x580d, 0x0c, 0, 0}, {0x580e, 0x12, 0, 0}, {0x580f, 0x19, 0, 0}, + {0x5810, 0x0b, 0, 0}, {0x5811, 0x07, 0, 0}, {0x5812, 0x04, 0, 0}, + {0x5813, 0x03, 0, 0}, {0x5814, 0x03, 0, 0}, {0x5815, 0x06, 0, 0}, + {0x5816, 0x0a, 0, 0}, {0x5817, 0x0f, 0, 0}, {0x5818, 0x0a, 0, 0}, + {0x5819, 0x05, 0, 0}, {0x581a, 0x01, 0, 0}, {0x581b, 0x00, 0, 0}, + {0x581c, 0x00, 0, 0}, {0x581d, 0x03, 0, 0}, {0x581e, 0x08, 0, 0}, + {0x581f, 0x0c, 0, 0}, {0x5820, 0x0a, 0, 0}, {0x5821, 0x05, 0, 0}, + {0x5822, 0x01, 0, 0}, {0x5823, 0x00, 0, 0}, {0x5824, 0x00, 0, 0}, + {0x5825, 0x03, 0, 0}, {0x5826, 0x08, 0, 0}, {0x5827, 0x0c, 0, 0}, + {0x5828, 0x0e, 0, 0}, {0x5829, 0x08, 0, 0}, {0x582a, 0x06, 0, 0}, + {0x582b, 0x04, 0, 0}, {0x582c, 0x05, 0, 0}, {0x582d, 0x07, 0, 0}, + {0x582e, 0x0b, 0, 0}, {0x582f, 0x12, 0, 0}, {0x5830, 0x18, 0, 0}, + {0x5831, 0x10, 0, 0}, {0x5832, 0x0c, 0, 0}, {0x5833, 0x0a, 0, 0}, + {0x5834, 0x0b, 0, 0}, {0x5835, 0x0e, 0, 0}, {0x5836, 0x15, 0, 0}, + {0x5837, 0x19, 0, 0}, {0x5838, 0x32, 0, 0}, {0x5839, 0x1f, 0, 0}, + {0x583a, 0x18, 0, 0}, {0x583b, 0x16, 0, 0}, {0x583c, 0x17, 0, 0}, + {0x583d, 0x1e, 0, 0}, {0x583e, 0x26, 0, 0}, {0x583f, 0x53, 0, 0}, + {0x5840, 0x10, 0, 0}, {0x5841, 0x0f, 0, 0}, {0x5842, 0x0d, 0, 0}, + {0x5843, 0x0c, 0, 0}, {0x5844, 0x0e, 0, 0}, {0x5845, 0x09, 0, 0}, + {0x5846, 0x11, 0, 0}, {0x5847, 0x10, 0, 0}, {0x5848, 0x10, 0, 0}, + {0x5849, 0x10, 0, 0}, {0x584a, 0x10, 0, 0}, {0x584b, 0x0e, 0, 0}, + {0x584c, 0x10, 0, 0}, {0x584d, 0x10, 0, 0}, {0x584e, 0x11, 0, 0}, + {0x584f, 0x10, 0, 0}, {0x5850, 0x0f, 0, 0}, {0x5851, 0x0c, 0, 0}, + {0x5852, 0x0f, 0, 0}, {0x5853, 0x10, 0, 0}, {0x5854, 0x10, 0, 0}, + {0x5855, 0x0f, 0, 0}, {0x5856, 0x0e, 0, 0}, {0x5857, 0x0b, 0, 0}, + {0x5858, 0x10, 0, 0}, {0x5859, 0x0d, 0, 0}, {0x585a, 0x0d, 0, 0}, + {0x585b, 0x0c, 0, 0}, {0x585c, 0x0c, 0, 0}, {0x585d, 0x0c, 0, 0}, + {0x585e, 0x0b, 0, 0}, {0x585f, 0x0c, 0, 0}, {0x5860, 0x0c, 0, 0}, + {0x5861, 0x0c, 0, 0}, {0x5862, 0x0d, 0, 0}, {0x5863, 0x08, 0, 0}, + {0x5864, 0x11, 0, 0}, {0x5865, 0x18, 0, 0}, {0x5866, 0x18, 0, 0}, + {0x5867, 0x19, 0, 0}, {0x5868, 0x17, 0, 0}, {0x5869, 0x19, 0, 0}, + {0x586a, 0x16, 0, 0}, {0x586b, 0x13, 0, 0}, {0x586c, 0x13, 0, 0}, + {0x586d, 0x12, 0, 0}, {0x586e, 0x13, 0, 0}, {0x586f, 0x16, 0, 0}, + {0x5870, 0x14, 0, 0}, {0x5871, 0x12, 0, 0}, {0x5872, 0x10, 0, 0}, + {0x5873, 0x11, 0, 0}, {0x5874, 0x11, 0, 0}, {0x5875, 0x16, 0, 0}, + {0x5876, 0x14, 0, 0}, {0x5877, 0x11, 0, 0}, {0x5878, 0x10, 0, 0}, + {0x5879, 0x0f, 0, 0}, {0x587a, 0x10, 0, 0}, {0x587b, 0x14, 0, 0}, + {0x587c, 0x13, 0, 0}, {0x587d, 0x12, 0, 0}, {0x587e, 0x11, 0, 0}, + {0x587f, 0x11, 0, 0}, {0x5880, 0x12, 0, 0}, {0x5881, 0x15, 0, 0}, + {0x5882, 0x14, 0, 0}, {0x5883, 0x15, 0, 0}, {0x5884, 0x15, 0, 0}, + {0x5885, 0x15, 0, 0}, {0x5886, 0x13, 0, 0}, {0x5887, 0x17, 0, 0}, + {0x3710, 0x10, 0, 0}, {0x3632, 0x51, 0, 0}, {0x3702, 0x10, 0, 0}, + {0x3703, 0xb2, 0, 0}, {0x3704, 0x18, 0, 0}, {0x370b, 0x40, 0, 0}, + {0x370d, 0x03, 0, 0}, {0x3631, 0x01, 0, 0}, {0x3632, 0x52, 0, 0}, + {0x3606, 0x24, 0, 0}, {0x3620, 0x96, 0, 0}, {0x5785, 0x07, 0, 0}, + {0x3a13, 0x30, 0, 0}, {0x3600, 0x52, 0, 0}, {0x3604, 0x48, 0, 0}, + {0x3606, 0x1b, 0, 0}, {0x370d, 0x0b, 0, 0}, {0x370f, 0xc0, 0, 0}, + {0x3709, 0x01, 0, 0}, {0x3823, 0x00, 0, 0}, {0x5007, 0x00, 0, 0}, + {0x5009, 0x00, 0, 0}, {0x5011, 0x00, 0, 0}, {0x5013, 0x00, 0, 0}, + {0x519e, 0x00, 0, 0}, {0x5086, 0x00, 0, 0}, {0x5087, 0x00, 0, 0}, + {0x5088, 0x00, 0, 0}, {0x5089, 0x00, 0, 0}, {0x302b, 0x00, 0, 0}, + {0x3824, 0x11, 0, 0}, {0x3825, 0xdc, 0, 0}, {0x3826, 0x00, 0, 0}, + {0x3827, 0x08, 0, 0}, {0x380c, 0x0c, 0, 0}, {0x380d, 0x80, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xe8, 0, 0}, {0x3808, 0x02, 0, 0}, + {0x3809, 0xd0, 0, 0}, {0x380A, 0x02, 0, 0}, {0x380B, 0x40, 0, 0}, + {0x3804, 0x04, 0, 0}, {0x3805, 0xb0, 0, 0}, {0x3806, 0x03, 0, 0}, + {0x3807, 0xc0, 0, 0}, {0x5686, 0x03, 0, 0}, {0x5687, 0xc0, 0, 0}, + {0x5682, 0x04, 0, 0}, {0x5683, 0xb0, 0, 0}, +}; + +static struct ov5642_mode_info ov5642_mode_info_data[2][ov5642_mode_MAX + 1] = { + { + {ov5642_mode_VGA_640_480, 640, 480, + ov5642_setting_15fps_VGA_640_480, + ARRAY_SIZE(ov5642_setting_15fps_VGA_640_480)}, + {ov5642_mode_QVGA_320_240, 320, 240, + ov5642_setting_15fps_QVGA_320_240, + ARRAY_SIZE(ov5642_setting_15fps_QVGA_320_240)}, + {ov5642_mode_NTSC_720_480, 720, 480, + ov5642_setting_15fps_NTSC_720_480, + ARRAY_SIZE(ov5642_setting_15fps_NTSC_720_480)}, + {ov5642_mode_PAL_720_576, 720, 576, + ov5642_setting_15fps_PAL_720_576, + ARRAY_SIZE(ov5642_setting_15fps_PAL_720_576)}, + {ov5642_mode_720P_1280_720, 1280, 720, + ov5642_setting_15fps_720P_1280_720, + ARRAY_SIZE(ov5642_setting_15fps_720P_1280_720)}, + {ov5642_mode_1080P_1920_1080, 1920, 1080, + ov5642_setting_15fps_1080P_1920_1080, + ARRAY_SIZE(ov5642_setting_15fps_1080P_1920_1080)}, + {ov5642_mode_QSXGA_2592_1944, 2592, 1944, + ov5642_setting_15fps_QSXGA_2592_1944, + ARRAY_SIZE(ov5642_setting_15fps_QSXGA_2592_1944)}, + {ov5642_mode_QCIF_176_144, 176, 144, + ov5642_setting_15fps_QCIF_176_144, + ARRAY_SIZE(ov5642_setting_15fps_QCIF_176_144)}, + {ov5642_mode_XGA_1024_768, 1024, 768, + ov5642_setting_15fps_XGA_1024_768, + ARRAY_SIZE(ov5642_setting_15fps_XGA_1024_768)}, + }, + { + {ov5642_mode_VGA_640_480, 640, 480, + ov5642_setting_30fps_VGA_640_480, + ARRAY_SIZE(ov5642_setting_30fps_VGA_640_480)}, + {ov5642_mode_QVGA_320_240, 320, 240, + ov5642_setting_30fps_QVGA_320_240, + ARRAY_SIZE(ov5642_setting_30fps_QVGA_320_240)}, + {ov5642_mode_NTSC_720_480, 720, 480, + ov5642_setting_30fps_NTSC_720_480, + ARRAY_SIZE(ov5642_setting_30fps_NTSC_720_480)}, + {ov5642_mode_PAL_720_576, 720, 576, + ov5642_setting_30fps_PAL_720_576, + ARRAY_SIZE(ov5642_setting_30fps_PAL_720_576)}, + {ov5642_mode_720P_1280_720, 1280, 720, + ov5642_setting_30fps_720P_1280_720, + ARRAY_SIZE(ov5642_setting_30fps_720P_1280_720)}, + {ov5642_mode_1080P_1920_1080, 0, 0, NULL, 0}, + {ov5642_mode_QSXGA_2592_1944, 0, 0, NULL, 0}, + {ov5642_mode_QCIF_176_144, 176, 144, + ov5642_setting_30fps_QCIF_176_144, + ARRAY_SIZE(ov5642_setting_30fps_QCIF_176_144)}, + {ov5642_mode_XGA_1024_768, 1024, 768, + ov5642_setting_30fps_XGA_1024_768, + ARRAY_SIZE(ov5642_setting_30fps_XGA_1024_768)}, + }, +}; + +static struct regulator *io_regulator; +static struct regulator *core_regulator; +static struct regulator *analog_regulator; +static struct regulator *gpo_regulator; + +static int ov5642_probe(struct i2c_client *adapter, + const struct i2c_device_id *device_id); +static int ov5642_remove(struct i2c_client *client); + +static s32 ov5642_read_reg(u16 reg, u8 *val); +static s32 ov5642_write_reg(u16 reg, u8 val); + +static const struct i2c_device_id ov5642_id[] = { + {"ov5642", 0}, + {"ov564x", 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, ov5642_id); + +static struct i2c_driver ov5642_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "ov5642", + }, + .probe = ov5642_probe, + .remove = ov5642_remove, + .id_table = ov5642_id, +}; + +static void ov5642_standby(s32 enable) +{ + if (enable) + gpio_set_value(pwn_gpio, 1); + else + gpio_set_value(pwn_gpio, 0); + + msleep(2); +} + +static void ov5642_reset(void) +{ + /* camera reset */ + gpio_set_value(rst_gpio, 1); + + /* camera power down */ + gpio_set_value(pwn_gpio, 1); + msleep(5); + + gpio_set_value(pwn_gpio, 0); + msleep(5); + + gpio_set_value(rst_gpio, 0); + msleep(1); + + gpio_set_value(rst_gpio, 1); + msleep(5); + + gpio_set_value(pwn_gpio, 1); +} + +static int ov5642_power_on(struct device *dev) +{ + int ret = 0; + + io_regulator = devm_regulator_get(dev, "DOVDD"); + if (!IS_ERR(io_regulator)) { + regulator_set_voltage(io_regulator, + OV5642_VOLTAGE_DIGITAL_IO, + OV5642_VOLTAGE_DIGITAL_IO); + ret = regulator_enable(io_regulator); + if (ret) { + pr_err("%s:io set voltage error\n", __func__); + return ret; + } else { + dev_dbg(dev, + "%s:io set voltage ok\n", __func__); + } + } else { + pr_err("%s: cannot get io voltage error\n", __func__); + io_regulator = NULL; + } + + core_regulator = devm_regulator_get(dev, "DVDD"); + if (!IS_ERR(core_regulator)) { + regulator_set_voltage(core_regulator, + OV5642_VOLTAGE_DIGITAL_CORE, + OV5642_VOLTAGE_DIGITAL_CORE); + ret = regulator_enable(core_regulator); + if (ret) { + pr_err("%s:core set voltage error\n", __func__); + return ret; + } else { + dev_dbg(dev, + "%s:core set voltage ok\n", __func__); + } + } else { + core_regulator = NULL; + pr_err("%s: cannot get core voltage error\n", __func__); + } + + analog_regulator = devm_regulator_get(dev, "AVDD"); + if (!IS_ERR(analog_regulator)) { + regulator_set_voltage(analog_regulator, + OV5642_VOLTAGE_ANALOG, + OV5642_VOLTAGE_ANALOG); + ret = regulator_enable(analog_regulator); + if (ret) { + pr_err("%s:analog set voltage error\n", + __func__); + return ret; + } else { + dev_dbg(dev, + "%s:analog set voltage ok\n", __func__); + } + } else { + analog_regulator = NULL; + pr_err("%s: cannot get analog voltage error\n", __func__); + } + + return ret; +} + +static s32 ov5642_write_reg(u16 reg, u8 val) +{ + u8 au8Buf[3] = {0}; + + au8Buf[0] = reg >> 8; + au8Buf[1] = reg & 0xff; + au8Buf[2] = val; + + if (i2c_master_send(ov5642_data.i2c_client, au8Buf, 3) < 0) { + pr_err("%s:write reg error:reg=%x,val=%x\n", + __func__, reg, val); + return -1; + } + + return 0; +} + +static s32 ov5642_read_reg(u16 reg, u8 *val) +{ + u8 au8RegBuf[2] = {0}; + u8 u8RdVal = 0; + + au8RegBuf[0] = reg >> 8; + au8RegBuf[1] = reg & 0xff; + + if (2 != i2c_master_send(ov5642_data.i2c_client, au8RegBuf, 2)) { + pr_err("%s:write reg error:reg=%x\n", + __func__, reg); + return -1; + } + + if (1 != i2c_master_recv(ov5642_data.i2c_client, &u8RdVal, 1)) { + pr_err("%s:read reg error:reg=%x,val=%x\n", + __func__, reg, u8RdVal); + return -1; + } + + *val = u8RdVal; + + return u8RdVal; +} + +static int ov5642_set_rot_mode(struct reg_value *rot_mode) +{ + s32 i = 0; + s32 iModeSettingArySize = 2; + register u32 Delay_ms = 0; + register u16 RegAddr = 0; + register u8 Mask = 0; + register u8 Val = 0; + u8 RegVal = 0; + int retval = 0; + for (i = 0; i < iModeSettingArySize; ++i, ++rot_mode) { + Delay_ms = rot_mode->u32Delay_ms; + RegAddr = rot_mode->u16RegAddr; + Val = rot_mode->u8Val; + Mask = rot_mode->u8Mask; + + if (Mask) { + retval = ov5642_read_reg(RegAddr, &RegVal); + if (retval < 0) { + pr_err("%s, read reg 0x%x failed\n", + __func__, RegAddr); + goto err; + } + + Val |= RegVal; + Val &= Mask; + } + + retval = ov5642_write_reg(RegAddr, Val); + if (retval < 0) { + pr_err("%s, write reg 0x%x failed\n", + __func__, RegAddr); + goto err; + } + + if (Delay_ms) + mdelay(Delay_ms); + } +err: + return retval; +} +static int ov5642_init_mode(enum ov5642_frame_rate frame_rate, + enum ov5642_mode mode); +static int ov5642_write_snapshot_para(enum ov5642_frame_rate frame_rate, + enum ov5642_mode mode); +static int ov5642_change_mode(enum ov5642_frame_rate new_frame_rate, + enum ov5642_frame_rate old_frame_rate, + enum ov5642_mode new_mode, + enum ov5642_mode orig_mode) +{ + struct reg_value *pModeSetting = NULL; + s32 i = 0; + s32 iModeSettingArySize = 0; + register u32 Delay_ms = 0; + register u16 RegAddr = 0; + register u8 Mask = 0; + register u8 Val = 0; + u8 RegVal = 0; + int retval = 0; + + if (new_mode > ov5642_mode_MAX || new_mode < ov5642_mode_MIN) { + pr_err("Wrong ov5642 mode detected!\n"); + return -1; + } + + if ((new_frame_rate == old_frame_rate) && + (new_mode == ov5642_mode_VGA_640_480) && + (orig_mode == ov5642_mode_QSXGA_2592_1944)) { + pModeSetting = ov5642_setting_QSXGA_2_VGA; + iModeSettingArySize = ARRAY_SIZE(ov5642_setting_QSXGA_2_VGA); + ov5642_data.pix.width = 640; + ov5642_data.pix.height = 480; + } else if ((new_frame_rate == old_frame_rate) && + (new_mode == ov5642_mode_QVGA_320_240) && + (orig_mode == ov5642_mode_VGA_640_480)) { + pModeSetting = ov5642_setting_VGA_2_QVGA; + iModeSettingArySize = ARRAY_SIZE(ov5642_setting_VGA_2_QVGA); + ov5642_data.pix.width = 320; + ov5642_data.pix.height = 240; + } else { + retval = ov5642_write_snapshot_para(new_frame_rate, new_mode); + goto err; + } + + if (ov5642_data.pix.width == 0 || ov5642_data.pix.height == 0 || + pModeSetting == NULL || iModeSettingArySize == 0) + return -EINVAL; + + for (i = 0; i < iModeSettingArySize; ++i, ++pModeSetting) { + Delay_ms = pModeSetting->u32Delay_ms; + RegAddr = pModeSetting->u16RegAddr; + Val = pModeSetting->u8Val; + Mask = pModeSetting->u8Mask; + + if (Mask) { + retval = ov5642_read_reg(RegAddr, &RegVal); + if (retval < 0) { + pr_err("read reg error addr=0x%x", RegAddr); + goto err; + } + + RegVal &= ~(u8)Mask; + Val &= Mask; + Val |= RegVal; + } + + retval = ov5642_write_reg(RegAddr, Val); + if (retval < 0) { + pr_err("write reg error addr=0x%x", RegAddr); + goto err; + } + + if (Delay_ms) + msleep(Delay_ms); + } +err: + return retval; +} +static int ov5642_init_mode(enum ov5642_frame_rate frame_rate, + enum ov5642_mode mode) +{ + struct reg_value *pModeSetting = NULL; + s32 i = 0; + s32 iModeSettingArySize = 0; + register u32 Delay_ms = 0; + register u16 RegAddr = 0; + register u8 Mask = 0; + register u8 Val = 0; + u8 RegVal = 0; + int retval = 0; + + if (mode > ov5642_mode_MAX || mode < ov5642_mode_MIN) { + pr_err("Wrong ov5642 mode detected!\n"); + return -1; + } + + pModeSetting = ov5642_mode_info_data[frame_rate][mode].init_data_ptr; + iModeSettingArySize = + ov5642_mode_info_data[frame_rate][mode].init_data_size; + + ov5642_data.pix.width = ov5642_mode_info_data[frame_rate][mode].width; + ov5642_data.pix.height = ov5642_mode_info_data[frame_rate][mode].height; + + if (ov5642_data.pix.width == 0 || ov5642_data.pix.height == 0 || + pModeSetting == NULL || iModeSettingArySize == 0) + return -EINVAL; + + for (i = 0; i < iModeSettingArySize; ++i, ++pModeSetting) { + Delay_ms = pModeSetting->u32Delay_ms; + RegAddr = pModeSetting->u16RegAddr; + Val = pModeSetting->u8Val; + Mask = pModeSetting->u8Mask; + + if (Mask) { + retval = ov5642_read_reg(RegAddr, &RegVal); + if (retval < 0) { + pr_err("read reg error addr=0x%x", RegAddr); + goto err; + } + + RegVal &= ~(u8)Mask; + Val &= Mask; + Val |= RegVal; + } + + retval = ov5642_write_reg(RegAddr, Val); + if (retval < 0) { + pr_err("write reg error addr=0x%x", RegAddr); + goto err; + } + + if (Delay_ms) + msleep(Delay_ms); + } +err: + return retval; +} + +static int ov5642_write_snapshot_para(enum ov5642_frame_rate frame_rate, + enum ov5642_mode mode) +{ + int ret = 0; + bool m_60Hz = false; + u16 cap_frame_rate = 50; + u16 g_prev_frame_rate = 225; + + u8 ev_low, ev_mid, ev_high; + u8 ret_l, ret_m, ret_h, gain, lines_10ms; + u16 ulcap_ev, icap_gain, prev_maxlines; + u32 ulcap_ev_gain, cap_maxlines, g_prev_ev; + + ov5642_write_reg(0x3503, 0x07); + + ret_h = ret_m = ret_l = 0; + g_prev_ev = 0; + ov5642_read_reg(0x3500, &ret_h); + ov5642_read_reg(0x3501, &ret_m); + ov5642_read_reg(0x3502, &ret_l); + g_prev_ev = (ret_h << 12) + (ret_m << 4) + (ret_l >> 4); + + ret_h = ret_m = ret_l = 0; + prev_maxlines = 0; + ov5642_read_reg(0x380e, &ret_h); + ov5642_read_reg(0x380f, &ret_l); + prev_maxlines = (ret_h << 8) + ret_l; + /*Read back AGC Gain for preview*/ + gain = 0; + ov5642_read_reg(0x350b, &gain); + + ret = ov5642_init_mode(frame_rate, mode); + if (ret < 0) + return ret; + + ret_h = ret_m = ret_l = 0; + ov5642_read_reg(0x380e, &ret_h); + ov5642_read_reg(0x380f, &ret_l); + cap_maxlines = (ret_h << 8) + ret_l; + if (m_60Hz == true) + lines_10ms = cap_frame_rate * cap_maxlines/12000; + else + lines_10ms = cap_frame_rate * cap_maxlines/10000; + + if (prev_maxlines == 0) + prev_maxlines = 1; + + ulcap_ev = (g_prev_ev*(cap_frame_rate)*(cap_maxlines))/ + (((prev_maxlines)*(g_prev_frame_rate))); + icap_gain = (gain & 0x0f) + 16; + if (gain & 0x10) + icap_gain = icap_gain << 1; + + if (gain & 0x20) + icap_gain = icap_gain << 1; + + if (gain & 0x40) + icap_gain = icap_gain << 1; + + if (gain & 0x80) + icap_gain = icap_gain << 1; + + ulcap_ev_gain = 2 * ulcap_ev * icap_gain; + + if (ulcap_ev_gain < cap_maxlines*16) { + ulcap_ev = ulcap_ev_gain/16; + if (ulcap_ev > lines_10ms) { + ulcap_ev /= lines_10ms; + ulcap_ev *= lines_10ms; + } + } else + ulcap_ev = cap_maxlines; + + if (ulcap_ev == 0) + ulcap_ev = 1; + + icap_gain = (ulcap_ev_gain*2/ulcap_ev + 1)/2; + ev_low = ((unsigned char)ulcap_ev)<<4; + ev_mid = (unsigned char)(ulcap_ev >> 4) & 0xff; + ev_high = (unsigned char)(ulcap_ev >> 12); + + gain = 0; + if (icap_gain > 31) { + gain |= 0x10; + icap_gain = icap_gain >> 1; + } + if (icap_gain > 31) { + gain |= 0x20; + icap_gain = icap_gain >> 1; + } + if (icap_gain > 31) { + gain |= 0x40; + icap_gain = icap_gain >> 1; + } + if (icap_gain > 31) { + gain |= 0x80; + icap_gain = icap_gain >> 1; + } + if (icap_gain > 16) + gain |= ((icap_gain - 16) & 0x0f); + + if (gain == 0x10) + gain = 0x11; + + ov5642_write_reg(0x350b, gain); + ov5642_write_reg(0x3502, ev_low); + ov5642_write_reg(0x3501, ev_mid); + ov5642_write_reg(0x3500, ev_high); + msleep(500); + + return ret ; +} + + +/* --------------- IOCTL functions from v4l2_int_ioctl_desc --------------- */ + +static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p) +{ + if (s == NULL) { + pr_err(" ERROR!! no slave device set!\n"); + return -1; + } + + memset(p, 0, sizeof(*p)); + p->u.bt656.clock_curr = ov5642_data.mclk; + pr_debug(" clock_curr=mclk=%d\n", ov5642_data.mclk); + p->if_type = V4L2_IF_TYPE_BT656; + p->u.bt656.mode = V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT; + p->u.bt656.clock_min = OV5642_XCLK_MIN; + p->u.bt656.clock_max = OV5642_XCLK_MAX; + p->u.bt656.bt_sync_correct = 1; /* Indicate external vsync */ + + return 0; +} + +/*! + * ioctl_s_power - V4L2 sensor interface handler for VIDIOC_S_POWER ioctl + * @s: pointer to standard V4L2 device structure + * @on: indicates power mode (on or off) + * + * Turns the power on or off, depending on the value of on and returns the + * appropriate error code. + */ +static int ioctl_s_power(struct v4l2_int_device *s, int on) +{ + struct sensor_data *sensor = s->priv; + + if (on && !sensor->on) { + if (io_regulator) + if (regulator_enable(io_regulator) != 0) + return -EIO; + if (core_regulator) + if (regulator_enable(core_regulator) != 0) + return -EIO; + if (gpo_regulator) + if (regulator_enable(gpo_regulator) != 0) + return -EIO; + if (analog_regulator) + if (regulator_enable(analog_regulator) != 0) + return -EIO; + /* Make sure power on */ + ov5642_standby(0); + } else if (!on && sensor->on) { + if (analog_regulator) + regulator_disable(analog_regulator); + if (core_regulator) + regulator_disable(core_regulator); + if (io_regulator) + regulator_disable(io_regulator); + if (gpo_regulator) + regulator_disable(gpo_regulator); + + ov5642_standby(1); + } + + sensor->on = on; + + return 0; +} + +/*! + * ioctl_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl + * @s: pointer to standard V4L2 device structure + * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure + * + * Returns the sensor's video CAPTURE parameters. + */ +static int ioctl_g_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) +{ + struct sensor_data *sensor = s->priv; + struct v4l2_captureparm *cparm = &a->parm.capture; + int ret = 0; + + switch (a->type) { + /* This is the only case currently handled. */ + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + memset(a, 0, sizeof(*a)); + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + cparm->capability = sensor->streamcap.capability; + cparm->timeperframe = sensor->streamcap.timeperframe; + cparm->capturemode = sensor->streamcap.capturemode; + ret = 0; + break; + + /* These are all the possible cases. */ + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + ret = -EINVAL; + break; + + default: + pr_debug(" type is unknown - %d\n", a->type); + ret = -EINVAL; + break; + } + + return ret; +} + +/*! + * ioctl_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl + * @s: pointer to standard V4L2 device structure + * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure + * + * Configures the sensor to use the input parameters, if possible. If + * not possible, reverts to the old parameters and returns the + * appropriate error code. + */ +static int ioctl_s_parm(struct v4l2_int_device *s, struct v4l2_streamparm *a) +{ + struct sensor_data *sensor = s->priv; + struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe; + u32 tgt_fps, old_fps; /* target frames per secound */ + enum ov5642_frame_rate new_frame_rate, old_frame_rate; + int ret = 0; + + /* Make sure power on */ + ov5642_standby(0); + + switch (a->type) { + /* This is the only case currently handled. */ + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + /* Check that the new frame rate is allowed. */ + if ((timeperframe->numerator == 0) || + (timeperframe->denominator == 0)) { + timeperframe->denominator = DEFAULT_FPS; + timeperframe->numerator = 1; + } + + tgt_fps = timeperframe->denominator / + timeperframe->numerator; + + if (tgt_fps > MAX_FPS) { + timeperframe->denominator = MAX_FPS; + timeperframe->numerator = 1; + } else if (tgt_fps < MIN_FPS) { + timeperframe->denominator = MIN_FPS; + timeperframe->numerator = 1; + } + + /* Actual frame rate we use */ + tgt_fps = timeperframe->denominator / + timeperframe->numerator; + + if (tgt_fps == 15) + new_frame_rate = ov5642_15_fps; + else if (tgt_fps == 30) + new_frame_rate = ov5642_30_fps; + else { + pr_err(" The camera frame rate is not supported!\n"); + return -EINVAL; + } + + if (sensor->streamcap.timeperframe.numerator != 0) + old_fps = sensor->streamcap.timeperframe.denominator / + sensor->streamcap.timeperframe.numerator; + else + old_fps = 30; + + if (old_fps == 15) + old_frame_rate = ov5642_15_fps; + else if (old_fps == 30) + old_frame_rate = ov5642_30_fps; + else { + pr_warning(" No valid frame rate set!\n"); + old_frame_rate = ov5642_30_fps; + } + + ret = ov5642_change_mode(new_frame_rate, old_frame_rate, + a->parm.capture.capturemode, + sensor->streamcap.capturemode); + if (ret < 0) + return ret; + + sensor->streamcap.timeperframe = *timeperframe; + sensor->streamcap.capturemode = + (u32)a->parm.capture.capturemode; + break; + + /* These are all the possible cases. */ + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + pr_debug(" type is not " \ + "V4L2_BUF_TYPE_VIDEO_CAPTURE but %d\n", + a->type); + ret = -EINVAL; + break; + + default: + pr_debug(" type is unknown - %d\n", a->type); + ret = -EINVAL; + break; + } + + return ret; +} + +/*! + * ioctl_g_fmt_cap - V4L2 sensor interface handler for ioctl_g_fmt_cap + * @s: pointer to standard V4L2 device structure + * @f: pointer to standard V4L2 v4l2_format structure + * + * Returns the sensor's current pixel format in the v4l2_format + * parameter. + */ +static int ioctl_g_fmt_cap(struct v4l2_int_device *s, struct v4l2_format *f) +{ + struct sensor_data *sensor = s->priv; + + f->fmt.pix = sensor->pix; + + return 0; +} + +/*! + * ioctl_g_ctrl - V4L2 sensor interface handler for VIDIOC_G_CTRL ioctl + * @s: pointer to standard V4L2 device structure + * @vc: standard V4L2 VIDIOC_G_CTRL ioctl structure + * + * If the requested control is supported, returns the control's current + * value from the video_control[] array. Otherwise, returns -EINVAL + * if the control is not supported. + */ +static int ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) +{ + int ret = 0; + + switch (vc->id) { + case V4L2_CID_BRIGHTNESS: + vc->value = ov5642_data.brightness; + break; + case V4L2_CID_HUE: + vc->value = ov5642_data.hue; + break; + case V4L2_CID_CONTRAST: + vc->value = ov5642_data.contrast; + break; + case V4L2_CID_SATURATION: + vc->value = ov5642_data.saturation; + break; + case V4L2_CID_RED_BALANCE: + vc->value = ov5642_data.red; + break; + case V4L2_CID_BLUE_BALANCE: + vc->value = ov5642_data.blue; + break; + case V4L2_CID_EXPOSURE: + vc->value = ov5642_data.ae_mode; + break; + default: + ret = -EINVAL; + } + + return ret; +} + +/*! + * ioctl_s_ctrl - V4L2 sensor interface handler for VIDIOC_S_CTRL ioctl + * @s: pointer to standard V4L2 device structure + * @vc: standard V4L2 VIDIOC_S_CTRL ioctl structure + * + * If the requested control is supported, sets the control's current + * value in HW (and updates the video_control[] array). Otherwise, + * returns -EINVAL if the control is not supported. + */ +static int ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *vc) +{ + int retval = 0; + struct sensor_data *sensor = s->priv; + __u32 captureMode = sensor->streamcap.capturemode; + struct reg_value *rot_mode = NULL; + + pr_debug("In ov5642:ioctl_s_ctrl %d\n", + vc->id); + + switch (vc->id) { + case V4L2_CID_BRIGHTNESS: + break; + case V4L2_CID_CONTRAST: + break; + case V4L2_CID_SATURATION: + break; + case V4L2_CID_HUE: + break; + case V4L2_CID_AUTO_WHITE_BALANCE: + break; + case V4L2_CID_DO_WHITE_BALANCE: + break; + case V4L2_CID_RED_BALANCE: + break; + case V4L2_CID_BLUE_BALANCE: + break; + case V4L2_CID_GAMMA: + break; + case V4L2_CID_EXPOSURE: + break; + case V4L2_CID_AUTOGAIN: + break; + case V4L2_CID_GAIN: + break; + case V4L2_CID_HFLIP: + break; + case V4L2_CID_VFLIP: + break; + case V4L2_CID_MXC_ROT: + case V4L2_CID_MXC_VF_ROT: + switch (vc->value) { + case V4L2_MXC_ROTATE_NONE: + if (captureMode == ov5642_mode_QSXGA_2592_1944) + rot_mode = ov5642_rot_none_FULL; + else + rot_mode = ov5642_rot_none_VGA; + + if (ov5642_set_rot_mode(rot_mode)) + retval = -EPERM; + break; + case V4L2_MXC_ROTATE_VERT_FLIP: + if (captureMode == ov5642_mode_QSXGA_2592_1944) + rot_mode = ov5642_rot_vert_flip_FULL; + else + rot_mode = ov5642_rot_vert_flip_VGA ; + + if (ov5642_set_rot_mode(rot_mode)) + retval = -EPERM; + break; + case V4L2_MXC_ROTATE_HORIZ_FLIP: + if (captureMode == ov5642_mode_QSXGA_2592_1944) + rot_mode = ov5642_rot_horiz_flip_FULL; + else + rot_mode = ov5642_rot_horiz_flip_VGA; + + if (ov5642_set_rot_mode(rot_mode)) + retval = -EPERM; + break; + case V4L2_MXC_ROTATE_180: + if (captureMode == ov5642_mode_QSXGA_2592_1944) + rot_mode = ov5642_rot_180_FULL; + else + rot_mode = ov5642_rot_180_VGA; + + if (ov5642_set_rot_mode(rot_mode)) + retval = -EPERM; + break; + default: + retval = -EPERM; + break; + } + break; + default: + retval = -EPERM; + break; + } + + return retval; +} + +/*! + * ioctl_enum_framesizes - V4L2 sensor interface handler for + * VIDIOC_ENUM_FRAMESIZES ioctl + * @s: pointer to standard V4L2 device structure + * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure + * + * Return 0 if successful, otherwise -EINVAL. + */ +static int ioctl_enum_framesizes(struct v4l2_int_device *s, + struct v4l2_frmsizeenum *fsize) +{ + if (fsize->index > ov5642_mode_MAX) + return -EINVAL; + + fsize->pixel_format = ov5642_data.pix.pixelformat; + fsize->discrete.width = + max(ov5642_mode_info_data[0][fsize->index].width, + ov5642_mode_info_data[1][fsize->index].width); + fsize->discrete.height = + max(ov5642_mode_info_data[0][fsize->index].height, + ov5642_mode_info_data[1][fsize->index].height); + return 0; +} + +/*! + * ioctl_enum_frameintervals - V4L2 sensor interface handler for + * VIDIOC_ENUM_FRAMEINTERVALS ioctl + * @s: pointer to standard V4L2 device structure + * @fival: standard V4L2 VIDIOC_ENUM_FRAMEINTERVALS ioctl structure + * + * Return 0 if successful, otherwise -EINVAL. + */ +static int ioctl_enum_frameintervals(struct v4l2_int_device *s, + struct v4l2_frmivalenum *fival) +{ + int i, j, count; + + if (fival->index < 0 || fival->index > ov5642_mode_MAX) + return -EINVAL; + + if (fival->pixel_format == 0 || fival->width == 0 || + fival->height == 0) { + pr_warning("Please assign pixelformat, width and height.\n"); + return -EINVAL; + } + + fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; + fival->discrete.numerator = 1; + + count = 0; + for (i = 0; i < ARRAY_SIZE(ov5642_mode_info_data); i++) { + for (j = 0; j < (ov5642_mode_MAX + 1); j++) { + if (fival->pixel_format == ov5642_data.pix.pixelformat + && fival->width == ov5642_mode_info_data[i][j].width + && fival->height == ov5642_mode_info_data[i][j].height + && ov5642_mode_info_data[i][j].init_data_ptr != NULL) { + count++; + } + if (fival->index == (count - 1)) { + fival->discrete.denominator = + ov5642_framerates[i]; + return 0; + } + } + } + + return -EINVAL; +} + +/*! + * ioctl_g_chip_ident - V4L2 sensor interface handler for + * VIDIOC_DBG_G_CHIP_IDENT ioctl + * @s: pointer to standard V4L2 device structure + * @id: pointer to int + * + * Return 0. + */ +static int ioctl_g_chip_ident(struct v4l2_int_device *s, int *id) +{ + ((struct v4l2_dbg_chip_ident *)id)->match.type = + V4L2_CHIP_MATCH_I2C_DRIVER; + strcpy(((struct v4l2_dbg_chip_ident *)id)->match.name, "ov5642_camera"); + + return 0; +} + +/*! + * ioctl_init - V4L2 sensor interface handler for VIDIOC_INT_INIT + * @s: pointer to standard V4L2 device structure + */ +static int ioctl_init(struct v4l2_int_device *s) +{ + + return 0; +} + +/*! + * ioctl_enum_fmt_cap - V4L2 sensor interface handler for VIDIOC_ENUM_FMT + * @s: pointer to standard V4L2 device structure + * @fmt: pointer to standard V4L2 fmt description structure + * + * Return 0. + */ +static int ioctl_enum_fmt_cap(struct v4l2_int_device *s, + struct v4l2_fmtdesc *fmt) +{ + if (fmt->index > 0) /* only 1 pixelformat support so far */ + return -EINVAL; + + fmt->pixelformat = ov5642_data.pix.pixelformat; + + return 0; +} + +/*! + * ioctl_dev_init - V4L2 sensor interface handler for vidioc_int_dev_init_num + * @s: pointer to standard V4L2 device structure + * + * Initialise the device when slave attaches to the master. + */ +static int ioctl_dev_init(struct v4l2_int_device *s) +{ + struct reg_value *pModeSetting = NULL; + s32 i = 0; + s32 iModeSettingArySize = 0; + register u32 Delay_ms = 0; + register u16 RegAddr = 0; + register u8 Mask = 0; + register u8 Val = 0; + u8 RegVal = 0; + int retval = 0; + + struct sensor_data *sensor = s->priv; + u32 tgt_xclk; /* target xclk */ + u32 tgt_fps; /* target frames per secound */ + enum ov5642_frame_rate frame_rate; + + ov5642_data.on = true; + + /* mclk */ + tgt_xclk = ov5642_data.mclk; + tgt_xclk = min(tgt_xclk, (u32)OV5642_XCLK_MAX); + tgt_xclk = max(tgt_xclk, (u32)OV5642_XCLK_MIN); + ov5642_data.mclk = tgt_xclk; + + pr_debug(" Setting mclk to %d MHz\n", tgt_xclk / 1000000); + + /* Default camera frame rate is set in probe */ + tgt_fps = sensor->streamcap.timeperframe.denominator / + sensor->streamcap.timeperframe.numerator; + + if (tgt_fps == 15) + frame_rate = ov5642_15_fps; + else if (tgt_fps == 30) + frame_rate = ov5642_30_fps; + else + return -EINVAL; /* Only support 15fps or 30fps now. */ + + pModeSetting = ov5642_initial_setting; + iModeSettingArySize = ARRAY_SIZE(ov5642_initial_setting); + + for (i = 0; i < iModeSettingArySize; ++i, ++pModeSetting) { + Delay_ms = pModeSetting->u32Delay_ms; + RegAddr = pModeSetting->u16RegAddr; + Val = pModeSetting->u8Val; + Mask = pModeSetting->u8Mask; + if (Mask) { + retval = ov5642_read_reg(RegAddr, &RegVal); + if (retval < 0) + goto err; + + RegVal &= ~(u8)Mask; + Val &= Mask; + Val |= RegVal; + } + + retval = ov5642_write_reg(RegAddr, Val); + if (retval < 0) + goto err; + + if (Delay_ms) + msleep(Delay_ms); + } +err: + return retval; +} + +/*! + * ioctl_dev_exit - V4L2 sensor interface handler for vidioc_int_dev_exit_num + * @s: pointer to standard V4L2 device structure + * + * Delinitialise the device when slave detaches to the master. + */ +static int ioctl_dev_exit(struct v4l2_int_device *s) +{ + return 0; +} + +/*! + * This structure defines all the ioctls for this module and links them to the + * enumeration. + */ +static struct v4l2_int_ioctl_desc ov5642_ioctl_desc[] = { + { vidioc_int_dev_init_num, + (v4l2_int_ioctl_func *)ioctl_dev_init }, + { vidioc_int_dev_exit_num, ioctl_dev_exit}, + { vidioc_int_s_power_num, + (v4l2_int_ioctl_func *)ioctl_s_power }, + { vidioc_int_g_ifparm_num, + (v4l2_int_ioctl_func *)ioctl_g_ifparm }, +/* { vidioc_int_g_needs_reset_num, + (v4l2_int_ioctl_func *)ioctl_g_needs_reset }, */ +/* { vidioc_int_reset_num, + (v4l2_int_ioctl_func *)ioctl_reset }, */ + { vidioc_int_init_num, + (v4l2_int_ioctl_func *)ioctl_init }, + { vidioc_int_enum_fmt_cap_num, + (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap }, +/* { vidioc_int_try_fmt_cap_num, + (v4l2_int_ioctl_func *)ioctl_try_fmt_cap }, */ + { vidioc_int_g_fmt_cap_num, + (v4l2_int_ioctl_func *)ioctl_g_fmt_cap }, +/* { vidioc_int_s_fmt_cap_num, + (v4l2_int_ioctl_func *)ioctl_s_fmt_cap }, */ + { vidioc_int_g_parm_num, + (v4l2_int_ioctl_func *)ioctl_g_parm }, + { vidioc_int_s_parm_num, + (v4l2_int_ioctl_func *)ioctl_s_parm }, +/* { vidioc_int_queryctrl_num, + (v4l2_int_ioctl_func *)ioctl_queryctrl }, */ + { vidioc_int_g_ctrl_num, + (v4l2_int_ioctl_func *)ioctl_g_ctrl }, + { vidioc_int_s_ctrl_num, + (v4l2_int_ioctl_func *)ioctl_s_ctrl }, + { vidioc_int_enum_framesizes_num, + (v4l2_int_ioctl_func *)ioctl_enum_framesizes }, + { vidioc_int_enum_frameintervals_num, + (v4l2_int_ioctl_func *)ioctl_enum_frameintervals }, + { vidioc_int_g_chip_ident_num, + (v4l2_int_ioctl_func *)ioctl_g_chip_ident }, +}; + +static struct v4l2_int_slave ov5642_slave = { + .ioctls = ov5642_ioctl_desc, + .num_ioctls = ARRAY_SIZE(ov5642_ioctl_desc), +}; + +static struct v4l2_int_device ov5642_int_device = { + .module = THIS_MODULE, + .name = "ov5642", + .type = v4l2_int_type_slave, + .u = { + .slave = &ov5642_slave, + }, +}; + +/*! + * ov5642 I2C probe function + * + * @param adapter struct i2c_adapter * + * @return Error code indicating success or failure + */ +static int ov5642_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pinctrl *pinctrl; + struct device *dev = &client->dev; + int retval; + u8 chip_id_high, chip_id_low; + + /* ov5642 pinctrl */ + pinctrl = devm_pinctrl_get_select_default(dev); + if (IS_ERR(pinctrl)) { + dev_err(dev, "ov5642 setup pinctrl failed!"); + return PTR_ERR(pinctrl); + } + + /* request power down pin */ + pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0); + if (!gpio_is_valid(pwn_gpio)) { + dev_warn(dev, "no sensor pwdn pin available"); + return -EINVAL; + } + retval = devm_gpio_request_one(dev, pwn_gpio, GPIOF_OUT_INIT_HIGH, + "ov5642_pwdn"); + if (retval < 0) + return retval; + + /* request reset pin */ + rst_gpio = of_get_named_gpio(dev->of_node, "rst-gpios", 0); + if (!gpio_is_valid(rst_gpio)) { + dev_warn(dev, "no sensor reset pin available"); + return -EINVAL; + } + retval = devm_gpio_request_one(dev, rst_gpio, GPIOF_OUT_INIT_HIGH, + "ov5642_reset"); + if (retval < 0) + return retval; + + /* Set initial values for the sensor struct. */ + memset(&ov5642_data, 0, sizeof(ov5642_data)); + ov5642_data.sensor_clk = devm_clk_get(dev, "csi_mclk"); + if (IS_ERR(ov5642_data.sensor_clk)) { + /* assuming clock enabled by default */ + ov5642_data.sensor_clk = NULL; + dev_err(dev, "clock-frequency missing or invalid\n"); + return PTR_ERR(ov5642_data.sensor_clk); + } + + retval = of_property_read_u32(dev->of_node, "mclk", + (u32 *) &(ov5642_data.mclk)); + if (retval) { + dev_err(dev, "mclk missing or invalid\n"); + return retval; + } + + retval = of_property_read_u32(dev->of_node, "mclk_source", + (u32 *) &(ov5642_data.mclk_source)); + if (retval) { + dev_err(dev, "mclk_source missing or invalid\n"); + return retval; + } + + retval = of_property_read_u32(dev->of_node, "csi_id", + &(ov5642_data.csi)); + if (retval) { + dev_err(dev, "csi_id missing or invalid\n"); + return retval; + } + + clk_prepare_enable(ov5642_data.sensor_clk); + + ov5642_data.io_init = ov5642_reset; + ov5642_data.i2c_client = client; + ov5642_data.pix.pixelformat = V4L2_PIX_FMT_YUYV; + ov5642_data.pix.width = 640; + ov5642_data.pix.height = 480; + ov5642_data.streamcap.capability = V4L2_MODE_HIGHQUALITY | + V4L2_CAP_TIMEPERFRAME; + ov5642_data.streamcap.capturemode = 0; + ov5642_data.streamcap.timeperframe.denominator = DEFAULT_FPS; + ov5642_data.streamcap.timeperframe.numerator = 1; + + ov5642_power_on(&client->dev); + + ov5642_reset(); + + ov5642_standby(0); + + retval = ov5642_read_reg(OV5642_CHIP_ID_HIGH_BYTE, &chip_id_high); + if (retval < 0 || chip_id_high != 0x56) { + pr_warning("camera ov5642 is not found\n"); + clk_disable_unprepare(ov5642_data.sensor_clk); + return -ENODEV; + } + retval = ov5642_read_reg(OV5642_CHIP_ID_LOW_BYTE, &chip_id_low); + if (retval < 0 || chip_id_low != 0x42) { + pr_warning("camera ov5642 is not found\n"); + clk_disable_unprepare(ov5642_data.sensor_clk); + return -ENODEV; + } + + ov5642_standby(1); + + ov5642_int_device.priv = &ov5642_data; + retval = v4l2_int_device_register(&ov5642_int_device); + + clk_disable_unprepare(ov5642_data.sensor_clk); + + pr_info("camera ov5642 is found\n"); + return retval; +} + +/*! + * ov5642 I2C detach function + * + * @param client struct i2c_client * + * @return Error code indicating success or failure + */ +static int ov5642_remove(struct i2c_client *client) +{ + v4l2_int_device_unregister(&ov5642_int_device); + + if (gpo_regulator) + regulator_disable(gpo_regulator); + + if (analog_regulator) + regulator_disable(analog_regulator); + + if (core_regulator) + regulator_disable(core_regulator); + + if (io_regulator) + regulator_disable(io_regulator); + + return 0; +} + +/*! + * ov5642 init function + * Called by insmod ov5642_camera.ko. + * + * @return Error code indicating success or failure + */ +static __init int ov5642_init(void) +{ + u8 err; + + err = i2c_add_driver(&ov5642_i2c_driver); + if (err != 0) + pr_err("%s:driver registration failed, error=%d\n", + __func__, err); + + return err; +} + +/*! + * OV5642 cleanup function + * Called on rmmod ov5642_camera.ko + * + * @return Error code indicating success or failure + */ +static void __exit ov5642_clean(void) +{ + i2c_del_driver(&ov5642_i2c_driver); +} + +module_init(ov5642_init); +module_exit(ov5642_clean); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("OV5642 Camera Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("1.0"); +MODULE_ALIAS("CSI"); diff --git a/drivers/media/platform/mxc/capture/v4l2-int-device.c b/drivers/media/platform/mxc/capture/v4l2-int-device.c new file mode 100644 index 000000000000..e49da150f887 --- /dev/null +++ b/drivers/media/platform/mxc/capture/v4l2-int-device.c @@ -0,0 +1,165 @@ +/* + * drivers/media/video/v4l2-int-device.c + * + * V4L2 internal ioctl interface. + * + * Copyright 2005-2014 Freescale Semiconductor, Inc. + * Copyright (C) 2007 Nokia Corporation. + * + * Contact: Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +#include "v4l2-int-device.h" + +static DEFINE_MUTEX(mutex); +static LIST_HEAD(int_list); + +void v4l2_int_device_try_attach_all(void) +{ + struct v4l2_int_device *m, *s; + + list_for_each_entry(m, &int_list, head) { + if (m->type != v4l2_int_type_master) + continue; + + list_for_each_entry(s, &int_list, head) { + if (s->type != v4l2_int_type_slave) + continue; + + /* Slave is connected? */ + if (s->u.slave->master) + continue; + + /* Slave wants to attach to master? */ + if (s->u.slave->attach_to[0] != 0 + && strncmp(m->name, s->u.slave->attach_to, + V4L2NAMESIZE)) + continue; + + if (!try_module_get(m->module)) + continue; + + s->u.slave->master = m; + if (m->u.master->attach(s)) { + s->u.slave->master = NULL; + module_put(m->module); + continue; + } + } + } +} +EXPORT_SYMBOL_GPL(v4l2_int_device_try_attach_all); + +static int ioctl_sort_cmp(const void *a, const void *b) +{ + const struct v4l2_int_ioctl_desc *d1 = a, *d2 = b; + + if (d1->num > d2->num) + return 1; + + if (d1->num < d2->num) + return -1; + + return 0; +} + +int v4l2_int_device_register(struct v4l2_int_device *d) +{ + if (d->type == v4l2_int_type_slave) + sort(d->u.slave->ioctls, d->u.slave->num_ioctls, + sizeof(struct v4l2_int_ioctl_desc), + &ioctl_sort_cmp, NULL); + mutex_lock(&mutex); + list_add(&d->head, &int_list); + v4l2_int_device_try_attach_all(); + mutex_unlock(&mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_int_device_register); + +void v4l2_int_device_unregister(struct v4l2_int_device *d) +{ + mutex_lock(&mutex); + list_del(&d->head); + if (d->type == v4l2_int_type_slave + && d->u.slave->master != NULL) { + d->u.slave->master->u.master->detach(d); + module_put(d->u.slave->master->module); + d->u.slave->master = NULL; + } + mutex_unlock(&mutex); +} +EXPORT_SYMBOL_GPL(v4l2_int_device_unregister); + +/* Adapted from search_extable in extable.c. */ +static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd, + v4l2_int_ioctl_func *no_such_ioctl) +{ + const struct v4l2_int_ioctl_desc *first = slave->ioctls; + const struct v4l2_int_ioctl_desc *last = + first + slave->num_ioctls - 1; + + while (first <= last) { + const struct v4l2_int_ioctl_desc *mid; + + mid = (last - first) / 2 + first; + + if (mid->num < cmd) + first = mid + 1; + else if (mid->num > cmd) + last = mid - 1; + else + return mid->func; + } + + return no_such_ioctl; +} + +static int no_such_ioctl_0(struct v4l2_int_device *d) +{ + return -ENOIOCTLCMD; +} + +int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd) +{ + return ((v4l2_int_ioctl_func_0 *) + find_ioctl(d->u.slave, cmd, + (v4l2_int_ioctl_func *)no_such_ioctl_0))(d); +} +EXPORT_SYMBOL_GPL(v4l2_int_ioctl_0); + +static int no_such_ioctl_1(struct v4l2_int_device *d, void *arg) +{ + return -ENOIOCTLCMD; +} + +int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg) +{ + return ((v4l2_int_ioctl_func_1 *) + find_ioctl(d->u.slave, cmd, + (v4l2_int_ioctl_func *)no_such_ioctl_1))(d, arg); +} +EXPORT_SYMBOL_GPL(v4l2_int_ioctl_1); + +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/mxc/capture/v4l2-int-device.h b/drivers/media/platform/mxc/capture/v4l2-int-device.h new file mode 100644 index 000000000000..810d87f28794 --- /dev/null +++ b/drivers/media/platform/mxc/capture/v4l2-int-device.h @@ -0,0 +1,309 @@ +/* + * include/media/v4l2-int-device.h + * + * V4L2 internal ioctl interface. + * + * Copyright 2005-2014 Freescale Semiconductor, Inc. + * Copyright (C) 2007 Nokia Corporation. + * + * Contact: Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef V4L2_INT_DEVICE_H +#define V4L2_INT_DEVICE_H + +#include + +#define V4L2NAMESIZE 32 + +/* + * + * The internal V4L2 device interface core. + * + */ + +enum v4l2_int_type { + v4l2_int_type_master = 1, + v4l2_int_type_slave +}; + +struct module; + +struct v4l2_int_device; + +struct v4l2_int_master { + int (*attach)(struct v4l2_int_device *slave); + void (*detach)(struct v4l2_int_device *slave); +}; + +typedef int (v4l2_int_ioctl_func)(struct v4l2_int_device *); +typedef int (v4l2_int_ioctl_func_0)(struct v4l2_int_device *); +typedef int (v4l2_int_ioctl_func_1)(struct v4l2_int_device *, void *); + +struct v4l2_int_ioctl_desc { + int num; + v4l2_int_ioctl_func *func; +}; + +struct v4l2_int_slave { + /* Don't touch master. */ + struct v4l2_int_device *master; + + char attach_to[V4L2NAMESIZE]; + + int num_ioctls; + struct v4l2_int_ioctl_desc *ioctls; +}; + +struct v4l2_int_device { + /* Don't touch head. */ + struct list_head head; + + struct module *module; + + char name[V4L2NAMESIZE]; + + enum v4l2_int_type type; + union { + struct v4l2_int_master *master; + struct v4l2_int_slave *slave; + } u; + + void *priv; +}; + +void v4l2_int_device_try_attach_all(void); + +int v4l2_int_device_register(struct v4l2_int_device *d); +void v4l2_int_device_unregister(struct v4l2_int_device *d); + +int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd); +int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg); + +/* + * + * Types and definitions for IOCTL commands. + * + */ + +enum v4l2_power { + V4L2_POWER_OFF = 0, + V4L2_POWER_ON, + V4L2_POWER_STANDBY, +}; + +/* Slave interface type. */ +enum v4l2_if_type { + /* + * Parallel 8-, 10- or 12-bit interface, used by for example + * on certain image sensors. + */ + V4L2_IF_TYPE_BT656, +}; + +enum v4l2_if_type_bt656_mode { + /* + * Modes without Bt synchronisation codes. Separate + * synchronisation signal lines are used. + */ + V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT, + V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT, + V4L2_IF_TYPE_BT656_MODE_NOBT_12BIT, + /* + * Use Bt synchronisation codes. The vertical and horizontal + * synchronisation is done based on synchronisation codes. + */ + V4L2_IF_TYPE_BT656_MODE_BT_8BIT, + V4L2_IF_TYPE_BT656_MODE_BT_10BIT, +}; + +struct v4l2_if_type_bt656 { + /* + * 0: Frame begins when vsync is high. + * 1: Frame begins when vsync changes from low to high. + */ + unsigned frame_start_on_rising_vs:1; + /* Use Bt synchronisation codes for sync correction. */ + unsigned bt_sync_correct:1; + /* Swap every two adjacent image data elements. */ + unsigned swap:1; + /* Inverted latch clock polarity from slave. */ + unsigned latch_clk_inv:1; + /* Hs polarity. 0 is active high, 1 active low. */ + unsigned nobt_hs_inv:1; + /* Vs polarity. 0 is active high, 1 active low. */ + unsigned nobt_vs_inv:1; + enum v4l2_if_type_bt656_mode mode; + /* Minimum accepted bus clock for slave (in Hz). */ + u32 clock_min; + /* Maximum accepted bus clock for slave. */ + u32 clock_max; + /* + * Current wish of the slave. May only change in response to + * ioctls that affect image capture. + */ + u32 clock_curr; +}; + +struct v4l2_ifparm { + enum v4l2_if_type if_type; + union { + struct v4l2_if_type_bt656 bt656; + } u; +}; + +/* IOCTL command numbers. */ +enum v4l2_int_ioctl_num { + /* + * + * "Proper" V4L ioctls, as in struct video_device. + * + */ + vidioc_int_enum_fmt_cap_num = 1, + vidioc_int_g_fmt_cap_num, + vidioc_int_s_fmt_cap_num, + vidioc_int_try_fmt_cap_num, + vidioc_int_queryctrl_num, + vidioc_int_g_ctrl_num, + vidioc_int_s_ctrl_num, + vidioc_int_cropcap_num, + vidioc_int_g_crop_num, + vidioc_int_s_crop_num, + vidioc_int_g_parm_num, + vidioc_int_s_parm_num, + vidioc_int_querystd_num, + vidioc_int_s_std_num, + vidioc_int_s_video_routing_num, + + /* + * + * Strictly internal ioctls. + * + */ + /* Initialise the device when slave attaches to the master. */ + vidioc_int_dev_init_num = 1000, + /* Delinitialise the device at slave detach. */ + vidioc_int_dev_exit_num, + /* Set device power state. */ + vidioc_int_s_power_num, + /* + * Get slave private data, e.g. platform-specific slave + * configuration used by the master. + */ + vidioc_int_g_priv_num, + /* Get slave interface parameters. */ + vidioc_int_g_ifparm_num, + /* Does the slave need to be reset after VIDIOC_DQBUF? */ + vidioc_int_g_needs_reset_num, + vidioc_int_enum_framesizes_num, + vidioc_int_enum_frameintervals_num, + + /* + * + * VIDIOC_INT_* ioctls. + * + */ + /* VIDIOC_INT_RESET */ + vidioc_int_reset_num, + /* VIDIOC_INT_INIT */ + vidioc_int_init_num, + /* VIDIOC_DBG_G_CHIP_IDENT */ + vidioc_int_g_chip_ident_num, + + /* + * + * Start of private ioctls. + * + */ + vidioc_int_priv_start_num = 2000, +}; + +/* + * + * IOCTL wrapper functions for better type checking. + * + */ + +#define V4L2_INT_WRAPPER_0(name) \ + static inline int vidioc_int_##name(struct v4l2_int_device *d) \ + { \ + return v4l2_int_ioctl_0(d, vidioc_int_##name##_num); \ + } \ + \ + static inline struct v4l2_int_ioctl_desc \ + vidioc_int_##name##_cb(int (*func) \ + (struct v4l2_int_device *)) \ + { \ + struct v4l2_int_ioctl_desc desc; \ + \ + desc.num = vidioc_int_##name##_num; \ + desc.func = (v4l2_int_ioctl_func *)func; \ + \ + return desc; \ + } + +#define V4L2_INT_WRAPPER_1(name, arg_type, asterisk) \ + static inline int vidioc_int_##name(struct v4l2_int_device *d, \ + arg_type asterisk arg) \ + { \ + return v4l2_int_ioctl_1(d, vidioc_int_##name##_num, \ + (void *)(unsigned long)arg); \ + } \ + \ + static inline struct v4l2_int_ioctl_desc \ + vidioc_int_##name##_cb(int (*func) \ + (struct v4l2_int_device *, \ + arg_type asterisk)) \ + { \ + struct v4l2_int_ioctl_desc desc; \ + \ + desc.num = vidioc_int_##name##_num; \ + desc.func = (v4l2_int_ioctl_func *)func; \ + \ + return desc; \ + } + +V4L2_INT_WRAPPER_1(enum_fmt_cap, struct v4l2_fmtdesc, *); +V4L2_INT_WRAPPER_1(g_fmt_cap, struct v4l2_format, *); +V4L2_INT_WRAPPER_1(s_fmt_cap, struct v4l2_format, *); +V4L2_INT_WRAPPER_1(try_fmt_cap, struct v4l2_format, *); +V4L2_INT_WRAPPER_1(queryctrl, struct v4l2_queryctrl, *); +V4L2_INT_WRAPPER_1(g_ctrl, struct v4l2_control, *); +V4L2_INT_WRAPPER_1(s_ctrl, struct v4l2_control, *); +V4L2_INT_WRAPPER_1(cropcap, struct v4l2_cropcap, *); +V4L2_INT_WRAPPER_1(g_crop, struct v4l2_crop, *); +V4L2_INT_WRAPPER_1(s_crop, struct v4l2_crop, *); +V4L2_INT_WRAPPER_1(g_parm, struct v4l2_streamparm, *); +V4L2_INT_WRAPPER_1(s_parm, struct v4l2_streamparm, *); +V4L2_INT_WRAPPER_1(querystd, v4l2_std_id, *); +V4L2_INT_WRAPPER_1(s_std, v4l2_std_id, *); +V4L2_INT_WRAPPER_1(s_video_routing, struct v4l2_routing, *); + +V4L2_INT_WRAPPER_0(dev_init); +V4L2_INT_WRAPPER_0(dev_exit); +V4L2_INT_WRAPPER_1(s_power, enum v4l2_power, /*dummy arg*/); +V4L2_INT_WRAPPER_1(g_priv, void, *); +V4L2_INT_WRAPPER_1(g_ifparm, struct v4l2_ifparm, *); +V4L2_INT_WRAPPER_1(g_needs_reset, void, *); +V4L2_INT_WRAPPER_1(enum_framesizes, struct v4l2_frmsizeenum, *); +V4L2_INT_WRAPPER_1(enum_frameintervals, struct v4l2_frmivalenum, *); + +V4L2_INT_WRAPPER_0(reset); +V4L2_INT_WRAPPER_0(init); +V4L2_INT_WRAPPER_1(g_chip_ident, int, *); + +#endif diff --git a/drivers/media/platform/mxc/subdev/Kconfig b/drivers/media/platform/mxc/subdev/Kconfig new file mode 100644 index 000000000000..b8e0ebb1a5e5 --- /dev/null +++ b/drivers/media/platform/mxc/subdev/Kconfig @@ -0,0 +1,38 @@ +if VIDEO_MXC_CAPTURE + +config VIDEO_MXC_CSI_CAMERA + tristate "CSI camera support" + depends on VIDEO_MXC_CAPTURE && VIDEO_V4L2 + ---help--- + This is the video4linux2 capture driver based on CSI module. + +config MXC_CAMERA_OV5640 + tristate "OmniVision ov5640 camera support" + depends on VIDEO_MXC_CAPTURE && I2C + ---help--- + If you plan to use the ov5640 Camera with your MXC system, say Y here. + +config MXC_VADC + tristate "mxc VADC support" + depends on VIDEO_MXC_CAPTURE && VIDEO_V4L2 + ---help--- + If you plan to use the VADC with your MXC system, say Y here. + +config MXC_MIPI_CSI + tristate "mxc mipi csi driver" + depends on VIDEO_MXC_CAPTURE && VIDEO_V4L2 + ---help--- + This is a V4L2 driver for i.MX7D SoC MIPI-CSI2 receiver devices. + +config MXC_CAMERA_OV5640_MIPI + tristate "OmniVision ov5640 camera support using mipi" + depends on MXC_MIPI_CSI && I2C + ---help--- + If you plan to use the ov5640 Camera with mipi interface in your MXC system, say Y here. + +config MXC_CAMERA_OV5647_MIPI + tristate "OmniVision ov5647 camera support using mipi" + depends on MXC_MIPI_CSI && I2C + ---help--- + If you plan to use the ov5647 Camera with mipi interface in your MXC system, say Y here. +endif diff --git a/drivers/media/platform/mxc/subdev/Makefile b/drivers/media/platform/mxc/subdev/Makefile new file mode 100644 index 000000000000..25b0d64dff8f --- /dev/null +++ b/drivers/media/platform/mxc/subdev/Makefile @@ -0,0 +1,14 @@ +#Makefile for mxc csi driver + +obj-$(CONFIG_VIDEO_MXC_CSI_CAMERA) += mx6s_capture.o +obj-$(CONFIG_MXC_VADC) += mxc_vadc.o +obj-$(CONFIG_MXC_MIPI_CSI) += mxc_mipi_csi.o + +ov5640_camera-objs := ov5640.o +obj-$(CONFIG_MXC_CAMERA_OV5640) += ov5640_camera.o + +ov5640_camera_mipi-objs := ov5640_mipi.o +obj-$(CONFIG_MXC_CAMERA_OV5640_MIPI) += ov5640_camera_mipi.o + +ov5647_camera_mipi-objs := ov5647_mipi.o +obj-$(CONFIG_MXC_CAMERA_OV5647_MIPI) += ov5647_camera_mipi.o diff --git a/drivers/media/platform/mxc/subdev/mx6s_capture.c b/drivers/media/platform/mxc/subdev/mx6s_capture.c new file mode 100644 index 000000000000..a5b2d3d2f0f2 --- /dev/null +++ b/drivers/media/platform/mxc/subdev/mx6s_capture.c @@ -0,0 +1,1971 @@ +/* + * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file mx6s_csi.c + * + * @brief mx6sx CMOS Sensor interface functions + * + * @ingroup CSI + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MX6S_CAM_DRV_NAME "mx6s-csi" +#define MX6S_CAM_VERSION "0.0.1" +#define MX6S_CAM_DRIVER_DESCRIPTION "i.MX6S_CSI" + +#define MAX_VIDEO_MEM 64 + +/* reset values */ +#define CSICR1_RESET_VAL 0x40000800 +#define CSICR2_RESET_VAL 0x0 +#define CSICR3_RESET_VAL 0x0 + +/* csi control reg 1 */ +#define BIT_SWAP16_EN (0x1 << 31) +#define BIT_EXT_VSYNC (0x1 << 30) +#define BIT_EOF_INT_EN (0x1 << 29) +#define BIT_PRP_IF_EN (0x1 << 28) +#define BIT_CCIR_MODE (0x1 << 27) +#define BIT_COF_INT_EN (0x1 << 26) +#define BIT_SF_OR_INTEN (0x1 << 25) +#define BIT_RF_OR_INTEN (0x1 << 24) +#define BIT_SFF_DMA_DONE_INTEN (0x1 << 22) +#define BIT_STATFF_INTEN (0x1 << 21) +#define BIT_FB2_DMA_DONE_INTEN (0x1 << 20) +#define BIT_FB1_DMA_DONE_INTEN (0x1 << 19) +#define BIT_RXFF_INTEN (0x1 << 18) +#define BIT_SOF_POL (0x1 << 17) +#define BIT_SOF_INTEN (0x1 << 16) +#define BIT_MCLKDIV (0xF << 12) +#define BIT_HSYNC_POL (0x1 << 11) +#define BIT_CCIR_EN (0x1 << 10) +#define BIT_MCLKEN (0x1 << 9) +#define BIT_FCC (0x1 << 8) +#define BIT_PACK_DIR (0x1 << 7) +#define BIT_CLR_STATFIFO (0x1 << 6) +#define BIT_CLR_RXFIFO (0x1 << 5) +#define BIT_GCLK_MODE (0x1 << 4) +#define BIT_INV_DATA (0x1 << 3) +#define BIT_INV_PCLK (0x1 << 2) +#define BIT_REDGE (0x1 << 1) +#define BIT_PIXEL_BIT (0x1 << 0) + +#define SHIFT_MCLKDIV 12 + +/* control reg 3 */ +#define BIT_FRMCNT (0xFFFF << 16) +#define BIT_FRMCNT_RST (0x1 << 15) +#define BIT_DMA_REFLASH_RFF (0x1 << 14) +#define BIT_DMA_REFLASH_SFF (0x1 << 13) +#define BIT_DMA_REQ_EN_RFF (0x1 << 12) +#define BIT_DMA_REQ_EN_SFF (0x1 << 11) +#define BIT_STATFF_LEVEL (0x7 << 8) +#define BIT_HRESP_ERR_EN (0x1 << 7) +#define BIT_RXFF_LEVEL (0x7 << 4) +#define BIT_TWO_8BIT_SENSOR (0x1 << 3) +#define BIT_ZERO_PACK_EN (0x1 << 2) +#define BIT_ECC_INT_EN (0x1 << 1) +#define BIT_ECC_AUTO_EN (0x1 << 0) + +#define SHIFT_FRMCNT 16 +#define SHIFT_RXFIFO_LEVEL 4 + +/* csi status reg */ +#define BIT_ADDR_CH_ERR_INT (0x1 << 28) +#define BIT_FIELD0_INT (0x1 << 27) +#define BIT_FIELD1_INT (0x1 << 26) +#define BIT_SFF_OR_INT (0x1 << 25) +#define BIT_RFF_OR_INT (0x1 << 24) +#define BIT_DMA_TSF_DONE_SFF (0x1 << 22) +#define BIT_STATFF_INT (0x1 << 21) +#define BIT_DMA_TSF_DONE_FB2 (0x1 << 20) +#define BIT_DMA_TSF_DONE_FB1 (0x1 << 19) +#define BIT_RXFF_INT (0x1 << 18) +#define BIT_EOF_INT (0x1 << 17) +#define BIT_SOF_INT (0x1 << 16) +#define BIT_F2_INT (0x1 << 15) +#define BIT_F1_INT (0x1 << 14) +#define BIT_COF_INT (0x1 << 13) +#define BIT_HRESP_ERR_INT (0x1 << 7) +#define BIT_ECC_INT (0x1 << 1) +#define BIT_DRDY (0x1 << 0) + +/* csi control reg 18 */ +#define BIT_CSI_ENABLE (0x1 << 31) +#define BIT_MIPI_DATA_FORMAT_RAW8 (0x2a << 25) +#define BIT_MIPI_DATA_FORMAT_RAW10 (0x2b << 25) +#define BIT_MIPI_DATA_FORMAT_YUV422_8B (0x1e << 25) +#define BIT_MIPI_DATA_FORMAT_MASK (0x3F << 25) +#define BIT_MIPI_DATA_FORMAT_OFFSET 25 +#define BIT_DATA_FROM_MIPI (0x1 << 22) +#define BIT_MIPI_YU_SWAP (0x1 << 21) +#define BIT_MIPI_DOUBLE_CMPNT (0x1 << 20) +#define BIT_BASEADDR_CHG_ERR_EN (0x1 << 9) +#define BIT_BASEADDR_SWITCH_SEL (0x1 << 5) +#define BIT_BASEADDR_SWITCH_EN (0x1 << 4) +#define BIT_PARALLEL24_EN (0x1 << 3) +#define BIT_DEINTERLACE_EN (0x1 << 2) +#define BIT_TVDECODER_IN_EN (0x1 << 1) +#define BIT_NTSC_EN (0x1 << 0) + +#define CSI_MCLK_VF 1 +#define CSI_MCLK_ENC 2 +#define CSI_MCLK_RAW 4 +#define CSI_MCLK_I2C 8 + +#define CSI_CSICR1 0x0 +#define CSI_CSICR2 0x4 +#define CSI_CSICR3 0x8 +#define CSI_STATFIFO 0xC +#define CSI_CSIRXFIFO 0x10 +#define CSI_CSIRXCNT 0x14 +#define CSI_CSISR 0x18 + +#define CSI_CSIDBG 0x1C +#define CSI_CSIDMASA_STATFIFO 0x20 +#define CSI_CSIDMATS_STATFIFO 0x24 +#define CSI_CSIDMASA_FB1 0x28 +#define CSI_CSIDMASA_FB2 0x2C +#define CSI_CSIFBUF_PARA 0x30 +#define CSI_CSIIMAG_PARA 0x34 + +#define CSI_CSICR18 0x48 +#define CSI_CSICR19 0x4c + +#define NUM_FORMATS ARRAY_SIZE(formats) +#define MX6SX_MAX_SENSORS 1 + +struct csi_signal_cfg_t { + unsigned data_width:3; + unsigned clk_mode:2; + unsigned ext_vsync:1; + unsigned Vsync_pol:1; + unsigned Hsync_pol:1; + unsigned pixclk_pol:1; + unsigned data_pol:1; + unsigned sens_clksrc:1; +}; + +struct csi_config_t { + /* control reg 1 */ + unsigned int swap16_en:1; + unsigned int ext_vsync:1; + unsigned int eof_int_en:1; + unsigned int prp_if_en:1; + unsigned int ccir_mode:1; + unsigned int cof_int_en:1; + unsigned int sf_or_inten:1; + unsigned int rf_or_inten:1; + unsigned int sff_dma_done_inten:1; + unsigned int statff_inten:1; + unsigned int fb2_dma_done_inten:1; + unsigned int fb1_dma_done_inten:1; + unsigned int rxff_inten:1; + unsigned int sof_pol:1; + unsigned int sof_inten:1; + unsigned int mclkdiv:4; + unsigned int hsync_pol:1; + unsigned int ccir_en:1; + unsigned int mclken:1; + unsigned int fcc:1; + unsigned int pack_dir:1; + unsigned int gclk_mode:1; + unsigned int inv_data:1; + unsigned int inv_pclk:1; + unsigned int redge:1; + unsigned int pixel_bit:1; + + /* control reg 3 */ + unsigned int frmcnt:16; + unsigned int frame_reset:1; + unsigned int dma_reflash_rff:1; + unsigned int dma_reflash_sff:1; + unsigned int dma_req_en_rff:1; + unsigned int dma_req_en_sff:1; + unsigned int statff_level:3; + unsigned int hresp_err_en:1; + unsigned int rxff_level:3; + unsigned int two_8bit_sensor:1; + unsigned int zero_pack_en:1; + unsigned int ecc_int_en:1; + unsigned int ecc_auto_en:1; + /* fifo counter */ + unsigned int rxcnt; +}; + +/* + * Basic structures + */ +struct mx6s_fmt { + char name[32]; + u32 fourcc; /* v4l2 format id */ + u32 pixelformat; + u32 mbus_code; + int bpp; +}; + +static struct mx6s_fmt formats[] = { + { + .name = "UYVY-16", + .fourcc = V4L2_PIX_FMT_UYVY, + .pixelformat = V4L2_PIX_FMT_UYVY, + .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, + .bpp = 2, + }, { + .name = "YUYV-16", + .fourcc = V4L2_PIX_FMT_YUYV, + .pixelformat = V4L2_PIX_FMT_YUYV, + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, + .bpp = 2, + }, { + .name = "YUV32 (X-Y-U-V)", + .fourcc = V4L2_PIX_FMT_YUV32, + .pixelformat = V4L2_PIX_FMT_YUV32, + .mbus_code = MEDIA_BUS_FMT_AYUV8_1X32, + .bpp = 4, + }, { + .name = "RAWRGB8 (SBGGR8)", + .fourcc = V4L2_PIX_FMT_SBGGR8, + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, + .bpp = 1, + } +}; + +struct mx6s_buf_internal { + struct list_head queue; + int bufnum; + bool discard; +}; + +/* buffer for one video frame */ +struct mx6s_buffer { + /* common v4l buffer stuff -- must be first */ + struct vb2_buffer vb; + struct mx6s_buf_internal internal; +}; + +struct mx6s_csi_mux { + struct regmap *gpr; + u8 req_gpr; + u8 req_bit; +}; + +struct mx6s_csi_dev { + struct device *dev; + struct video_device *vdev; + struct v4l2_subdev *sd; + struct v4l2_device v4l2_dev; + + struct vb2_queue vb2_vidq; + struct vb2_alloc_ctx *alloc_ctx; + struct v4l2_ctrl_handler ctrl_handler; + + struct mutex lock; + spinlock_t slock; + + /* clock */ + struct clk *clk_disp_axi; + struct clk *clk_disp_dcic; + struct clk *clk_csi_mclk; + + void __iomem *regbase; + int irq; + + u32 type; + u32 bytesperline; + v4l2_std_id std; + struct mx6s_fmt *fmt; + struct v4l2_pix_format pix; + u32 mbus_code; + + unsigned int frame_count; + + struct list_head capture; + struct list_head active_bufs; + struct list_head discard; + + void *discard_buffer; + dma_addr_t discard_buffer_dma; + size_t discard_size; + struct mx6s_buf_internal buf_discard[2]; + + struct v4l2_async_subdev asd; + struct v4l2_async_notifier subdev_notifier; + struct v4l2_async_subdev *async_subdevs[2]; + + bool csi_mux_mipi; + struct mx6s_csi_mux csi_mux; +}; + +static inline int csi_read(struct mx6s_csi_dev *csi, unsigned int offset) +{ + return __raw_readl(csi->regbase + offset); +} +static inline void csi_write(struct mx6s_csi_dev *csi, unsigned int value, + unsigned int offset) +{ + __raw_writel(value, csi->regbase + offset); +} + +static inline struct mx6s_csi_dev + *notifier_to_mx6s_dev(struct v4l2_async_notifier *n) +{ + return container_of(n, struct mx6s_csi_dev, subdev_notifier); +} + +struct mx6s_fmt *format_by_fourcc(int fourcc) +{ + int i; + + for (i = 0; i < NUM_FORMATS; i++) { + if (formats[i].pixelformat == fourcc) + return formats + i; + } + + pr_err("unknown pixelformat:'%4.4s'\n", (char *)&fourcc); + return NULL; +} + +struct mx6s_fmt *format_by_mbus(u32 code) +{ + int i; + + for (i = 0; i < NUM_FORMATS; i++) { + if (formats[i].mbus_code == code) + return formats + i; + } + + pr_err("unknown mbus:0x%x\n", code); + return NULL; +} + +static struct mx6s_buffer *mx6s_ibuf_to_buf(struct mx6s_buf_internal *int_buf) +{ + return container_of(int_buf, struct mx6s_buffer, internal); +} + +void csi_clk_enable(struct mx6s_csi_dev *csi_dev) +{ + clk_prepare_enable(csi_dev->clk_disp_axi); + clk_prepare_enable(csi_dev->clk_disp_dcic); + clk_prepare_enable(csi_dev->clk_csi_mclk); +} + +void csi_clk_disable(struct mx6s_csi_dev *csi_dev) +{ + clk_disable_unprepare(csi_dev->clk_csi_mclk); + clk_disable_unprepare(csi_dev->clk_disp_dcic); + clk_disable_unprepare(csi_dev->clk_disp_axi); +} + +static void csihw_reset(struct mx6s_csi_dev *csi_dev) +{ + __raw_writel(__raw_readl(csi_dev->regbase + CSI_CSICR3) + | BIT_FRMCNT_RST, + csi_dev->regbase + CSI_CSICR3); + + __raw_writel(CSICR1_RESET_VAL, csi_dev->regbase + CSI_CSICR1); + __raw_writel(CSICR2_RESET_VAL, csi_dev->regbase + CSI_CSICR2); + __raw_writel(CSICR3_RESET_VAL, csi_dev->regbase + CSI_CSICR3); +} + +static void csisw_reset(struct mx6s_csi_dev *csi_dev) +{ + int cr1, cr3, cr18, isr; + + /* Disable csi */ + cr18 = csi_read(csi_dev, CSI_CSICR18); + cr18 &= ~BIT_CSI_ENABLE; + csi_write(csi_dev, cr18, CSI_CSICR18); + + /* Clear RX FIFO */ + cr1 = csi_read(csi_dev, CSI_CSICR1); + csi_write(csi_dev, cr1 & ~BIT_FCC, CSI_CSICR1); + cr1 = csi_read(csi_dev, CSI_CSICR1); + csi_write(csi_dev, cr1 | BIT_CLR_RXFIFO, CSI_CSICR1); + + /* DMA reflash */ + cr3 = csi_read(csi_dev, CSI_CSICR3); + cr3 |= BIT_DMA_REFLASH_RFF | BIT_FRMCNT_RST; + csi_write(csi_dev, cr3, CSI_CSICR3); + + msleep(2); + + cr1 = csi_read(csi_dev, CSI_CSICR1); + csi_write(csi_dev, cr1 | BIT_FCC, CSI_CSICR1); + + isr = csi_read(csi_dev, CSI_CSISR); + csi_write(csi_dev, isr, CSI_CSISR); + + /* Ensable csi */ + cr18 |= BIT_CSI_ENABLE; + csi_write(csi_dev, cr18, CSI_CSICR18); +} + +/*! + * csi_init_interface + * Init csi interface + */ +static void csi_init_interface(struct mx6s_csi_dev *csi_dev) +{ + unsigned int val = 0; + unsigned int imag_para; + + val |= BIT_SOF_POL; + val |= BIT_REDGE; + val |= BIT_GCLK_MODE; + val |= BIT_HSYNC_POL; + val |= BIT_FCC; + val |= 1 << SHIFT_MCLKDIV; + val |= BIT_MCLKEN; + __raw_writel(val, csi_dev->regbase + CSI_CSICR1); + + imag_para = (640 << 16) | 960; + __raw_writel(imag_para, csi_dev->regbase + CSI_CSIIMAG_PARA); + + val = BIT_DMA_REFLASH_RFF; + __raw_writel(val, csi_dev->regbase + CSI_CSICR3); +} + +static void csi_enable_int(struct mx6s_csi_dev *csi_dev, int arg) +{ + unsigned long cr1 = __raw_readl(csi_dev->regbase + CSI_CSICR1); + + cr1 |= BIT_SOF_INTEN; + cr1 |= BIT_RFF_OR_INT; + if (arg == 1) { + /* still capture needs DMA intterrupt */ + cr1 |= BIT_FB1_DMA_DONE_INTEN; + cr1 |= BIT_FB2_DMA_DONE_INTEN; + } + __raw_writel(cr1, csi_dev->regbase + CSI_CSICR1); +} + +static void csi_disable_int(struct mx6s_csi_dev *csi_dev) +{ + unsigned long cr1 = __raw_readl(csi_dev->regbase + CSI_CSICR1); + + cr1 &= ~BIT_SOF_INTEN; + cr1 &= ~BIT_RFF_OR_INT; + cr1 &= ~BIT_FB1_DMA_DONE_INTEN; + cr1 &= ~BIT_FB2_DMA_DONE_INTEN; + __raw_writel(cr1, csi_dev->regbase + CSI_CSICR1); +} + +static void csi_enable(struct mx6s_csi_dev *csi_dev, int arg) +{ + unsigned long cr = __raw_readl(csi_dev->regbase + CSI_CSICR18); + + if (arg == 1) + cr |= BIT_CSI_ENABLE; + else + cr &= ~BIT_CSI_ENABLE; + __raw_writel(cr, csi_dev->regbase + CSI_CSICR18); +} + +static void csi_buf_stride_set(struct mx6s_csi_dev *csi_dev, u32 stride) +{ + __raw_writel(stride, csi_dev->regbase + CSI_CSIFBUF_PARA); +} + +static void csi_deinterlace_enable(struct mx6s_csi_dev *csi_dev, bool enable) +{ + unsigned long cr18 = __raw_readl(csi_dev->regbase + CSI_CSICR18); + + if (enable == true) + cr18 |= BIT_DEINTERLACE_EN; + else + cr18 &= ~BIT_DEINTERLACE_EN; + + __raw_writel(cr18, csi_dev->regbase + CSI_CSICR18); +} + +static void csi_deinterlace_mode(struct mx6s_csi_dev *csi_dev, int mode) +{ + unsigned long cr18 = __raw_readl(csi_dev->regbase + CSI_CSICR18); + + if (mode == V4L2_STD_NTSC) + cr18 |= BIT_NTSC_EN; + else + cr18 &= ~BIT_NTSC_EN; + + __raw_writel(cr18, csi_dev->regbase + CSI_CSICR18); +} + +static void csi_tvdec_enable(struct mx6s_csi_dev *csi_dev, bool enable) +{ + unsigned long cr18 = __raw_readl(csi_dev->regbase + CSI_CSICR18); + unsigned long cr1 = __raw_readl(csi_dev->regbase + CSI_CSICR1); + + if (enable == true) { + cr18 |= (BIT_TVDECODER_IN_EN | + BIT_BASEADDR_SWITCH_EN | + BIT_BASEADDR_SWITCH_SEL | + BIT_BASEADDR_CHG_ERR_EN); + cr1 |= BIT_CCIR_MODE; + cr1 &= ~(BIT_SOF_POL | BIT_REDGE); + } else { + cr18 &= ~(BIT_TVDECODER_IN_EN | + BIT_BASEADDR_SWITCH_EN | + BIT_BASEADDR_SWITCH_SEL | + BIT_BASEADDR_CHG_ERR_EN); + cr1 &= ~BIT_CCIR_MODE; + cr1 |= BIT_SOF_POL | BIT_REDGE; + } + + __raw_writel(cr18, csi_dev->regbase + CSI_CSICR18); + __raw_writel(cr1, csi_dev->regbase + CSI_CSICR1); +} + +static void csi_dmareq_rff_enable(struct mx6s_csi_dev *csi_dev) +{ + unsigned long cr3 = __raw_readl(csi_dev->regbase + CSI_CSICR3); + unsigned long cr2 = __raw_readl(csi_dev->regbase + CSI_CSICR2); + + /* Burst Type of DMA Transfer from RxFIFO. INCR16 */ + cr2 |= 0xC0000000; + + cr3 |= BIT_DMA_REQ_EN_RFF; + cr3 |= BIT_HRESP_ERR_EN; + cr3 &= ~BIT_RXFF_LEVEL; + cr3 |= 0x2 << 4; + + __raw_writel(cr3, csi_dev->regbase + CSI_CSICR3); + __raw_writel(cr2, csi_dev->regbase + CSI_CSICR2); +} + +static void csi_dmareq_rff_disable(struct mx6s_csi_dev *csi_dev) +{ + unsigned long cr3 = __raw_readl(csi_dev->regbase + CSI_CSICR3); + + cr3 &= ~BIT_DMA_REQ_EN_RFF; + cr3 &= ~BIT_HRESP_ERR_EN; + __raw_writel(cr3, csi_dev->regbase + CSI_CSICR3); +} + +static void csi_set_32bit_imagpara(struct mx6s_csi_dev *csi, + int width, int height) +{ + int imag_para = 0; + unsigned long cr3 = __raw_readl(csi->regbase + CSI_CSICR3); + + imag_para = (width << 16) | height; + __raw_writel(imag_para, csi->regbase + CSI_CSIIMAG_PARA); + + /* reflash the embeded DMA controller */ + __raw_writel(cr3 | BIT_DMA_REFLASH_RFF, csi->regbase + CSI_CSICR3); +} + +static void csi_set_16bit_imagpara(struct mx6s_csi_dev *csi, + int width, int height) +{ + int imag_para = 0; + unsigned long cr3 = __raw_readl(csi->regbase + CSI_CSICR3); + + imag_para = ((width * 2) << 16) | height; + __raw_writel(imag_para, csi->regbase + CSI_CSIIMAG_PARA); + + /* reflash the embeded DMA controller */ + __raw_writel(cr3 | BIT_DMA_REFLASH_RFF, csi->regbase + CSI_CSICR3); +} + +static void csi_set_8bit_imagpara(struct mx6s_csi_dev *csi, + int width, int height) +{ + int imag_para = 0; + unsigned long cr3 = __raw_readl(csi->regbase + CSI_CSICR3); + + imag_para = (width << 16) | height; + __raw_writel(imag_para, csi->regbase + CSI_CSIIMAG_PARA); + + /* reflash the embeded DMA controller */ + __raw_writel(cr3 | BIT_DMA_REFLASH_RFF, csi->regbase + CSI_CSICR3); +} + +/* + * Videobuf operations + */ +static int mx6s_videobuf_setup(struct vb2_queue *vq, + const struct v4l2_format *fmt, + unsigned int *count, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]) +{ + struct mx6s_csi_dev *csi_dev = vb2_get_drv_priv(vq); + + dev_dbg(csi_dev->dev, "count=%d, size=%d\n", *count, sizes[0]); + + /* TODO: support for VIDIOC_CREATE_BUFS not ready */ + if (fmt != NULL) + return -ENOTTY; + + alloc_ctxs[0] = csi_dev->alloc_ctx; + + sizes[0] = csi_dev->pix.sizeimage; + + pr_debug("size=%d\n", sizes[0]); + if (0 == *count) + *count = 32; + if (!*num_planes && + sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024) + *count = (MAX_VIDEO_MEM * 1024 * 1024) / sizes[0]; + + *num_planes = 1; + + return 0; +} + +static int mx6s_videobuf_prepare(struct vb2_buffer *vb) +{ + struct mx6s_csi_dev *csi_dev = vb2_get_drv_priv(vb->vb2_queue); + int ret = 0; + + dev_dbg(csi_dev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__, + vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); + +#ifdef DEBUG + /* + * This can be useful if you want to see if we actually fill + * the buffer with something + */ + if (vb2_plane_vaddr(vb, 0)) + memset((void *)vb2_plane_vaddr(vb, 0), + 0xaa, vb2_get_plane_payload(vb, 0)); +#endif + + vb2_set_plane_payload(vb, 0, csi_dev->pix.sizeimage); + if (vb2_plane_vaddr(vb, 0) && + vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) { + ret = -EINVAL; + goto out; + } + + return 0; + +out: + return ret; +} + +static void mx6s_videobuf_queue(struct vb2_buffer *vb) +{ + struct mx6s_csi_dev *csi_dev = vb2_get_drv_priv(vb->vb2_queue); + struct mx6s_buffer *buf = container_of(vb, struct mx6s_buffer, vb); + unsigned long flags; + + dev_dbg(csi_dev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__, + vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); + + spin_lock_irqsave(&csi_dev->slock, flags); + + list_add_tail(&buf->internal.queue, &csi_dev->capture); + + spin_unlock_irqrestore(&csi_dev->slock, flags); +} + +static void mx6s_update_csi_buf(struct mx6s_csi_dev *csi_dev, + unsigned long phys, int bufnum) +{ + if (bufnum == 1) + csi_write(csi_dev, phys, CSI_CSIDMASA_FB2); + else + csi_write(csi_dev, phys, CSI_CSIDMASA_FB1); +} + +static void mx6s_csi_init(struct mx6s_csi_dev *csi_dev) +{ + csi_clk_enable(csi_dev); + csihw_reset(csi_dev); + csi_init_interface(csi_dev); + csi_dmareq_rff_disable(csi_dev); +} + +static void mx6s_csi_deinit(struct mx6s_csi_dev *csi_dev) +{ + csihw_reset(csi_dev); + csi_init_interface(csi_dev); + csi_dmareq_rff_disable(csi_dev); + csi_clk_disable(csi_dev); +} + +static int mx6s_csi_enable(struct mx6s_csi_dev *csi_dev) +{ + struct v4l2_pix_format *pix = &csi_dev->pix; + unsigned long flags; + unsigned long val; + int timeout, timeout2; + + csisw_reset(csi_dev); + + if (pix->field == V4L2_FIELD_INTERLACED) + csi_tvdec_enable(csi_dev, true); + + /* For mipi csi input only */ + if (csi_dev->csi_mux_mipi == true) { + csi_dmareq_rff_enable(csi_dev); + csi_enable_int(csi_dev, 1); + csi_enable(csi_dev, 1); + return 0; + } + + local_irq_save(flags); + for (timeout = 10000000; timeout > 0; timeout--) { + if (csi_read(csi_dev, CSI_CSISR) & BIT_SOF_INT) { + val = csi_read(csi_dev, CSI_CSICR3); + csi_write(csi_dev, val | BIT_DMA_REFLASH_RFF, + CSI_CSICR3); + /* Wait DMA reflash done */ + for (timeout2 = 1000000; timeout2 > 0; timeout2--) { + if (csi_read(csi_dev, CSI_CSICR3) & + BIT_DMA_REFLASH_RFF) + cpu_relax(); + else + break; + } + if (timeout2 <= 0) { + pr_err("timeout when wait for reflash done.\n"); + local_irq_restore(flags); + return -ETIME; + } + /* For imx6sl csi, DMA FIFO will auto start when sensor ready to work, + * so DMA should enable right after FIFO reset, otherwise dma will lost data + * and image will split. + */ + csi_dmareq_rff_enable(csi_dev); + csi_enable_int(csi_dev, 1); + csi_enable(csi_dev, 1); + break; + } else + cpu_relax(); + } + if (timeout <= 0) { + pr_err("timeout when wait for SOF\n"); + local_irq_restore(flags); + return -ETIME; + } + local_irq_restore(flags); + + return 0; +} + +static void mx6s_csi_disable(struct mx6s_csi_dev *csi_dev) +{ + struct v4l2_pix_format *pix = &csi_dev->pix; + + csi_dmareq_rff_disable(csi_dev); + csi_disable_int(csi_dev); + + /* set CSI_CSIDMASA_FB1 and CSI_CSIDMASA_FB2 to default value */ + csi_write(csi_dev, 0, CSI_CSIDMASA_FB1); + csi_write(csi_dev, 0, CSI_CSIDMASA_FB2); + + csi_buf_stride_set(csi_dev, 0); + + if (pix->field == V4L2_FIELD_INTERLACED) { + csi_deinterlace_enable(csi_dev, false); + csi_tvdec_enable(csi_dev, false); + } + + csi_enable(csi_dev, 0); +} + +static int mx6s_configure_csi(struct mx6s_csi_dev *csi_dev) +{ + struct v4l2_pix_format *pix = &csi_dev->pix; + u32 cr1, cr18; + + if (pix->field == V4L2_FIELD_INTERLACED) { + csi_deinterlace_enable(csi_dev, true); + csi_buf_stride_set(csi_dev, csi_dev->pix.width); + csi_deinterlace_mode(csi_dev, csi_dev->std); + } else { + csi_deinterlace_enable(csi_dev, false); + csi_buf_stride_set(csi_dev, 0); + } + + switch (csi_dev->fmt->pixelformat) { + case V4L2_PIX_FMT_YUV32: + csi_set_32bit_imagpara(csi_dev, pix->width, pix->height); + break; + case V4L2_PIX_FMT_UYVY: + csi_set_16bit_imagpara(csi_dev, pix->width, pix->height); + break; + case V4L2_PIX_FMT_YUYV: + csi_set_16bit_imagpara(csi_dev, pix->width, pix->height); + break; + case V4L2_PIX_FMT_SBGGR8: + csi_set_8bit_imagpara(csi_dev, pix->width, pix->height); + break; + default: + pr_debug(" case not supported\n"); + return -EINVAL; + } + + if (csi_dev->csi_mux_mipi == true) { + cr1 = csi_read(csi_dev, CSI_CSICR1); + cr1 &= ~BIT_GCLK_MODE; + csi_write(csi_dev, cr1, CSI_CSICR1); + + cr18 = csi_read(csi_dev, CSI_CSICR18); + cr18 &= BIT_MIPI_DATA_FORMAT_MASK; + cr18 |= BIT_DATA_FROM_MIPI; + + switch (csi_dev->fmt->pixelformat) { + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YUYV: + cr18 |= BIT_MIPI_DATA_FORMAT_YUV422_8B; + break; + case V4L2_PIX_FMT_SBGGR8: + cr18 |= BIT_MIPI_DATA_FORMAT_RAW8; + break; + default: + pr_debug(" fmt not supported\n"); + return -EINVAL; + } + + csi_write(csi_dev, cr18, CSI_CSICR18); + } + return 0; +} + +static int mx6s_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct mx6s_csi_dev *csi_dev = vb2_get_drv_priv(vq); + struct vb2_buffer *vb; + struct mx6s_buffer *buf; + unsigned long phys; + unsigned long flags; + + if (count < 2) + return -ENOBUFS; + + /* + * I didn't manage to properly enable/disable + * a per frame basis during running transfers, + * thus we allocate a buffer here and use it to + * discard frames when no buffer is available. + * Feel free to work on this ;) + */ + csi_dev->discard_size = csi_dev->pix.sizeimage; + csi_dev->discard_buffer = dma_alloc_coherent(csi_dev->v4l2_dev.dev, + PAGE_ALIGN(csi_dev->discard_size), + &csi_dev->discard_buffer_dma, + GFP_DMA | GFP_KERNEL); + if (!csi_dev->discard_buffer) + return -ENOMEM; + + spin_lock_irqsave(&csi_dev->slock, flags); + + csi_dev->buf_discard[0].discard = true; + list_add_tail(&csi_dev->buf_discard[0].queue, + &csi_dev->discard); + + csi_dev->buf_discard[1].discard = true; + list_add_tail(&csi_dev->buf_discard[1].queue, + &csi_dev->discard); + + /* csi buf 0 */ + buf = list_first_entry(&csi_dev->capture, struct mx6s_buffer, + internal.queue); + buf->internal.bufnum = 0; + vb = &buf->vb; + vb->state = VB2_BUF_STATE_ACTIVE; + + phys = vb2_dma_contig_plane_dma_addr(vb, 0); + + mx6s_update_csi_buf(csi_dev, phys, buf->internal.bufnum); + list_move_tail(csi_dev->capture.next, &csi_dev->active_bufs); + + /* csi buf 1 */ + buf = list_first_entry(&csi_dev->capture, struct mx6s_buffer, + internal.queue); + buf->internal.bufnum = 1; + vb = &buf->vb; + vb->state = VB2_BUF_STATE_ACTIVE; + + phys = vb2_dma_contig_plane_dma_addr(vb, 0); + mx6s_update_csi_buf(csi_dev, phys, buf->internal.bufnum); + list_move_tail(csi_dev->capture.next, &csi_dev->active_bufs); + + spin_unlock_irqrestore(&csi_dev->slock, flags); + + return mx6s_csi_enable(csi_dev); +} + +static void mx6s_stop_streaming(struct vb2_queue *vq) +{ + struct mx6s_csi_dev *csi_dev = vb2_get_drv_priv(vq); + unsigned long flags; + struct mx6s_buffer *buf, *tmp; + void *b; + + mx6s_csi_disable(csi_dev); + + spin_lock_irqsave(&csi_dev->slock, flags); + + list_for_each_entry_safe(buf, tmp, + &csi_dev->active_bufs, internal.queue) { + list_del_init(&buf->internal.queue); + if (buf->vb.state == VB2_BUF_STATE_ACTIVE) + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + } + + list_for_each_entry_safe(buf, tmp, + &csi_dev->capture, internal.queue) { + list_del_init(&buf->internal.queue); + if (buf->vb.state == VB2_BUF_STATE_ACTIVE) + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + } + + INIT_LIST_HEAD(&csi_dev->capture); + INIT_LIST_HEAD(&csi_dev->active_bufs); + INIT_LIST_HEAD(&csi_dev->discard); + + b = csi_dev->discard_buffer; + csi_dev->discard_buffer = NULL; + + spin_unlock_irqrestore(&csi_dev->slock, flags); + + dma_free_coherent(csi_dev->v4l2_dev.dev, + csi_dev->discard_size, b, + csi_dev->discard_buffer_dma); +} + +static struct vb2_ops mx6s_videobuf_ops = { + .queue_setup = mx6s_videobuf_setup, + .buf_prepare = mx6s_videobuf_prepare, + .buf_queue = mx6s_videobuf_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = mx6s_start_streaming, + .stop_streaming = mx6s_stop_streaming, +}; + +static void mx6s_csi_frame_done(struct mx6s_csi_dev *csi_dev, + int bufnum, bool err) +{ + struct mx6s_buf_internal *ibuf; + struct mx6s_buffer *buf; + struct vb2_buffer *vb; + unsigned long phys; + + ibuf = list_first_entry(&csi_dev->active_bufs, struct mx6s_buf_internal, + queue); + + if (ibuf->discard) { + /* + * Discard buffer must not be returned to user space. + * Just return it to the discard queue. + */ + list_move_tail(csi_dev->active_bufs.next, &csi_dev->discard); + } else { + buf = mx6s_ibuf_to_buf(ibuf); + + vb = &buf->vb; + phys = vb2_dma_contig_plane_dma_addr(vb, 0); + if (bufnum == 1) { + if (csi_read(csi_dev, CSI_CSIDMASA_FB2) != phys) { + dev_err(csi_dev->dev, "%lx != %x\n", phys, + csi_read(csi_dev, CSI_CSIDMASA_FB2)); + } + } else { + if (csi_read(csi_dev, CSI_CSIDMASA_FB1) != phys) { + dev_err(csi_dev->dev, "%lx != %x\n", phys, + csi_read(csi_dev, CSI_CSIDMASA_FB1)); + } + } + dev_dbg(csi_dev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__, vb, + vb2_plane_vaddr(vb, 0), + vb2_get_plane_payload(vb, 0)); + + list_del_init(&buf->internal.queue); + v4l2_get_timestamp(&vb->v4l2_buf.timestamp); + vb->v4l2_buf.sequence = csi_dev->frame_count; + if (err) + vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); + else + vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + } + + csi_dev->frame_count++; + + /* Config discard buffer to active_bufs */ + if (list_empty(&csi_dev->capture)) { + if (list_empty(&csi_dev->discard)) { + dev_warn(csi_dev->dev, + "%s: trying to access empty discard list\n", + __func__); + return; + } + + ibuf = list_first_entry(&csi_dev->discard, + struct mx6s_buf_internal, queue); + ibuf->bufnum = bufnum; + + list_move_tail(csi_dev->discard.next, &csi_dev->active_bufs); + + mx6s_update_csi_buf(csi_dev, + csi_dev->discard_buffer_dma, bufnum); + return; + } + + buf = list_first_entry(&csi_dev->capture, struct mx6s_buffer, + internal.queue); + + buf->internal.bufnum = bufnum; + + list_move_tail(csi_dev->capture.next, &csi_dev->active_bufs); + + vb = &buf->vb; + vb->state = VB2_BUF_STATE_ACTIVE; + + phys = vb2_dma_contig_plane_dma_addr(vb, 0); + mx6s_update_csi_buf(csi_dev, phys, bufnum); +} + +static irqreturn_t mx6s_csi_irq_handler(int irq, void *data) +{ + struct mx6s_csi_dev *csi_dev = data; + unsigned long status; + u32 cr1, cr3, cr18; + + spin_lock(&csi_dev->slock); + + status = csi_read(csi_dev, CSI_CSISR); + csi_write(csi_dev, status, CSI_CSISR); + + if (list_empty(&csi_dev->active_bufs)) { + dev_warn(csi_dev->dev, + "%s: called while active list is empty\n", + __func__); + + spin_unlock(&csi_dev->slock); + return IRQ_HANDLED; + } + + if (status & BIT_RFF_OR_INT) + dev_warn(csi_dev->dev, "%s Rx fifo overflow\n", __func__); + + if (status & BIT_HRESP_ERR_INT) { + /* software reset */ + + /* Disable csi */ + cr18 = csi_read(csi_dev, CSI_CSICR18); + cr18 &= ~BIT_CSI_ENABLE; + csi_write(csi_dev, cr18, CSI_CSICR18); + + /* Clear RX FIFO */ + cr1 = csi_read(csi_dev, CSI_CSICR1); + csi_write(csi_dev, cr1 & ~BIT_FCC, CSI_CSICR1); + cr1 = csi_read(csi_dev, CSI_CSICR1); + csi_write(csi_dev, cr1 | BIT_CLR_RXFIFO, CSI_CSICR1); + + cr1 = csi_read(csi_dev, CSI_CSICR1); + csi_write(csi_dev, cr1 | BIT_FCC, CSI_CSICR1); + + /* DMA reflash */ + cr3 = csi_read(csi_dev, CSI_CSICR3); + cr3 |= BIT_DMA_REFLASH_RFF; + csi_write(csi_dev, cr3, CSI_CSICR3); + + /* Ensable csi */ + cr18 |= BIT_CSI_ENABLE; + csi_write(csi_dev, cr18, CSI_CSICR18); + + pr_warning("Hresponse error is detected.\n"); + } + + if (status & BIT_ADDR_CH_ERR_INT) { + /* Disable csi */ + cr18 = csi_read(csi_dev, CSI_CSICR18); + cr18 &= ~BIT_CSI_ENABLE; + csi_write(csi_dev, cr18, CSI_CSICR18); + + /* DMA reflash */ + cr3 = csi_read(csi_dev, CSI_CSICR3); + cr3 |= BIT_DMA_REFLASH_RFF; + csi_write(csi_dev, cr3, CSI_CSICR3); + + /* Ensable csi */ + cr18 |= BIT_CSI_ENABLE; + csi_write(csi_dev, cr18, CSI_CSICR18); + + pr_debug("base address switching Change Err.\n"); + } + + if ((status & BIT_DMA_TSF_DONE_FB1) && + (status & BIT_DMA_TSF_DONE_FB2)) { + /* For both FB1 and FB2 interrupter bits set case, + * CSI DMA is work in one of FB1 and FB2 buffer, + * but software can not know the state. + * Skip it to avoid base address updated + * when csi work in field0 and field1 will write to + * new base address. + * PDM TKT230775 */ + pr_debug("Skip two frames\n"); + } else if (status & BIT_DMA_TSF_DONE_FB1) { + mx6s_csi_frame_done(csi_dev, 0, false); + } else if (status & BIT_DMA_TSF_DONE_FB2) { + mx6s_csi_frame_done(csi_dev, 1, false); + } + + spin_unlock(&csi_dev->slock); + + return IRQ_HANDLED; +} + +/* + * File operations for the device + */ +static int mx6s_csi_open(struct file *file) +{ + struct mx6s_csi_dev *csi_dev = video_drvdata(file); + struct v4l2_subdev *sd = csi_dev->sd; + struct vb2_queue *q = &csi_dev->vb2_vidq; + int ret = 0; + + file->private_data = csi_dev; + + if (mutex_lock_interruptible(&csi_dev->lock)) + return -ERESTARTSYS; + + csi_dev->alloc_ctx = vb2_dma_contig_init_ctx(csi_dev->dev); + if (IS_ERR(csi_dev->alloc_ctx)) + goto unlock; + + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR; + q->drv_priv = csi_dev; + q->ops = &mx6s_videobuf_ops; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = sizeof(struct mx6s_buffer); + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &csi_dev->lock; + + ret = vb2_queue_init(q); + if (ret < 0) + goto eallocctx; + + pm_runtime_get_sync(csi_dev->dev); + + request_bus_freq(BUS_FREQ_HIGH); + + v4l2_subdev_call(sd, core, s_power, 1); + mx6s_csi_init(csi_dev); + + mutex_unlock(&csi_dev->lock); + + return ret; +eallocctx: + vb2_dma_contig_cleanup_ctx(csi_dev->alloc_ctx); +unlock: + mutex_unlock(&csi_dev->lock); + return ret; +} + +static int mx6s_csi_close(struct file *file) +{ + struct mx6s_csi_dev *csi_dev = video_drvdata(file); + struct v4l2_subdev *sd = csi_dev->sd; + + mutex_lock(&csi_dev->lock); + + vb2_queue_release(&csi_dev->vb2_vidq); + + mx6s_csi_deinit(csi_dev); + v4l2_subdev_call(sd, core, s_power, 0); + + vb2_dma_contig_cleanup_ctx(csi_dev->alloc_ctx); + mutex_unlock(&csi_dev->lock); + + file->private_data = NULL; + + release_bus_freq(BUS_FREQ_HIGH); + + pm_runtime_put_sync_suspend(csi_dev->dev); + return 0; +} + +static ssize_t mx6s_csi_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct mx6s_csi_dev *csi_dev = video_drvdata(file); + int ret; + + dev_dbg(csi_dev->dev, "read called, buf %p\n", buf); + + mutex_lock(&csi_dev->lock); + ret = vb2_read(&csi_dev->vb2_vidq, buf, count, ppos, + file->f_flags & O_NONBLOCK); + mutex_unlock(&csi_dev->lock); + return ret; +} + +static int mx6s_csi_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct mx6s_csi_dev *csi_dev = video_drvdata(file); + int ret; + + if (mutex_lock_interruptible(&csi_dev->lock)) + return -ERESTARTSYS; + ret = vb2_mmap(&csi_dev->vb2_vidq, vma); + mutex_unlock(&csi_dev->lock); + + pr_debug("vma start=0x%08lx, size=%ld, ret=%d\n", + (unsigned long)vma->vm_start, + (unsigned long)vma->vm_end-(unsigned long)vma->vm_start, + ret); + + return ret; +} + +static struct v4l2_file_operations mx6s_csi_fops = { + .owner = THIS_MODULE, + .open = mx6s_csi_open, + .release = mx6s_csi_close, + .read = mx6s_csi_read, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ + .mmap = mx6s_csi_mmap, +}; + +/* + * Video node IOCTLs + */ +static int mx6s_vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *inp) +{ + if (inp->index != 0) + return -EINVAL; + + /* default is camera */ + inp->type = V4L2_INPUT_TYPE_CAMERA; + strcpy(inp->name, "Camera"); + + return 0; +} + +static int mx6s_vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + *i = 0; + + return 0; +} + +static int mx6s_vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + if (i > 0) + return -EINVAL; + + return 0; +} + +static int mx6s_vidioc_querystd(struct file *file, void *priv, v4l2_std_id *a) +{ + struct mx6s_csi_dev *csi_dev = video_drvdata(file); + struct v4l2_subdev *sd = csi_dev->sd; + + return v4l2_subdev_call(sd, video, querystd, a); +} + +static int mx6s_vidioc_s_std(struct file *file, void *priv, v4l2_std_id a) +{ + struct mx6s_csi_dev *csi_dev = video_drvdata(file); + struct v4l2_subdev *sd = csi_dev->sd; + + return v4l2_subdev_call(sd, video, s_std, a); +} + +static int mx6s_vidioc_g_std(struct file *file, void *priv, v4l2_std_id *a) +{ + struct mx6s_csi_dev *csi_dev = video_drvdata(file); + struct v4l2_subdev *sd = csi_dev->sd; + + return v4l2_subdev_call(sd, video, g_std, a); +} + +static int mx6s_vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + struct mx6s_csi_dev *csi_dev = video_drvdata(file); + + WARN_ON(priv != file->private_data); + + return vb2_reqbufs(&csi_dev->vb2_vidq, p); +} + +static int mx6s_vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct mx6s_csi_dev *csi_dev = video_drvdata(file); + int ret; + + WARN_ON(priv != file->private_data); + + ret = vb2_querybuf(&csi_dev->vb2_vidq, p); + + if (!ret) { + /* return physical address */ + struct vb2_buffer *vb = csi_dev->vb2_vidq.bufs[p->index]; + if (p->flags & V4L2_BUF_FLAG_MAPPED) + p->m.offset = vb2_dma_contig_plane_dma_addr(vb, 0); + } + return ret; +} + +static int mx6s_vidioc_qbuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct mx6s_csi_dev *csi_dev = video_drvdata(file); + + WARN_ON(priv != file->private_data); + + return vb2_qbuf(&csi_dev->vb2_vidq, p); +} + +static int mx6s_vidioc_dqbuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct mx6s_csi_dev *csi_dev = video_drvdata(file); + + WARN_ON(priv != file->private_data); + + return vb2_dqbuf(&csi_dev->vb2_vidq, p, file->f_flags & O_NONBLOCK); +} + +static int mx6s_vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct mx6s_csi_dev *csi_dev = video_drvdata(file); + struct v4l2_subdev *sd = csi_dev->sd; + u32 code; + struct mx6s_fmt *fmt; + int ret; + + int index = f->index; + + WARN_ON(priv != file->private_data); + + ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, index, &code); + if (ret < 0) { + /* no more formats */ + dev_dbg(csi_dev->dev, "No more fmt\n"); + return -EINVAL; + } + + fmt = format_by_mbus(code); + if (!fmt) { + dev_err(csi_dev->dev, "mbus (0x%08x) invalid.\n", code); + return -EINVAL; + } + + strlcpy(f->description, fmt->name, sizeof(f->description)); + f->pixelformat = fmt->pixelformat; + + return 0; +} + +static int mx6s_vidioc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct mx6s_csi_dev *csi_dev = video_drvdata(file); + struct v4l2_subdev *sd = csi_dev->sd; + struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_mbus_framefmt mbus_fmt; + struct mx6s_fmt *fmt; + int ret; + + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + if (!fmt) { + dev_err(csi_dev->dev, "Fourcc format (0x%08x) invalid.", + f->fmt.pix.pixelformat); + return -EINVAL; + } + + v4l2_fill_mbus_format(&mbus_fmt, pix, fmt->mbus_code); + ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mbus_fmt); + v4l2_fill_pix_format(pix, &mbus_fmt); + + if (pix->field != V4L2_FIELD_INTERLACED) + pix->field = V4L2_FIELD_NONE; + + pix->sizeimage = fmt->bpp * pix->height * pix->width; + pix->bytesperline = fmt->bpp * pix->width; + + return ret; +} + +/* + * The real work of figuring out a workable format. + */ + +static int mx6s_vidioc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct mx6s_csi_dev *csi_dev = video_drvdata(file); + int ret; + + ret = mx6s_vidioc_try_fmt_vid_cap(file, csi_dev, f); + if (ret < 0) + return ret; + + csi_dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat); + csi_dev->mbus_code = csi_dev->fmt->mbus_code; + csi_dev->pix.width = f->fmt.pix.width; + csi_dev->pix.height = f->fmt.pix.height; + csi_dev->pix.sizeimage = f->fmt.pix.sizeimage; + csi_dev->pix.field = f->fmt.pix.field; + csi_dev->type = f->type; + dev_dbg(csi_dev->dev, "set to pixelformat '%4.6s'\n", + (char *)&csi_dev->fmt->name); + + /* Config csi */ + mx6s_configure_csi(csi_dev); + + return 0; +} + +static int mx6s_vidioc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct mx6s_csi_dev *csi_dev = video_drvdata(file); + + WARN_ON(priv != file->private_data); + + f->fmt.pix = csi_dev->pix; + + return 0; +} + +static int mx6s_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct mx6s_csi_dev *csi_dev = video_drvdata(file); + + WARN_ON(priv != file->private_data); + + /* cap->name is set by the friendly caller:-> */ + strlcpy(cap->driver, MX6S_CAM_DRV_NAME, sizeof(cap->driver)); + strlcpy(cap->card, MX6S_CAM_DRIVER_DESCRIPTION, sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", + dev_name(csi_dev->dev)); + + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + return 0; +} + +static int mx6s_vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type i) +{ + struct mx6s_csi_dev *csi_dev = video_drvdata(file); + struct v4l2_subdev *sd = csi_dev->sd; + int ret; + + WARN_ON(priv != file->private_data); + + if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + ret = vb2_streamon(&csi_dev->vb2_vidq, i); + if (!ret) + v4l2_subdev_call(sd, video, s_stream, 1); + + return ret; +} + +static int mx6s_vidioc_streamoff(struct file *file, void *priv, + enum v4l2_buf_type i) +{ + struct mx6s_csi_dev *csi_dev = video_drvdata(file); + struct v4l2_subdev *sd = csi_dev->sd; + + WARN_ON(priv != file->private_data); + + if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + /* + * This calls buf_release from host driver's videobuf_queue_ops for all + * remaining buffers. When the last buffer is freed, stop capture + */ + vb2_streamoff(&csi_dev->vb2_vidq, i); + + v4l2_subdev_call(sd, video, s_stream, 0); + + return 0; +} + +static int mx6s_vidioc_cropcap(struct file *file, void *fh, + struct v4l2_cropcap *a) +{ + struct mx6s_csi_dev *csi_dev = video_drvdata(file); + + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + dev_dbg(csi_dev->dev, "VIDIOC_CROPCAP not implemented\n"); + + return 0; +} + +static int mx6s_vidioc_g_crop(struct file *file, void *priv, + struct v4l2_crop *a) +{ + struct mx6s_csi_dev *csi_dev = video_drvdata(file); + + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + dev_dbg(csi_dev->dev, "VIDIOC_G_CROP not implemented\n"); + + return 0; +} + +static int mx6s_vidioc_s_crop(struct file *file, void *priv, + const struct v4l2_crop *a) +{ + struct mx6s_csi_dev *csi_dev = video_drvdata(file); + + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + dev_dbg(csi_dev->dev, "VIDIOC_S_CROP not implemented\n"); + + return 0; +} + +static int mx6s_vidioc_g_parm(struct file *file, void *priv, + struct v4l2_streamparm *a) +{ + struct mx6s_csi_dev *csi_dev = video_drvdata(file); + struct v4l2_subdev *sd = csi_dev->sd; + + return v4l2_subdev_call(sd, video, g_parm, a); +} + +static int mx6s_vidioc_s_parm(struct file *file, void *priv, + struct v4l2_streamparm *a) +{ + struct mx6s_csi_dev *csi_dev = video_drvdata(file); + struct v4l2_subdev *sd = csi_dev->sd; + + return v4l2_subdev_call(sd, video, s_parm, a); +} + +static int mx6s_vidioc_enum_framesizes(struct file *file, void *priv, + struct v4l2_frmsizeenum *fsize) +{ + struct mx6s_csi_dev *csi_dev = video_drvdata(file); + struct v4l2_subdev *sd = csi_dev->sd; + struct mx6s_fmt *fmt; + struct v4l2_subdev_frame_size_enum fse = { + .index = fsize->index, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + int ret; + + fmt = format_by_fourcc(fsize->pixel_format); + if (fmt->pixelformat != fsize->pixel_format) + return -EINVAL; + fse.code = fmt->mbus_code; + + ret = v4l2_subdev_call(sd, pad, enum_frame_size, NULL, &fse); + if (ret) + return ret; + + if (fse.min_width == fse.max_width && + fse.min_height == fse.max_height) { + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = fse.min_width; + fsize->discrete.height = fse.min_height; + return 0; + } + + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->stepwise.min_width = fse.min_width; + fsize->stepwise.max_width = fse.max_width; + fsize->stepwise.min_height = fse.min_height; + fsize->stepwise.max_height = fse.max_height; + fsize->stepwise.step_width = 1; + fsize->stepwise.step_height = 1; + + return 0; +} + +static int mx6s_vidioc_enum_frameintervals(struct file *file, void *priv, + struct v4l2_frmivalenum *interval) +{ + struct mx6s_csi_dev *csi_dev = video_drvdata(file); + struct v4l2_subdev *sd = csi_dev->sd; + struct mx6s_fmt *fmt; + struct v4l2_subdev_frame_interval_enum fie = { + .index = interval->index, + .width = interval->width, + .height = interval->height, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + int ret; + + fmt = format_by_fourcc(interval->pixel_format); + if (fmt->pixelformat != interval->pixel_format) + return -EINVAL; + fie.code = fmt->mbus_code; + + ret = v4l2_subdev_call(sd, pad, enum_frame_interval, NULL, &fie); + if (ret) + return ret; + interval->type = V4L2_FRMIVAL_TYPE_DISCRETE; + interval->discrete = fie.interval; + return 0; +} + +static const struct v4l2_ioctl_ops mx6s_csi_ioctl_ops = { + .vidioc_querycap = mx6s_vidioc_querycap, + .vidioc_enum_fmt_vid_cap = mx6s_vidioc_enum_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = mx6s_vidioc_try_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = mx6s_vidioc_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = mx6s_vidioc_s_fmt_vid_cap, + .vidioc_cropcap = mx6s_vidioc_cropcap, + .vidioc_s_crop = mx6s_vidioc_s_crop, + .vidioc_g_crop = mx6s_vidioc_g_crop, + .vidioc_reqbufs = mx6s_vidioc_reqbufs, + .vidioc_querybuf = mx6s_vidioc_querybuf, + .vidioc_qbuf = mx6s_vidioc_qbuf, + .vidioc_dqbuf = mx6s_vidioc_dqbuf, + .vidioc_g_std = mx6s_vidioc_g_std, + .vidioc_s_std = mx6s_vidioc_s_std, + .vidioc_querystd = mx6s_vidioc_querystd, + .vidioc_enum_input = mx6s_vidioc_enum_input, + .vidioc_g_input = mx6s_vidioc_g_input, + .vidioc_s_input = mx6s_vidioc_s_input, + .vidioc_streamon = mx6s_vidioc_streamon, + .vidioc_streamoff = mx6s_vidioc_streamoff, + .vidioc_g_parm = mx6s_vidioc_g_parm, + .vidioc_s_parm = mx6s_vidioc_s_parm, + .vidioc_enum_framesizes = mx6s_vidioc_enum_framesizes, + .vidioc_enum_frameintervals = mx6s_vidioc_enum_frameintervals, +}; + +static int subdev_notifier_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) +{ + struct mx6s_csi_dev *csi_dev = notifier_to_mx6s_dev(notifier); + + /* Find platform data for this sensor subdev */ + if (csi_dev->asd.match.of.node == subdev->dev->of_node) + csi_dev->sd = subdev; + + if (subdev == NULL) + return -EINVAL; + + v4l2_info(&csi_dev->v4l2_dev, "Registered sensor subdevice: %s\n", + subdev->name); + + return 0; +} + +static int mx6s_csi_mux_sel(struct mx6s_csi_dev *csi_dev) +{ + struct device_node *np = csi_dev->dev->of_node; + struct device_node *node; + phandle phandle; + u32 out_val[3]; + int ret; + + ret = of_property_read_u32_array(np, "csi-mux-mipi", out_val, 3); + if (ret) { + dev_dbg(csi_dev->dev, "no csi-mux-mipi property found\n"); + csi_dev->csi_mux_mipi = false; + } else { + phandle = *out_val; + + node = of_find_node_by_phandle(phandle); + if (!node) { + dev_dbg(csi_dev->dev, "not find gpr node by phandle\n"); + ret = PTR_ERR(node); + } + csi_dev->csi_mux.gpr = syscon_node_to_regmap(node); + if (IS_ERR(csi_dev->csi_mux.gpr)) { + dev_err(csi_dev->dev, "failed to get gpr regmap\n"); + ret = PTR_ERR(csi_dev->csi_mux.gpr); + } + of_node_put(node); + if (ret < 0) + return ret; + + csi_dev->csi_mux.req_gpr = out_val[1]; + csi_dev->csi_mux.req_bit = out_val[2]; + + regmap_update_bits(csi_dev->csi_mux.gpr, csi_dev->csi_mux.req_gpr, + 1 << csi_dev->csi_mux.req_bit, 1 << csi_dev->csi_mux.req_bit); + + csi_dev->csi_mux_mipi = true; + } + return ret; +} + +static int mx6sx_register_subdevs(struct mx6s_csi_dev *csi_dev) +{ + struct device_node *parent = csi_dev->dev->of_node; + struct device_node *node, *port, *rem; + int ret; + + /* Attach sensors linked to csi receivers */ + for_each_available_child_of_node(parent, node) { + if (of_node_cmp(node->name, "port")) + continue; + + /* The csi node can have only port subnode. */ + port = of_get_next_child(node, NULL); + if (!port) + continue; + rem = of_graph_get_remote_port_parent(port); + of_node_put(port); + if (rem == NULL) { + v4l2_info(&csi_dev->v4l2_dev, + "Remote device at %s not found\n", + port->full_name); + return -1; + } + + csi_dev->asd.match_type = V4L2_ASYNC_MATCH_OF; + csi_dev->asd.match.of.node = rem; + csi_dev->async_subdevs[0] = &csi_dev->asd; + + of_node_put(rem); + break; + } + + csi_dev->subdev_notifier.subdevs = csi_dev->async_subdevs; + csi_dev->subdev_notifier.num_subdevs = 1; + csi_dev->subdev_notifier.bound = subdev_notifier_bound; + + ret = v4l2_async_notifier_register(&csi_dev->v4l2_dev, + &csi_dev->subdev_notifier); + if (ret) + dev_err(csi_dev->dev, + "Error register async notifier regoster\n"); + + return ret; +} + +static int mx6s_csi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mx6s_csi_dev *csi_dev; + struct video_device *vdev; + struct resource *res; + int ret = 0; + + dev_dbg(dev, "initialising\n"); + + /* Prepare our private structure */ + csi_dev = devm_kzalloc(dev, sizeof(struct mx6s_csi_dev), GFP_ATOMIC); + if (!csi_dev) { + dev_err(dev, "Can't allocate private structure\n"); + return -ENODEV; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + csi_dev->irq = platform_get_irq(pdev, 0); + if (res == NULL || csi_dev->irq < 0) { + dev_err(dev, "Missing platform resources data\n"); + return -ENODEV; + } + + csi_dev->regbase = devm_ioremap_resource(dev, res); + if (IS_ERR(csi_dev->regbase)) { + dev_err(dev, "Failed platform resources map\n"); + return -ENODEV; + } + + /* init video dma queues */ + INIT_LIST_HEAD(&csi_dev->capture); + INIT_LIST_HEAD(&csi_dev->active_bufs); + INIT_LIST_HEAD(&csi_dev->discard); + + csi_dev->clk_disp_axi = devm_clk_get(dev, "disp-axi"); + if (IS_ERR(csi_dev->clk_disp_axi)) { + dev_err(dev, "Could not get csi axi clock\n"); + return -ENODEV; + } + + csi_dev->clk_disp_dcic = devm_clk_get(dev, "disp_dcic"); + if (IS_ERR(csi_dev->clk_disp_dcic)) { + dev_err(dev, "Could not get disp dcic clock\n"); + return -ENODEV; + } + + csi_dev->clk_csi_mclk = devm_clk_get(dev, "csi_mclk"); + if (IS_ERR(csi_dev->clk_csi_mclk)) { + dev_err(dev, "Could not get csi mclk clock\n"); + return -ENODEV; + } + + csi_dev->dev = dev; + + mx6s_csi_mux_sel(csi_dev); + + snprintf(csi_dev->v4l2_dev.name, + sizeof(csi_dev->v4l2_dev.name), "CSI"); + + ret = v4l2_device_register(dev, &csi_dev->v4l2_dev); + if (ret < 0) { + dev_err(dev, "v4l2_device_register() failed: %d\n", ret); + return -ENODEV; + } + + /* initialize locks */ + mutex_init(&csi_dev->lock); + spin_lock_init(&csi_dev->slock); + + /* Allocate memory for video device */ + vdev = video_device_alloc(); + if (vdev == NULL) { + ret = -ENOMEM; + goto err_vdev; + } + + snprintf(vdev->name, sizeof(vdev->name), "mx6s-csi"); + + vdev->v4l2_dev = &csi_dev->v4l2_dev; + vdev->fops = &mx6s_csi_fops; + vdev->ioctl_ops = &mx6s_csi_ioctl_ops; + vdev->release = video_device_release; + vdev->lock = &csi_dev->lock; + + vdev->queue = &csi_dev->vb2_vidq; + + csi_dev->vdev = vdev; + + video_set_drvdata(csi_dev->vdev, csi_dev); + mutex_lock(&csi_dev->lock); + + ret = video_register_device(csi_dev->vdev, VFL_TYPE_GRABBER, -1); + if (ret < 0) { + video_device_release(csi_dev->vdev); + mutex_unlock(&csi_dev->lock); + goto err_vdev; + } + + /* install interrupt handler */ + if (devm_request_irq(dev, csi_dev->irq, mx6s_csi_irq_handler, + 0, "csi", (void *)csi_dev)) { + mutex_unlock(&csi_dev->lock); + dev_err(dev, "Request CSI IRQ failed.\n"); + ret = -ENODEV; + goto err_irq; + } + + mutex_unlock(&csi_dev->lock); + + ret = mx6sx_register_subdevs(csi_dev); + if (ret < 0) + goto err_irq; + + pm_runtime_enable(csi_dev->dev); + return 0; + +err_irq: + video_unregister_device(csi_dev->vdev); +err_vdev: + v4l2_device_unregister(&csi_dev->v4l2_dev); + return ret; +} + +static int mx6s_csi_remove(struct platform_device *pdev) +{ + struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); + struct mx6s_csi_dev *csi_dev = + container_of(v4l2_dev, struct mx6s_csi_dev, v4l2_dev); + + v4l2_async_notifier_unregister(&csi_dev->subdev_notifier); + + video_unregister_device(csi_dev->vdev); + v4l2_device_unregister(&csi_dev->v4l2_dev); + + pm_runtime_disable(csi_dev->dev); + return 0; +} + +static int mx6s_csi_runtime_suspend(struct device *dev) +{ + dev_dbg(dev, "csi v4l2 busfreq high release.\n"); + return 0; +} + +static int mx6s_csi_runtime_resume(struct device *dev) +{ + dev_dbg(dev, "csi v4l2 busfreq high request.\n"); + return 0; +} + +static const struct dev_pm_ops mx6s_csi_pm_ops = { + SET_RUNTIME_PM_OPS(mx6s_csi_runtime_suspend, mx6s_csi_runtime_resume, NULL) +}; + +static const struct of_device_id mx6s_csi_dt_ids[] = { + { .compatible = "fsl,imx6s-csi", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mx6s_csi_dt_ids); + +static struct platform_driver mx6s_csi_driver = { + .driver = { + .name = MX6S_CAM_DRV_NAME, + .of_match_table = of_match_ptr(mx6s_csi_dt_ids), + .pm = &mx6s_csi_pm_ops, + }, + .probe = mx6s_csi_probe, + .remove = mx6s_csi_remove, +}; + +module_platform_driver(mx6s_csi_driver); + +MODULE_DESCRIPTION("i.MX6Sx SoC Camera Host driver"); +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_LICENSE("GPL"); +MODULE_VERSION(MX6S_CAM_VERSION); diff --git a/drivers/media/platform/mxc/subdev/mxc_mipi_csi.c b/drivers/media/platform/mxc/subdev/mxc_mipi_csi.c new file mode 100644 index 000000000000..b677a472a523 --- /dev/null +++ b/drivers/media/platform/mxc/subdev/mxc_mipi_csi.c @@ -0,0 +1,1255 @@ +/* + * Freescale i.MX7 SoC series MIPI-CSI V3.3 receiver driver + * + * Copyright (C) 2015 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +/* + * Samsung S5P/EXYNOS SoC series MIPI-CSI receiver driver + * + * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. + * Author: Sylwester Nawrocki + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level (0-2)"); + +#define CSIS_DRIVER_NAME "mxc_mipi-csi" +#define CSIS_SUBDEV_NAME CSIS_DRIVER_NAME +#define CSIS_MAX_ENTITIES 2 +#define CSIS0_MAX_LANES 4 +#define CSIS1_MAX_LANES 2 + +#define MIPI_CSIS_DEF_PIX_WIDTH 640 +#define MIPI_CSIS_DEF_PIX_HEIGHT 480 + +/* Register map definition */ + +/* CSIS version */ +#define MIPI_CSIS_VERSION 0x00 + +/* CSIS common control */ +#define MIPI_CSIS_CMN_CTRL 0x04 +#define MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW (1 << 16) +#define MIPI_CSIS_CMN_CTRL_INTER_MODE (1 << 10) +#define MIPI_CSIS_CMN_CTRL_LANE_NR_OFFSET 8 +#define MIPI_CSIS_CMN_CTRL_LANE_NR_MASK (3 << 8) +#define MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW_CTRL (1 << 2) +#define MIPI_CSIS_CMN_CTRL_RESET (1 << 1) +#define MIPI_CSIS_CMN_CTRL_ENABLE (1 << 0) + +/* CSIS clock control */ +#define MIPI_CSIS_CLK_CTRL 0x08 +#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH3(x) (x << 28) +#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH2(x) (x << 24) +#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH1(x) (x << 20) +#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH0(x) (x << 16) +#define MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MSK (0xf << 4) +#define MIPI_CSIS_CLK_CTRL_WCLK_SRC (1 << 0) + +/* CSIS Interrupt mask */ +#define MIPI_CSIS_INTMSK 0x10 +#define MIPI_CSIS_INTMSK_EVEN_BEFORE (1 << 31) +#define MIPI_CSIS_INTMSK_EVEN_AFTER (1 << 30) +#define MIPI_CSIS_INTMSK_ODD_BEFORE (1 << 29) +#define MIPI_CSIS_INTMSK_ODD_AFTER (1 << 28) +#define MIPI_CSIS_INTMSK_FRAME_START (1 << 24) +#define MIPI_CSIS_INTMSK_FRAME_END (1 << 20) +#define MIPI_CSIS_INTMSK_ERR_SOT_HS (1 << 16) +#define MIPI_CSIS_INTMSK_ERR_LOST_FS (1 << 12) +#define MIPI_CSIS_INTMSK_ERR_LOST_FE (1 << 8) +#define MIPI_CSIS_INTMSK_ERR_OVER (1 << 4) +#define MIPI_CSIS_INTMSK_ERR_WRONG_CFG (1 << 3) +#define MIPI_CSIS_INTMSK_ERR_ECC (1 << 2) +#define MIPI_CSIS_INTMSK_ERR_CRC (1 << 1) +#define MIPI_CSIS_INTMSK_ERR_UNKNOWN (1 << 0) + +/* CSIS Interrupt source */ +#define MIPI_CSIS_INTSRC 0x14 +#define MIPI_CSIS_INTSRC_EVEN_BEFORE (1 << 31) +#define MIPI_CSIS_INTSRC_EVEN_AFTER (1 << 30) +#define MIPI_CSIS_INTSRC_EVEN (0x3 << 30) +#define MIPI_CSIS_INTSRC_ODD_BEFORE (1 << 29) +#define MIPI_CSIS_INTSRC_ODD_AFTER (1 << 28) +#define MIPI_CSIS_INTSRC_ODD (0x3 << 28) +#define MIPI_CSIS_INTSRC_NON_IMAGE_DATA (0xf << 28) +#define MIPI_CSIS_INTSRC_FRAME_START (1 << 24) +#define MIPI_CSIS_INTSRC_FRAME_END (1 << 20) +#define MIPI_CSIS_INTSRC_ERR_SOT_HS (1 << 16) +#define MIPI_CSIS_INTSRC_ERR_LOST_FS (1 << 12) +#define MIPI_CSIS_INTSRC_ERR_LOST_FE (1 << 8) +#define MIPI_CSIS_INTSRC_ERR_OVER (1 << 4) +#define MIPI_CSIS_INTSRC_ERR_WRONG_CFG (1 << 3) +#define MIPI_CSIS_INTSRC_ERR_ECC (1 << 2) +#define MIPI_CSIS_INTSRC_ERR_CRC (1 << 1) +#define MIPI_CSIS_INTSRC_ERR_UNKNOWN (1 << 0) +#define MIPI_CSIS_INTSRC_ERRORS 0xfffff + +/* D-PHY status control */ +#define MIPI_CSIS_DPHYSTATUS 0x20 +#define MIPI_CSIS_DPHYSTATUS_ULPS_DAT (1 << 8) +#define MIPI_CSIS_DPHYSTATUS_STOPSTATE_DAT (1 << 4) +#define MIPI_CSIS_DPHYSTATUS_ULPS_CLK (1 << 1) +#define MIPI_CSIS_DPHYSTATUS_STOPSTATE_CLK (1 << 0) + +/* D-PHY common control */ +#define MIPI_CSIS_DPHYCTRL 0x24 +#define MIPI_CSIS_DPHYCTRL_HSS_MASK (0xff << 24) +#define MIPI_CSIS_DPHYCTRL_HSS_OFFSET 24 +#define MIPI_CSIS_DPHYCTRL_SCLKS_MASK (0x3 << 22) +#define MIPI_CSIS_DPHYCTRL_SCLKS_OFFSET 22 +#define MIPI_CSIS_DPHYCTRL_DPDN_SWAP_CLK (1 << 6) +#define MIPI_CSIS_DPHYCTRL_DPDN_SWAP_DAT (1 << 5) +#define MIPI_CSIS_DPHYCTRL_ENABLE_DAT (1 << 1) +#define MIPI_CSIS_DPHYCTRL_ENABLE_CLK (1 << 0) +#define MIPI_CSIS_DPHYCTRL_ENABLE (0x1f << 0) + +/* D-PHY Master and Slave Control register Low */ +#define MIPI_CSIS_DPHYBCTRL_L 0x30 +/* D-PHY Master and Slave Control register High */ +#define MIPI_CSIS_DPHYBCTRL_H 0x34 +/* D-PHY Slave Control register Low */ +#define MIPI_CSIS_DPHYSCTRL_L 0x38 +/* D-PHY Slave Control register High */ +#define MIPI_CSIS_DPHYSCTRL_H 0x3c + + +/* ISP Configuration register */ +#define MIPI_CSIS_ISPCONFIG_CH0 0x40 +#define MIPI_CSIS_ISPCONFIG_CH1 0x50 +#define MIPI_CSIS_ISPCONFIG_CH2 0x60 +#define MIPI_CSIS_ISPCONFIG_CH3 0x70 + +#define MIPI_CSIS_ISPCFG_MEM_FULL_GAP_MSK (0xff << 24) +#define MIPI_CSIS_ISPCFG_MEM_FULL_GAP(x) (x << 24) +#define MIPI_CSIS_ISPCFG_DOUBLE_CMPNT (1 << 12) +#define MIPI_CSIS_ISPCFG_ALIGN_32BIT (1 << 11) +#define MIPI_CSIS_ISPCFG_FMT_YCBCR422_8BIT (0x1e << 2) +#define MIPI_CSIS_ISPCFG_FMT_RAW8 (0x2a << 2) +#define MIPI_CSIS_ISPCFG_FMT_RAW10 (0x2b << 2) +#define MIPI_CSIS_ISPCFG_FMT_RAW12 (0x2c << 2) +/* User defined formats, x = 1...4 */ +#define MIPI_CSIS_ISPCFG_FMT_USER(x) ((0x30 + x - 1) << 2) +#define MIPI_CSIS_ISPCFG_FMT_MASK (0x3f << 2) + +/* ISP Image Resolution register */ +#define MIPI_CSIS_ISPRESOL_CH0 0x44 +#define MIPI_CSIS_ISPRESOL_CH1 0x54 +#define MIPI_CSIS_ISPRESOL_CH2 0x64 +#define MIPI_CSIS_ISPRESOL_CH3 0x74 +#define CSIS_MAX_PIX_WIDTH 0xffff +#define CSIS_MAX_PIX_HEIGHT 0xffff + +/* ISP SYNC register */ +#define MIPI_CSIS_ISPSYNC_CH0 0x48 +#define MIPI_CSIS_ISPSYNC_CH1 0x58 +#define MIPI_CSIS_ISPSYNC_CH2 0x68 +#define MIPI_CSIS_ISPSYNC_CH3 0x78 + +#define MIPI_CSIS_ISPSYNC_HSYNC_LINTV_OFFSET 18 +#define MIPI_CSIS_ISPSYNC_VSYNC_SINTV_OFFSET 12 +#define MIPI_CSIS_ISPSYNC_VSYNC_EINTV_OFFSET 0 + +/* Non-image packet data buffers */ +#define MIPI_CSIS_PKTDATA_ODD 0x2000 +#define MIPI_CSIS_PKTDATA_EVEN 0x3000 +#define MIPI_CSIS_PKTDATA_SIZE SZ_4K + +#define DEFAULT_SCLK_CSIS_FREQ 166000000UL + +enum { + ST_POWERED = 1, + ST_STREAMING = 2, + ST_SUSPENDED = 4, +}; + +struct mipi_csis_event { + u32 mask; + const char * const name; + unsigned int counter; +}; + +static const struct mipi_csis_event mipi_csis_events[] = { + /* Errors */ + { MIPI_CSIS_INTSRC_ERR_SOT_HS, "SOT Error" }, + { MIPI_CSIS_INTSRC_ERR_LOST_FS, "Lost Frame Start Error" }, + { MIPI_CSIS_INTSRC_ERR_LOST_FE, "Lost Frame End Error" }, + { MIPI_CSIS_INTSRC_ERR_OVER, "FIFO Overflow Error" }, + { MIPI_CSIS_INTSRC_ERR_ECC, "ECC Error" }, + { MIPI_CSIS_INTSRC_ERR_CRC, "CRC Error" }, + { MIPI_CSIS_INTSRC_ERR_UNKNOWN, "Unknown Error" }, + /* Non-image data receive events */ + { MIPI_CSIS_INTSRC_EVEN_BEFORE, "Non-image data before even frame" }, + { MIPI_CSIS_INTSRC_EVEN_AFTER, "Non-image data after even frame" }, + { MIPI_CSIS_INTSRC_ODD_BEFORE, "Non-image data before odd frame" }, + { MIPI_CSIS_INTSRC_ODD_AFTER, "Non-image data after odd frame" }, + /* Frame start/end */ + { MIPI_CSIS_INTSRC_FRAME_START, "Frame Start" }, + { MIPI_CSIS_INTSRC_FRAME_END, "Frame End" }, +}; +#define MIPI_CSIS_NUM_EVENTS ARRAY_SIZE(mipi_csis_events) + +struct csis_pktbuf { + u32 *data; + unsigned int len; +}; + +struct csis_hw_reset { + struct regmap *src; + u8 req_src; + u8 rst_bit; +}; + +/** + * struct csi_state - the driver's internal state data structure + * @lock: mutex serializing the subdev and power management operations, + * protecting @format and @flags members + * @sd: v4l2_subdev associated with CSIS device instance + * @index: the hardware instance index + * @pdev: CSIS platform device + * @phy: pointer to the CSIS generic PHY + * @regs: mmaped I/O registers memory + * @supplies: CSIS regulator supplies + * @clock: CSIS clocks + * @irq: requested s5p-mipi-csis irq number + * @flags: the state variable for power and streaming control + * @clock_frequency: device bus clock frequency + * @hs_settle: HS-RX settle time + * @num_lanes: number of MIPI-CSI data lanes used + * @max_num_lanes: maximum number of MIPI-CSI data lanes supported + * @wclk_ext: CSI wrapper clock: 0 - bus clock, 1 - external SCLK_CAM + * @csis_fmt: current CSIS pixel format + * @format: common media bus format for the source and sink pad + * @slock: spinlock protecting structure members below + * @pkt_buf: the frame embedded (non-image) data buffer + * @events: MIPI-CSIS event (error) counters + */ +struct csi_state { + struct mutex lock; + struct device *dev; + struct v4l2_subdev mipi_sd; + struct v4l2_subdev *sensor_sd; + struct v4l2_device v4l2_dev; + + u8 index; + struct platform_device *pdev; + struct phy *phy; + void __iomem *regs; + struct clk *mipi_clk; + struct clk *phy_clk; + int irq; + u32 flags; + + u32 clk_frequency; + u32 hs_settle; + u32 num_lanes; + u32 max_num_lanes; + u8 wclk_ext; + + const struct csis_pix_format *csis_fmt; + struct v4l2_mbus_framefmt format; + + spinlock_t slock; + struct csis_pktbuf pkt_buf; + struct mipi_csis_event events[MIPI_CSIS_NUM_EVENTS]; + + struct v4l2_async_subdev asd; + struct v4l2_async_notifier subdev_notifier; + struct v4l2_async_subdev *async_subdevs[2]; + + struct csis_hw_reset hw_reset; + struct regulator *mipi_phy_regulator; +}; + +/** + * struct csis_pix_format - CSIS pixel format description + * @pix_width_alignment: horizontal pixel alignment, width will be + * multiple of 2^pix_width_alignment + * @code: corresponding media bus code + * @fmt_reg: MIPI_CSIS_CONFIG register value + * @data_alignment: MIPI-CSI data alignment in bits + */ +struct csis_pix_format { + unsigned int pix_width_alignment; + u32 code; + u32 fmt_reg; + u8 data_alignment; +}; + +static const struct csis_pix_format mipi_csis_formats[] = { + { + .code = MEDIA_BUS_FMT_YUYV8_2X8, + .fmt_reg = MIPI_CSIS_ISPCFG_FMT_YCBCR422_8BIT, + .data_alignment = 16, + }, { + .code = MEDIA_BUS_FMT_VYUY8_2X8, + .fmt_reg = MIPI_CSIS_ISPCFG_FMT_YCBCR422_8BIT, + .data_alignment = 16, + }, { + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW8, + .data_alignment = 8, + } +}; + +#define mipi_csis_write(__csis, __r, __v) writel(__v, __csis->regs + __r) +#define mipi_csis_read(__csis, __r) readl(__csis->regs + __r) + +static struct csi_state *mipi_sd_to_csi_state(struct v4l2_subdev *sdev) +{ + return container_of(sdev, struct csi_state, mipi_sd); +} + +static inline struct csi_state + *notifier_to_mipi_dev(struct v4l2_async_notifier *n) +{ + return container_of(n, struct csi_state, subdev_notifier); +} + +static const struct csis_pix_format *find_csis_format(u32 code) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mipi_csis_formats); i++) + if (code == mipi_csis_formats[i].code) + return &mipi_csis_formats[i]; + return NULL; +} + +static void mipi_csis_enable_interrupts(struct csi_state *state, bool on) +{ + u32 val = mipi_csis_read(state, MIPI_CSIS_INTMSK); + if (on) + val |= 0xf00fffff; + else + val &= ~0xf00fffff; + mipi_csis_write(state, MIPI_CSIS_INTMSK, val); +} + +static void mipi_csis_sw_reset(struct csi_state *state) +{ + u32 val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL); + + mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val | MIPI_CSIS_CMN_CTRL_RESET); + udelay(10); +} + +static int mipi_csis_phy_init(struct csi_state *state) +{ + int ret; + + state->mipi_phy_regulator = devm_regulator_get(state->dev, + "mipi-phy"); + + ret = regulator_set_voltage(state->mipi_phy_regulator, + 1000000, 1000000); + + ret = regulator_enable(state->mipi_phy_regulator); + if (ret) { + dev_err(state->dev, "failed to set mipi regulator.\n"); + return ret; + } + return ret; +} + +static int mipi_csis_phy_reset(struct csi_state *state) +{ + struct device_node *np = state->dev->of_node; + struct device_node *node; + phandle phandle; + u32 out_val[3]; + int ret; + + ret = of_property_read_u32_array(np, "csis-phy-reset", out_val, 3); + if (ret) { + dev_dbg(state->dev, "no csis-hw-reset property found\n"); + } else { + phandle = *out_val; + + node = of_find_node_by_phandle(phandle); + if (!node) { + dev_dbg(state->dev, "not find src node by phandle\n"); + ret = PTR_ERR(node); + } + state->hw_reset.src = syscon_node_to_regmap(node); + if (IS_ERR(state->hw_reset.src)) { + dev_err(state->dev, "failed to get src regmap\n"); + ret = PTR_ERR(state->hw_reset.src); + } + of_node_put(node); + if (ret < 0) + return ret; + + state->hw_reset.req_src = out_val[1]; + state->hw_reset.rst_bit = out_val[2]; + + /* reset mipi phy */ + regmap_update_bits(state->hw_reset.src, state->hw_reset.req_src, + 1 << state->hw_reset.rst_bit, 1 << state->hw_reset.rst_bit); + msleep(20); + regmap_update_bits(state->hw_reset.src, state->hw_reset.req_src, + 1 << state->hw_reset.rst_bit, 0); + + } + return ret; +} + +static void mipi_csis_system_enable(struct csi_state *state, int on) +{ + u32 val, mask; + + val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL); + if (on) + val |= MIPI_CSIS_CMN_CTRL_ENABLE; + else + val &= ~MIPI_CSIS_CMN_CTRL_ENABLE; + mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val); + + val = mipi_csis_read(state, MIPI_CSIS_DPHYCTRL); + val &= ~MIPI_CSIS_DPHYCTRL_ENABLE; + if (on) { + mask = (1 << (state->num_lanes + 1)) - 1; + val |= (mask & MIPI_CSIS_DPHYCTRL_ENABLE); + } + mipi_csis_write(state, MIPI_CSIS_DPHYCTRL, val); +} + +/* Called with the state.lock mutex held */ +static void __mipi_csis_set_format(struct csi_state *state) +{ + struct v4l2_mbus_framefmt *mf = &state->format; + u32 val; + + v4l2_dbg(1, debug, &state->mipi_sd, "fmt: %#x, %d x %d\n", + mf->code, mf->width, mf->height); + + /* Color format */ + val = mipi_csis_read(state, MIPI_CSIS_ISPCONFIG_CH0); + val = (val & ~MIPI_CSIS_ISPCFG_FMT_MASK) | state->csis_fmt->fmt_reg; + mipi_csis_write(state, MIPI_CSIS_ISPCONFIG_CH0, val); + + /* Pixel resolution */ + val = mf->width | (mf->height << 16); + mipi_csis_write(state, MIPI_CSIS_ISPRESOL_CH0, val); +} + +static void mipi_csis_set_hsync_settle(struct csi_state *state, int settle) +{ + u32 val = mipi_csis_read(state, MIPI_CSIS_DPHYCTRL); + + val = (val & ~MIPI_CSIS_DPHYCTRL_HSS_MASK) | (settle << 24); + mipi_csis_write(state, MIPI_CSIS_DPHYCTRL, val); +} + +static void mipi_csis_set_params(struct csi_state *state) +{ + u32 val; + + val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL); + val &= ~MIPI_CSIS_CMN_CTRL_LANE_NR_MASK; + val |= (state->num_lanes - 1) << MIPI_CSIS_CMN_CTRL_LANE_NR_OFFSET; + mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val); + + __mipi_csis_set_format(state); + + mipi_csis_set_hsync_settle(state, state->hs_settle); + + val = mipi_csis_read(state, MIPI_CSIS_ISPCONFIG_CH0); + if (state->csis_fmt->data_alignment == 32) + val |= MIPI_CSIS_ISPCFG_ALIGN_32BIT; + else /* Normal output */ + val &= ~MIPI_CSIS_ISPCFG_ALIGN_32BIT; + mipi_csis_write(state, MIPI_CSIS_ISPCONFIG_CH0, val); + + val = (0 << MIPI_CSIS_ISPSYNC_HSYNC_LINTV_OFFSET) | + (0 << MIPI_CSIS_ISPSYNC_VSYNC_SINTV_OFFSET) | + (0 << MIPI_CSIS_ISPSYNC_VSYNC_EINTV_OFFSET); + mipi_csis_write(state, MIPI_CSIS_ISPSYNC_CH0, val); + + val = mipi_csis_read(state, MIPI_CSIS_CLK_CTRL); + val &= ~MIPI_CSIS_CLK_CTRL_WCLK_SRC; + if (state->wclk_ext) + val |= MIPI_CSIS_CLK_CTRL_WCLK_SRC; + val |= MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH0(15); + val &= ~MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MSK; + mipi_csis_write(state, MIPI_CSIS_CLK_CTRL, val); + + mipi_csis_write(state, MIPI_CSIS_DPHYBCTRL_L, 0x1f4); + mipi_csis_write(state, MIPI_CSIS_DPHYBCTRL_H, 0); + + /* Update the shadow register. */ + val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL); + mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val | MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW | + MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW_CTRL); +} + +static void mipi_csis_clk_enable(struct csi_state *state) +{ + clk_prepare_enable(state->mipi_clk); + clk_prepare_enable(state->phy_clk); +} + +static void mipi_csis_clk_disable(struct csi_state *state) +{ + clk_disable_unprepare(state->mipi_clk); + clk_disable_unprepare(state->phy_clk); +} + +static int mipi_csis_clk_get(struct csi_state *state) +{ + struct device *dev = &state->pdev->dev; + int ret = true; + + state->mipi_clk = devm_clk_get(dev, "mipi_clk"); + if (IS_ERR(state->mipi_clk)) { + dev_err(dev, "Could not get mipi csi clock\n"); + return -ENODEV; + } + + state->phy_clk = devm_clk_get(dev, "phy_clk"); + if (IS_ERR(state->phy_clk)) { + dev_err(dev, "Could not get mipi phy clock\n"); + return -ENODEV; + } + + /* Set clock rate */ + if (state->clk_frequency) + ret = clk_set_rate(state->mipi_clk, + state->clk_frequency); + else + dev_WARN(dev, "No clock frequency specified!\n"); + if (ret < 0) { + dev_err(dev, "set rate filed, rate=%d\n", state->clk_frequency); + return -EINVAL; + } + + return ret; +} + +static void dump_regs(struct csi_state *state, const char *label) +{ + struct { + u32 offset; + const char * const name; + } registers[] = { + { 0x00, "CTRL" }, + { 0x04, "DPHYCTRL" }, + { 0x08, "CONFIG" }, + { 0x0c, "DPHYSTS" }, + { 0x10, "INTMSK" }, + { 0x2c, "RESOL" }, + { 0x38, "SDW_CONFIG" }, + }; + u32 i; + + v4l2_info(&state->mipi_sd, "--- %s ---\n", label); + + for (i = 0; i < ARRAY_SIZE(registers); i++) { + u32 cfg = mipi_csis_read(state, registers[i].offset); + v4l2_info(&state->mipi_sd, "%10s: 0x%08x\n", registers[i].name, cfg); + } +} + +static void mipi_csis_start_stream(struct csi_state *state) +{ + mipi_csis_sw_reset(state); + mipi_csis_set_params(state); + mipi_csis_system_enable(state, true); + mipi_csis_enable_interrupts(state, true); +} + +static void mipi_csis_stop_stream(struct csi_state *state) +{ + mipi_csis_enable_interrupts(state, false); + mipi_csis_system_enable(state, false); +} + +static void mipi_csis_clear_counters(struct csi_state *state) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(&state->slock, flags); + for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) + state->events[i].counter = 0; + spin_unlock_irqrestore(&state->slock, flags); +} + +static void mipi_csis_log_counters(struct csi_state *state, bool non_errors) +{ + int i = non_errors ? MIPI_CSIS_NUM_EVENTS : MIPI_CSIS_NUM_EVENTS - 4; + unsigned long flags; + + spin_lock_irqsave(&state->slock, flags); + + for (i--; i >= 0; i--) { + if (state->events[i].counter > 0 || debug) + v4l2_info(&state->mipi_sd, "%s events: %d\n", + state->events[i].name, + state->events[i].counter); + } + spin_unlock_irqrestore(&state->slock, flags); +} + +/* + * V4L2 subdev operations + */ +static int mipi_csis_s_power(struct v4l2_subdev *mipi_sd, int on) +{ + struct csi_state *state = mipi_sd_to_csi_state(mipi_sd); + struct device *dev = &state->pdev->dev; + + v4l2_subdev_call(state->sensor_sd, core, s_power, on); + + if (on) + return pm_runtime_get_sync(dev); + + return pm_runtime_put_sync(dev); +} + +static int mipi_csis_s_stream(struct v4l2_subdev *mipi_sd, int enable) +{ + struct csi_state *state = mipi_sd_to_csi_state(mipi_sd); + int ret = 0; + + v4l2_dbg(1, debug, mipi_sd, "%s: %d, state: 0x%x\n", + __func__, enable, state->flags); + + if (enable) { + mipi_csis_clear_counters(state); + ret = pm_runtime_get_sync(&state->pdev->dev); + if (ret && ret != 1) + return ret; + } + + mutex_lock(&state->lock); + if (enable) { + if (state->flags & ST_SUSPENDED) { + ret = -EBUSY; + goto unlock; + } + mipi_csis_start_stream(state); + state->flags |= ST_STREAMING; + } else { + mipi_csis_stop_stream(state); + state->flags &= ~ST_STREAMING; + if (debug > 0) + mipi_csis_log_counters(state, true); + } +unlock: + mutex_unlock(&state->lock); + if (!enable) + pm_runtime_put(&state->pdev->dev); + + return ret == 1 ? 0 : ret; +} + +static int mipi_csis_enum_mbus_fmt(struct v4l2_subdev *mipi_sd, unsigned int index, + u32 *code) +{ + struct csi_state *state = mipi_sd_to_csi_state(mipi_sd); + struct v4l2_subdev *sensor_sd = state->sensor_sd; + struct csis_pix_format const *csis_fmt; + int ret; + + ret = v4l2_subdev_call(sensor_sd, video, enum_mbus_fmt, index, code); + if (ret < 0) + return -EINVAL; + + csis_fmt = find_csis_format(*code); + if (csis_fmt == NULL) { + dev_err(state->dev, "format not match\n"); + return -EINVAL; + } + + return ret; +} + +static struct csis_pix_format const *mipi_csis_try_format( + struct v4l2_subdev *mipi_sd, struct v4l2_mbus_framefmt *mf) +{ + struct csi_state *state = mipi_sd_to_csi_state(mipi_sd); + struct v4l2_subdev *sensor_sd = state->sensor_sd; + struct csis_pix_format const *csis_fmt; + + csis_fmt = find_csis_format(mf->code); + if (csis_fmt == NULL) + csis_fmt = &mipi_csis_formats[0]; + + v4l2_subdev_call(sensor_sd, video, s_mbus_fmt, mf); + + mf->code = csis_fmt->code; + v4l_bound_align_image(&mf->width, 1, CSIS_MAX_PIX_WIDTH, + csis_fmt->pix_width_alignment, + &mf->height, 1, CSIS_MAX_PIX_HEIGHT, 1, + 0); + + state->format.code = mf->code; + state->format.width = mf->width; + state->format.height = mf->height; + + return csis_fmt; +} + +static int mipi_csis_set_fmt(struct v4l2_subdev *mipi_sd, + struct v4l2_mbus_framefmt *fmt) +{ + struct csi_state *state = mipi_sd_to_csi_state(mipi_sd); + struct csis_pix_format const *csis_fmt; + + csis_fmt = mipi_csis_try_format(mipi_sd, fmt); + if (csis_fmt) { + mutex_lock(&state->lock); + state->csis_fmt = csis_fmt; + mutex_unlock(&state->lock); + } + return 0; +} + +static int mipi_csis_get_fmt(struct v4l2_subdev *mipi_sd, + struct v4l2_mbus_framefmt *fmt) +{ + struct csi_state *state = mipi_sd_to_csi_state(mipi_sd); + struct v4l2_subdev *sensor_sd = state->sensor_sd; + + v4l2_subdev_call(sensor_sd, video, g_mbus_fmt, fmt); + if (!fmt) + return -EINVAL; + + return 0; +} + +static int mipi_csis_s_rx_buffer(struct v4l2_subdev *mipi_sd, void *buf, + unsigned int *size) +{ + struct csi_state *state = mipi_sd_to_csi_state(mipi_sd); + unsigned long flags; + + *size = min_t(unsigned int, *size, MIPI_CSIS_PKTDATA_SIZE); + + spin_lock_irqsave(&state->slock, flags); + state->pkt_buf.data = buf; + state->pkt_buf.len = *size; + spin_unlock_irqrestore(&state->slock, flags); + + return 0; +} + +static int mipi_csis_try_fmt(struct v4l2_subdev *mipi_sd, + struct v4l2_mbus_framefmt *mf) +{ + struct csi_state *state = mipi_sd_to_csi_state(mipi_sd); + struct v4l2_subdev *sensor_sd = state->sensor_sd; + + return v4l2_subdev_call(sensor_sd, video, try_mbus_fmt, mf); +} + +static int mipi_csis_s_parm(struct v4l2_subdev *mipi_sd, struct v4l2_streamparm *a) +{ + struct csi_state *state = mipi_sd_to_csi_state(mipi_sd); + struct v4l2_subdev *sensor_sd = state->sensor_sd; + + return v4l2_subdev_call(sensor_sd, video, s_parm, a); +} + +static int mipi_csis_g_parm(struct v4l2_subdev *mipi_sd, struct v4l2_streamparm *a) +{ + struct csi_state *state = mipi_sd_to_csi_state(mipi_sd); + struct v4l2_subdev *sensor_sd = state->sensor_sd; + + return v4l2_subdev_call(sensor_sd, video, g_parm, a); +} + +static int mipi_csis_enum_framesizes(struct v4l2_subdev *mipi_sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct csi_state *state = mipi_sd_to_csi_state(mipi_sd); + struct v4l2_subdev *sensor_sd = state->sensor_sd; + + return v4l2_subdev_call(sensor_sd, pad, enum_frame_size, NULL, fse); +} + +static int mipi_csis_enum_frameintervals(struct v4l2_subdev *mipi_sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_interval_enum *fie) +{ + struct csi_state *state = mipi_sd_to_csi_state(mipi_sd); + struct v4l2_subdev *sensor_sd = state->sensor_sd; + + return v4l2_subdev_call(sensor_sd, pad, enum_frame_interval, NULL, fie); +} + +static int mipi_csis_log_status(struct v4l2_subdev *mipi_sd) +{ + struct csi_state *state = mipi_sd_to_csi_state(mipi_sd); + + mutex_lock(&state->lock); + mipi_csis_log_counters(state, true); + if (debug && (state->flags & ST_POWERED)) + dump_regs(state, __func__); + mutex_unlock(&state->lock); + return 0; +} + +static struct v4l2_subdev_core_ops mipi_csis_core_ops = { + .s_power = mipi_csis_s_power, + .log_status = mipi_csis_log_status, +}; + +static struct v4l2_subdev_video_ops mipi_csis_video_ops = { + .s_rx_buffer = mipi_csis_s_rx_buffer, + .s_stream = mipi_csis_s_stream, + + .enum_mbus_fmt = mipi_csis_enum_mbus_fmt, + .try_mbus_fmt = mipi_csis_try_fmt, + .g_mbus_fmt = mipi_csis_get_fmt, + .s_mbus_fmt = mipi_csis_set_fmt, + + .s_parm = mipi_csis_s_parm, + .g_parm = mipi_csis_g_parm, +}; + +static const struct v4l2_subdev_pad_ops mipi_csis_pad_ops = { + .enum_frame_size = mipi_csis_enum_framesizes, + .enum_frame_interval = mipi_csis_enum_frameintervals, +}; + +static struct v4l2_subdev_ops mipi_csis_subdev_ops = { + .core = &mipi_csis_core_ops, + .video = &mipi_csis_video_ops, + .pad = &mipi_csis_pad_ops, +}; + +static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id) +{ + struct csi_state *state = dev_id; + struct csis_pktbuf *pktbuf = &state->pkt_buf; + unsigned long flags; + u32 status; + + status = mipi_csis_read(state, MIPI_CSIS_INTSRC); + + spin_lock_irqsave(&state->slock, flags); + + if ((status & MIPI_CSIS_INTSRC_NON_IMAGE_DATA) && pktbuf->data) { + u32 offset; + + if (status & MIPI_CSIS_INTSRC_EVEN) + offset = MIPI_CSIS_PKTDATA_EVEN; + else + offset = MIPI_CSIS_PKTDATA_ODD; + + memcpy(pktbuf->data, state->regs + offset, pktbuf->len); + pktbuf->data = NULL; + rmb(); + } + + /* Update the event/error counters */ + if ((status & MIPI_CSIS_INTSRC_ERRORS) || debug) { + int i; + for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) { + if (!(status & state->events[i].mask)) + continue; + state->events[i].counter++; + v4l2_dbg(2, debug, &state->mipi_sd, "%s: %d\n", + state->events[i].name, + state->events[i].counter); + } + v4l2_dbg(2, debug, &state->mipi_sd, "status: %08x\n", status); + } + spin_unlock_irqrestore(&state->slock, flags); + + mipi_csis_write(state, MIPI_CSIS_INTSRC, status); + return IRQ_HANDLED; +} + +static int subdev_notifier_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) +{ + struct csi_state *state = notifier_to_mipi_dev(notifier); + + /* Find platform data for this sensor subdev */ + if (state->asd.match.of.node == subdev->dev->of_node) + state->sensor_sd = subdev; + + if (subdev == NULL) + return -EINVAL; + + v4l2_info(&state->v4l2_dev, "Registered sensor subdevice: %s\n", + subdev->name); + + return 0; +} + +static int mipi_csis_parse_dt(struct platform_device *pdev, + struct csi_state *state) +{ + struct device_node *node = pdev->dev.of_node; + + if (of_property_read_u32(node, "clock-frequency", + &state->clk_frequency)) + state->clk_frequency = DEFAULT_SCLK_CSIS_FREQ; + if (of_property_read_u32(node, "bus-width", + &state->max_num_lanes)) + return -EINVAL; + + node = of_graph_get_next_endpoint(node, NULL); + if (!node) { + dev_err(&pdev->dev, "No port node at %s\n", + pdev->dev.of_node->full_name); + return -EINVAL; + } + + /* Get MIPI CSI-2 bus configration from the endpoint node. */ + of_property_read_u32(node, "csis-hs-settle", + &state->hs_settle); + state->wclk_ext = of_property_read_bool(node, + "csis-wclk"); + + of_property_read_u32(node, "data-lanes", + &state->num_lanes); + of_node_put(node); + + return 0; +} + +static int mipi_csis_pm_resume(struct device *dev, bool runtime); +static const struct of_device_id mipi_csis_of_match[]; + +/* register parent dev */ +static int mipi_csis_subdev_host(struct csi_state *state) +{ + struct device_node *parent = state->dev->of_node; + struct device_node *node, *port, *rem; + int ret; + + /* Attach sensors linked to csi receivers */ + for_each_available_child_of_node(parent, node) { + if (of_node_cmp(node->name, "port")) + continue; + + /* The csi node can have only port subnode. */ + port = of_get_next_child(node, NULL); + if (!port) + continue; + rem = of_graph_get_remote_port_parent(port); + of_node_put(port); + if (rem == NULL) { + v4l2_info(&state->v4l2_dev, + "Remote device at %s not found\n", + port->full_name); + return -1; + } + + state->asd.match_type = V4L2_ASYNC_MATCH_OF; + state->asd.match.of.node = rem; + state->async_subdevs[0] = &state->asd; + + of_node_put(rem); + break; + } + + state->subdev_notifier.subdevs = state->async_subdevs; + state->subdev_notifier.num_subdevs = 1; + state->subdev_notifier.bound = subdev_notifier_bound; + + ret = v4l2_async_notifier_register(&state->v4l2_dev, + &state->subdev_notifier); + if (ret) + dev_err(state->dev, + "Error register async notifier regoster\n"); + + return ret; +} + +/* init subdev */ +static int mipi_csis_subdev_init(struct v4l2_subdev *mipi_sd, + struct platform_device *pdev, + const struct v4l2_subdev_ops *ops) +{ + struct csi_state *state = platform_get_drvdata(pdev); + int ret = 0; + + v4l2_subdev_init(mipi_sd, ops); + mipi_sd->owner = THIS_MODULE; + snprintf(mipi_sd->name, sizeof(mipi_sd->name), "%s.%d", + CSIS_SUBDEV_NAME, state->index); + mipi_sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + mipi_sd->dev = &pdev->dev; + + state->csis_fmt = &mipi_csis_formats[0]; + state->format.code = mipi_csis_formats[0].code; + state->format.width = MIPI_CSIS_DEF_PIX_WIDTH; + state->format.height = MIPI_CSIS_DEF_PIX_HEIGHT; + + /* This allows to retrieve the platform device id by the host driver */ + v4l2_set_subdevdata(mipi_sd, pdev); + + ret = v4l2_async_register_subdev(mipi_sd); + if (ret < 0) + dev_err(&pdev->dev, "%s--Async register faialed, ret=%d\n", __func__, ret); + + return ret; +} + +static int mipi_csis_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct v4l2_subdev *mipi_sd; + struct resource *mem_res; + struct csi_state *state; + int ret = -ENOMEM; + + state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + mutex_init(&state->lock); + spin_lock_init(&state->slock); + + state->pdev = pdev; + mipi_sd = &state->mipi_sd; + state->dev = dev; + + ret = mipi_csis_parse_dt(pdev, state); + if (ret < 0) + return ret; + + if (state->num_lanes == 0 || state->num_lanes > state->max_num_lanes) { + dev_err(dev, "Unsupported number of data lanes: %d (max. %d)\n", + state->num_lanes, state->max_num_lanes); + return -EINVAL; + } + + mipi_csis_phy_init(state); + mipi_csis_phy_reset(state); + + mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + state->regs = devm_ioremap_resource(dev, mem_res); + if (IS_ERR(state->regs)) + return PTR_ERR(state->regs); + + state->irq = platform_get_irq(pdev, 0); + if (state->irq < 0) { + dev_err(dev, "Failed to get irq\n"); + return state->irq; + } + + ret = mipi_csis_clk_get(state); + if (ret < 0) + return ret; + + mipi_csis_clk_enable(state); + + ret = devm_request_irq(dev, state->irq, mipi_csis_irq_handler, + 0, dev_name(dev), state); + if (ret) { + dev_err(dev, "Interrupt request failed\n"); + goto e_clkdis; + } + + /* First register a v4l2 device */ + ret = v4l2_device_register(dev, &state->v4l2_dev); + if (ret) { + v4l2_err(dev->driver, + "Unable to register v4l2 device.\n"); + goto e_clkdis; + } + v4l2_info(&state->v4l2_dev, "mipi csi v4l2 device registered\n"); + + /* .. and a pointer to the subdev. */ + platform_set_drvdata(pdev, state); + + ret = mipi_csis_subdev_init(&state->mipi_sd, pdev, &mipi_csis_subdev_ops); + if (ret < 0) + goto e_sd_mipi; + + memcpy(state->events, mipi_csis_events, sizeof(state->events)); + + /* subdev host register */ + ret = mipi_csis_subdev_host(state); + if (ret < 0) + goto e_sd_host; + + pm_runtime_enable(dev); + if (!pm_runtime_enabled(dev)) { + ret = mipi_csis_pm_resume(dev, true); + if (ret < 0) + goto e_sd_host; + } + + dev_info(&pdev->dev, "lanes: %d, hs_settle: %d, wclk: %d, freq: %u\n", + state->num_lanes, state->hs_settle, state->wclk_ext, + state->clk_frequency); + return 0; + +e_sd_host: + v4l2_async_notifier_unregister(&state->subdev_notifier); + v4l2_device_unregister(&state->v4l2_dev); +e_sd_mipi: + v4l2_async_unregister_subdev(&state->mipi_sd); +e_clkdis: + mipi_csis_clk_disable(state); + return ret; +} + +static int mipi_csis_pm_suspend(struct device *dev, bool runtime) +{ + struct platform_device *pdev = to_platform_device(dev); + struct csi_state *state = platform_get_drvdata(pdev); + struct v4l2_subdev *mipi_sd = &state->mipi_sd; + int ret = 0; + + v4l2_dbg(1, debug, mipi_sd, "%s: flags: 0x%x\n", + __func__, state->flags); + + mutex_lock(&state->lock); + if (state->flags & ST_POWERED) { + mipi_csis_stop_stream(state); + ret = regulator_disable(state->mipi_phy_regulator); + if (ret) + goto unlock; + mipi_csis_clk_disable(state); + state->flags &= ~ST_POWERED; + if (!runtime) + state->flags |= ST_SUSPENDED; + } + unlock: + mutex_unlock(&state->lock); + return ret ? -EAGAIN : 0; +} + +static int mipi_csis_pm_resume(struct device *dev, bool runtime) +{ + struct platform_device *pdev = to_platform_device(dev); + struct csi_state *state = platform_get_drvdata(pdev); + struct v4l2_subdev *mipi_sd = &state->mipi_sd; + int ret = 0; + + v4l2_dbg(1, debug, mipi_sd, "%s: flags: 0x%x\n", + __func__, state->flags); + + mutex_lock(&state->lock); + if (!runtime && !(state->flags & ST_SUSPENDED)) + goto unlock; + + if (!(state->flags & ST_POWERED)) { + ret = regulator_enable(state->mipi_phy_regulator); + if (!ret) { + state->flags |= ST_POWERED; + } else { + goto unlock; + } + mipi_csis_clk_enable(state); + } + if (state->flags & ST_STREAMING) + mipi_csis_start_stream(state); + + state->flags &= ~ST_SUSPENDED; + unlock: + mutex_unlock(&state->lock); + return ret ? -EAGAIN : 0; +} + +#ifdef CONFIG_PM_SLEEP +static int mipi_csis_suspend(struct device *dev) +{ + return mipi_csis_pm_suspend(dev, false); +} + +static int mipi_csis_resume(struct device *dev) +{ + return mipi_csis_pm_resume(dev, false); +} +#endif + +static int mipi_csis_runtime_suspend(struct device *dev) +{ + return mipi_csis_pm_suspend(dev, true); +} + +static int mipi_csis_runtime_resume(struct device *dev) +{ + return mipi_csis_pm_resume(dev, true); +} + +static int mipi_csis_remove(struct platform_device *pdev) +{ + struct csi_state *state = platform_get_drvdata(pdev); + + v4l2_async_unregister_subdev(&state->mipi_sd); + v4l2_async_notifier_unregister(&state->subdev_notifier); + v4l2_device_unregister(&state->v4l2_dev); + + pm_runtime_disable(&pdev->dev); + mipi_csis_pm_suspend(&pdev->dev, true); + mipi_csis_clk_disable(state); + pm_runtime_set_suspended(&pdev->dev); + + return 0; +} + +static const struct dev_pm_ops mipi_csis_pm_ops = { + SET_RUNTIME_PM_OPS(mipi_csis_runtime_suspend, mipi_csis_runtime_resume, + NULL) + SET_SYSTEM_SLEEP_PM_OPS(mipi_csis_suspend, mipi_csis_resume) +}; + +static const struct of_device_id mipi_csis_of_match[] = { + { .compatible = "fsl,imx7d-mipi-csi",}, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, mipi_csis_of_match); + +static struct platform_driver mipi_csis_driver = { + .probe = mipi_csis_probe, + .remove = mipi_csis_remove, + .driver = { + .of_match_table = mipi_csis_of_match, + .name = CSIS_DRIVER_NAME, + .owner = THIS_MODULE, + .pm = &mipi_csis_pm_ops, + }, +}; + +module_platform_driver(mipi_csis_driver); + +MODULE_DESCRIPTION("Freescale MIPI-CSI2 receiver driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/mxc/subdev/mxc_vadc.c b/drivers/media/platform/mxc/subdev/mxc_vadc.c new file mode 100644 index 000000000000..385f186ab9ba --- /dev/null +++ b/drivers/media/platform/mxc/subdev/mxc_vadc.c @@ -0,0 +1,817 @@ +/* + * Copyright (C) 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mxc_vadc.h" + +/* Resource names for the VADC driver. */ +#define VAFE_REGS_ADDR_RES_NAME "vadc-vafe" +#define VDEC_REGS_ADDR_RES_NAME "vadc-vdec" + +#define reg32_write(addr, val) __raw_writel(val, addr) +#define reg32_read(addr) __raw_readl(addr) +#define reg32setbit(addr, bitpos) \ + reg32_write((addr), (reg32_read((addr)) | (1<<(bitpos)))) + +#define reg32clrbit(addr, bitpos) \ + reg32_write((addr), (reg32_read((addr)) & (0xFFFFFFFF ^ (1<<(bitpos))))) + +#define GPC_CNTR 0x00 +#define IMX6SX_GPC_CNTR_VADC_ANALOG_OFF_MASK BIT(17) +#define IMX6SX_GPC_CNTR_VADC_POWER_DOWN_MASK BIT(18) + +void __iomem *vafe_regbase; +void __iomem *vdec_regbase; + + +/* List of input video formats supported. The video formats is corresponding + * with v4l2 id in video_fmt + */ +enum video_fmt_idx { + VADC_NTSC = 0, /* Locked on (M) NTSC video signal. */ + VADC_PAL, /* (B, G, H, I, N)PAL video signal. */ +}; + +/* Number of video standards supported (including 'not locked' signal). */ +#define VADC_STD_MAX (VADC_PAL + 1) + +/* Video format structure. */ +struct video_fmt{ + v4l2_std_id v4l2_std; /* Video for linux ID. */ + char name[16]; /* Name (e.g., "NTSC", "PAL", etc.) */ + u16 raw_width; /* Raw width. */ + u16 raw_height; /* Raw height. */ + u16 active_width; /* Active width. */ + u16 active_height; /* Active height. */ + u16 framerates; +}; + +/* + * Maintains the information on the current state of the sensor. + */ +struct vadc_state { + struct v4l2_device v4l2_dev; + struct v4l2_subdev sd; + struct video_fmt *fmt; + + struct clk *vadc_clk; + struct clk *csi_clk; + struct regmap *gpr; + void __iomem *gpc_reg; + + u32 vadc_in; + u32 csi_id; +}; + +static int vadc_querystd(struct v4l2_subdev *sd, v4l2_std_id *std); + +/* Description of video formats supported. + * + * PAL: raw=720x625, active=720x576. + * NTSC: raw=720x525, active=720x480. + */ +static struct video_fmt video_fmts[] = { + /* NTSC */ + { + .v4l2_std = V4L2_STD_NTSC, + .name = "NTSC", + .raw_width = 720, + .raw_height = 525, + .active_width = 720, + .active_height = 480, + .framerates = 30, + }, + /* (B, G, H, I, N) PAL */ + { + .v4l2_std = V4L2_STD_PAL, + .name = "PAL", + .raw_width = 720, + .raw_height = 625, + .active_width = 720, + .active_height = 576, + .framerates = 25, + }, +}; + +static void afe_voltage_clampingmode(void) +{ + reg32_write(AFE_CLAMP, 0x07); + reg32_write(AFE_CLMPAMP, 0x60); + reg32_write(AFE_CLMPDAT, 0xF0); +} + +static void afe_alwayson_clampingmode(void) +{ + reg32_write(AFE_CLAMP, 0x15); + reg32_write(AFE_CLMPDAT, 0x08); + reg32_write(AFE_CLMPAMP, 0x00); +} + +static void afe_init(void) +{ + pr_debug("%s\n", __func__); + + reg32_write(AFE_PDBUF, 0x1f); + reg32_write(AFE_PDADC, 0x0f); + reg32_write(AFE_PDSARH, 0x01); + reg32_write(AFE_PDSARL, 0xff); + reg32_write(AFE_PDADCRFH, 0x01); + reg32_write(AFE_PDADCRFL, 0xff); + reg32_write(AFE_ICTRL, 0x3a); + reg32_write(AFE_ICTLSTG, 0x1e); + + reg32_write(AFE_RCTRLSTG, 0x1e); + reg32_write(AFE_INPBUF, 0x035); + reg32_write(AFE_INPFLT, 0x02); + reg32_write(AFE_ADCDGN, 0x40); + reg32_write(AFE_TSTSEL, 0x10); + + reg32_write(AFE_ACCTST, 0x07); + + reg32_write(AFE_BGREG, 0x08); + + reg32_write(AFE_ADCGN, 0x09); + + /* set current controlled clamping + * always on, low current */ + reg32_write(AFE_CLAMP, 0x11); + reg32_write(AFE_CLMPAMP, 0x08); +} + +static void vdec_mode_timing_init(int std) +{ + if (std == V4L2_STD_NTSC) { + /* NTSC 720x480 */ + reg32_write(VDEC_HACTS, 0x66); + reg32_write(VDEC_HACTE, 0x24); + + reg32_write(VDEC_VACTS, 0x29); + reg32_write(VDEC_VACTE, 0x04); + + /* set V Position */ + reg32_write(VDEC_VRTPOS, 0x2); + } else if (std == V4L2_STD_PAL) { + /* PAL 720x576 */ + reg32_write(VDEC_HACTS, 0x66); + reg32_write(VDEC_HACTE, 0x24); + + reg32_write(VDEC_VACTS, 0x29); + reg32_write(VDEC_VACTE, 0x04); + + /* set V Position */ + reg32_write(VDEC_VRTPOS, 0x6); + } else + pr_debug("Error not support video mode\n"); + + /* set H Position */ + reg32_write(VDEC_HZPOS, 0x60); + + /* set H ignore start */ + reg32_write(VDEC_HSIGS, 0xf8); + + /* set H ignore end */ + reg32_write(VDEC_HSIGE, 0x18); +} + +/* +* vdec_init() +* Initialises the VDEC registers +* Returns: nothing +*/ +static void vdec_init(struct vadc_state *vadc) +{ + v4l2_std_id std; + + pr_debug("%s\n", __func__); + + /* Get work mode PAL or NTSC */ + vadc_querystd(&vadc->sd, &std); + + vdec_mode_timing_init(std); + + /* vcr detect threshold high, automatic detections */ + reg32_write(VDEC_VSCON2, 0); + + reg32_write(VDEC_BASE + 0x110, 0x01); + + /* set the noramp mode on the Hloop PLL. */ + reg32_write(VDEC_BASE+(0x14*4), 0x10); + + /* set the YC relative delay.*/ + reg32_write(VDEC_YCDEL, 0x90); + + /* setup the Hpll */ + reg32_write(VDEC_BASE+(0x13*4), 0x13); + + /* setup the 2d comb */ + /* set the gain of the Hdetail output to 3 + * set the notch alpha gain to 1 */ + reg32_write(VDEC_CFC2, 0x34); + + /* setup various 2d comb bits.*/ + reg32_write(VDEC_BASE+(0x02*4), 0x01); + reg32_write(VDEC_BASE+(0x03*4), 0x18); + reg32_write(VDEC_BASE+(0x04*4), 0x34); + + /* set the start of the burst gate */ + reg32_write(VDEC_BRSTGT, 0x30); + + /* set 1f motion gain */ + reg32_write(VDEC_BASE+(0x0f*4), 0x20); + + /* set the 1F chroma motion detector thresh + * for colour reverse detection */ + reg32_write(VDEC_THSH1, 0x02); + reg32_write(VDEC_BASE+(0x4a*4), 0x20); + reg32_write(VDEC_BASE+(0x4b*4), 0x08); + + reg32_write(VDEC_BASE+(0x4c*4), 0x08); + + /* set the threshold for the narrow/wide adaptive chroma BW */ + reg32_write(VDEC_BASE+(0x20*4), 0x20); + + /* turn up the colour with the new colour gain reg */ + /* hue: */ + reg32_write(VDEC_HUE, 0x00); + + /* cbgain: 22 B4 */ + reg32_write(VDEC_CBGN, 0xb4); + /* cr gain 80 */ + reg32_write(VDEC_CRGN, 0x80); + /* luma gain (contrast) */ + reg32_write(VDEC_CNTR, 0x80); + + /* setup the signed black level register, brightness */ + reg32_write(VDEC_BRT, 0x00); + + /* filter the standard detection + * enable the comb for the ntsc443 */ + reg32_write(VDEC_STDDBG, 0x20); + + /* setup chroma kill thresh for no chroma */ + reg32_write(VDEC_CHBTH, 0x0); + + /* set chroma loop to wider BW + * no set it to normal BW. i fixed the bw problem.*/ + reg32_write(VDEC_YCDEL, 0x00); + + /* set the compensation in the chroma loop for the Hloop + * set the ratio for the nonarithmetic 3d comb modes.*/ + reg32_write(VDEC_BASE + (0x1d*4), 0x90); + + /* set the threshold for the nonarithmetic mode for the 2d comb + * the higher the value the more Fc Fh offset + * we will tolerate before turning off the comb. */ + reg32_write(VDEC_BASE + (0x33*4), 0xa0); + + /* setup the bluescreen output colour */ + reg32_write(VDEC_BASE + (0x3d*4), 35); + reg32_write(VDEC_BLSCRCR, 114); + reg32_write(VDEC_BLSCRCB, 212); + + /* disable the active blanking */ + reg32_write(VDEC_BASE + (0x15*4), 0x02); + + /* setup the luma agc for automatic gain. */ + reg32_write(VDEC_LMAGC2, 0x5e); + reg32_write(VDEC_LMAGC1, 0x81); + + /* setup chroma agc */ + reg32_write(VDEC_CHAGC2, 0xa0); + reg32_write(VDEC_CHAGC1, 0x01); + + /* setup the MV thresh lower nibble + * setup the sync top cap, upper nibble */ + reg32_write(VDEC_BASE + (0x3a*4), 0x80); + reg32_write(VDEC_SHPIMP, 0x00); + + /* setup the vsync block */ + reg32_write(VDEC_VSCON1, 0x87); + + /* set the nosignal threshold + * set the vsync threshold */ + reg32_write(VDEC_VSSGTH, 0x35); + + /* set length for min hphase filter + * (or saturate limit if saturate is chosen) */ + reg32_write(VDEC_BASE + (0x45*4), 0x40); + + /* enable the internal resampler, + * select min filter not saturate for + * hphase noise filter for vcr detect. + * enable vcr pause mode different field lengths */ + reg32_write(VDEC_BASE + (0x46*4), 0x90); + + /* disable VCR detection, lock to the Hsync rather than the Vsync */ + reg32_write(VDEC_VSCON2, 0x04); + + /* set tiplevel goal for dc clamp. */ + reg32_write(VDEC_BASE + (0x3c*4), 0xB0); + + /* override SECAM detection and force SECAM off */ + reg32_write(VDEC_BASE + (0x2f*4), 0x20); + + /* Set r3d_hardblend in 3D control2 reg */ + reg32_write(VDEC_BASE + (0x0c*4), 0x04); +} + +/* set Input selector & input pull-downs */ +static void vadc_s_routing(int vadc_in) +{ + switch (vadc_in) { + case 0: + reg32_write(AFE_INPFLT, 0x02); + reg32_write(AFE_OFFDRV, 0x00); + reg32_write(AFE_INPCONFIG, 0x1e); + break; + case 1: + reg32_write(AFE_INPFLT, 0x02); + reg32_write(AFE_OFFDRV, 0x00); + reg32_write(AFE_INPCONFIG, 0x2d); + break; + case 2: + reg32_write(AFE_INPFLT, 0x02); + reg32_write(AFE_OFFDRV, 0x00); + reg32_write(AFE_INPCONFIG, 0x4b); + break; + case 3: + reg32_write(AFE_INPFLT, 0x02); + reg32_write(AFE_OFFDRV, 0x00); + reg32_write(AFE_INPCONFIG, 0x87); + break; + default: + pr_debug("error video input %d\n", vadc_in); + } +} + +static void vadc_power_up(struct vadc_state *state) +{ + /* Power on vadc analog */ + reg32clrbit(state->gpc_reg + GPC_CNTR, 17); + + /* Power down vadc ext power */ + reg32clrbit(state->gpc_reg + GPC_CNTR, 18); + + /* software reset afe */ + regmap_update_bits(state->gpr, IOMUXC_GPR1, + IMX6SX_GPR1_VADC_SW_RST_MASK, + IMX6SX_GPR1_VADC_SW_RST_RESET); + + msleep(10); + + /* clock config for vadc */ + reg32_write(VDEC_BASE + 0x320, 0xe3); + reg32_write(VDEC_BASE + 0x324, 0x38); + reg32_write(VDEC_BASE + 0x328, 0x8e); + reg32_write(VDEC_BASE + 0x32c, 0x23); + + /* Release reset bit */ + regmap_update_bits(state->gpr, IOMUXC_GPR1, + IMX6SX_GPR1_VADC_SW_RST_MASK, + IMX6SX_GPR1_VADC_SW_RST_RELEASE); + + /* Power on vadc ext power */ + reg32setbit(state->gpc_reg + GPC_CNTR, 18); +} + +static void vadc_power_down(struct vadc_state *state) +{ + /* Power down vadc analog */ + reg32setbit(state->gpc_reg + GPC_CNTR, 17); + + /* Power down vadc ext power */ + reg32clrbit(state->gpc_reg + GPC_CNTR, 18); + +} +static void vadc_init(struct vadc_state *vadc) +{ + pr_debug("%s\n", __func__); + + vadc_power_up(vadc); + + afe_init(); + + /* select Video Input 0-3 */ + vadc_s_routing(vadc->vadc_in); + + afe_voltage_clampingmode(); + + vdec_init(vadc); + + /* + * current control loop will move sinewave input off below + * the bottom of the signal range visible + * when the testbus is viewed as magnitude, + * so have to break before this point while capturing ENOB data: + */ + afe_alwayson_clampingmode(); +} + +static inline struct vadc_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct vadc_state, sd); +} + +static int vadc_g_std(struct v4l2_subdev *sd, v4l2_std_id *std) +{ + struct vadc_state *state = to_state(sd); + + *std = state->fmt->v4l2_std; + return 0; +} + +/*! + * Return attributes of current video standard. + * Since this device autodetects the current standard, this function also + * sets the values that need to be changed if the standard changes. + * There is no set std equivalent function. + * + * @return None. + */ +static int vadc_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) +{ + struct vadc_state *state = to_state(sd); + int mod; + int idx; + int i; + + /* Read auto mode detected result */ + printk(KERN_INFO"wait vadc auto detect video mode....\n"); + for (i = 0; i < 10; i++) { + msleep(200); + mod = reg32_read(VDEC_VIDMOD); + /* Check video signal states */ + if ((mod & VDEC_VIDMOD_SIGNAL_MASK) + == VDEC_VIDMOD_SIGNAL_DETECT) + break; + } + if (i == 10) + printk(KERN_INFO"Timeout detect video signal mod=0x%x\n", mod); + + if ((mod & VDEC_VIDMOD_PAL_MASK) || (mod & VDEC_VIDMOD_M625_MASK)) + idx = VADC_PAL; + else + idx = VADC_NTSC; + + *std = video_fmts[idx].v4l2_std; + state->fmt = &video_fmts[idx]; + + printk(KERN_INFO"video mode %s\n", video_fmts[idx].name); + return 0; +} + +static int vadc_enum_mbus_fmt(struct v4l2_subdev *sd, + unsigned index, u32 *code) +{ + /* support only one format */ + if (index >= 1) + return -EINVAL; + + *code = MEDIA_BUS_FMT_AYUV8_1X32; + return 0; +} + +static int vadc_mbus_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *fmt) +{ + struct vadc_state *state = to_state(sd); + + fmt->code = MEDIA_BUS_FMT_AYUV8_1X32; + fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; + fmt->field = V4L2_FIELD_INTERLACED; + fmt->width = 720; + fmt->height = state->fmt->v4l2_std & V4L2_STD_NTSC ? 480 : 576; + + return 0; +} + +static int vadc_enum_framesizes(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct vadc_state *state = to_state(sd); + if (fse->index >= 1) + return -EINVAL; + + fse->min_width = state->fmt->active_width; + fse->max_width = state->fmt->active_width; + fse->min_height = state->fmt->active_height; + fse->max_height = state->fmt->active_height; + + return 0; +} +static int vadc_enum_frameintervals(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_interval_enum *fie) +{ + struct vadc_state *state = to_state(sd); + + if (fie->index < 0 || fie->index >= 1) + return -EINVAL; + + fie->interval.numerator = 1; + + fie->interval.denominator = state->fmt->framerates; + + return 0; +} + +static int vadc_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +{ + struct vadc_state *state = to_state(sd); + + if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (parms->parm.capture.timeperframe.denominator + != state->fmt->framerates) + parms->parm.capture.timeperframe.denominator + = state->fmt->framerates; + + return 0; +} + +static const struct v4l2_subdev_video_ops vadc_video_ops = { + .querystd = vadc_querystd, + .enum_mbus_fmt = vadc_enum_mbus_fmt, + .try_mbus_fmt = vadc_mbus_fmt, + .g_mbus_fmt = vadc_mbus_fmt, + .s_mbus_fmt = vadc_mbus_fmt, + .s_parm = vadc_s_parm, + .g_std = vadc_g_std, +}; + +static const struct v4l2_subdev_pad_ops vadc_pad_ops = { + .enum_frame_size = vadc_enum_framesizes, + .enum_frame_interval = vadc_enum_frameintervals, +}; + +static const struct v4l2_subdev_ops vadc_ops = { + .video = &vadc_video_ops, + .pad = &vadc_pad_ops, +}; + +static const struct of_device_id fsl_vadc_dt_ids[] = { + { .compatible = "fsl,imx6sx-vadc", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, fsl_vadc_dt_ids); + +static int vadc_of_init(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *gpc_np; + struct vadc_state *state = platform_get_drvdata(pdev); + int csi_id; + int ret; + + /* Get csi_id to setting vadc to csi mux in gpr */ + ret = of_property_read_u32(np, "csi_id", &csi_id); + if (ret) { + dev_err(&pdev->dev, "failed to read of property csi_id\n"); + return ret; + } + + state->csi_id = csi_id; + + /* remap GPR register */ + state->gpr = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "gpr"); + if (IS_ERR(state->gpr)) { + dev_dbg(&pdev->dev, "can not get gpr\n"); + return -ENOMEM; + } + + /* Configuration vadc-to-csi 0 or 1 */ + if (csi_id) { + regmap_update_bits(state->gpr, IOMUXC_GPR5, + IMX6SX_GPR5_CSI2_MUX_CTRL_MASK, + IMX6SX_GPR5_CSI2_MUX_CTRL_CVD); + } else { + regmap_update_bits(state->gpr, IOMUXC_GPR5, + IMX6SX_GPR5_CSI1_MUX_CTRL_MASK, + IMX6SX_GPR5_CSI1_MUX_CTRL_CVD); + } + + /* Get default vadc_in number */ + ret = of_property_read_u32(np, "vadc_in", &state->vadc_in); + if (ret) { + dev_err(&pdev->dev, "failed to read of property vadc_in\n"); + return ret; + } + + /* map GPC register */ + gpc_np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpc"); + state->gpc_reg = of_iomap(gpc_np, 0); + if (!state->gpc_reg) { + dev_err(&pdev->dev, "ioremap failed with gpc base\n"); + goto error; + } + + return ret; + +error: + iounmap(state->gpc_reg); + return ret; +} + +static void vadc_v4l2_subdev_init(struct v4l2_subdev *sd, + struct platform_device *pdev, + const struct v4l2_subdev_ops *ops) +{ + struct vadc_state *state = platform_get_drvdata(pdev); + int ret = 0; + + v4l2_subdev_init(sd, ops); + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->owner = pdev->dev.driver->owner; + sd->dev = &pdev->dev; + + /* initialize name */ + snprintf(sd->name, sizeof(sd->name), "%s", + pdev->dev.driver->name); + + v4l2_set_subdevdata(sd, state); + + ret = v4l2_async_register_subdev(sd); + if (ret < 0) + dev_err(&pdev->dev, "%s--Async register faialed, ret=%d\n", __func__, ret); +} + +static int vadc_probe(struct platform_device *pdev) +{ + struct vadc_state *state; + struct v4l2_subdev *sd; + struct resource *res; + int ret = 0; + + state = devm_kzalloc(&pdev->dev, sizeof(struct vadc_state), GFP_KERNEL); + if (!state) { + dev_err(&pdev->dev, "Cannot allocate device data\n"); + return -ENOMEM; + } + + /* Set initial values for the sensor struct. */ + state->fmt = &video_fmts[VADC_NTSC]; + + sd = &state->sd; + + /* map vafe address */ + res = platform_get_resource_byname(pdev, + IORESOURCE_MEM, VAFE_REGS_ADDR_RES_NAME); + if (!res) { + dev_err(&pdev->dev, "No vafe base address found.\n"); + return -ENOMEM; + } + vafe_regbase = devm_ioremap_resource(&pdev->dev, res); + if (!vafe_regbase) { + dev_err(&pdev->dev, "ioremap failed with vafe base\n"); + return -ENOMEM; + } + + /* map vdec address */ + res = platform_get_resource_byname(pdev, + IORESOURCE_MEM, VDEC_REGS_ADDR_RES_NAME); + if (!res) { + dev_err(&pdev->dev, "No vdec base address found.\n"); + return -ENODEV; + } + vdec_regbase = devm_ioremap_resource(&pdev->dev, res); + if (!vdec_regbase) { + dev_err(&pdev->dev, "ioremap failed with vdec base\n"); + return -ENOMEM; + } + + /* Get clock */ + state->vadc_clk = devm_clk_get(&pdev->dev, "vadc"); + if (IS_ERR(state->vadc_clk)) { + ret = PTR_ERR(state->vadc_clk); + return ret; + } + + state->csi_clk = devm_clk_get(&pdev->dev, "csi"); + if (IS_ERR(state->csi_clk)) { + ret = PTR_ERR(state->csi_clk); + return ret; + } + + /* clock */ + clk_prepare_enable(state->csi_clk); + clk_prepare_enable(state->vadc_clk); + + platform_set_drvdata(pdev, state); + + vadc_v4l2_subdev_init(sd, pdev, &vadc_ops); + + pm_runtime_enable(&pdev->dev); + + pm_runtime_get_sync(&pdev->dev); + /* Init VADC */ + ret = vadc_of_init(pdev); + if (ret < 0) + goto err; + vadc_init(state); + + pr_info("vadc driver loaded\n"); + + return 0; +err: + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + v4l2_async_unregister_subdev(&state->sd); + clk_disable_unprepare(state->csi_clk); + clk_disable_unprepare(state->vadc_clk); + return ret; +} + +static int vadc_remove(struct platform_device *pdev) +{ + struct vadc_state *state = platform_get_drvdata(pdev); + + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + v4l2_async_unregister_subdev(&state->sd); + clk_disable_unprepare(state->csi_clk); + clk_disable_unprepare(state->vadc_clk); + + vadc_power_down(state); + return true; +} + +static int vadc_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct vadc_state *state = platform_get_drvdata(pdev); + + clk_disable(state->csi_clk); + clk_disable(state->vadc_clk); + + vadc_power_down(state); + + return 0; +} + +static int vadc_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct vadc_state *state = platform_get_drvdata(pdev); + + clk_enable(state->csi_clk); + clk_enable(state->vadc_clk); + + vadc_init(state); + return 0; +} + +static const struct dev_pm_ops vadc_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(vadc_suspend, vadc_resume) +}; + +static struct platform_driver vadc_driver = { + .driver = { + .name = "fsl_vadc", + .of_match_table = of_match_ptr(fsl_vadc_dt_ids), + .pm = &vadc_pm_ops, + }, + .probe = vadc_probe, + .remove = vadc_remove, +}; + +module_platform_driver(vadc_driver); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("fsl VADC/VDEC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/mxc/subdev/mxc_vadc.h b/drivers/media/platform/mxc/subdev/mxc_vadc.h new file mode 100644 index 000000000000..d5c1389cbc58 --- /dev/null +++ b/drivers/media/platform/mxc/subdev/mxc_vadc.h @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2011-2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef MXC_VDEC_H +#define MXC_VDEC_H + +/*** define base address ***/ +#define VDEC_BASE vdec_regbase +#define AFE_BASE vafe_regbase + +/* AFE - Register offsets */ +#define AFE_BLOCK_ID_OFFSET 0x00000000 +#define AFE_PDBUF_OFFSET 0x00000004 +#define AFE_SWRST_OFFSET 0x00000008 +#define AFE_TSTSEL_OFFSET 0x0000000c +#define AFE_TSTMSC_OFFSET 0x00000010 +#define AFE_ENPADIO_OFFSET 0x00000014 +#define AFE_BGREG_OFFSET 0x00000018 +#define AFE_ACCESSAR_ID_OFFSET 0x00000400 +#define AFE_PDADC_OFFSET 0x00000404 +#define AFE_PDSARH_OFFSET 0x00000408 +#define AFE_PDSARL_OFFSET 0x0000040C +#define AFE_PDADCRFH_OFFSET 0x00000410 +#define AFE_PDADCRFL_OFFSET 0x00000414 +#define AFE_ACCTST_OFFSET 0x00000418 +#define AFE_ADCGN_OFFSET 0x0000041C +#define AFE_ICTRL_OFFSET 0x00000420 +#define AFE_ICTLSTG_OFFSET 0x00000424 +#define AFE_RCTRLSTG_OFFSET 0x00000428 +#define AFE_TCTRLSTG_OFFSET 0x0000042c +#define AFE_REFMOD_OFFSET 0x00000430 +#define AFE_REFTRIML_OFFSET 0x00000434 +#define AFE_REFTRIMH_OFFSET 0x00000438 +#define AFE_ADCR_OFFSET 0x0000043c +#define AFE_DUMMY0_OFFSET 0x00000440 +#define AFE_DUMMY1_OFFSET 0x00000444 +#define AFE_DUMMY2_OFFSET 0x00000448 +#define AFE_DACAMP_OFFSET 0x0000044c +#define AFE_CLMPTST_OFFSET 0x00000450 +#define AFE_CLMPDAT_OFFSET 0x00000454 +#define AFE_CLMPAMP_OFFSET 0x00000458 +#define AFE_CLAMP_OFFSET 0x0000045c +#define AFE_INPBUF_OFFSET 0x00000460 +#define AFE_INPFLT_OFFSET 0x00000464 +#define AFE_ADCDGN_OFFSET 0x00000468 +#define AFE_OFFDRV_OFFSET 0x0000046c +#define AFE_INPCONFIG_OFFSET 0x00000470 +#define AFE_PROGDELAY_OFFSET 0x00000474 +#define AFE_ADCOMT_OFFSET 0x00000478 +#define AFE_ALGDELAY_OFFSET 0x0000047c +#define AFE_ACC_ID_OFFSET 0x00000800 +#define AFE_ACCSTA_OFFSET 0x00000804 +#define AFE_ACCNOSLI_OFFSET 0x00000808 +#define AFE_ACCCALCON_OFFSET 0x0000080c +#define AFE_BWEWRICTRL_OFFSET 0x00000810 +#define AFE_SELSLI_OFFSET 0x00000814 +#define AFE_SELBYT_OFFSET 0x00000818 +#define AFE_REDVAL_OFFSET 0x00000820 +#define AFE_WRIBYT_OFFSET 0x00000824 + +/* AFE Register per module */ +#define AFE_BLOCK_ID (AFE_BASE + AFE_BLOCK_ID_OFFSET) +#define AFE_PDBUF (AFE_BASE + AFE_PDBUF_OFFSET) +#define AFE_SWRST (AFE_BASE + AFE_SWRST_OFFSET) +#define AFE_TSTSEL (AFE_BASE + AFE_TSTSEL_OFFSET) +#define AFE_TSTMSC (AFE_BASE + AFE_TSTMSC_OFFSET) +#define AFE_ENPADIO (AFE_BASE + AFE_ENPADIO_OFFSET) +#define AFE_BGREG (AFE_BASE + AFE_BGREG_OFFSET) +#define AFE_ACCESSAR_ID (AFE_BASE + AFE_ACCESSAR_ID_OFFSET) +#define AFE_PDADC (AFE_BASE + AFE_PDADC_OFFSET) +#define AFE_PDSARH (AFE_BASE + AFE_PDSARH_OFFSET) +#define AFE_PDSARL (AFE_BASE + AFE_PDSARL_OFFSET) +#define AFE_PDADCRFH (AFE_BASE + AFE_PDADCRFH_OFFSET) +#define AFE_PDADCRFL (AFE_BASE + AFE_PDADCRFL_OFFSET) +#define AFE_ACCTST (AFE_BASE + AFE_ACCTST_OFFSET) +#define AFE_ADCGN (AFE_BASE + AFE_ADCGN_OFFSET) +#define AFE_ICTRL (AFE_BASE + AFE_ICTRL_OFFSET) +#define AFE_ICTLSTG (AFE_BASE + AFE_ICTLSTG_OFFSET) +#define AFE_RCTRLSTG (AFE_BASE + AFE_RCTRLSTG_OFFSET) +#define AFE_TCTRLSTG (AFE_BASE + AFE_TCTRLSTG_OFFSET) +#define AFE_REFMOD (AFE_BASE + AFE_REFMOD_OFFSET) +#define AFE_REFTRIML (AFE_BASE + AFE_REFTRIML_OFFSET) +#define AFE_REFTRIMH (AFE_BASE + AFE_REFTRIMH_OFFSET) +#define AFE_ADCR (AFE_BASE + AFE_ADCR_OFFSET) +#define AFE_DUMMY0 (AFE_BASE + AFE_DUMMY0_OFFSET) +#define AFE_DUMMY1 (AFE_BASE + AFE_DUMMY1_OFFSET) +#define AFE_DUMMY2 (AFE_BASE + AFE_DUMMY2_OFFSET) +#define AFE_DACAMP (AFE_BASE + AFE_DACAMP_OFFSET) +#define AFE_CLMPTST (AFE_BASE + AFE_CLMPTST_OFFSET) +#define AFE_CLMPDAT (AFE_BASE + AFE_CLMPDAT_OFFSET) +#define AFE_CLMPAMP (AFE_BASE + AFE_CLMPAMP_OFFSET) +#define AFE_CLAMP (AFE_BASE + AFE_CLAMP_OFFSET) +#define AFE_INPBUF (AFE_BASE + AFE_INPBUF_OFFSET) +#define AFE_INPFLT (AFE_BASE + AFE_INPFLT_OFFSET) +#define AFE_ADCDGN (AFE_BASE + AFE_ADCDGN_OFFSET) +#define AFE_OFFDRV (AFE_BASE + AFE_OFFDRV_OFFSET) +#define AFE_INPCONFIG (AFE_BASE + AFE_INPCONFIG_OFFSET) +#define AFE_PROGDELAY (AFE_BASE + AFE_PROGDELAY_OFFSET) +#define AFE_ADCOMT (AFE_BASE + AFE_ADCOMT_OFFSET) +#define AFE_ALGDELAY (AFE_BASE + AFE_ALGDELAY_OFFSET) +#define AFE_ACC_ID (AFE_BASE + AFE_ACC_ID_OFFSET) +#define AFE_ACCSTA (AFE_BASE + AFE_ACCSTA_OFFSET) +#define AFE_ACCNOSLI (AFE_BASE + AFE_ACCNOSLI_OFFSET) +#define AFE_ACCCALCON (AFE_BASE + AFE_ACCCALCON_OFFSET) +#define AFE_BWEWRICTRL (AFE_BASE + AFE_BWEWRICTRL_OFFSET) +#define AFE_SELSLI (AFE_BASE + AFE_SELSLI_OFFSET) +#define AFE_SELBYT (AFE_BASE + AFE_SELBYT_OFFSET) +#define AFE_REDVAL (AFE_BASE + AFE_REDVAL_OFFSET) +#define AFE_WRIBYT (AFE_BASE + AFE_WRIBYT_OFFSET) + +/* VDEC - Register offsets */ +#define VDEC_CFC1_OFFSET 0x00000000 +#define VDEC_CFC2_OFFSET 0x00000004 +#define VDEC_BRSTGT_OFFSET 0x00000024 +#define VDEC_HZPOS_OFFSET 0x00000040 +#define VDEC_VRTPOS_OFFSET 0x00000044 +#define VDEC_HVSHIFT_OFFSET 0x00000054 +#define VDEC_HSIGS_OFFSET 0x00000058 +#define VDEC_HSIGE_OFFSET 0x0000005C +#define VDEC_VSCON1_OFFSET 0x00000060 +#define VDEC_VSCON2_OFFSET 0x00000064 +#define VDEC_YCDEL_OFFSET 0x0000006C +#define VDEC_AFTCLP_OFFSET 0x00000070 +#define VDEC_DCOFF_OFFSET 0x00000078 +#define VDEC_CSID_OFFSET 0x00000084 +#define VDEC_CBGN_OFFSET 0x00000088 +#define VDEC_CRGN_OFFSET 0x0000008C +#define VDEC_CNTR_OFFSET 0x00000090 +#define VDEC_BRT_OFFSET 0x00000094 +#define VDEC_HUE_OFFSET 0x00000098 +#define VDEC_CHBTH_OFFSET 0x0000009C +#define VDEC_SHPIMP_OFFSET 0x000000A4 +#define VDEC_CHPLLIM_OFFSET 0x000000A8 +#define VDEC_VIDMOD_OFFSET 0x000000AC +#define VDEC_VIDSTS_OFFSET 0x000000B0 +#define VDEC_NOISE_OFFSET 0x000000B4 +#define VDEC_STDDBG_OFFSET 0x000000B8 +#define VDEC_MANOVR_OFFSET 0x000000BC +#define VDEC_VSSGTH_OFFSET 0x000000C8 +#define VDEC_DBGFBH_OFFSET 0x000000D0 +#define VDEC_DBGFBL_OFFSET 0x000000D4 +#define VDEC_HACTS_OFFSET 0x000000D8 +#define VDEC_HACTE_OFFSET 0x000000DC +#define VDEC_VACTS_OFFSET 0x000000E0 +#define VDEC_VACTE_OFFSET 0x000000E4 +#define VDEC_HSTIP_OFFSET 0x000000EC +#define VDEC_BLSCRY_OFFSET 0x000000F4 +#define VDEC_BLSCRCR_OFFSET 0x000000F8 +#define VDEC_BLSCRCB_OFFSET 0x000000FC +#define VDEC_LMAGC1_OFFSET 0x00000100 +#define VDEC_LMAGC2_OFFSET 0x00000104 +#define VDEC_CHAGC1_OFFSET 0x00000108 +#define VDEC_CHAGC2_OFFSET 0x0000010C +#define VDEC_MINTH_OFFSET 0x00000114 +#define VDEC_VFRQOH_OFFSET 0x0000011C +#define VDEC_VFRQOL_OFFSET 0x00000120 +#define VDEC_THSH1_OFFSET 0x00000124 +#define VDEC_THSH2_OFFSET 0x00000128 +#define VDEC_NCHTH_OFFSET 0x0000012C +#define VDEC_TH1F_OFFSET 0x00000130 + +/* VDEC Register per module */ +#define VDEC_CFC1 (VDEC_BASE + VDEC_CFC1_OFFSET) +#define VDEC_CFC2 (VDEC_BASE + VDEC_CFC2_OFFSET) +#define VDEC_BRSTGT (VDEC_BASE + VDEC_BRSTGT_OFFSET) +#define VDEC_HZPOS (VDEC_BASE + VDEC_HZPOS_OFFSET) +#define VDEC_VRTPOS (VDEC_BASE + VDEC_VRTPOS_OFFSET) +#define VDEC_HVSHIFT (VDEC_BASE + VDEC_HVSHIFT_OFFSET) +#define VDEC_HSIGS (VDEC_BASE + VDEC_HSIGS_OFFSET) +#define VDEC_HSIGE (VDEC_BASE + VDEC_HSIGE_OFFSET) +#define VDEC_VSCON1 (VDEC_BASE + VDEC_VSCON1_OFFSET) +#define VDEC_VSCON2 (VDEC_BASE + VDEC_VSCON2_OFFSET) +#define VDEC_YCDEL (VDEC_BASE + VDEC_YCDEL_OFFSET) +#define VDEC_AFTCLP (VDEC_BASE + VDEC_AFTCLP_OFFSET) +#define VDEC_DCOFF (VDEC_BASE + VDEC_DCOFF_OFFSET) +#define VDEC_CSID (VDEC_BASE + VDEC_CSID_OFFSET) +#define VDEC_CBGN (VDEC_BASE + VDEC_CBGN_OFFSET) +#define VDEC_CRGN (VDEC_BASE + VDEC_CRGN_OFFSET) +#define VDEC_CNTR (VDEC_BASE + VDEC_CNTR_OFFSET) +#define VDEC_BRT (VDEC_BASE + VDEC_BRT_OFFSET) +#define VDEC_HUE (VDEC_BASE + VDEC_HUE_OFFSET) +#define VDEC_CHBTH (VDEC_BASE + VDEC_CHBTH_OFFSET) +#define VDEC_SHPIMP (VDEC_BASE + VDEC_SHPIMP_OFFSET) +#define VDEC_CHPLLIM (VDEC_BASE + VDEC_CHPLLIM_OFFSET) +#define VDEC_VIDMOD (VDEC_BASE + VDEC_VIDMOD_OFFSET) +#define VDEC_VIDSTS (VDEC_BASE + VDEC_VIDSTS_OFFSET) +#define VDEC_NOISE (VDEC_BASE + VDEC_NOISE_OFFSET) +#define VDEC_STDDBG (VDEC_BASE + VDEC_STDDBG_OFFSET) +#define VDEC_MANOVR (VDEC_BASE + VDEC_MANOVR_OFFSET) +#define VDEC_VSSGTH (VDEC_BASE + VDEC_VSSGTH_OFFSET) +#define VDEC_DBGFBH (VDEC_BASE + VDEC_DBGFBH_OFFSET) +#define VDEC_DBGFBL (VDEC_BASE + VDEC_DBGFBL_OFFSET) +#define VDEC_HACTS (VDEC_BASE + VDEC_HACTS_OFFSET) +#define VDEC_HACTE (VDEC_BASE + VDEC_HACTE_OFFSET) +#define VDEC_VACTS (VDEC_BASE + VDEC_VACTS_OFFSET) +#define VDEC_VACTE (VDEC_BASE + VDEC_VACTE_OFFSET) +#define VDEC_HSTIP (VDEC_BASE + VDEC_HSTIP_OFFSET) +#define VDEC_BLSCRY (VDEC_BASE + VDEC_BLSCRY_OFFSET) +#define VDEC_BLSCRCR (VDEC_BASE + VDEC_BLSCRCR_OFFSET) +#define VDEC_BLSCRCB (VDEC_BASE + VDEC_BLSCRCB_OFFSET) +#define VDEC_LMAGC1 (VDEC_BASE + VDEC_LMAGC1_OFFSET) +#define VDEC_LMAGC2 (VDEC_BASE + VDEC_LMAGC2_OFFSET) +#define VDEC_CHAGC1 (VDEC_BASE + VDEC_CHAGC1_OFFSET) +#define VDEC_CHAGC2 (VDEC_BASE + VDEC_CHAGC2_OFFSET) +#define VDEC_MINTH (VDEC_BASE + VDEC_MINTH_OFFSET) +#define VDEC_VFRQOH (VDEC_BASE + VDEC_VFRQOH_OFFSET) +#define VDEC_VFRQOL (VDEC_BASE + VDEC_VFRQOL_OFFSET) +#define VDEC_THSH1 (VDEC_BASE + VDEC_THSH1_OFFSET) +#define VDEC_THSH2 (VDEC_BASE + VDEC_THSH2_OFFSET) +#define VDEC_NCHTH (VDEC_BASE + VDEC_NCHTH_OFFSET) +#define VDEC_TH1F (VDEC_BASE + VDEC_TH1F_OFFSET) + +#define VDEC_VIDMOD_SIGNAL_MASK 0x0F +#define VDEC_VIDMOD_SIGNAL_DETECT 0x0F + +#define VDEC_VIDMOD_M625_SHIFT 4 +#define VDEC_VIDMOD_M625_MASK (1 << VDEC_VIDMOD_M625_SHIFT) + +#define VDEC_VIDMOD_PAL_SHIFT 7 +#define VDEC_VIDMOD_PAL_MASK (1 << VDEC_VIDMOD_PAL_SHIFT) +/*** define base address ***/ + +#endif diff --git a/drivers/media/platform/mxc/subdev/ov5640.c b/drivers/media/platform/mxc/subdev/ov5640.c new file mode 100644 index 000000000000..feb29629464a --- /dev/null +++ b/drivers/media/platform/mxc/subdev/ov5640.c @@ -0,0 +1,1899 @@ +/* + * Copyright (C) 2012-2015 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OV5640_VOLTAGE_ANALOG 2800000 +#define OV5640_VOLTAGE_DIGITAL_CORE 1500000 +#define OV5640_VOLTAGE_DIGITAL_IO 1800000 + +#define MIN_FPS 15 +#define MAX_FPS 30 +#define DEFAULT_FPS 30 + +#define OV5640_XCLK_MIN 6000000 +#define OV5640_XCLK_MAX 24000000 + +#define OV5640_CHIP_ID_HIGH_BYTE 0x300A +#define OV5640_CHIP_ID_LOW_BYTE 0x300B + +enum ov5640_mode { + ov5640_mode_MIN = 0, + ov5640_mode_VGA_640_480 = 0, + ov5640_mode_QVGA_320_240 = 1, + ov5640_mode_NTSC_720_480 = 2, + ov5640_mode_PAL_720_576 = 3, + ov5640_mode_720P_1280_720 = 4, + ov5640_mode_1080P_1920_1080 = 5, + ov5640_mode_QSXGA_2592_1944 = 6, + ov5640_mode_QCIF_176_144 = 7, + ov5640_mode_XGA_1024_768 = 8, + ov5640_mode_MAX = 8 +}; + +enum ov5640_frame_rate { + ov5640_15_fps, + ov5640_30_fps +}; + +static int ov5640_framerates[] = { + [ov5640_15_fps] = 15, + [ov5640_30_fps] = 30, +}; + +struct ov5640_datafmt { + u32 code; + enum v4l2_colorspace colorspace; +}; + +struct reg_value { + u16 u16RegAddr; + u8 u8Val; + u8 u8Mask; + u32 u32Delay_ms; +}; + +struct ov5640_mode_info { + enum ov5640_mode mode; + u32 width; + u32 height; + struct reg_value *init_data_ptr; + u32 init_data_size; +}; + +struct ov5640 { + struct v4l2_subdev subdev; + struct i2c_client *i2c_client; + struct v4l2_pix_format pix; + const struct ov5640_datafmt *fmt; + struct v4l2_captureparm streamcap; + bool on; + + /* control settings */ + int brightness; + int hue; + int contrast; + int saturation; + int red; + int green; + int blue; + int ae_mode; + + u32 mclk; + u8 mclk_source; + struct clk *sensor_clk; + int csi; + + void (*io_init)(void); +}; + +/*! + * Maintains the information on the current state of the sesor. + */ +static struct ov5640 ov5640_data; +static int pwn_gpio, rst_gpio; +static int prev_sysclk; +static int AE_Target = 52, night_mode; +static int prev_HTS; +static int AE_high, AE_low; + +static struct reg_value ov5640_global_init_setting[] = { + {0x3008, 0x42, 0, 0}, + {0x3103, 0x03, 0, 0}, {0x3017, 0xff, 0, 0}, {0x3018, 0xff, 0, 0}, + {0x3034, 0x1a, 0, 0}, {0x3037, 0x13, 0, 0}, {0x3108, 0x01, 0, 0}, + {0x3630, 0x36, 0, 0}, {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, + {0x3633, 0x12, 0, 0}, {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, + {0x3703, 0x5a, 0, 0}, {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, + {0x370b, 0x60, 0, 0}, {0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, + {0x3906, 0x10, 0, 0}, {0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, + {0x3600, 0x08, 0, 0}, {0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, + {0x3620, 0x52, 0, 0}, {0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, + {0x3a13, 0x43, 0, 0}, {0x3a18, 0x00, 0, 0}, {0x3a19, 0x7c, 0, 0}, + {0x3635, 0x13, 0, 0}, {0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, + {0x3622, 0x01, 0, 0}, {0x3c01, 0x34, 0, 0}, {0x3c04, 0x28, 0, 0}, + {0x3c05, 0x98, 0, 0}, {0x3c06, 0x00, 0, 0}, {0x3c07, 0x07, 0, 0}, + {0x3c08, 0x00, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, + {0x3c0b, 0x40, 0, 0}, {0x3810, 0x00, 0, 0}, {0x3811, 0x10, 0, 0}, + {0x3812, 0x00, 0, 0}, {0x3708, 0x64, 0, 0}, {0x4001, 0x02, 0, 0}, + {0x4005, 0x1a, 0, 0}, {0x3000, 0x00, 0, 0}, {0x3004, 0xff, 0, 0}, + {0x300e, 0x58, 0, 0}, {0x302e, 0x00, 0, 0}, {0x4300, 0x30, 0, 0}, + {0x501f, 0x00, 0, 0}, {0x440e, 0x00, 0, 0}, {0x5000, 0xa7, 0, 0}, + {0x3008, 0x02, 0, 0}, +}; + +static struct reg_value ov5640_init_setting_30fps_VGA[] = { + {0x3008, 0x42, 0, 0}, + {0x3103, 0x03, 0, 0}, {0x3017, 0xff, 0, 0}, {0x3018, 0xff, 0, 0}, + {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, {0x3036, 0x46, 0, 0}, + {0x3037, 0x13, 0, 0}, {0x3108, 0x01, 0, 0}, {0x3630, 0x36, 0, 0}, + {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0}, + {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0}, + {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0}, + {0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0}, + {0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0}, + {0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0}, + {0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0}, + {0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0}, + {0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0}, + {0x3c01, 0x34, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0}, + {0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, + {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0}, + {0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x300e, 0x58, 0, 0}, {0x302e, 0x00, 0, 0}, {0x4300, 0x30, 0, 0}, + {0x501f, 0x00, 0, 0}, {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, + {0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, {0x5000, 0xa7, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0}, {0x5181, 0xf2, 0, 0}, + {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0}, {0x5184, 0x25, 0, 0}, + {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0}, {0x5187, 0x09, 0, 0}, + {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0}, {0x518a, 0x54, 0, 0}, + {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0}, {0x518d, 0x50, 0, 0}, + {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0}, {0x5190, 0x46, 0, 0}, + {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, {0x5193, 0x70, 0, 0}, + {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, {0x5196, 0x03, 0, 0}, + {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, {0x5199, 0x6c, 0, 0}, + {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, {0x519c, 0x09, 0, 0}, + {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0}, {0x5381, 0x1e, 0, 0}, + {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0}, {0x5384, 0x0a, 0, 0}, + {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0}, {0x5387, 0x7c, 0, 0}, + {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0}, {0x538a, 0x01, 0, 0}, + {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0}, {0x5301, 0x30, 0, 0}, + {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0}, {0x5304, 0x08, 0, 0}, + {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0}, {0x5307, 0x16, 0, 0}, + {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0}, {0x530b, 0x04, 0, 0}, + {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0}, {0x5481, 0x08, 0, 0}, + {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0}, {0x5484, 0x51, 0, 0}, + {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0}, {0x5487, 0x7d, 0, 0}, + {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0}, {0x548a, 0x9a, 0, 0}, + {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0}, {0x548d, 0xcd, 0, 0}, + {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0}, {0x5490, 0x1d, 0, 0}, + {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0}, {0x5584, 0x10, 0, 0}, + {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0}, {0x558b, 0xf8, 0, 0}, + {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0}, {0x5802, 0x0f, 0, 0}, + {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0}, {0x5805, 0x26, 0, 0}, + {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0}, {0x5808, 0x05, 0, 0}, + {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0}, {0x580b, 0x0d, 0, 0}, + {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0}, {0x580e, 0x00, 0, 0}, + {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0}, {0x5811, 0x09, 0, 0}, + {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0}, {0x5814, 0x00, 0, 0}, + {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0}, {0x5817, 0x08, 0, 0}, + {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0}, {0x581a, 0x05, 0, 0}, + {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0}, {0x581d, 0x0e, 0, 0}, + {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0}, {0x5820, 0x11, 0, 0}, + {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0}, {0x5823, 0x28, 0, 0}, + {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0}, {0x5826, 0x08, 0, 0}, + {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0}, {0x5829, 0x26, 0, 0}, + {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0}, {0x582c, 0x24, 0, 0}, + {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0}, {0x582f, 0x22, 0, 0}, + {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0}, {0x5832, 0x24, 0, 0}, + {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0}, {0x5835, 0x22, 0, 0}, + {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0}, {0x5838, 0x44, 0, 0}, + {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0}, {0x583b, 0x28, 0, 0}, + {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0}, {0x5025, 0x00, 0, 0}, + {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0}, {0x3a1b, 0x30, 0, 0}, + {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x14, 0, 0}, + {0x3008, 0x02, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_VGA_640_480[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, + {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, {0x3503, 0x00, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_VGA_640_480[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, + {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, {0x3503, 0x00, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_QVGA_320_240[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, + {0x380a, 0x00, 0, 0}, {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_QVGA_320_240[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, + {0x380a, 0x00, 0, 0}, {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_NTSC_720_480[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, + {0x3807, 0xd4, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, + {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_NTSC_720_480[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, + {0x3807, 0xd4, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, + {0x380a, 0x01, 0, 0}, {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_PAL_720_576[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x60, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x09, 0, 0}, {0x3805, 0x7e, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, + {0x380a, 0x02, 0, 0}, {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_PAL_720_576[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x60, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x09, 0, 0}, {0x3805, 0x7e, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, + {0x380a, 0x02, 0, 0}, {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_720P_1280_720[] = { + {0x3035, 0x21, 0, 0}, {0x3036, 0x69, 0, 0}, {0x3c07, 0x07, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0}, + {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0}, + {0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0}, + {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3813, 0x04, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3709, 0x52, 0, 0}, + {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, {0x3a03, 0xe0, 0, 0}, + {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe0, 0, 0}, {0x4004, 0x02, 0, 0}, + {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, + {0x4837, 0x16, 0, 0}, {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, + {0x3503, 0x00, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_720P_1280_720[] = { + {0x3035, 0x41, 0, 0}, {0x3036, 0x69, 0, 0}, {0x3c07, 0x07, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0}, + {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0}, + {0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0}, + {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3813, 0x04, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3709, 0x52, 0, 0}, + {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, {0x3a03, 0xe0, 0, 0}, + {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe0, 0, 0}, {0x4004, 0x02, 0, 0}, + {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, + {0x4837, 0x16, 0, 0}, {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, + {0x3503, 0x00, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_QCIF_176_144[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, + {0x380a, 0x00, 0, 0}, {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x11, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_QCIF_176_144[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, + {0x380a, 0x00, 0, 0}, {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x22, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_XGA_1024_768[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0}, + {0x380a, 0x03, 0, 0}, {0x380b, 0x00, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x20, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x01, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x69, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_XGA_1024_768[] = { + {0x3c07, 0x08, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9b, 0, 0}, {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0}, + {0x380a, 0x03, 0, 0}, {0x380b, 0x00, 0, 0}, {0x380c, 0x07, 0, 0}, + {0x380d, 0x68, 0, 0}, {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, + {0x3813, 0x06, 0, 0}, {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x0b, 0, 0}, + {0x3a03, 0x88, 0, 0}, {0x3a14, 0x0b, 0, 0}, {0x3a15, 0x88, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, + {0x460c, 0x20, 0, 0}, {0x4837, 0x22, 0, 0}, {0x3824, 0x01, 0, 0}, + {0x5001, 0xa3, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + + +static struct reg_value ov5640_setting_15fps_1080P_1920_1080[] = { + {0x3c07, 0x07, 0, 0}, {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, + {0x3814, 0x11, 0, 0}, {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0xee, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x05, 0, 0}, + {0x3807, 0xc3, 0, 0}, {0x3808, 0x07, 0, 0}, {0x3809, 0x80, 0, 0}, + {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0}, {0x380c, 0x0b, 0, 0}, + {0x380d, 0x1c, 0, 0}, {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, + {0x3813, 0x04, 0, 0}, {0x3618, 0x04, 0, 0}, {0x3612, 0x2b, 0, 0}, + {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x07, 0, 0}, + {0x3a03, 0xae, 0, 0}, {0x3a14, 0x07, 0, 0}, {0x3a15, 0xae, 0, 0}, + {0x4004, 0x06, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x02, 0, 0}, {0x4407, 0x0c, 0, 0}, {0x460b, 0x37, 0, 0}, + {0x460c, 0x20, 0, 0}, {0x4837, 0x2c, 0, 0}, {0x3824, 0x01, 0, 0}, + {0x5001, 0x83, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x69, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = { + {0x3c07, 0x07, 0, 0}, {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, + {0x3814, 0x11, 0, 0}, {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, + {0x3801, 0x00, 0, 0}, {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, + {0x3804, 0x0a, 0, 0}, {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, + {0x3807, 0x9f, 0, 0}, {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, + {0x380a, 0x07, 0, 0}, {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, + {0x380d, 0x1c, 0, 0}, {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, + {0x3813, 0x04, 0, 0}, {0x3618, 0x04, 0, 0}, {0x3612, 0x2b, 0, 0}, + {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x07, 0, 0}, + {0x3a03, 0xae, 0, 0}, {0x3a14, 0x07, 0, 0}, {0x3a15, 0xae, 0, 0}, + {0x4004, 0x06, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x4713, 0x02, 0, 0}, {0x4407, 0x0c, 0, 0}, {0x460b, 0x37, 0, 0}, + {0x460c, 0x20, 0, 0}, {0x4837, 0x2c, 0, 0}, {0x3824, 0x01, 0, 0}, + {0x5001, 0x83, 0, 0}, {0x3034, 0x1a, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x69, 0, 0}, {0x3037, 0x13, 0, 0}, +}; + +static struct ov5640_mode_info ov5640_mode_info_data[2][ov5640_mode_MAX + 1] = { + { + {ov5640_mode_VGA_640_480, 640, 480, + ov5640_setting_15fps_VGA_640_480, + ARRAY_SIZE(ov5640_setting_15fps_VGA_640_480)}, + {ov5640_mode_QVGA_320_240, 320, 240, + ov5640_setting_15fps_QVGA_320_240, + ARRAY_SIZE(ov5640_setting_15fps_QVGA_320_240)}, + {ov5640_mode_NTSC_720_480, 720, 480, + ov5640_setting_15fps_NTSC_720_480, + ARRAY_SIZE(ov5640_setting_15fps_NTSC_720_480)}, + {ov5640_mode_PAL_720_576, 720, 576, + ov5640_setting_15fps_PAL_720_576, + ARRAY_SIZE(ov5640_setting_15fps_PAL_720_576)}, + {ov5640_mode_720P_1280_720, 1280, 720, + ov5640_setting_15fps_720P_1280_720, + ARRAY_SIZE(ov5640_setting_15fps_720P_1280_720)}, + {ov5640_mode_1080P_1920_1080, 1920, 1080, + ov5640_setting_15fps_1080P_1920_1080, + ARRAY_SIZE(ov5640_setting_15fps_1080P_1920_1080)}, + {ov5640_mode_QSXGA_2592_1944, 2592, 1944, + ov5640_setting_15fps_QSXGA_2592_1944, + ARRAY_SIZE(ov5640_setting_15fps_QSXGA_2592_1944)}, + {ov5640_mode_QCIF_176_144, 176, 144, + ov5640_setting_15fps_QCIF_176_144, + ARRAY_SIZE(ov5640_setting_15fps_QCIF_176_144)}, + {ov5640_mode_XGA_1024_768, 1024, 768, + ov5640_setting_15fps_XGA_1024_768, + ARRAY_SIZE(ov5640_setting_15fps_XGA_1024_768)}, + }, + { + {ov5640_mode_VGA_640_480, 640, 480, + ov5640_setting_30fps_VGA_640_480, + ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480)}, + {ov5640_mode_QVGA_320_240, 320, 240, + ov5640_setting_30fps_QVGA_320_240, + ARRAY_SIZE(ov5640_setting_30fps_QVGA_320_240)}, + {ov5640_mode_NTSC_720_480, 720, 480, + ov5640_setting_30fps_NTSC_720_480, + ARRAY_SIZE(ov5640_setting_30fps_NTSC_720_480)}, + {ov5640_mode_PAL_720_576, 720, 576, + ov5640_setting_30fps_PAL_720_576, + ARRAY_SIZE(ov5640_setting_30fps_PAL_720_576)}, + {ov5640_mode_720P_1280_720, 1280, 720, + ov5640_setting_30fps_720P_1280_720, + ARRAY_SIZE(ov5640_setting_30fps_720P_1280_720)}, + {ov5640_mode_1080P_1920_1080, 0, 0, NULL, 0}, + {ov5640_mode_QSXGA_2592_1944, 0, 0, NULL, 0}, + {ov5640_mode_QCIF_176_144, 176, 144, + ov5640_setting_30fps_QCIF_176_144, + ARRAY_SIZE(ov5640_setting_30fps_QCIF_176_144)}, + {ov5640_mode_XGA_1024_768, 1024, 768, + ov5640_setting_30fps_XGA_1024_768, + ARRAY_SIZE(ov5640_setting_30fps_XGA_1024_768)}, + }, +}; + +static struct regulator *io_regulator; +static struct regulator *core_regulator; +static struct regulator *analog_regulator; + +static int ov5640_probe(struct i2c_client *adapter, + const struct i2c_device_id *device_id); +static int ov5640_remove(struct i2c_client *client); + +static s32 ov5640_read_reg(u16 reg, u8 *val); +static s32 ov5640_write_reg(u16 reg, u8 val); + +static const struct i2c_device_id ov5640_id[] = { + {"ov5640", 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, ov5640_id); + +static struct i2c_driver ov5640_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "ov5640", + }, + .probe = ov5640_probe, + .remove = ov5640_remove, + .id_table = ov5640_id, +}; + +static const struct ov5640_datafmt ov5640_colour_fmts[] = { + {MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG}, +}; + +static struct ov5640 *to_ov5640(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), struct ov5640, subdev); +} + +/* Find a data format by a pixel code in an array */ +static const struct ov5640_datafmt + *ov5640_find_datafmt(u32 code) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ov5640_colour_fmts); i++) + if (ov5640_colour_fmts[i].code == code) + return ov5640_colour_fmts + i; + + return NULL; +} + +static inline void ov5640_power_down(int enable) +{ + gpio_set_value_cansleep(pwn_gpio, enable); + + msleep(2); +} + +static inline void ov5640_reset(void) +{ + /* camera reset */ + gpio_set_value_cansleep(rst_gpio, 1); + + /* camera power down */ + gpio_set_value_cansleep(pwn_gpio, 1); + msleep(5); + gpio_set_value_cansleep(pwn_gpio, 0); + msleep(5); + gpio_set_value_cansleep(rst_gpio, 0); + msleep(1); + gpio_set_value_cansleep(rst_gpio, 1); + msleep(5); + gpio_set_value_cansleep(pwn_gpio, 1); +} + +static int ov5640_regulator_enable(struct device *dev) +{ + int ret = 0; + + io_regulator = devm_regulator_get(dev, "DOVDD"); + if (!IS_ERR(io_regulator)) { + regulator_set_voltage(io_regulator, + OV5640_VOLTAGE_DIGITAL_IO, + OV5640_VOLTAGE_DIGITAL_IO); + ret = regulator_enable(io_regulator); + if (ret) { + dev_err(dev, "set io voltage failed\n"); + return ret; + } else { + dev_dbg(dev, "set io voltage ok\n"); + } + } else { + io_regulator = NULL; + dev_warn(dev, "cannot get io voltage\n"); + } + + core_regulator = devm_regulator_get(dev, "DVDD"); + if (!IS_ERR(core_regulator)) { + regulator_set_voltage(core_regulator, + OV5640_VOLTAGE_DIGITAL_CORE, + OV5640_VOLTAGE_DIGITAL_CORE); + ret = regulator_enable(core_regulator); + if (ret) { + dev_err(dev, "set core voltage failed\n"); + return ret; + } else { + dev_dbg(dev, "set core voltage ok\n"); + } + } else { + core_regulator = NULL; + dev_warn(dev, "cannot get core voltage\n"); + } + + analog_regulator = devm_regulator_get(dev, "AVDD"); + if (!IS_ERR(analog_regulator)) { + regulator_set_voltage(analog_regulator, + OV5640_VOLTAGE_ANALOG, + OV5640_VOLTAGE_ANALOG); + ret = regulator_enable(analog_regulator); + if (ret) { + dev_err(dev, "set analog voltage failed\n"); + return ret; + } else { + dev_dbg(dev, "set analog voltage ok\n"); + } + } else { + analog_regulator = NULL; + dev_warn(dev, "cannot get analog voltage\n"); + } + + return ret; +} + +static s32 ov5640_write_reg(u16 reg, u8 val) +{ + u8 au8Buf[3] = {0}; + + au8Buf[0] = reg >> 8; + au8Buf[1] = reg & 0xff; + au8Buf[2] = val; + + if (i2c_master_send(ov5640_data.i2c_client, au8Buf, 3) < 0) { + pr_err("%s:write reg error:reg=%x,val=%x\n", + __func__, reg, val); + return -1; + } + + return 0; +} + +static s32 ov5640_read_reg(u16 reg, u8 *val) +{ + u8 au8RegBuf[2] = {0}; + u8 u8RdVal = 0; + + au8RegBuf[0] = reg >> 8; + au8RegBuf[1] = reg & 0xff; + + if (2 != i2c_master_send(ov5640_data.i2c_client, au8RegBuf, 2)) { + pr_err("%s:write reg error:reg=%x\n", + __func__, reg); + return -1; + } + + if (1 != i2c_master_recv(ov5640_data.i2c_client, &u8RdVal, 1)) { + pr_err("%s:read reg error:reg=%x,val=%x\n", + __func__, reg, u8RdVal); + return -1; + } + + *val = u8RdVal; + + return u8RdVal; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int ov5640_get_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + u8 val; + + if (reg->reg & ~0xffff) + return -EINVAL; + + reg->size = 1; + + ret = ov5640_read_reg(reg->reg, &val); + if (!ret) + reg->val = (__u64)val; + + return ret; +} + +static int ov5640_set_register(struct v4l2_subdev *sd, + const struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (reg->reg & ~0xffff || reg->val & ~0xff) + return -EINVAL; + + return ov5640_write_reg(reg->reg, reg->val); +} +#endif + +static void ov5640_soft_reset(void) +{ + /* sysclk from pad */ + ov5640_write_reg(0x3103, 0x11); + + /* software reset */ + ov5640_write_reg(0x3008, 0x82); + + /* delay at least 5ms */ + msleep(10); +} + +/* set sensor driver capability + * 0x302c[7:6] - strength + 00 - 1x + 01 - 2x + 10 - 3x + 11 - 4x + */ +static int ov5640_driver_capability(int strength) +{ + u8 temp = 0; + + if (strength > 4 || strength < 1) { + pr_err("The valid driver capability of ov5640 is 1x~4x\n"); + return -EINVAL; + } + + ov5640_read_reg(0x302c, &temp); + + temp &= ~0xc0; /* clear [7:6] */ + temp |= ((strength - 1) << 6); /* set [7:6] */ + + ov5640_write_reg(0x302c, temp); + + return 0; +} + +/* calculate sysclk */ +static int ov5640_get_sysclk(void) +{ + int xvclk = ov5640_data.mclk / 10000; + int sysclk; + int temp1, temp2; + int Multiplier, PreDiv, VCO, SysDiv, Pll_rdiv, Bit_div2x, sclk_rdiv; + int sclk_rdiv_map[] = {1, 2, 4, 8}; + u8 regval = 0; + + temp1 = ov5640_read_reg(0x3034, ®val); + temp2 = temp1 & 0x0f; + if (temp2 == 8 || temp2 == 10) { + Bit_div2x = temp2 / 2; + } else { + pr_err("ov5640: unsupported bit mode %d\n", temp2); + return -1; + } + + temp1 = ov5640_read_reg(0x3035, ®val); + SysDiv = temp1 >> 4; + if (SysDiv == 0) + SysDiv = 16; + + temp1 = ov5640_read_reg(0x3036, ®val); + Multiplier = temp1; + temp1 = ov5640_read_reg(0x3037, ®val); + PreDiv = temp1 & 0x0f; + Pll_rdiv = ((temp1 >> 4) & 0x01) + 1; + + temp1 = ov5640_read_reg(0x3108, ®val); + temp2 = temp1 & 0x03; + + sclk_rdiv = sclk_rdiv_map[temp2]; + VCO = xvclk * Multiplier / PreDiv; + sysclk = VCO / SysDiv / Pll_rdiv * 2 / Bit_div2x / sclk_rdiv; + + return sysclk; +} + +/* read HTS from register settings */ +static int ov5640_get_HTS(void) +{ + int HTS; + u8 temp = 0; + + HTS = ov5640_read_reg(0x380c, &temp); + HTS = (HTS<<8) + ov5640_read_reg(0x380d, &temp); + return HTS; +} + +/* read VTS from register settings */ +static int ov5640_get_VTS(void) +{ + int VTS; + u8 temp = 0; + + VTS = ov5640_read_reg(0x380e, &temp); + VTS = (VTS<<8) + ov5640_read_reg(0x380f, &temp); + + return VTS; +} + +/* write VTS to registers */ +static int ov5640_set_VTS(int VTS) +{ + int temp; + + temp = VTS & 0xff; + ov5640_write_reg(0x380f, temp); + + temp = VTS>>8; + ov5640_write_reg(0x380e, temp); + return 0; +} + +/* read shutter, in number of line period */ +static int ov5640_get_shutter(void) +{ + int shutter; + u8 regval; + + shutter = (ov5640_read_reg(0x03500, ®val) & 0x0f); + + shutter = (shutter<<8) + ov5640_read_reg(0x3501, ®val); + shutter = (shutter<<4) + (ov5640_read_reg(0x3502, ®val)>>4); + + return shutter; +} + +/* write shutter, in number of line period */ +static int ov5640_set_shutter(int shutter) +{ + int temp; + + shutter = shutter & 0xffff; + temp = shutter & 0x0f; + temp = temp<<4; + ov5640_write_reg(0x3502, temp); + + temp = shutter & 0xfff; + temp = temp>>4; + ov5640_write_reg(0x3501, temp); + + temp = shutter>>12; + ov5640_write_reg(0x3500, temp); + + return 0; +} + +/* read gain, 16 = 1x */ +static int ov5640_get_gain16(void) +{ + int gain16; + u8 regval; + + gain16 = ov5640_read_reg(0x350a, ®val) & 0x03; + gain16 = (gain16<<8) + ov5640_read_reg(0x350b, ®val); + + return gain16; +} + +/* write gain, 16 = 1x */ +static int ov5640_set_gain16(int gain16) +{ + int temp; + + gain16 = gain16 & 0x3ff; + temp = gain16 & 0xff; + + ov5640_write_reg(0x350b, temp); + temp = gain16>>8; + + ov5640_write_reg(0x350a, temp); + return 0; +} + +/* get banding filter value */ +static int ov5640_get_light_freq(void) +{ + int temp, temp1, light_frequency; + u8 regval; + + temp = ov5640_read_reg(0x3c01, ®val); + if (temp & 0x80) { + /* manual */ + temp1 = ov5640_read_reg(0x3c00, ®val); + if (temp1 & 0x04) { + /* 50Hz */ + light_frequency = 50; + } else { + /* 60Hz */ + light_frequency = 60; + } + } else { + /* auto */ + temp1 = ov5640_read_reg(0x3c0c, ®val); + if (temp1 & 0x01) { + /* 50Hz */ + light_frequency = 50; + } else { + /* 60Hz */ + light_frequency = 60; + } + } + + return light_frequency; +} + +static void ov5640_set_bandingfilter(void) +{ + int prev_VTS; + int band_step60, max_band60, band_step50, max_band50; + + /* read preview PCLK */ + prev_sysclk = ov5640_get_sysclk(); + + /* read preview HTS */ + prev_HTS = ov5640_get_HTS(); + + /* read preview VTS */ + prev_VTS = ov5640_get_VTS(); + + /* calculate banding filter */ + /* 60Hz */ + band_step60 = prev_sysclk * 100/prev_HTS * 100/120; + ov5640_write_reg(0x3a0a, (band_step60 >> 8)); + ov5640_write_reg(0x3a0b, (band_step60 & 0xff)); + + max_band60 = (int)((prev_VTS-4)/band_step60); + ov5640_write_reg(0x3a0d, max_band60); + + /* 50Hz */ + band_step50 = prev_sysclk * 100/prev_HTS; + ov5640_write_reg(0x3a08, (band_step50 >> 8)); + ov5640_write_reg(0x3a09, (band_step50 & 0xff)); + + max_band50 = (int)((prev_VTS-4)/band_step50); + ov5640_write_reg(0x3a0e, max_band50); +} + +/* stable in high */ +static int ov5640_set_AE_target(int target) +{ + int fast_high, fast_low; + + AE_low = target * 23 / 25; /* 0.92 */ + AE_high = target * 27 / 25; /* 1.08 */ + fast_high = AE_high << 1; + + if (fast_high > 255) + fast_high = 255; + fast_low = AE_low >> 1; + + ov5640_write_reg(0x3a0f, AE_high); + ov5640_write_reg(0x3a10, AE_low); + ov5640_write_reg(0x3a1b, AE_high); + ov5640_write_reg(0x3a1e, AE_low); + ov5640_write_reg(0x3a11, fast_high); + ov5640_write_reg(0x3a1f, fast_low); + + return 0; +} + +/* enable = 0 to turn off night mode + enable = 1 to turn on night mode */ +static int ov5640_set_night_mode(int enable) +{ + u8 mode; + + ov5640_read_reg(0x3a00, &mode); + + if (enable) { + /* night mode on */ + mode |= 0x04; + ov5640_write_reg(0x3a00, mode); + } else { + /* night mode off */ + mode &= 0xfb; + ov5640_write_reg(0x3a00, mode); + } + + return 0; +} + +/* enable = 0 to turn off AEC/AGC + enable = 1 to turn on AEC/AGC */ +static void ov5640_turn_on_AE_AG(int enable) +{ + u8 ae_ag_ctrl; + + ov5640_read_reg(0x3503, &ae_ag_ctrl); + if (enable) { + /* turn on auto AE/AG */ + ae_ag_ctrl = ae_ag_ctrl & ~(0x03); + } else { + /* turn off AE/AG */ + ae_ag_ctrl = ae_ag_ctrl | 0x03; + } + ov5640_write_reg(0x3503, ae_ag_ctrl); +} + +/* download ov5640 settings to sensor through i2c */ +static int ov5640_download_firmware(struct reg_value *pModeSetting, s32 ArySize) +{ + register u32 Delay_ms = 0; + register u16 RegAddr = 0; + register u8 Mask = 0; + register u8 Val = 0; + u8 RegVal = 0; + int i, retval = 0; + + for (i = 0; i < ArySize; ++i, ++pModeSetting) { + Delay_ms = pModeSetting->u32Delay_ms; + RegAddr = pModeSetting->u16RegAddr; + Val = pModeSetting->u8Val; + Mask = pModeSetting->u8Mask; + + if (Mask) { + retval = ov5640_read_reg(RegAddr, &RegVal); + if (retval < 0) + goto err; + + RegVal &= ~(u8)Mask; + Val &= Mask; + Val |= RegVal; + } + + retval = ov5640_write_reg(RegAddr, Val); + if (retval < 0) + goto err; + + if (Delay_ms) + msleep(Delay_ms); + } +err: + return retval; +} + +static int ov5640_init_mode(void) +{ + struct reg_value *pModeSetting = NULL; + int ArySize = 0, retval = 0; + + ov5640_soft_reset(); + + pModeSetting = ov5640_global_init_setting; + ArySize = ARRAY_SIZE(ov5640_global_init_setting); + retval = ov5640_download_firmware(pModeSetting, ArySize); + if (retval < 0) + goto err; + + pModeSetting = ov5640_init_setting_30fps_VGA; + ArySize = ARRAY_SIZE(ov5640_init_setting_30fps_VGA); + retval = ov5640_download_firmware(pModeSetting, ArySize); + if (retval < 0) + goto err; + + /* change driver capability to 2x according to validation board. + * if the image is not stable, please increase the driver strength. + */ + ov5640_driver_capability(2); + ov5640_set_bandingfilter(); + ov5640_set_AE_target(AE_Target); + ov5640_set_night_mode(night_mode); + + /* skip 9 vysnc: start capture at 10th vsync */ + msleep(300); + + /* turn off night mode */ + night_mode = 0; + ov5640_data.pix.width = 640; + ov5640_data.pix.height = 480; +err: + return retval; +} + +/* change to or back to subsampling mode set the mode directly + * image size below 1280 * 960 is subsampling mode */ +static int ov5640_change_mode_direct(enum ov5640_frame_rate frame_rate, + enum ov5640_mode mode) +{ + struct reg_value *pModeSetting = NULL; + s32 ArySize = 0; + int retval = 0; + + if (mode > ov5640_mode_MAX || mode < ov5640_mode_MIN) { + pr_err("Wrong ov5640 mode detected!\n"); + return -1; + } + + pModeSetting = ov5640_mode_info_data[frame_rate][mode].init_data_ptr; + ArySize = + ov5640_mode_info_data[frame_rate][mode].init_data_size; + + ov5640_data.pix.width = ov5640_mode_info_data[frame_rate][mode].width; + ov5640_data.pix.height = ov5640_mode_info_data[frame_rate][mode].height; + + if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 || + pModeSetting == NULL || ArySize == 0) + return -EINVAL; + + /* set ov5640 to subsampling mode */ + retval = ov5640_download_firmware(pModeSetting, ArySize); + + /* turn on AE AG for subsampling mode, in case the firmware didn't */ + ov5640_turn_on_AE_AG(1); + + /* calculate banding filter */ + ov5640_set_bandingfilter(); + + /* set AE target */ + ov5640_set_AE_target(AE_Target); + + /* update night mode setting */ + ov5640_set_night_mode(night_mode); + + /* skip 9 vysnc: start capture at 10th vsync */ + if (mode == ov5640_mode_XGA_1024_768 && frame_rate == ov5640_30_fps) { + pr_warning("ov5640: actual frame rate of XGA is 22.5fps\n"); + /* 1/22.5 * 9*/ + msleep(400); + return retval; + } + + if (frame_rate == ov5640_15_fps) { + /* 1/15 * 9*/ + msleep(600); + } else if (frame_rate == ov5640_30_fps) { + /* 1/30 * 9*/ + msleep(300); + } + + return retval; +} + +/* change to scaling mode go through exposure calucation + * image size above 1280 * 960 is scaling mode */ +static int ov5640_change_mode_exposure_calc(enum ov5640_frame_rate frame_rate, + enum ov5640_mode mode) +{ + int prev_shutter, prev_gain16, average; + int cap_shutter, cap_gain16; + int cap_sysclk, cap_HTS, cap_VTS; + int light_freq, cap_bandfilt, cap_maxband; + long cap_gain16_shutter; + u8 temp; + struct reg_value *pModeSetting = NULL; + s32 ArySize = 0; + int retval = 0; + + /* check if the input mode and frame rate is valid */ + pModeSetting = + ov5640_mode_info_data[frame_rate][mode].init_data_ptr; + ArySize = + ov5640_mode_info_data[frame_rate][mode].init_data_size; + + ov5640_data.pix.width = + ov5640_mode_info_data[frame_rate][mode].width; + ov5640_data.pix.height = + ov5640_mode_info_data[frame_rate][mode].height; + + if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 || + pModeSetting == NULL || ArySize == 0) + return -EINVAL; + + /* read preview shutter */ + prev_shutter = ov5640_get_shutter(); + + /* read preview gain */ + prev_gain16 = ov5640_get_gain16(); + + /* get average */ + average = ov5640_read_reg(0x56a1, &temp); + + /* turn off night mode for capture */ + ov5640_set_night_mode(0); + + /* turn off overlay */ + ov5640_write_reg(0x3022, 0x06); + + /* Write capture setting */ + retval = ov5640_download_firmware(pModeSetting, ArySize); + if (retval < 0) + goto err; + + /* turn off AE AG when capture image. */ + ov5640_turn_on_AE_AG(0); + + /* read capture VTS */ + cap_VTS = ov5640_get_VTS(); + cap_HTS = ov5640_get_HTS(); + cap_sysclk = ov5640_get_sysclk(); + + /* calculate capture banding filter */ + light_freq = ov5640_get_light_freq(); + if (light_freq == 60) { + /* 60Hz */ + cap_bandfilt = cap_sysclk * 100 / cap_HTS * 100 / 120; + } else { + /* 50Hz */ + cap_bandfilt = cap_sysclk * 100 / cap_HTS; + } + cap_maxband = (int)((cap_VTS - 4)/cap_bandfilt); + /* calculate capture shutter/gain16 */ + if (average > AE_low && average < AE_high) { + /* in stable range */ + cap_gain16_shutter = + prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk * + prev_HTS/cap_HTS * AE_Target / average; + } else { + cap_gain16_shutter = + prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk * + prev_HTS/cap_HTS; + } + + /* gain to shutter */ + if (cap_gain16_shutter < (cap_bandfilt * 16)) { + /* shutter < 1/100 */ + cap_shutter = cap_gain16_shutter/16; + if (cap_shutter < 1) + cap_shutter = 1; + cap_gain16 = cap_gain16_shutter/cap_shutter; + if (cap_gain16 < 16) + cap_gain16 = 16; + } else { + if (cap_gain16_shutter > (cap_bandfilt*cap_maxband*16)) { + /* exposure reach max */ + cap_shutter = cap_bandfilt*cap_maxband; + cap_gain16 = cap_gain16_shutter / cap_shutter; + } else { + /* 1/100 < cap_shutter =< max, cap_shutter = n/100 */ + cap_shutter = + ((int)(cap_gain16_shutter/16/cap_bandfilt)) + * cap_bandfilt; + cap_gain16 = cap_gain16_shutter / cap_shutter; + } + } + + /* write capture gain */ + ov5640_set_gain16(cap_gain16); + + /* write capture shutter */ + if (cap_shutter > (cap_VTS - 4)) { + cap_VTS = cap_shutter + 4; + ov5640_set_VTS(cap_VTS); + } + + ov5640_set_shutter(cap_shutter); + + /* skip 2 vysnc: start capture at 3rd vsync + * frame rate of QSXGA and 1080P is 7.5fps: 1/7.5 * 2 + */ + pr_warning("ov5640: the actual frame rate of %s is 7.5fps\n", + mode == ov5640_mode_1080P_1920_1080 ? "1080P" : "QSXGA"); + msleep(267); +err: + return retval; +} + +static int ov5640_change_mode(enum ov5640_frame_rate frame_rate, + enum ov5640_mode mode) +{ + int retval = 0; + + if (mode > ov5640_mode_MAX || mode < ov5640_mode_MIN) { + pr_err("Wrong ov5640 mode detected!\n"); + return -1; + } + + if (mode == ov5640_mode_1080P_1920_1080 || + mode == ov5640_mode_QSXGA_2592_1944) { + /* change to scaling mode go through exposure calucation + * image size above 1280 * 960 is scaling mode */ + retval = ov5640_change_mode_exposure_calc(frame_rate, mode); + } else { + /* change back to subsampling modem download firmware directly + * image size below 1280 * 960 is subsampling mode */ + retval = ov5640_change_mode_direct(frame_rate, mode); + } + + return retval; +} + +/*! + * ov5640_s_power - V4L2 sensor interface handler for VIDIOC_S_POWER ioctl + * @s: pointer to standard V4L2 device structure + * @on: indicates power mode (on or off) + * + * Turns the power on or off, depending on the value of on and returns the + * appropriate error code. + */ +static int ov5640_s_power(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5640 *sensor = to_ov5640(client); + + if (on) + clk_enable(ov5640_data.sensor_clk); + else + clk_disable(ov5640_data.sensor_clk); + + sensor->on = on; + + return 0; +} + +/*! + * ov5640_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl + * @s: pointer to standard V4L2 sub device structure + * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure + * + * Returns the sensor's video CAPTURE parameters. + */ +static int ov5640_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5640 *sensor = to_ov5640(client); + struct v4l2_captureparm *cparm = &a->parm.capture; + int ret = 0; + + switch (a->type) { + /* This is the only case currently handled. */ + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + memset(a, 0, sizeof(*a)); + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + cparm->capability = sensor->streamcap.capability; + cparm->timeperframe = sensor->streamcap.timeperframe; + cparm->capturemode = sensor->streamcap.capturemode; + ret = 0; + break; + + /* These are all the possible cases. */ + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + ret = -EINVAL; + break; + + default: + pr_debug(" type is unknown - %d\n", a->type); + ret = -EINVAL; + break; + } + + return ret; +} + +/*! + * ov5460_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl + * @s: pointer to standard V4L2 sub device structure + * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure + * + * Configures the sensor to use the input parameters, if possible. If + * not possible, reverts to the old parameters and returns the + * appropriate error code. + */ +static int ov5640_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5640 *sensor = to_ov5640(client); + struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe; + u32 tgt_fps; /* target frames per secound */ + enum ov5640_frame_rate frame_rate; + int ret = 0; + + switch (a->type) { + /* This is the only case currently handled. */ + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + /* Check that the new frame rate is allowed. */ + if ((timeperframe->numerator == 0) || + (timeperframe->denominator == 0)) { + timeperframe->denominator = DEFAULT_FPS; + timeperframe->numerator = 1; + } + + tgt_fps = timeperframe->denominator / + timeperframe->numerator; + + if (tgt_fps > MAX_FPS) { + timeperframe->denominator = MAX_FPS; + timeperframe->numerator = 1; + } else if (tgt_fps < MIN_FPS) { + timeperframe->denominator = MIN_FPS; + timeperframe->numerator = 1; + } + + /* Actual frame rate we use */ + tgt_fps = timeperframe->denominator / + timeperframe->numerator; + + if (tgt_fps == 15) + frame_rate = ov5640_15_fps; + else if (tgt_fps == 30) + frame_rate = ov5640_30_fps; + else { + pr_err(" The camera frame rate is not supported!\n"); + goto error; + } + + ret = ov5640_change_mode(frame_rate, + a->parm.capture.capturemode); + if (ret < 0) + goto error; + + sensor->streamcap.timeperframe = *timeperframe; + sensor->streamcap.capturemode = a->parm.capture.capturemode; + + break; + + /* These are all the possible cases. */ + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + pr_debug(" type is not " \ + "V4L2_BUF_TYPE_VIDEO_CAPTURE but %d\n", + a->type); + ret = -EINVAL; + break; + + default: + pr_debug(" type is unknown - %d\n", a->type); + ret = -EINVAL; + break; + } + +error: + return ret; +} + +static int ov5640_try_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + const struct ov5640_datafmt *fmt = ov5640_find_datafmt(mf->code); + + if (!fmt) { + mf->code = ov5640_colour_fmts[0].code; + mf->colorspace = ov5640_colour_fmts[0].colorspace; + } + + mf->field = V4L2_FIELD_NONE; + + return 0; +} + +static int ov5640_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5640 *sensor = to_ov5640(client); + + /* MIPI CSI could have changed the format, double-check */ + if (!ov5640_find_datafmt(mf->code)) + return -EINVAL; + + ov5640_try_fmt(sd, mf); + sensor->fmt = ov5640_find_datafmt(mf->code); + + return 0; +} + +static int ov5640_g_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5640 *sensor = to_ov5640(client); + + const struct ov5640_datafmt *fmt = sensor->fmt; + + mf->code = fmt->code; + mf->colorspace = fmt->colorspace; + mf->field = V4L2_FIELD_NONE; + + return 0; +} + +static int ov5640_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + u32 *code) +{ + if (index >= ARRAY_SIZE(ov5640_colour_fmts)) + return -EINVAL; + + *code = ov5640_colour_fmts[index].code; + return 0; +} + +/*! + * ov5640_enum_framesizes - V4L2 sensor interface handler for + * VIDIOC_ENUM_FRAMESIZES ioctl + * @s: pointer to standard V4L2 device structure + * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure + * + * Return 0 if successful, otherwise -EINVAL. + */ +static int ov5640_enum_framesizes(struct v4l2_subdev *sd, + // struct v4l2_frmsizeenum *fsize) + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index > ov5640_mode_MAX) + return -EINVAL; + +// fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fse->max_width = + max(ov5640_mode_info_data[0][fse->index].width, + ov5640_mode_info_data[1][fse->index].width); + fse->min_width = fse->max_width; + fse->max_height = + max(ov5640_mode_info_data[0][fse->index].height, + ov5640_mode_info_data[1][fse->index].height); + fse->min_height = fse->max_height; + return 0; +} + +/*! + * ov5640_enum_frameintervals - V4L2 sensor interface handler for + * VIDIOC_ENUM_FRAMEINTERVALS ioctl + * @s: pointer to standard V4L2 device structure + * @fival: standard V4L2 VIDIOC_ENUM_FRAMEINTERVALS ioctl structure + * + * Return 0 if successful, otherwise -EINVAL. + */ +static int ov5640_enum_frameintervals(struct v4l2_subdev *sd, + //struct v4l2_frmivalenum *fival) + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_interval_enum *fie) +{ + int i, j, count; + + if (fie->index < 0 || fie->index > ov5640_mode_MAX) + return -EINVAL; + + if (fie->width == 0 || fie->height == 0 || + fie->code == 0) { + pr_warning("Please assign pixel format, width and height.\n"); + return -EINVAL; + } + + fie->interval.numerator = 1; + + count = 0; + for (i = 0; i < ARRAY_SIZE(ov5640_mode_info_data); i++) { + for (j = 0; j < (ov5640_mode_MAX + 1); j++) { + if (fie->width == ov5640_mode_info_data[i][j].width + && fie->height == ov5640_mode_info_data[i][j].height + && ov5640_mode_info_data[i][j].init_data_ptr != NULL) { + count++; + } + if (fie->index == (count - 1)) { + fie->interval.denominator = + ov5640_framerates[i]; + return 0; + } + } + } + + return -EINVAL; +} + +static int ov5640_set_clk_rate(void) +{ + u32 tgt_xclk; /* target xclk */ + int ret; + + /* mclk */ + tgt_xclk = ov5640_data.mclk; + tgt_xclk = min(tgt_xclk, (u32)OV5640_XCLK_MAX); + tgt_xclk = max(tgt_xclk, (u32)OV5640_XCLK_MIN); + ov5640_data.mclk = tgt_xclk; + + pr_debug(" Setting mclk to %d MHz\n", tgt_xclk / 1000000); + ret = clk_set_rate(ov5640_data.sensor_clk, ov5640_data.mclk); + if (ret < 0) + pr_debug("set rate filed, rate=%d\n", ov5640_data.mclk); + return ret; +} + +/*! + * dev_init - V4L2 sensor init + * @s: pointer to standard V4L2 device structure + * + */ +static int init_device(void) +{ + u32 tgt_xclk; /* target xclk */ + u32 tgt_fps; /* target frames per secound */ + enum ov5640_frame_rate frame_rate; + int ret; + + ov5640_data.on = true; + + /* mclk */ + tgt_xclk = ov5640_data.mclk; + + /* Default camera frame rate is set in probe */ + tgt_fps = ov5640_data.streamcap.timeperframe.denominator / + ov5640_data.streamcap.timeperframe.numerator; + + if (tgt_fps == 15) + frame_rate = ov5640_15_fps; + else if (tgt_fps == 30) + frame_rate = ov5640_30_fps; + else + return -EINVAL; /* Only support 15fps or 30fps now. */ + + ret = ov5640_init_mode(); + + return ret; +} + +static struct v4l2_subdev_video_ops ov5640_subdev_video_ops = { + .g_parm = ov5640_g_parm, + .s_parm = ov5640_s_parm, + + .s_mbus_fmt = ov5640_s_fmt, + .g_mbus_fmt = ov5640_g_fmt, + .try_mbus_fmt = ov5640_try_fmt, + .enum_mbus_fmt = ov5640_enum_fmt, +}; + +static const struct v4l2_subdev_pad_ops ov5640_subdev_pad_ops = { + .enum_frame_size = ov5640_enum_framesizes, + .enum_frame_interval = ov5640_enum_frameintervals, +}; + +static struct v4l2_subdev_core_ops ov5640_subdev_core_ops = { + .s_power = ov5640_s_power, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = ov5640_get_register, + .s_register = ov5640_set_register, +#endif +}; + +static struct v4l2_subdev_ops ov5640_subdev_ops = { + .core = &ov5640_subdev_core_ops, + .video = &ov5640_subdev_video_ops, + .pad = &ov5640_subdev_pad_ops, +}; + +/*! + * ov5640 I2C probe function + * + * @param adapter struct i2c_adapter * + * @return Error code indicating success or failure + */ +static int ov5640_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pinctrl *pinctrl; + struct device *dev = &client->dev; + int retval; + u8 chip_id_high, chip_id_low; + + /* ov5640 pinctrl */ + pinctrl = devm_pinctrl_get_select_default(dev); + if (IS_ERR(pinctrl)) { + dev_err(dev, "setup pinctrl failed\n"); + return PTR_ERR(pinctrl); + } + + /* request power down pin */ + pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0); + if (!gpio_is_valid(pwn_gpio)) { + dev_err(dev, "no sensor pwdn pin available\n"); + return -ENODEV; + } + retval = devm_gpio_request_one(dev, pwn_gpio, GPIOF_OUT_INIT_HIGH, + "ov5640_pwdn"); + if (retval < 0) + return retval; + + /* request reset pin */ + rst_gpio = of_get_named_gpio(dev->of_node, "rst-gpios", 0); + if (!gpio_is_valid(rst_gpio)) { + dev_err(dev, "no sensor reset pin available\n"); + return -EINVAL; + } + retval = devm_gpio_request_one(dev, rst_gpio, GPIOF_OUT_INIT_HIGH, + "ov5640_reset"); + if (retval < 0) + return retval; + + /* Set initial values for the sensor struct. */ + memset(&ov5640_data, 0, sizeof(ov5640_data)); + ov5640_data.sensor_clk = devm_clk_get(dev, "csi_mclk"); + if (IS_ERR(ov5640_data.sensor_clk)) { + dev_err(dev, "get mclk failed\n"); + return PTR_ERR(ov5640_data.sensor_clk); + } + + retval = of_property_read_u32(dev->of_node, "mclk", + &ov5640_data.mclk); + if (retval) { + dev_err(dev, "mclk frequency is invalid\n"); + return retval; + } + + retval = of_property_read_u32(dev->of_node, "mclk_source", + (u32 *) &(ov5640_data.mclk_source)); + if (retval) { + dev_err(dev, "mclk_source invalid\n"); + return retval; + } + + retval = of_property_read_u32(dev->of_node, "csi_id", + &(ov5640_data.csi)); + if (retval) { + dev_err(dev, "csi_id invalid\n"); + return retval; + } + + /* Set mclk rate before clk on */ + ov5640_set_clk_rate(); + + clk_prepare_enable(ov5640_data.sensor_clk); + + ov5640_data.io_init = ov5640_reset; + ov5640_data.i2c_client = client; + ov5640_data.pix.pixelformat = V4L2_PIX_FMT_YUYV; + ov5640_data.pix.width = 640; + ov5640_data.pix.height = 480; + ov5640_data.streamcap.capability = V4L2_MODE_HIGHQUALITY | + V4L2_CAP_TIMEPERFRAME; + ov5640_data.streamcap.capturemode = 0; + ov5640_data.streamcap.timeperframe.denominator = DEFAULT_FPS; + ov5640_data.streamcap.timeperframe.numerator = 1; + + ov5640_regulator_enable(&client->dev); + + ov5640_reset(); + + ov5640_power_down(0); + + retval = ov5640_read_reg(OV5640_CHIP_ID_HIGH_BYTE, &chip_id_high); + if (retval < 0 || chip_id_high != 0x56) { + clk_disable_unprepare(ov5640_data.sensor_clk); + pr_warning("camera ov5640 is not found\n"); + return -ENODEV; + } + retval = ov5640_read_reg(OV5640_CHIP_ID_LOW_BYTE, &chip_id_low); + if (retval < 0 || chip_id_low != 0x40) { + clk_disable_unprepare(ov5640_data.sensor_clk); + pr_warning("camera ov5640 is not found\n"); + return -ENODEV; + } + + retval = init_device(); + if (retval < 0) { + clk_disable_unprepare(ov5640_data.sensor_clk); + pr_warning("camera ov5640 init failed\n"); + ov5640_power_down(1); + return retval; + } + + clk_disable(ov5640_data.sensor_clk); + + v4l2_i2c_subdev_init(&ov5640_data.subdev, client, &ov5640_subdev_ops); + + retval = v4l2_async_register_subdev(&ov5640_data.subdev); + if (retval < 0) + dev_err(&client->dev, + "%s--Async register failed, ret=%d\n", __func__, retval); + + pr_info("camera ov5640, is found\n"); + return retval; +} + +/*! + * ov5640 I2C detach function + * + * @param client struct i2c_client * + * @return Error code indicating success or failure + */ +static int ov5640_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + v4l2_async_unregister_subdev(sd); + + clk_unprepare(ov5640_data.sensor_clk); + + ov5640_power_down(1); + + if (analog_regulator) + regulator_disable(analog_regulator); + + if (core_regulator) + regulator_disable(core_regulator); + + if (io_regulator) + regulator_disable(io_regulator); + + return 0; +} + +module_i2c_driver(ov5640_i2c_driver); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("OV5640 Camera Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("1.0"); +MODULE_ALIAS("CSI"); diff --git a/drivers/media/platform/mxc/subdev/ov5640_mipi.c b/drivers/media/platform/mxc/subdev/ov5640_mipi.c new file mode 100644 index 000000000000..de68d4c39925 --- /dev/null +++ b/drivers/media/platform/mxc/subdev/ov5640_mipi.c @@ -0,0 +1,1952 @@ +/* + * Copyright (C) 2011-2015 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OV5640_VOLTAGE_ANALOG 2800000 +#define OV5640_VOLTAGE_DIGITAL_CORE 1500000 +#define OV5640_VOLTAGE_DIGITAL_IO 1800000 + +#define MIN_FPS 15 +#define MAX_FPS 30 +#define DEFAULT_FPS 30 + +#define OV5640_XCLK_MIN 6000000 +#define OV5640_XCLK_MAX 24000000 + +#define OV5640_CHIP_ID_HIGH_BYTE 0x300A +#define OV5640_CHIP_ID_LOW_BYTE 0x300B + +enum ov5640_mode { + ov5640_mode_MIN = 0, + ov5640_mode_VGA_640_480 = 0, + ov5640_mode_QVGA_320_240 = 1, + ov5640_mode_NTSC_720_480 = 2, + ov5640_mode_PAL_720_576 = 3, + ov5640_mode_720P_1280_720 = 4, + ov5640_mode_1080P_1920_1080 = 5, + ov5640_mode_QSXGA_2592_1944 = 6, + ov5640_mode_QCIF_176_144 = 7, + ov5640_mode_XGA_1024_768 = 8, + ov5640_mode_MAX = 8, + ov5640_mode_INIT = 0xff, /*only for sensor init*/ +}; + +enum ov5640_frame_rate { + ov5640_15_fps, + ov5640_30_fps +}; + +static int ov5640_framerates[] = { + [ov5640_15_fps] = 15, + [ov5640_30_fps] = 30, +}; + +struct ov5640_datafmt { + u32 code; + enum v4l2_colorspace colorspace; +}; + +/* image size under 1280 * 960 are SUBSAMPLING + * image size upper 1280 * 960 are SCALING + */ +enum ov5640_downsize_mode { + SUBSAMPLING, + SCALING, +}; + +struct reg_value { + u16 u16RegAddr; + u8 u8Val; + u8 u8Mask; + u32 u32Delay_ms; +}; + +struct ov5640_mode_info { + enum ov5640_mode mode; + enum ov5640_downsize_mode dn_mode; + u32 width; + u32 height; + struct reg_value *init_data_ptr; + u32 init_data_size; +}; + +struct ov5640 { + struct v4l2_subdev subdev; + struct i2c_client *i2c_client; + struct v4l2_pix_format pix; + const struct ov5640_datafmt *fmt; + struct v4l2_captureparm streamcap; + bool on; + + /* control settings */ + int brightness; + int hue; + int contrast; + int saturation; + int red; + int green; + int blue; + int ae_mode; + + u32 mclk; + u8 mclk_source; + struct clk *sensor_clk; + int csi; + + void (*io_init)(void); +}; +/*! + * Maintains the information on the current state of the sesor. + */ +static struct ov5640 ov5640_data; +static int pwn_gpio, rst_gpio; + +static struct reg_value ov5640_init_setting_30fps_VGA[] = { + + {0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0}, + {0x3103, 0x03, 0, 0}, {0x3017, 0x00, 0, 0}, {0x3018, 0x00, 0, 0}, + {0x3034, 0x18, 0, 0}, {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, + {0x3037, 0x13, 0, 0}, {0x3108, 0x01, 0, 0}, {0x3630, 0x36, 0, 0}, + {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0}, + {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0}, + {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0}, + {0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0}, + {0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0}, + {0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0}, + {0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0}, + {0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0}, + {0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0}, + {0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0}, + {0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, + {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0}, + {0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0}, + {0x300e, 0x45, 0, 0}, {0x302e, 0x08, 0, 0}, {0x4300, 0x30, 0, 0}, + {0x501f, 0x00, 0, 0}, {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, + {0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x4837, 0x0a, 0, 0}, {0x4800, 0x04, 0, 0}, {0x3824, 0x02, 0, 0}, + {0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0}, + {0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0}, + {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0}, + {0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0}, + {0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0}, + {0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0}, + {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, + {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, + {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, + {0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, + {0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0}, + {0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0}, + {0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0}, + {0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0}, + {0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0}, + {0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0}, + {0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0}, + {0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0}, + {0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0}, + {0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0}, + {0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0}, + {0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0}, + {0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0}, + {0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0}, + {0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0}, + {0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0}, + {0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0}, + {0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0}, + {0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0}, + {0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0}, + {0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0}, + {0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0}, + {0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0}, + {0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0}, + {0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0}, + {0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0}, + {0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0}, + {0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0}, + {0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0}, + {0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0}, + {0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0}, + {0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0}, + {0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0}, + {0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0}, + {0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0}, + {0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0}, + {0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0}, + {0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0}, + {0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0}, + {0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300}, +}; + +static struct reg_value ov5640_setting_30fps_VGA_640_480[] = { + + {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, + {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x04, 0, 0}, {0x380f, 0x38, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x0e, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3503, 0x00, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_VGA_640_480[] = { + {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, + {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_XGA_1024_768[] = { + + {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, + {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x04, 0, 0}, {0x380f, 0x38, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x0e, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3503, 0x00, 0, 0}, + {0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x03, 0, 0}, + {0x380b, 0x00, 0, 0}, {0x3035, 0x12, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_XGA_1024_768[] = { + {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, + {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3808, 0x04, 0, 0}, + {0x3809, 0x00, 0, 0}, {0x380a, 0x03, 0, 0}, {0x380b, 0x00, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_QVGA_320_240[] = { + {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0}, + {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_QVGA_320_240[] = { + {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0}, + {0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_QCIF_176_144[] = { + {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, {0x380a, 0x00, 0, 0}, + {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; +static struct reg_value ov5640_setting_15fps_QCIF_176_144[] = { + {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, {0x380a, 0x00, 0, 0}, + {0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_NTSC_720_480[] = { + {0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x01, 0, 0}, + {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_NTSC_720_480[] = { + {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x01, 0, 0}, + {0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_PAL_720_576[] = { + {0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x02, 0, 0}, + {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_PAL_720_576[] = { + {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x02, 0, 0}, + {0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_720P_1280_720[] = { + {0x3008, 0x42, 0, 0}, + {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0}, + {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0}, + {0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0}, + {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, + {0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0}, + {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0}, + {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x02, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, + {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, {0x4005, 0x1a, 0, 0}, + {0x3008, 0x02, 0, 0}, {0x3503, 0, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_720P_1280_720[] = { + {0x3035, 0x41, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0}, + {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0}, + {0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0}, + {0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, + {0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0}, + {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0}, + {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x02, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, + {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, +}; + +static struct reg_value ov5640_setting_30fps_1080P_1920_1080[] = { + {0x3008, 0x42, 0, 0}, + {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, {0x3814, 0x11, 0, 0}, + {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0}, + {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, + {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0}, + {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, + {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, + {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, {0x3035, 0x11, 0, 0}, + {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0}, + {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0}, + {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, {0x3808, 0x07, 0, 0}, + {0x3809, 0x80, 0, 0}, {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0}, + {0x380c, 0x09, 0, 0}, {0x380d, 0xc4, 0, 0}, {0x380e, 0x04, 0, 0}, + {0x380f, 0x60, 0, 0}, {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0}, + {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0}, + {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0}, + {0x3a15, 0x60, 0, 0}, {0x4713, 0x02, 0, 0}, {0x4407, 0x04, 0, 0}, + {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0}, + {0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0}, + {0x3503, 0, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_1080P_1920_1080[] = { + {0x3008, 0x42, 0, 0}, + {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, {0x3814, 0x11, 0, 0}, + {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0}, + {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, + {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0}, + {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, + {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, + {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3036, 0x54, 0, 1}, {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0}, + {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0}, + {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, {0x3808, 0x07, 0, 0}, + {0x3809, 0x80, 0, 0}, {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0}, + {0x380c, 0x09, 0, 0}, {0x380d, 0xc4, 0, 0}, {0x380e, 0x04, 0, 0}, + {0x380f, 0x60, 0, 0}, {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0}, + {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0}, + {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0}, + {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0}, + {0x3a15, 0x60, 0, 0}, {0x4713, 0x02, 0, 0}, {0x4407, 0x04, 0, 0}, + {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0}, + {0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3503, 0, 0, 0}, +}; + +static struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = { + {0x4202, 0x0f, 0, 0}, /* stream off the sensor */ + {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, /*disable flip*/ + {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3820, 0x40, 0, 0}, {0x3821, 0x06, 0, 0}, {0x3814, 0x11, 0, 0}, + {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0}, + {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, + {0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0}, + {0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0}, + {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0}, + {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, + {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, + {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70}, + {0x4202, 0x00, 0, 0}, /* stream on the sensor */ +}; + +static struct ov5640_mode_info ov5640_mode_info_data[2][ov5640_mode_MAX + 1] = { + { + {ov5640_mode_VGA_640_480, SUBSAMPLING, 640, 480, + ov5640_setting_15fps_VGA_640_480, + ARRAY_SIZE(ov5640_setting_15fps_VGA_640_480)}, + {ov5640_mode_QVGA_320_240, SUBSAMPLING, 320, 240, + ov5640_setting_15fps_QVGA_320_240, + ARRAY_SIZE(ov5640_setting_15fps_QVGA_320_240)}, + {ov5640_mode_NTSC_720_480, SUBSAMPLING, 720, 480, + ov5640_setting_15fps_NTSC_720_480, + ARRAY_SIZE(ov5640_setting_15fps_NTSC_720_480)}, + {ov5640_mode_PAL_720_576, SUBSAMPLING, 720, 576, + ov5640_setting_15fps_PAL_720_576, + ARRAY_SIZE(ov5640_setting_15fps_PAL_720_576)}, + {ov5640_mode_720P_1280_720, SUBSAMPLING, 1280, 720, + ov5640_setting_15fps_720P_1280_720, + ARRAY_SIZE(ov5640_setting_15fps_720P_1280_720)}, + {ov5640_mode_1080P_1920_1080, SCALING, 1920, 1080, + ov5640_setting_15fps_1080P_1920_1080, + ARRAY_SIZE(ov5640_setting_15fps_1080P_1920_1080)}, + {ov5640_mode_QSXGA_2592_1944, SCALING, 2592, 1944, + ov5640_setting_15fps_QSXGA_2592_1944, + ARRAY_SIZE(ov5640_setting_15fps_QSXGA_2592_1944)}, + {ov5640_mode_QCIF_176_144, SUBSAMPLING, 176, 144, + ov5640_setting_15fps_QCIF_176_144, + ARRAY_SIZE(ov5640_setting_15fps_QCIF_176_144)}, + {ov5640_mode_XGA_1024_768, SUBSAMPLING, 1024, 768, + ov5640_setting_15fps_XGA_1024_768, + ARRAY_SIZE(ov5640_setting_15fps_XGA_1024_768)}, + }, + { + {ov5640_mode_VGA_640_480, SUBSAMPLING, 640, 480, + ov5640_setting_30fps_VGA_640_480, + ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480)}, + {ov5640_mode_QVGA_320_240, SUBSAMPLING, 320, 240, + ov5640_setting_30fps_QVGA_320_240, + ARRAY_SIZE(ov5640_setting_30fps_QVGA_320_240)}, + {ov5640_mode_NTSC_720_480, SUBSAMPLING, 720, 480, + ov5640_setting_30fps_NTSC_720_480, + ARRAY_SIZE(ov5640_setting_30fps_NTSC_720_480)}, + {ov5640_mode_PAL_720_576, SUBSAMPLING, 720, 576, + ov5640_setting_30fps_PAL_720_576, + ARRAY_SIZE(ov5640_setting_30fps_PAL_720_576)}, + {ov5640_mode_720P_1280_720, SUBSAMPLING, 1280, 720, + ov5640_setting_30fps_720P_1280_720, + ARRAY_SIZE(ov5640_setting_30fps_720P_1280_720)}, + {ov5640_mode_1080P_1920_1080, SCALING, 1920, 1080, + ov5640_setting_30fps_1080P_1920_1080, + ARRAY_SIZE(ov5640_setting_30fps_1080P_1920_1080)}, + {ov5640_mode_QSXGA_2592_1944, -1, 0, 0, NULL, 0}, + {ov5640_mode_QCIF_176_144, SUBSAMPLING, 176, 144, + ov5640_setting_30fps_QCIF_176_144, + ARRAY_SIZE(ov5640_setting_30fps_QCIF_176_144)}, + {ov5640_mode_XGA_1024_768, SUBSAMPLING, 1024, 768, + ov5640_setting_30fps_XGA_1024_768, + ARRAY_SIZE(ov5640_setting_30fps_XGA_1024_768)}, + }, +}; + +static struct regulator *io_regulator; +static struct regulator *core_regulator; +static struct regulator *analog_regulator; +static struct regulator *gpo_regulator; + +static int ov5640_probe(struct i2c_client *adapter, + const struct i2c_device_id *device_id); +static int ov5640_remove(struct i2c_client *client); + +static s32 ov5640_read_reg(u16 reg, u8 *val); +static s32 ov5640_write_reg(u16 reg, u8 val); + +static const struct i2c_device_id ov5640_id[] = { + {"ov5640_mipi", 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, ov5640_id); + +static struct i2c_driver ov5640_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "ov5640_mipi", + }, + .probe = ov5640_probe, + .remove = ov5640_remove, + .id_table = ov5640_id, +}; + +static const struct ov5640_datafmt ov5640_colour_fmts[] = { + {MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG}, +}; + +static struct ov5640 *to_ov5640(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), struct ov5640, subdev); +} + +/* Find a data format by a pixel code in an array */ +static const struct ov5640_datafmt + *ov5640_find_datafmt(u32 code) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ov5640_colour_fmts); i++) + if (ov5640_colour_fmts[i].code == code) + return ov5640_colour_fmts + i; + + return NULL; +} + +static inline void ov5640_power_down(int enable) +{ + /* 19x19 pwdn pin invert by mipi daughter card */ + if (!enable) + gpio_set_value(pwn_gpio, 1); + else + gpio_set_value(pwn_gpio, 0); + + msleep(2); +} + +static void ov5640_reset(void) +{ + /* camera reset */ + gpio_set_value(rst_gpio, 1); + + /* camera power dowmn */ + gpio_set_value(pwn_gpio, 1); + msleep(5); + + gpio_set_value(pwn_gpio, 0); + msleep(5); + + gpio_set_value(rst_gpio, 0); + msleep(1); + + gpio_set_value(rst_gpio, 1); + msleep(5); + + gpio_set_value(pwn_gpio, 1); +} + +static int ov5640_regulator_enable(struct device *dev) +{ + int ret = 0; + + io_regulator = devm_regulator_get(dev, "DOVDD"); + if (!IS_ERR(io_regulator)) { + regulator_set_voltage(io_regulator, + OV5640_VOLTAGE_DIGITAL_IO, + OV5640_VOLTAGE_DIGITAL_IO); + ret = regulator_enable(io_regulator); + if (ret) { + pr_err("%s:io set voltage error\n", __func__); + return ret; + } else { + dev_dbg(dev, + "%s:io set voltage ok\n", __func__); + } + } else { + pr_err("%s: cannot get io voltage error\n", __func__); + io_regulator = NULL; + } + + core_regulator = devm_regulator_get(dev, "DVDD"); + if (!IS_ERR(core_regulator)) { + regulator_set_voltage(core_regulator, + OV5640_VOLTAGE_DIGITAL_CORE, + OV5640_VOLTAGE_DIGITAL_CORE); + ret = regulator_enable(core_regulator); + if (ret) { + pr_err("%s:core set voltage error\n", __func__); + return ret; + } else { + dev_dbg(dev, + "%s:core set voltage ok\n", __func__); + } + } else { + core_regulator = NULL; + pr_err("%s: cannot get core voltage error\n", __func__); + } + + analog_regulator = devm_regulator_get(dev, "AVDD"); + if (!IS_ERR(analog_regulator)) { + regulator_set_voltage(analog_regulator, + OV5640_VOLTAGE_ANALOG, + OV5640_VOLTAGE_ANALOG); + ret = regulator_enable(analog_regulator); + if (ret) { + pr_err("%s:analog set voltage error\n", + __func__); + return ret; + } else { + dev_dbg(dev, + "%s:analog set voltage ok\n", __func__); + } + } else { + analog_regulator = NULL; + pr_err("%s: cannot get analog voltage error\n", __func__); + } + + return ret; +} + +static s32 ov5640_write_reg(u16 reg, u8 val) +{ + u8 au8Buf[3] = {0}; + + au8Buf[0] = reg >> 8; + au8Buf[1] = reg & 0xff; + au8Buf[2] = val; + + if (i2c_master_send(ov5640_data.i2c_client, au8Buf, 3) < 0) { + pr_err("%s:write reg error:reg=%x,val=%x\n", + __func__, reg, val); + return -1; + } + + return 0; +} + +static s32 ov5640_read_reg(u16 reg, u8 *val) +{ + u8 au8RegBuf[2] = {0}; + u8 u8RdVal = 0; + + au8RegBuf[0] = reg >> 8; + au8RegBuf[1] = reg & 0xff; + + if (2 != i2c_master_send(ov5640_data.i2c_client, au8RegBuf, 2)) { + pr_err("%s:write reg error:reg=%x\n", + __func__, reg); + return -1; + } + + if (1 != i2c_master_recv(ov5640_data.i2c_client, &u8RdVal, 1)) { + pr_err("%s:read reg error:reg=%x,val=%x\n", + __func__, reg, u8RdVal); + return -1; + } + + *val = u8RdVal; + + return u8RdVal; +} + +static int prev_sysclk, prev_HTS; +static int AE_low, AE_high, AE_Target = 52; + +static void OV5640_stream_on(void) +{ + ov5640_write_reg(0x4202, 0x00); +} + +static void OV5640_stream_off(void) +{ + ov5640_write_reg(0x4202, 0x0f); +} + + +static int OV5640_get_sysclk(void) +{ + /* calculate sysclk */ + int xvclk = ov5640_data.mclk / 10000; + int temp1, temp2; + int Multiplier, PreDiv, VCO, SysDiv, Pll_rdiv; + int Bit_div2x = 1, sclk_rdiv, sysclk; + u8 temp; + + int sclk_rdiv_map[] = {1, 2, 4, 8}; + + temp1 = ov5640_read_reg(0x3034, &temp); + temp2 = temp1 & 0x0f; + if (temp2 == 8 || temp2 == 10) + Bit_div2x = temp2 / 2; + + temp1 = ov5640_read_reg(0x3035, &temp); + SysDiv = temp1>>4; + if (SysDiv == 0) + SysDiv = 16; + + temp1 = ov5640_read_reg(0x3036, &temp); + Multiplier = temp1; + + temp1 = ov5640_read_reg(0x3037, &temp); + PreDiv = temp1 & 0x0f; + Pll_rdiv = ((temp1 >> 4) & 0x01) + 1; + + temp1 = ov5640_read_reg(0x3108, &temp); + temp2 = temp1 & 0x03; + sclk_rdiv = sclk_rdiv_map[temp2]; + + VCO = xvclk * Multiplier / PreDiv; + + sysclk = VCO / SysDiv / Pll_rdiv * 2 / Bit_div2x / sclk_rdiv; + + return sysclk; +} + +static void OV5640_set_night_mode(void) +{ + /* read HTS from register settings */ + u8 mode; + + ov5640_read_reg(0x3a00, &mode); + mode &= 0xfb; + ov5640_write_reg(0x3a00, mode); +} + +static int OV5640_get_HTS(void) +{ + /* read HTS from register settings */ + int HTS; + u8 temp; + + HTS = ov5640_read_reg(0x380c, &temp); + HTS = (HTS<<8) + ov5640_read_reg(0x380d, &temp); + + return HTS; +} + +static int OV5640_get_VTS(void) +{ + /* read VTS from register settings */ + int VTS; + u8 temp; + + /* total vertical size[15:8] high byte */ + VTS = ov5640_read_reg(0x380e, &temp); + + VTS = (VTS<<8) + ov5640_read_reg(0x380f, &temp); + + return VTS; +} + +static int OV5640_set_VTS(int VTS) +{ + /* write VTS to registers */ + int temp; + + temp = VTS & 0xff; + ov5640_write_reg(0x380f, temp); + + temp = VTS>>8; + ov5640_write_reg(0x380e, temp); + + return 0; +} + +static int OV5640_get_shutter(void) +{ + /* read shutter, in number of line period */ + int shutter; + u8 temp; + + shutter = (ov5640_read_reg(0x03500, &temp) & 0x0f); + shutter = (shutter<<8) + ov5640_read_reg(0x3501, &temp); + shutter = (shutter<<4) + (ov5640_read_reg(0x3502, &temp)>>4); + + return shutter; +} + +static int OV5640_set_shutter(int shutter) +{ + /* write shutter, in number of line period */ + int temp; + + shutter = shutter & 0xffff; + + temp = shutter & 0x0f; + temp = temp<<4; + ov5640_write_reg(0x3502, temp); + + temp = shutter & 0xfff; + temp = temp>>4; + ov5640_write_reg(0x3501, temp); + + temp = shutter>>12; + ov5640_write_reg(0x3500, temp); + + return 0; +} + +static int OV5640_get_gain16(void) +{ + /* read gain, 16 = 1x */ + int gain16; + u8 temp; + + gain16 = ov5640_read_reg(0x350a, &temp) & 0x03; + gain16 = (gain16<<8) + ov5640_read_reg(0x350b, &temp); + + return gain16; +} + +static int OV5640_set_gain16(int gain16) +{ + /* write gain, 16 = 1x */ + u8 temp; + gain16 = gain16 & 0x3ff; + + temp = gain16 & 0xff; + ov5640_write_reg(0x350b, temp); + + temp = gain16>>8; + ov5640_write_reg(0x350a, temp); + + return 0; +} + +static int OV5640_get_light_freq(void) +{ + /* get banding filter value */ + int temp, temp1, light_freq = 0; + u8 tmp; + + temp = ov5640_read_reg(0x3c01, &tmp); + + if (temp & 0x80) { + /* manual */ + temp1 = ov5640_read_reg(0x3c00, &tmp); + if (temp1 & 0x04) { + /* 50Hz */ + light_freq = 50; + } else { + /* 60Hz */ + light_freq = 60; + } + } else { + /* auto */ + temp1 = ov5640_read_reg(0x3c0c, &tmp); + if (temp1 & 0x01) { + /* 50Hz */ + light_freq = 50; + } else { + /* 60Hz */ + } + } + return light_freq; +} + +static void OV5640_set_bandingfilter(void) +{ + int prev_VTS; + int band_step60, max_band60, band_step50, max_band50; + + /* read preview PCLK */ + prev_sysclk = OV5640_get_sysclk(); + /* read preview HTS */ + prev_HTS = OV5640_get_HTS(); + + /* read preview VTS */ + prev_VTS = OV5640_get_VTS(); + + /* calculate banding filter */ + /* 60Hz */ + band_step60 = prev_sysclk * 100/prev_HTS * 100/120; + ov5640_write_reg(0x3a0a, (band_step60 >> 8)); + ov5640_write_reg(0x3a0b, (band_step60 & 0xff)); + + max_band60 = (int)((prev_VTS-4)/band_step60); + ov5640_write_reg(0x3a0d, max_band60); + + /* 50Hz */ + band_step50 = prev_sysclk * 100/prev_HTS; + ov5640_write_reg(0x3a08, (band_step50 >> 8)); + ov5640_write_reg(0x3a09, (band_step50 & 0xff)); + + max_band50 = (int)((prev_VTS-4)/band_step50); + ov5640_write_reg(0x3a0e, max_band50); +} + +static int OV5640_set_AE_target(int target) +{ + /* stable in high */ + int fast_high, fast_low; + AE_low = target * 23 / 25; /* 0.92 */ + AE_high = target * 27 / 25; /* 1.08 */ + + fast_high = AE_high<<1; + if (fast_high > 255) + fast_high = 255; + + fast_low = AE_low >> 1; + + ov5640_write_reg(0x3a0f, AE_high); + ov5640_write_reg(0x3a10, AE_low); + ov5640_write_reg(0x3a1b, AE_high); + ov5640_write_reg(0x3a1e, AE_low); + ov5640_write_reg(0x3a11, fast_high); + ov5640_write_reg(0x3a1f, fast_low); + + return 0; +} + +static void OV5640_turn_on_AE_AG(int enable) +{ + u8 ae_ag_ctrl; + + ov5640_read_reg(0x3503, &ae_ag_ctrl); + if (enable) { + /* turn on auto AE/AG */ + ae_ag_ctrl = ae_ag_ctrl & ~(0x03); + } else { + /* turn off AE/AG */ + ae_ag_ctrl = ae_ag_ctrl | 0x03; + } + ov5640_write_reg(0x3503, ae_ag_ctrl); +} + +static bool binning_on(void) +{ + u8 temp; + ov5640_read_reg(0x3821, &temp); + temp &= 0xfe; + if (temp) + return true; + else + return false; +} + +static void ov5640_set_virtual_channel(int channel) +{ + u8 channel_id; + + ov5640_read_reg(0x4814, &channel_id); + channel_id &= ~(3 << 6); + ov5640_write_reg(0x4814, channel_id | (channel << 6)); +} + +/* download ov5640 settings to sensor through i2c */ +static int ov5640_download_firmware(struct reg_value *pModeSetting, s32 ArySize) +{ + register u32 Delay_ms = 0; + register u16 RegAddr = 0; + register u8 Mask = 0; + register u8 Val = 0; + u8 RegVal = 0; + int i, retval = 0; + + for (i = 0; i < ArySize; ++i, ++pModeSetting) { + Delay_ms = pModeSetting->u32Delay_ms; + RegAddr = pModeSetting->u16RegAddr; + Val = pModeSetting->u8Val; + Mask = pModeSetting->u8Mask; + + if (Mask) { + retval = ov5640_read_reg(RegAddr, &RegVal); + if (retval < 0) + goto err; + + RegVal &= ~(u8)Mask; + Val &= Mask; + Val |= RegVal; + } + + retval = ov5640_write_reg(RegAddr, Val); + if (retval < 0) + goto err; + + if (Delay_ms) + msleep(Delay_ms); + } +err: + return retval; +} + +/* sensor changes between scaling and subsampling + * go through exposure calcualtion + */ +static int ov5640_change_mode_exposure_calc(enum ov5640_frame_rate frame_rate, + enum ov5640_mode mode) +{ + struct reg_value *pModeSetting = NULL; + s32 ArySize = 0; + u8 average; + int prev_shutter, prev_gain16; + int cap_shutter, cap_gain16; + int cap_sysclk, cap_HTS, cap_VTS; + int light_freq, cap_bandfilt, cap_maxband; + long cap_gain16_shutter; + int retval = 0; + + /* check if the input mode and frame rate is valid */ + pModeSetting = + ov5640_mode_info_data[frame_rate][mode].init_data_ptr; + ArySize = + ov5640_mode_info_data[frame_rate][mode].init_data_size; + + ov5640_data.pix.width = + ov5640_mode_info_data[frame_rate][mode].width; + ov5640_data.pix.height = + ov5640_mode_info_data[frame_rate][mode].height; + + if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 || + pModeSetting == NULL || ArySize == 0) + return -EINVAL; + + /* auto focus */ + /* OV5640_auto_focus();//if no af function, just skip it */ + + /* turn off AE/AG */ + OV5640_turn_on_AE_AG(0); + + /* read preview shutter */ + prev_shutter = OV5640_get_shutter(); + if ((binning_on()) && (mode != ov5640_mode_720P_1280_720) + && (mode != ov5640_mode_1080P_1920_1080)) + prev_shutter *= 2; + + /* read preview gain */ + prev_gain16 = OV5640_get_gain16(); + + /* get average */ + ov5640_read_reg(0x56a1, &average); + + /* turn off night mode for capture */ + OV5640_set_night_mode(); + + /* turn off overlay */ + /* ov5640_write_reg(0x3022, 0x06);//if no af function, just skip it */ + + OV5640_stream_off(); + + /* Write capture setting */ + retval = ov5640_download_firmware(pModeSetting, ArySize); + if (retval < 0) + goto err; + + /* read capture VTS */ + cap_VTS = OV5640_get_VTS(); + cap_HTS = OV5640_get_HTS(); + cap_sysclk = OV5640_get_sysclk(); + + /* calculate capture banding filter */ + light_freq = OV5640_get_light_freq(); + if (light_freq == 60) { + /* 60Hz */ + cap_bandfilt = cap_sysclk * 100 / cap_HTS * 100 / 120; + } else { + /* 50Hz */ + cap_bandfilt = cap_sysclk * 100 / cap_HTS; + } + cap_maxband = (int)((cap_VTS - 4)/cap_bandfilt); + + /* calculate capture shutter/gain16 */ + if (average > AE_low && average < AE_high) { + /* in stable range */ + cap_gain16_shutter = + prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk + * prev_HTS/cap_HTS * AE_Target / average; + } else { + cap_gain16_shutter = + prev_gain16 * prev_shutter * cap_sysclk/prev_sysclk + * prev_HTS/cap_HTS; + } + + /* gain to shutter */ + if (cap_gain16_shutter < (cap_bandfilt * 16)) { + /* shutter < 1/100 */ + cap_shutter = cap_gain16_shutter/16; + if (cap_shutter < 1) + cap_shutter = 1; + + cap_gain16 = cap_gain16_shutter/cap_shutter; + if (cap_gain16 < 16) + cap_gain16 = 16; + } else { + if (cap_gain16_shutter > + (cap_bandfilt * cap_maxband * 16)) { + /* exposure reach max */ + cap_shutter = cap_bandfilt * cap_maxband; + cap_gain16 = cap_gain16_shutter / cap_shutter; + } else { + /* 1/100 < (cap_shutter = n/100) =< max */ + cap_shutter = + ((int) (cap_gain16_shutter/16 / cap_bandfilt)) + *cap_bandfilt; + cap_gain16 = cap_gain16_shutter / cap_shutter; + } + } + + /* write capture gain */ + OV5640_set_gain16(cap_gain16); + + /* write capture shutter */ + if (cap_shutter > (cap_VTS - 4)) { + cap_VTS = cap_shutter + 4; + OV5640_set_VTS(cap_VTS); + } + OV5640_set_shutter(cap_shutter); + + OV5640_stream_on(); + +err: + return retval; +} + +/* if sensor changes inside scaling or subsampling + * change mode directly + * */ +static int ov5640_change_mode_direct(enum ov5640_frame_rate frame_rate, + enum ov5640_mode mode) +{ + struct reg_value *pModeSetting = NULL; + s32 ArySize = 0; + int retval = 0; + + /* check if the input mode and frame rate is valid */ + pModeSetting = + ov5640_mode_info_data[frame_rate][mode].init_data_ptr; + ArySize = + ov5640_mode_info_data[frame_rate][mode].init_data_size; + + ov5640_data.pix.width = + ov5640_mode_info_data[frame_rate][mode].width; + ov5640_data.pix.height = + ov5640_mode_info_data[frame_rate][mode].height; + + if (ov5640_data.pix.width == 0 || ov5640_data.pix.height == 0 || + pModeSetting == NULL || ArySize == 0) + return -EINVAL; + + /* turn off AE/AG */ + OV5640_turn_on_AE_AG(0); + + OV5640_stream_off(); + + /* Write capture setting */ + retval = ov5640_download_firmware(pModeSetting, ArySize); + if (retval < 0) + goto err; + + OV5640_stream_on(); + + OV5640_turn_on_AE_AG(1); + +err: + return retval; +} + +static int ov5640_init_mode(enum ov5640_frame_rate frame_rate, + enum ov5640_mode mode, enum ov5640_mode orig_mode) +{ + struct reg_value *pModeSetting = NULL; + s32 ArySize = 0; + int retval = 0; + u32 msec_wait4stable = 0; + enum ov5640_downsize_mode dn_mode, orig_dn_mode; + + if ((mode > ov5640_mode_MAX || mode < ov5640_mode_MIN) + && (mode != ov5640_mode_INIT)) { + pr_err("Wrong ov5640 mode detected!\n"); + return -1; + } + + dn_mode = ov5640_mode_info_data[frame_rate][mode].dn_mode; + orig_dn_mode = ov5640_mode_info_data[frame_rate][orig_mode].dn_mode; + if (mode == ov5640_mode_INIT) { + pModeSetting = ov5640_init_setting_30fps_VGA; + ArySize = ARRAY_SIZE(ov5640_init_setting_30fps_VGA); + + ov5640_data.pix.width = 640; + ov5640_data.pix.height = 480; + retval = ov5640_download_firmware(pModeSetting, ArySize); + if (retval < 0) + goto err; + + pModeSetting = ov5640_setting_30fps_VGA_640_480; + ArySize = ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480); + retval = ov5640_download_firmware(pModeSetting, ArySize); + } else if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) || + (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) { + /* change between subsampling and scaling + * go through exposure calucation */ + retval = ov5640_change_mode_exposure_calc(frame_rate, mode); + } else { + /* change inside subsampling or scaling + * download firmware directly */ + retval = ov5640_change_mode_direct(frame_rate, mode); + } + + if (retval < 0) + goto err; + + OV5640_set_AE_target(AE_Target); + OV5640_get_light_freq(); + OV5640_set_bandingfilter(); + ov5640_set_virtual_channel(ov5640_data.csi); + + /* add delay to wait for sensor stable */ + if (mode == ov5640_mode_QSXGA_2592_1944) { + /* dump the first two frames: 1/7.5*2 + * the frame rate of QSXGA is 7.5fps */ + msec_wait4stable = 267; + } else if (frame_rate == ov5640_15_fps) { + /* dump the first nine frames: 1/15*9 */ + msec_wait4stable = 600; + } else if (frame_rate == ov5640_30_fps) { + /* dump the first nine frames: 1/30*9 */ + msec_wait4stable = 300; + } + msleep(msec_wait4stable); + +err: + return retval; +} + +/*! + * ov5640_s_power - V4L2 sensor interface handler for VIDIOC_S_POWER ioctl + * @s: pointer to standard V4L2 device structure + * @on: indicates power mode (on or off) + * + * Turns the power on or off, depending on the value of on and returns the + * appropriate error code. + */ +static int ov5640_s_power(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5640 *sensor = to_ov5640(client); + + if (on && !sensor->on) { + if (io_regulator) + if (regulator_enable(io_regulator) != 0) + return -EIO; + if (core_regulator) + if (regulator_enable(core_regulator) != 0) + return -EIO; + if (gpo_regulator) + if (regulator_enable(gpo_regulator) != 0) + return -EIO; + if (analog_regulator) + if (regulator_enable(analog_regulator) != 0) + return -EIO; + } else if (!on && sensor->on) { + if (analog_regulator) + regulator_disable(analog_regulator); + if (core_regulator) + regulator_disable(core_regulator); + if (io_regulator) + regulator_disable(io_regulator); + if (gpo_regulator) + regulator_disable(gpo_regulator); + } + + sensor->on = on; + + return 0; +} + +/*! + * ov5640_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl + * @s: pointer to standard V4L2 sub device structure + * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure + * + * Returns the sensor's video CAPTURE parameters. + */ +static int ov5640_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5640 *sensor = to_ov5640(client); + struct v4l2_captureparm *cparm = &a->parm.capture; + int ret = 0; + + switch (a->type) { + /* This is the only case currently handled. */ + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + memset(a, 0, sizeof(*a)); + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + cparm->capability = sensor->streamcap.capability; + cparm->timeperframe = sensor->streamcap.timeperframe; + cparm->capturemode = sensor->streamcap.capturemode; + ret = 0; + break; + + /* These are all the possible cases. */ + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + ret = -EINVAL; + break; + + default: + pr_debug(" type is unknown - %d\n", a->type); + ret = -EINVAL; + break; + } + + return ret; +} + +/*! + * ov5460_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl + * @s: pointer to standard V4L2 sub device structure + * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure + * + * Configures the sensor to use the input parameters, if possible. If + * not possible, reverts to the old parameters and returns the + * appropriate error code. + */ +static int ov5640_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5640 *sensor = to_ov5640(client); + struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe; + u32 tgt_fps; /* target frames per secound */ + enum ov5640_frame_rate frame_rate; + enum ov5640_mode orig_mode; + int ret = 0; + + switch (a->type) { + /* This is the only case currently handled. */ + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + /* Check that the new frame rate is allowed. */ + if ((timeperframe->numerator == 0) || + (timeperframe->denominator == 0)) { + timeperframe->denominator = DEFAULT_FPS; + timeperframe->numerator = 1; + } + + tgt_fps = timeperframe->denominator / + timeperframe->numerator; + + if (tgt_fps > MAX_FPS) { + timeperframe->denominator = MAX_FPS; + timeperframe->numerator = 1; + } else if (tgt_fps < MIN_FPS) { + timeperframe->denominator = MIN_FPS; + timeperframe->numerator = 1; + } + + /* Actual frame rate we use */ + tgt_fps = timeperframe->denominator / + timeperframe->numerator; + + if (tgt_fps == 15) + frame_rate = ov5640_15_fps; + else if (tgt_fps == 30) + frame_rate = ov5640_30_fps; + else { + pr_err(" The camera frame rate is not supported!\n"); + return -EINVAL; + } + + orig_mode = sensor->streamcap.capturemode; + ret = ov5640_init_mode(frame_rate, + (u32)a->parm.capture.capturemode, orig_mode); + if (ret < 0) + return ret; + + sensor->streamcap.timeperframe = *timeperframe; + sensor->streamcap.capturemode = + (u32)a->parm.capture.capturemode; + + break; + + /* These are all the possible cases. */ + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + pr_debug(" type is not " \ + "V4L2_BUF_TYPE_VIDEO_CAPTURE but %d\n", + a->type); + ret = -EINVAL; + break; + + default: + pr_debug(" type is unknown - %d\n", a->type); + ret = -EINVAL; + break; + } + + return ret; +} + +static int ov5640_try_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + const struct ov5640_datafmt *fmt = ov5640_find_datafmt(mf->code); + + if (!fmt) { + mf->code = ov5640_colour_fmts[0].code; + mf->colorspace = ov5640_colour_fmts[0].colorspace; + } + + mf->field = V4L2_FIELD_NONE; + + return 0; +} + +static int ov5640_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5640 *sensor = to_ov5640(client); + + /* MIPI CSI could have changed the format, double-check */ + if (!ov5640_find_datafmt(mf->code)) + return -EINVAL; + + ov5640_try_fmt(sd, mf); + sensor->fmt = ov5640_find_datafmt(mf->code); + + return 0; +} + +static int ov5640_g_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5640 *sensor = to_ov5640(client); + + const struct ov5640_datafmt *fmt = sensor->fmt; + + mf->code = fmt->code; + mf->colorspace = fmt->colorspace; + mf->field = V4L2_FIELD_NONE; + + return 0; +} + +static int ov5640_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + u32 *code) +{ + if (index >= ARRAY_SIZE(ov5640_colour_fmts)) + return -EINVAL; + + *code = ov5640_colour_fmts[index].code; + return 0; +} + +/*! + * ov5640_enum_framesizes - V4L2 sensor interface handler for + * VIDIOC_ENUM_FRAMESIZES ioctl + * @s: pointer to standard V4L2 device structure + * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure + * + * Return 0 if successful, otherwise -EINVAL. + */ +static int ov5640_enum_framesizes(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index > ov5640_mode_MAX) + return -EINVAL; + + fse->max_width = + max(ov5640_mode_info_data[0][fse->index].width, + ov5640_mode_info_data[1][fse->index].width); + fse->min_width = fse->max_width; + fse->max_height = + max(ov5640_mode_info_data[0][fse->index].height, + ov5640_mode_info_data[1][fse->index].height); + fse->min_height = fse->max_height; + return 0; +} + +/*! + * ov5640_enum_frameintervals - V4L2 sensor interface handler for + * VIDIOC_ENUM_FRAMEINTERVALS ioctl + * @s: pointer to standard V4L2 device structure + * @fival: standard V4L2 VIDIOC_ENUM_FRAMEINTERVALS ioctl structure + * + * Return 0 if successful, otherwise -EINVAL. + */ +static int ov5640_enum_frameintervals(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_interval_enum *fie) +{ + int i, j, count = 0; + + if (fie->index < 0 || fie->index > ov5640_mode_MAX) + return -EINVAL; + + if (fie->width == 0 || fie->height == 0 || + fie->code == 0) { + pr_warning("Please assign pixel format, width and height.\n"); + return -EINVAL; + } + + fie->interval.numerator = 1; + + count = 0; + for (i = 0; i < ARRAY_SIZE(ov5640_mode_info_data); i++) { + for (j = 0; j < (ov5640_mode_MAX + 1); j++) { + if (fie->width == ov5640_mode_info_data[i][j].width + && fie->height == ov5640_mode_info_data[i][j].height + && ov5640_mode_info_data[i][j].init_data_ptr != NULL) { + count++; + } + if (fie->index == (count - 1)) { + fie->interval.denominator = + ov5640_framerates[i]; + return 0; + } + } + } + + return -EINVAL; +} + +/*! + * dev_init - V4L2 sensor init + * @s: pointer to standard V4L2 device structure + * + */ +static int init_device(void) +{ + u32 tgt_xclk; /* target xclk */ + u32 tgt_fps; /* target frames per secound */ + enum ov5640_frame_rate frame_rate; + int ret; + + ov5640_data.on = true; + + /* mclk */ + tgt_xclk = ov5640_data.mclk; + tgt_xclk = min(tgt_xclk, (u32)OV5640_XCLK_MAX); + tgt_xclk = max(tgt_xclk, (u32)OV5640_XCLK_MIN); + ov5640_data.mclk = tgt_xclk; + + pr_debug(" Setting mclk to %d MHz\n", tgt_xclk / 1000000); + + /* Default camera frame rate is set in probe */ + tgt_fps = ov5640_data.streamcap.timeperframe.denominator / + ov5640_data.streamcap.timeperframe.numerator; + + if (tgt_fps == 15) + frame_rate = ov5640_15_fps; + else if (tgt_fps == 30) + frame_rate = ov5640_30_fps; + else + return -EINVAL; /* Only support 15fps or 30fps now. */ + + ret = ov5640_init_mode(frame_rate, ov5640_mode_INIT, ov5640_mode_INIT); + + return ret; +} + +static struct v4l2_subdev_video_ops ov5640_subdev_video_ops = { + .g_parm = ov5640_g_parm, + .s_parm = ov5640_s_parm, + + .s_mbus_fmt = ov5640_s_fmt, + .g_mbus_fmt = ov5640_g_fmt, + .try_mbus_fmt = ov5640_try_fmt, + .enum_mbus_fmt = ov5640_enum_fmt, +}; + +static const struct v4l2_subdev_pad_ops ov5640_subdev_pad_ops = { + .enum_frame_size = ov5640_enum_framesizes, + .enum_frame_interval = ov5640_enum_frameintervals, +}; + +static struct v4l2_subdev_core_ops ov5640_subdev_core_ops = { + .s_power = ov5640_s_power, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = ov5640_get_register, + .s_register = ov5640_set_register, +#endif +}; + +static struct v4l2_subdev_ops ov5640_subdev_ops = { + .core = &ov5640_subdev_core_ops, + .video = &ov5640_subdev_video_ops, + .pad = &ov5640_subdev_pad_ops, +}; + + +/*! + * ov5640 I2C probe function + * + * @param adapter struct i2c_adapter * + * @return Error code indicating success or failure + */ +static int ov5640_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pinctrl *pinctrl; + struct device *dev = &client->dev; + int retval; + u8 chip_id_high, chip_id_low; + + /* ov5640 pinctrl */ + pinctrl = devm_pinctrl_get_select_default(dev); + if (IS_ERR(pinctrl)) { + dev_warn(dev, "no pin available\n"); + } + + /* request power down pin */ + pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0); + if (!gpio_is_valid(pwn_gpio)) { + dev_warn(dev, "no sensor pwdn pin available"); + return -EINVAL; + } + retval = devm_gpio_request_one(dev, pwn_gpio, GPIOF_OUT_INIT_HIGH, + "ov5640_mipi_pwdn"); + if (retval < 0) + return retval; + + /* request reset pin */ + rst_gpio = of_get_named_gpio(dev->of_node, "rst-gpios", 0); + if (!gpio_is_valid(rst_gpio)) { + dev_warn(dev, "no sensor reset pin available"); + return -EINVAL; + } + retval = devm_gpio_request_one(dev, rst_gpio, GPIOF_OUT_INIT_HIGH, + "ov5640_mipi_reset"); + if (retval < 0) + return retval; + + /* Set initial values for the sensor struct. */ + memset(&ov5640_data, 0, sizeof(ov5640_data)); + ov5640_data.sensor_clk = devm_clk_get(dev, "csi_mclk"); + if (IS_ERR(ov5640_data.sensor_clk)) { + /* assuming clock enabled by default */ + ov5640_data.sensor_clk = NULL; + dev_err(dev, "clock-frequency missing or invalid\n"); + return PTR_ERR(ov5640_data.sensor_clk); + } + + retval = of_property_read_u32(dev->of_node, "mclk", + &(ov5640_data.mclk)); + if (retval) { + dev_err(dev, "mclk missing or invalid\n"); + return retval; + } + + retval = of_property_read_u32(dev->of_node, "mclk_source", + (u32 *) &(ov5640_data.mclk_source)); + if (retval) { + dev_err(dev, "mclk_source missing or invalid\n"); + return retval; + } + + retval = of_property_read_u32(dev->of_node, "csi_id", + &(ov5640_data.csi)); + if (retval) { + dev_err(dev, "csi id missing or invalid\n"); + return retval; + } + + clk_prepare_enable(ov5640_data.sensor_clk); + + ov5640_data.io_init = ov5640_reset; + ov5640_data.i2c_client = client; + ov5640_data.pix.pixelformat = V4L2_PIX_FMT_YUYV; + ov5640_data.pix.width = 640; + ov5640_data.pix.height = 480; + ov5640_data.streamcap.capability = V4L2_MODE_HIGHQUALITY | + V4L2_CAP_TIMEPERFRAME; + ov5640_data.streamcap.capturemode = 0; + ov5640_data.streamcap.timeperframe.denominator = DEFAULT_FPS; + ov5640_data.streamcap.timeperframe.numerator = 1; + + ov5640_regulator_enable(&client->dev); + + ov5640_reset(); + + ov5640_power_down(0); + + retval = ov5640_read_reg(OV5640_CHIP_ID_HIGH_BYTE, &chip_id_high); + if (retval < 0 || chip_id_high != 0x56) { + pr_warning("camera ov5640_mipi is not found\n"); + clk_disable_unprepare(ov5640_data.sensor_clk); + return -ENODEV; + } + retval = ov5640_read_reg(OV5640_CHIP_ID_LOW_BYTE, &chip_id_low); + if (retval < 0 || chip_id_low != 0x40) { + pr_warning("camera ov5640_mipi is not found\n"); + clk_disable_unprepare(ov5640_data.sensor_clk); + return -ENODEV; + } + + retval = init_device(); + if (retval < 0) { + clk_disable_unprepare(ov5640_data.sensor_clk); + pr_warning("camera ov5640 init failed\n"); + ov5640_power_down(1); + return retval; + } + + v4l2_i2c_subdev_init(&ov5640_data.subdev, client, &ov5640_subdev_ops); + + ov5640_data.subdev.grp_id = 678; + retval = v4l2_async_register_subdev(&ov5640_data.subdev); + if (retval < 0) + dev_err(&client->dev, + "%s--Async register failed, ret=%d\n", __func__, retval); + + pr_info("camera ov5640_mipi is found\n"); + return retval; +} + +/*! + * ov5640 I2C detach function + * + * @param client struct i2c_client * + * @return Error code indicating success or failure + */ +static int ov5640_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + v4l2_async_unregister_subdev(sd); + + clk_disable_unprepare(ov5640_data.sensor_clk); + + ov5640_power_down(1); + + if (gpo_regulator) + regulator_disable(gpo_regulator); + + if (analog_regulator) + regulator_disable(analog_regulator); + + if (core_regulator) + regulator_disable(core_regulator); + + if (io_regulator) + regulator_disable(io_regulator); + + return 0; +} + +module_i2c_driver(ov5640_i2c_driver); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("OV5640 MIPI Camera Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("1.0"); +MODULE_ALIAS("CSI"); diff --git a/drivers/media/platform/mxc/subdev/ov5647_mipi.c b/drivers/media/platform/mxc/subdev/ov5647_mipi.c new file mode 100644 index 000000000000..9b493bfc27fc --- /dev/null +++ b/drivers/media/platform/mxc/subdev/ov5647_mipi.c @@ -0,0 +1,1705 @@ +/* + * Copyright (C) 2011-2015 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OV5647_VOLTAGE_ANALOG 2800000 +#define OV5647_VOLTAGE_DIGITAL_CORE 1500000 +#define OV5647_VOLTAGE_DIGITAL_IO 1800000 + +#define MIN_FPS 15 +#define MAX_FPS 30 +#define DEFAULT_FPS 30 + +#define OV5647_XCLK_MIN 6000000 +#define OV5647_XCLK_MAX 24000000 + +#define OV5647_CHIP_ID_HIGH_BYTE 0x300A +#define OV5647_CHIP_ID_LOW_BYTE 0x300B + +enum ov5647_mode { + ov5647_mode_MIN = 0, + ov5647_mode_VGA_640_480 = 0, + ov5647_mode_720P_1280_720 = 1, + ov5647_mode_1080P_1920_1080 = 2, + ov5647_mode_QSXGA_2592_1944 = 3, + ov5647_mode_MAX = 3, + ov5647_mode_INIT = 0xff, /*only for sensor init*/ +}; + +enum ov5647_frame_rate { + ov5647_15_fps, + ov5647_30_fps +}; + +static int ov5647_framerates[] = { + [ov5647_15_fps] = 15, + [ov5647_30_fps] = 30, +}; + +struct ov5647_datafmt { + u32 code; + enum v4l2_colorspace colorspace; +}; + +/* image size under 1280 * 960 are SUBSAMPLING + * image size upper 1280 * 960 are SCALING + */ +enum ov5647_downsize_mode { + SUBSAMPLING, + SCALING, +}; + +struct reg_value { + u16 u16RegAddr; + u8 u8Val; + u8 u8Mask; + u32 u32Delay_ms; +}; + +struct ov5647_mode_info { + enum ov5647_mode mode; + enum ov5647_downsize_mode dn_mode; + u32 width; + u32 height; + struct reg_value *init_data_ptr; + u32 init_data_size; +}; + +struct otp_struct { + int customer_id; + int module_integrator_id; + int lens_id; + int rg_ratio; + int bg_ratio; + int user_data[3]; + int light_rg; + int light_bg; +}; + +struct ov5647 { + struct v4l2_subdev subdev; + struct i2c_client *i2c_client; + struct v4l2_pix_format pix; + const struct ov5647_datafmt *fmt; + struct v4l2_captureparm streamcap; + bool on; + + /* control settings */ + int brightness; + int hue; + int contrast; + int saturation; + int red; + int green; + int blue; + int ae_mode; + + u32 mclk; + u8 mclk_source; + struct clk *sensor_clk; + int csi; + + void (*io_init)(void); +}; +/*! + * Maintains the information on the current state of the sesor. + */ +static struct ov5647 ov5647_data; +static int pwn_gpio, rst_gpio; +static int prev_sysclk, prev_HTS; +static int AE_low, AE_high, AE_Target = 52; + +/* R/G and B/G of typical camera module is defined here, + * the typical camera module is selected by CameraAnalyzer. */ +static int RG_Ratio_Typical = 0x70; +static int BG_Ratio_Typical = 0x70; + + +static struct reg_value ov5647_init_setting[] = { + + {0x0100, 0x00, 0, 0}, {0x0103, 0x01, 0, 0}, {0x3035, 0x11, 0, 0}, + {0x3036, 0x69, 0, 0}, {0x303c, 0x11, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x370c, 0x0f, 0, 0}, {0x3612, 0x59, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x5000, 0x06, 0, 0}, {0x5002, 0x40, 0, 0}, + {0x5003, 0x08, 0, 0}, {0x5a00, 0x08, 0, 0}, {0x3000, 0xff, 0, 0}, + {0x3001, 0xff, 0, 0}, {0x3002, 0xff, 0, 0}, {0x301d, 0xf0, 0, 0}, + {0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3c01, 0x80, 0, 0}, + {0x3b07, 0x0c, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0}, + {0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3708, 0x64, 0, 0}, {0x3709, 0x52, 0, 0}, + {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x03, 0, 0}, + {0x380b, 0xc0, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x18, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x0e, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x27, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x95, 0, 0}, + {0x3630, 0x2e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x23, 0, 0}, + {0x3634, 0x44, 0, 0}, {0x3620, 0x64, 0, 0}, {0x3621, 0xe0, 0, 0}, + {0x3600, 0x37, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0}, + {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x3731, 0x02, 0, 0}, + {0x370b, 0x60, 0, 0}, {0x3705, 0x1a, 0, 0}, {0x3f05, 0x02, 0, 0}, + {0x3f06, 0x10, 0, 0}, {0x3f01, 0x0a, 0, 0}, {0x3a08, 0x01, 0, 0}, + {0x3a09, 0x27, 0, 0}, {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3a0f, 0x58, 0, 0}, + {0x3a10, 0x50, 0, 0}, {0x3a1b, 0x58, 0, 0}, {0x3a1e, 0x50, 0, 0}, + {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x28, 0, 0}, {0x4001, 0x02, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x4000, 0x09, 0, 0}, {0x4050, 0x6e, 0, 0}, + {0x4051, 0x8f, 0, 0}, {0x4837, 0x17, 0, 0}, {0x3503, 0x03, 0, 0}, + {0x3501, 0x44, 0, 0}, {0x3502, 0x80, 0, 0}, {0x350a, 0x00, 0, 0}, + {0x350b, 0x7f, 0, 0}, {0x5001, 0x01, 0, 0}, {0x5002, 0x41, 0, 0}, + {0x5180, 0x08, 0, 0}, {0x5186, 0x04, 0, 0}, {0x5187, 0x00, 0, 0}, + {0x5188, 0x04, 0, 0}, {0x5189, 0x00, 0, 0}, {0x518a, 0x04, 0, 0}, + {0x518b, 0x00, 0, 0}, {0x5000, 0x86, 0, 0}, {0x5800, 0x11, 0, 0}, + {0x5801, 0x0a, 0, 0}, {0x5802, 0x09, 0, 0}, {0x5803, 0x09, 0, 0}, + {0x5804, 0x0a, 0, 0}, {0x5805, 0x0f, 0, 0}, {0x5806, 0x07, 0, 0}, + {0x5807, 0x05, 0, 0}, {0x5808, 0x03, 0, 0}, {0x5809, 0x03, 0, 0}, + {0x580a, 0x05, 0, 0}, {0x580b, 0x07, 0, 0}, {0x580c, 0x05, 0, 0}, + {0x580d, 0x02, 0, 0}, {0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, + {0x5810, 0x02, 0, 0}, {0x5811, 0x05, 0, 0}, {0x5812, 0x05, 0, 0}, + {0x5813, 0x02, 0, 0}, {0x5814, 0x00, 0, 0}, {0x5815, 0x00, 0, 0}, + {0x5816, 0x01, 0, 0}, {0x5817, 0x05, 0, 0}, {0x5818, 0x08, 0, 0}, + {0x5819, 0x05, 0, 0}, {0x581a, 0x03, 0, 0}, {0x581b, 0x03, 0, 0}, + {0x581c, 0x04, 0, 0}, {0x581d, 0x07, 0, 0}, {0x581e, 0x10, 0, 0}, + {0x581f, 0x0b, 0, 0}, {0x5820, 0x09, 0, 0}, {0x5821, 0x09, 0, 0}, + {0x5822, 0x09, 0, 0}, {0x5823, 0x0e, 0, 0}, {0x5824, 0x28, 0, 0}, + {0x5825, 0x1a, 0, 0}, {0x5826, 0x1a, 0, 0}, {0x5827, 0x1a, 0, 0}, + {0x5828, 0x46, 0, 0}, {0x5829, 0x2a, 0, 0}, {0x582a, 0x26, 0, 0}, + {0x582b, 0x44, 0, 0}, {0x582c, 0x26, 0, 0}, {0x582d, 0x2a, 0, 0}, + {0x582e, 0x28, 0, 0}, {0x582f, 0x42, 0, 0}, {0x5830, 0x40, 0, 0}, + {0x5831, 0x42, 0, 0}, {0x5832, 0x28, 0, 0}, {0x5833, 0x0a, 0, 0}, + {0x5834, 0x16, 0, 0}, {0x5835, 0x44, 0, 0}, {0x5836, 0x26, 0, 0}, + {0x5837, 0x2a, 0, 0}, {0x5838, 0x28, 0, 0}, {0x5839, 0x0a, 0, 0}, + {0x583a, 0x0a, 0, 0}, {0x583b, 0x0a, 0, 0}, {0x583c, 0x26, 0, 0}, + {0x583d, 0xbe, 0, 0}, {0x0100, 0x01, 0, 0}, {0x3000, 0x00, 0, 0}, + {0x3001, 0x00, 0, 0}, {0x3002, 0x00, 0, 0}, {0x3017, 0xe0, 0, 0}, + {0x301c, 0xfc, 0, 0}, {0x3636, 0x06, 0, 0}, {0x3016, 0x08, 0, 0}, + {0x3827, 0xec, 0, 0}, {0x3018, 0x44, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3106, 0xf5, 0, 0}, {0x3034, 0x18, 0, 0}, {0x301c, 0xf8, 0, 0}, +}; + +static struct reg_value ov5647_setting_60fps_VGA_640_480[] = { + {0x0100, 0x00, 0, 0}, {0x0103, 0x01, 0, 0}, {0x3035, 0x11, 0, 0}, + {0x3036, 0x46, 0, 0}, {0x303c, 0x11, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3820, 0x41, 0, 0}, {0x370c, 0x0f, 0, 0}, {0x3612, 0x59, 0, 0}, + {0x3618, 0x00, 0, 0}, {0x5000, 0x06, 0, 0}, {0x5002, 0x40, 0, 0}, + {0x5003, 0x08, 0, 0}, {0x5a00, 0x08, 0, 0}, {0x3000, 0xff, 0, 0}, + {0x3001, 0xff, 0, 0}, {0x3002, 0xff, 0, 0}, {0x301d, 0xf0, 0, 0}, + {0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3c01, 0x80, 0, 0}, + {0x3b07, 0x0c, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x3c, 0, 0}, + {0x380e, 0x01, 0, 0}, {0x380f, 0xf8, 0, 0}, {0x3814, 0x71, 0, 0}, + {0x3815, 0x71, 0, 0}, {0x3708, 0x64, 0, 0}, {0x3709, 0x52, 0, 0}, + {0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0}, + {0x380b, 0xe0, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x10, 0, 0}, + {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0}, + {0x3805, 0x2f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0}, + {0x3630, 0x2e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x23, 0, 0}, + {0x3634, 0x44, 0, 0}, {0x3620, 0x64, 0, 0}, {0x3621, 0xe0, 0, 0}, + {0x3600, 0x37, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0}, + {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x3731, 0x02, 0, 0}, + {0x370b, 0x60, 0, 0}, {0x3705, 0x1a, 0, 0}, {0x3f05, 0x02, 0, 0}, + {0x3f06, 0x10, 0, 0}, {0x3f01, 0x0a, 0, 0}, {0x3a08, 0x01, 0, 0}, + {0x3a09, 0x2e, 0, 0}, {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xfb, 0, 0}, + {0x3a0d, 0x02, 0, 0}, {0x3a0e, 0x01, 0, 0}, {0x3a0f, 0x58, 0, 0}, + {0x3a10, 0x50, 0, 0}, {0x3a1b, 0x58, 0, 0}, {0x3a1e, 0x50, 0, 0}, + {0x3a11, 0x60, 0, 0}, {0x3a1f, 0x28, 0, 0}, {0x4001, 0x02, 0, 0}, + {0x4004, 0x02, 0, 0}, {0x4000, 0x09, 0, 0}, {0x4050, 0x6e, 0, 0}, + {0x4051, 0x8f, 0, 0}, {0x0100, 0x01, 0, 0}, {0x3000, 0x00, 0, 0}, + {0x3001, 0x00, 0, 0}, {0x3002, 0x00, 0, 0}, {0x3017, 0xe0, 0, 0}, + {0x301c, 0xfc, 0, 0}, {0x3636, 0x06, 0, 0}, {0x3016, 0x08, 0, 0}, + {0x3827, 0xec, 0, 0}, {0x3018, 0x44, 0, 0}, {0x3035, 0x21, 0, 0}, + {0x3106, 0xf5, 0, 0}, {0x3034, 0x18, 0, 0}, {0x301c, 0xf8, 0, 0}, +}; + +static struct reg_value ov5647_setting_30fps_720P_1280_720[] = { + {0x0100, 0x00, 0, 0}, {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, + {0x3612, 0x59, 0, 0}, {0x3618, 0x00, 0, 0}, {0x380c, 0x09, 0, 0}, + {0x380d, 0xe8, 0, 0}, {0x380e, 0x04, 0, 0}, {0x380f, 0x50, 0, 0}, + {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3709, 0x52, 0, 0}, + {0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0}, + {0x380b, 0xd0, 0, 0}, {0x3801, 0x18, 0, 0}, {0x3802, 0x00, 0, 0}, + {0x3803, 0xf8, 0, 0}, {0x3804, 0x0a, 0, 0}, {0x3805, 0x27, 0, 0}, + {0x3806, 0x06, 0, 0}, {0x3807, 0xa7, 0, 0}, {0x3a09, 0xbe, 0, 0}, + {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x74, 0, 0}, {0x3a0d, 0x02, 0, 0}, + {0x3a0e, 0x01, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4005, 0x18, 0, 0}, + {0x0100, 0x01, 0, 0}, +}; + +static struct reg_value ov5647_setting_30fps_1080P_1920_1080[] = { + {0x0100, 0x00, 0, 0}, {0x3820, 0x00, 0, 0}, {0x3821, 0x06, 0, 0}, + {0x3612, 0x5b, 0, 0}, {0x3618, 0x04, 0, 0}, {0x380c, 0x09, 0, 0}, + {0x380d, 0xe8, 0, 0}, {0x380e, 0x04, 0, 0}, {0x380f, 0x50, 0, 0}, + {0x3814, 0x11, 0, 0}, {0x3815, 0x11, 0, 0}, {0x3709, 0x12, 0, 0}, + {0x3808, 0x07, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x04, 0, 0}, + {0x380b, 0x38, 0, 0}, {0x3801, 0x5c, 0, 0}, {0x3802, 0x01, 0, 0}, + {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xe3, 0, 0}, + {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, {0x3a09, 0x4b, 0, 0}, + {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x13, 0, 0}, {0x3a0d, 0x04, 0, 0}, + {0x3a0e, 0x03, 0, 0}, {0x4004, 0x04, 0, 0}, {0x4005, 0x18, 0, 0}, + {0x0100, 0x01, 0, 0}, +}; + +static struct reg_value ov5647_setting_15fps_QSXGA_2592_1944[] = { + {0x0100, 0x00, 0, 0}, {0x3820, 0x00, 0, 0}, {0x3821, 0x06, 0, 0}, + {0x3612, 0x5b, 0, 0}, {0x3618, 0x04, 0, 0}, {0x380c, 0x0b, 0, 0}, + {0x380d, 0x10, 0, 0}, {0x380e, 0x07, 0, 0}, {0x380f, 0xb8, 0, 0}, + {0x3814, 0x11, 0, 0}, {0x3815, 0x11, 0, 0}, {0x3709, 0x12, 0, 0}, + {0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0}, + {0x380b, 0x98, 0, 0}, {0x3801, 0x0c, 0, 0}, {0x3802, 0x00, 0, 0}, + {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0}, {0x3805, 0x33, 0, 0}, + {0x3806, 0x07, 0, 0}, {0x3807, 0xa3, 0, 0}, {0x3a09, 0x28, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0d, 0x08, 0, 0}, + {0x3a0e, 0x06, 0, 0}, {0x4004, 0x04, 0, 0}, {0x4005, 0x1a, 0, 0}, + {0x0100, 0x01, 0, 0}, +}; + +static struct ov5647_mode_info ov5647_mode_info_data[2][ov5647_mode_MAX + 1] = { + { + {ov5647_mode_VGA_640_480, -1, 0, 0, NULL, 0}, + {ov5647_mode_720P_1280_720, -1, 0, 0, NULL, 0}, + {ov5647_mode_1080P_1920_1080, -1, 0, 0, NULL, 0}, + {ov5647_mode_QSXGA_2592_1944, SCALING, 2592, 1944, + ov5647_setting_15fps_QSXGA_2592_1944, + ARRAY_SIZE(ov5647_setting_15fps_QSXGA_2592_1944)}, + }, + { + /* Actually VGA working in 60fps mode */ + {ov5647_mode_VGA_640_480, SUBSAMPLING, 640, 480, + ov5647_setting_60fps_VGA_640_480, + ARRAY_SIZE(ov5647_setting_60fps_VGA_640_480)}, + {ov5647_mode_720P_1280_720, SUBSAMPLING, 1280, 720, + ov5647_setting_30fps_720P_1280_720, + ARRAY_SIZE(ov5647_setting_30fps_720P_1280_720)}, + {ov5647_mode_1080P_1920_1080, SCALING, 1920, 1080, + ov5647_setting_30fps_1080P_1920_1080, + ARRAY_SIZE(ov5647_setting_30fps_1080P_1920_1080)}, + {ov5647_mode_QSXGA_2592_1944, -1, 0, 0, NULL, 0}, + }, +}; + +static struct regulator *io_regulator; +static struct regulator *core_regulator; +static struct regulator *analog_regulator; +static struct regulator *gpo_regulator; + +static int ov5647_probe(struct i2c_client *adapter, + const struct i2c_device_id *device_id); +static int ov5647_remove(struct i2c_client *client); + +static s32 ov5647_read_reg(u16 reg, u8 *val); +static s32 ov5647_write_reg(u16 reg, u8 val); + +static const struct i2c_device_id ov5647_id[] = { + {"ov5647_mipi", 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, ov5647_id); + +static struct i2c_driver ov5647_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "ov5647_mipi", + }, + .probe = ov5647_probe, + .remove = ov5647_remove, + .id_table = ov5647_id, +}; + +static const struct ov5647_datafmt ov5647_colour_fmts[] = { + {MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_JPEG}, +}; + +static struct ov5647 *to_ov5647(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), struct ov5647, subdev); +} + +/* Find a data format by a pixel code in an array */ +static const struct ov5647_datafmt + *ov5647_find_datafmt(u32 code) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ov5647_colour_fmts); i++) + if (ov5647_colour_fmts[i].code == code) + return ov5647_colour_fmts + i; + + return NULL; +} + +static inline void ov5647_power_down(int enable) +{ + if (pwn_gpio < 0) + return; + + /* 19x19 pwdn pin invert by mipi daughter card */ + if (!enable) + gpio_set_value_cansleep(pwn_gpio, 1); + else + gpio_set_value_cansleep(pwn_gpio, 0); + + msleep(2); +} + +static void ov5647_reset(void) +{ + if (rst_gpio < 0 || pwn_gpio < 0) + return; + + /* camera reset */ + gpio_set_value_cansleep(rst_gpio, 1); + + /* camera power dowmn */ + gpio_set_value_cansleep(pwn_gpio, 1); + msleep(5); + + gpio_set_value_cansleep(pwn_gpio, 0); + msleep(5); + + gpio_set_value_cansleep(rst_gpio, 0); + msleep(1); + + gpio_set_value_cansleep(rst_gpio, 1); + msleep(5); + + gpio_set_value_cansleep(pwn_gpio, 1); +} + +static int ov5647_regulator_enable(struct device *dev) +{ + int ret = 0; + + io_regulator = devm_regulator_get(dev, "DOVDD"); + if (!IS_ERR(io_regulator)) { + regulator_set_voltage(io_regulator, + OV5647_VOLTAGE_DIGITAL_IO, + OV5647_VOLTAGE_DIGITAL_IO); + ret = regulator_enable(io_regulator); + if (ret) { + pr_err("%s:io set voltage error\n", __func__); + return ret; + } else { + dev_dbg(dev, + "%s:io set voltage ok\n", __func__); + } + } else { + pr_err("%s: cannot get io voltage error\n", __func__); + io_regulator = NULL; + } + + core_regulator = devm_regulator_get(dev, "DVDD"); + if (!IS_ERR(core_regulator)) { + regulator_set_voltage(core_regulator, + OV5647_VOLTAGE_DIGITAL_CORE, + OV5647_VOLTAGE_DIGITAL_CORE); + ret = regulator_enable(core_regulator); + if (ret) { + pr_err("%s:core set voltage error\n", __func__); + return ret; + } else { + dev_dbg(dev, + "%s:core set voltage ok\n", __func__); + } + } else { + core_regulator = NULL; + pr_err("%s: cannot get core voltage error\n", __func__); + } + + analog_regulator = devm_regulator_get(dev, "AVDD"); + if (!IS_ERR(analog_regulator)) { + regulator_set_voltage(analog_regulator, + OV5647_VOLTAGE_ANALOG, + OV5647_VOLTAGE_ANALOG); + ret = regulator_enable(analog_regulator); + if (ret) { + pr_err("%s:analog set voltage error\n", + __func__); + return ret; + } else { + dev_dbg(dev, + "%s:analog set voltage ok\n", __func__); + } + } else { + analog_regulator = NULL; + pr_err("%s: cannot get analog voltage error\n", __func__); + } + + return ret; +} + +static s32 ov5647_write_reg(u16 reg, u8 val) +{ + u8 au8Buf[3] = {0}; + + au8Buf[0] = reg >> 8; + au8Buf[1] = reg & 0xff; + au8Buf[2] = val; + + if (i2c_master_send(ov5647_data.i2c_client, au8Buf, 3) < 0) { + pr_err("%s:write reg error:reg=%x,val=%x\n", + __func__, reg, val); + return -1; + } + + return 0; +} + +static s32 ov5647_read_reg(u16 reg, u8 *val) +{ + u8 au8RegBuf[2] = {0}; + u8 u8RdVal = 0; + + au8RegBuf[0] = reg >> 8; + au8RegBuf[1] = reg & 0xff; + + if (2 != i2c_master_send(ov5647_data.i2c_client, au8RegBuf, 2)) { + pr_err("%s:write reg error:reg=%x\n", + __func__, reg); + return -1; + } + + if (1 != i2c_master_recv(ov5647_data.i2c_client, &u8RdVal, 1)) { + pr_err("%s:read reg error:reg=%x,val=%x\n", + __func__, reg, u8RdVal); + return -1; + } + + *val = u8RdVal; + + return u8RdVal; +} + +/* index: index of otp group. (0, 1, 2) + * return: + * 0, group index is empty + * 1, group index has invalid data + * 2, group index has valid data */ +static int ov5647_check_otp(int index) +{ + int i; + int address; + u8 temp; + + /* read otp into buffer */ + ov5647_write_reg(0x3d21, 0x01); + msleep(20); + address = 0x3d05 + index * 9; + temp = ov5647_read_reg(address, &temp); + + /* disable otp read */ + ov5647_write_reg(0x3d21, 0x00); + + /* clear otp buffer */ + for (i = 0; i < 32; i++) + ov5647_write_reg(0x3d00 + i, 0x00); + + if (!temp) + return 0; + else if ((!(temp & 0x80)) && (temp & 0x7f)) + return 2; + else + return 1; +} + +/* index: index of otp group. (0, 1, 2) + * return: 0 */ +static int ov5647_read_otp(int index, struct otp_struct *otp_ptr) +{ + int i; + int address; + u8 temp; + + /* read otp into buffer */ + ov5647_write_reg(0x3d21, 0x01); + msleep(2); + address = 0x3d05 + index * 9; + temp = ov5647_read_reg(address, &temp); + (*otp_ptr).customer_id = temp & 0x7f; + + (*otp_ptr).module_integrator_id = ov5647_read_reg(address, &temp); + (*otp_ptr).lens_id = ov5647_read_reg(address + 1, &temp); + (*otp_ptr).rg_ratio = ov5647_read_reg(address + 2, &temp); + (*otp_ptr).bg_ratio = ov5647_read_reg(address + 3, &temp); + (*otp_ptr).user_data[0] = ov5647_read_reg(address + 4, &temp); + (*otp_ptr).user_data[1] = ov5647_read_reg(address + 5, &temp); + (*otp_ptr).user_data[2] = ov5647_read_reg(address + 6, &temp); + (*otp_ptr).light_rg = ov5647_read_reg(address + 7, &temp); + (*otp_ptr).light_bg = ov5647_read_reg(address + 8, &temp); + + /* disable otp read */ + ov5647_write_reg(0x3d21, 0x00); + + /* clear otp buffer */ + for (i = 0; i < 32; i++) + ov5647_write_reg(0x3d00 + i, 0x00); + + return 0; +} + +/* R_gain, sensor red gain of AWB, 0x400 =1 + * G_gain, sensor green gain of AWB, 0x400 =1 + * B_gain, sensor blue gain of AWB, 0x400 =1 + * return 0 */ +static int ov5647_update_awb_gain(int R_gain, int G_gain, int B_gain) +{ + if (R_gain > 0x400) { + ov5647_write_reg(0x5186, R_gain >> 8); + ov5647_write_reg(0x5187, R_gain & 0x00ff); + } + if (G_gain > 0x400) { + ov5647_write_reg(0x5188, G_gain >> 8); + ov5647_write_reg(0x5189, G_gain & 0x00ff); + } + if (B_gain > 0x400) { + ov5647_write_reg(0x518a, B_gain >> 8); + ov5647_write_reg(0x518b, B_gain & 0x00ff); + } + + return 0; +} + +/* call this function after OV5647 initialization + * return value: + * 0 update success + * 1 no OTP */ +static int ov5647_update_otp(void) +{ + struct otp_struct current_otp; + int i; + int otp_index; + int temp; + int R_gain, G_gain, B_gain, G_gain_R, G_gain_B; + int rg, bg; + + /* R/G and B/G of current camera module is read out from sensor OTP + * check first OTP with valid data */ + for (i = 0; i < 3; i++) { + temp = ov5647_check_otp(i); + if (temp == 2) { + otp_index = i; + break; + } + } + if (i == 3) { + /* no valid wb OTP data */ + printk(KERN_WARNING "No valid wb otp data\n"); + return 1; + } + + ov5647_read_otp(otp_index, ¤t_otp); + if (current_otp.light_rg == 0) + rg = current_otp.rg_ratio; + else + rg = current_otp.rg_ratio * (current_otp.light_rg + 128) / 256; + + if (current_otp.light_bg == 0) + bg = current_otp.bg_ratio; + else + bg = current_otp.bg_ratio * (current_otp.light_bg + 128) / 256; + + /* calculate G gain + * 0x400 = 1x gain */ + if (bg < BG_Ratio_Typical) { + if (rg < RG_Ratio_Typical) { + /* current_otp.bg_ratio < BG_Ratio_typical && + * current_otp.rg_ratio < RG_Ratio_typical */ + G_gain = 0x400; + B_gain = 0x400 * BG_Ratio_Typical / bg; + R_gain = 0x400 * RG_Ratio_Typical / rg; + } else { + /* current_otp.bg_ratio < BG_Ratio_typical && + * current_otp.rg_ratio >= RG_Ratio_typical */ + R_gain = 0x400; + G_gain = 0x400 * rg / RG_Ratio_Typical; + B_gain = G_gain * BG_Ratio_Typical / bg; + } + } else { + if (rg < RG_Ratio_Typical) { + /* current_otp.bg_ratio >= BG_Ratio_typical && + * current_otp.rg_ratio < RG_Ratio_typical */ + B_gain = 0x400; + G_gain = 0x400 * bg / BG_Ratio_Typical; + R_gain = G_gain * RG_Ratio_Typical / rg; + } else { + /* current_otp.bg_ratio >= BG_Ratio_typical && + * current_otp.rg_ratio >= RG_Ratio_typical */ + G_gain_B = 0x400 * bg / BG_Ratio_Typical; + G_gain_R = 0x400 * rg / RG_Ratio_Typical; + if (G_gain_B > G_gain_R) { + B_gain = 0x400; + G_gain = G_gain_B; + R_gain = G_gain * RG_Ratio_Typical / rg; + } else { + R_gain = 0x400; + G_gain = G_gain_R; + B_gain = G_gain * BG_Ratio_Typical / bg; + } + } + } + ov5647_update_awb_gain(R_gain, G_gain, B_gain); + return 0; +} + +static void ov5647_stream_on(void) +{ + ov5647_write_reg(0x4202, 0x00); +} + +static void ov5647_stream_off(void) +{ + ov5647_write_reg(0x4202, 0x0f); +} + +static int ov5647_get_sysclk(void) +{ + /* calculate sysclk */ + int xvclk = ov5647_data.mclk / 10000; + int sysclk, temp1, temp2; + int pre_div02x, div_cnt7b, sdiv0, pll_rdiv, bit_div2x, sclk_div, VCO; + int pre_div02x_map[] = {2, 2, 4, 6, 8, 3, 12, 5, 16, 2, 2, 2, 2, 2, 2, 2}; + int sdiv0_map[] = {16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + int pll_rdiv_map[] = {1, 2}; + int bit_div2x_map[] = {2, 2, 2, 2, 2, 2, 2, 2, 4, 2, 5, 2, 2, 2, 2, 2}; + int sclk_div_map[] = {1, 2, 4, 1}; + u8 temp; + + temp1 = ov5647_read_reg(0x3037, &temp); + temp2 = temp1 & 0x0f; + pre_div02x = pre_div02x_map[temp2]; + temp2 = (temp1 >> 4) & 0x01; + pll_rdiv = pll_rdiv_map[temp2]; + temp1 = ov5647_read_reg(0x3036, &temp); + + div_cnt7b = temp1; + + VCO = xvclk * 2 / pre_div02x * div_cnt7b; + temp1 = ov5647_read_reg(0x3035, &temp); + temp2 = temp1 >> 4; + sdiv0 = sdiv0_map[temp2]; + temp1 = ov5647_read_reg(0x3034, &temp); + temp2 = temp1 & 0x0f; + bit_div2x = bit_div2x_map[temp2]; + temp1 = ov5647_read_reg(0x3106, &temp); + temp2 = (temp1 >> 2) & 0x03; + sclk_div = sclk_div_map[temp2]; + sysclk = VCO * 2 / sdiv0 / pll_rdiv / bit_div2x / sclk_div; + return sysclk; +} + +static void ov5647_set_night_mode(void) +{ + /* read HTS from register settings */ + u8 mode; + + ov5647_read_reg(0x3a00, &mode); + mode &= 0xfb; + ov5647_write_reg(0x3a00, mode); +} + +static int ov5647_get_HTS(void) +{ + /* read HTS from register settings */ + int HTS; + u8 temp; + + HTS = ov5647_read_reg(0x380c, &temp); + HTS = (HTS << 8) + ov5647_read_reg(0x380d, &temp); + + return HTS; +} + +static int ov5647_get_VTS(void) +{ + /* read VTS from register settings */ + int VTS; + u8 temp; + + /* total vertical size[15:8] high byte */ + VTS = ov5647_read_reg(0x380e, &temp); + + VTS = (VTS << 8) + ov5647_read_reg(0x380f, &temp); + + return VTS; +} + +static int ov5647_set_VTS(int VTS) +{ + /* write VTS to registers */ + int temp; + + temp = VTS & 0xff; + ov5647_write_reg(0x380f, temp); + + temp = VTS >> 8; + ov5647_write_reg(0x380e, temp); + + return 0; +} + +static int ov5647_get_shutter(void) +{ + /* read shutter, in number of line period */ + int shutter; + u8 temp; + + shutter = (ov5647_read_reg(0x03500, &temp) & 0x0f); + shutter = (shutter << 8) + ov5647_read_reg(0x3501, &temp); + shutter = (shutter << 4) + (ov5647_read_reg(0x3502, &temp)>>4); + + return shutter; +} + +static int ov5647_set_shutter(int shutter) +{ + /* write shutter, in number of line period */ + int temp; + + shutter = shutter & 0xffff; + + temp = shutter & 0x0f; + temp = temp << 4; + ov5647_write_reg(0x3502, temp); + + temp = shutter & 0xfff; + temp = temp >> 4; + ov5647_write_reg(0x3501, temp); + + temp = shutter >> 12; + ov5647_write_reg(0x3500, temp); + + return 0; +} + +static int ov5647_get_gain16(void) +{ + /* read gain, 16 = 1x */ + int gain16; + u8 temp; + + gain16 = ov5647_read_reg(0x350a, &temp) & 0x03; + gain16 = (gain16 << 8) + ov5647_read_reg(0x350b, &temp); + + return gain16; +} + +static int ov5647_set_gain16(int gain16) +{ + /* write gain, 16 = 1x */ + u8 temp; + gain16 = gain16 & 0x3ff; + + temp = gain16 & 0xff; + ov5647_write_reg(0x350b, temp); + + temp = gain16 >> 8; + ov5647_write_reg(0x350a, temp); + + return 0; +} + +static int ov5647_get_light_freq(void) +{ + /* get banding filter value */ + int temp, temp1, light_freq = 0; + u8 tmp; + + temp = ov5647_read_reg(0x3c01, &tmp); + + if (temp & 0x80) { + /* manual */ + temp1 = ov5647_read_reg(0x3c00, &tmp); + if (temp1 & 0x04) { + /* 50Hz */ + light_freq = 50; + } else { + /* 60Hz */ + light_freq = 60; + } + } else { + /* auto */ + temp1 = ov5647_read_reg(0x3c0c, &tmp); + if (temp1 & 0x01) { + /* 50Hz */ + light_freq = 50; + } else { + /* 60Hz */ + } + } + return light_freq; +} + +static void ov5647_set_bandingfilter(void) +{ + int prev_VTS; + int band_step60, max_band60, band_step50, max_band50; + + /* read preview PCLK */ + prev_sysclk = ov5647_get_sysclk(); + /* read preview HTS */ + prev_HTS = ov5647_get_HTS(); + + /* read preview VTS */ + prev_VTS = ov5647_get_VTS(); + + /* calculate banding filter */ + /* 60Hz */ + band_step60 = prev_sysclk * 100/prev_HTS * 100/120; + ov5647_write_reg(0x3a0a, (band_step60 >> 8)); + ov5647_write_reg(0x3a0b, (band_step60 & 0xff)); + + max_band60 = (int)((prev_VTS-4)/band_step60); + ov5647_write_reg(0x3a0d, max_band60); + + /* 50Hz */ + band_step50 = prev_sysclk * 100/prev_HTS; + ov5647_write_reg(0x3a08, (band_step50 >> 8)); + ov5647_write_reg(0x3a09, (band_step50 & 0xff)); + + max_band50 = (int)((prev_VTS-4)/band_step50); + ov5647_write_reg(0x3a0e, max_band50); +} + +static int ov5647_set_AE_target(int target) +{ + /* stable in high */ + int fast_high, fast_low; + AE_low = target * 23 / 25; /* 0.92 */ + AE_high = target * 27 / 25; /* 1.08 */ + + fast_high = AE_high<<1; + if (fast_high > 255) + fast_high = 255; + + fast_low = AE_low >> 1; + + ov5647_write_reg(0x3a0f, AE_high); + ov5647_write_reg(0x3a10, AE_low); + ov5647_write_reg(0x3a1b, AE_high); + ov5647_write_reg(0x3a1e, AE_low); + ov5647_write_reg(0x3a11, fast_high); + ov5647_write_reg(0x3a1f, fast_low); + + return 0; +} + +static void ov5647_turn_on_AE_AG(int enable) +{ + u8 ae_ag_ctrl; + + ov5647_read_reg(0x3503, &ae_ag_ctrl); + if (enable) { + /* turn on auto AE/AG */ + ae_ag_ctrl = ae_ag_ctrl & ~(0x03); + } else { + /* turn off AE/AG */ + ae_ag_ctrl = ae_ag_ctrl | 0x03; + } + ov5647_write_reg(0x3503, ae_ag_ctrl); +} + +static void ov5647_set_virtual_channel(int channel) +{ + u8 channel_id; + + ov5647_read_reg(0x4814, &channel_id); + channel_id &= ~(3 << 6); + ov5647_write_reg(0x4814, channel_id | (channel << 6)); +} + +/* download ov5647 settings to sensor through i2c */ +static int ov5647_download_firmware(struct reg_value *pModeSetting, s32 ArySize) +{ + register u32 Delay_ms = 0; + register u16 RegAddr = 0; + register u8 Mask = 0; + register u8 Val = 0; + u8 RegVal = 0; + int i, retval = 0; + + for (i = 0; i < ArySize; ++i, ++pModeSetting) { + Delay_ms = pModeSetting->u32Delay_ms; + RegAddr = pModeSetting->u16RegAddr; + Val = pModeSetting->u8Val; + Mask = pModeSetting->u8Mask; + + if (Mask) { + retval = ov5647_read_reg(RegAddr, &RegVal); + if (retval < 0) + goto err; + + RegVal &= ~(u8)Mask; + Val &= Mask; + Val |= RegVal; + } + + retval = ov5647_write_reg(RegAddr, Val); + if (retval < 0) + goto err; + + if (Delay_ms) + msleep(Delay_ms); + } +err: + return retval; +} + +/* sensor changes between scaling and subsampling + * go through exposure calcualtion + */ +static int ov5647_change_mode_exposure_calc(enum ov5647_frame_rate frame_rate, + enum ov5647_mode mode) +{ + struct reg_value *pModeSetting = NULL; + s32 ArySize = 0; + int pre_shutter, pre_gain16; + int cap_shutter, cap_gain16; + int pre_sysclk, pre_HTS; + int cap_sysclk, cap_HTS, cap_VTS; + long cap_gain16_shutter; + int retval = 0; + + /* check if the input mode and frame rate is valid */ + pModeSetting = + ov5647_mode_info_data[frame_rate][mode].init_data_ptr; + ArySize = + ov5647_mode_info_data[frame_rate][mode].init_data_size; + + ov5647_data.pix.width = + ov5647_mode_info_data[frame_rate][mode].width; + ov5647_data.pix.height = + ov5647_mode_info_data[frame_rate][mode].height; + + if (ov5647_data.pix.width == 0 || ov5647_data.pix.height == 0 || + pModeSetting == NULL || ArySize == 0) + return -EINVAL; + + ov5647_stream_off(); + + /* turn off night mode for capture */ + ov5647_set_night_mode(); + + pre_shutter = ov5647_get_shutter(); + pre_gain16 = ov5647_get_gain16(); + pre_HTS = ov5647_get_HTS(); + pre_sysclk = ov5647_get_sysclk(); + + /* Write capture setting */ + retval = ov5647_download_firmware(pModeSetting, ArySize); + if (retval < 0) + goto err; + + /* read capture VTS */ + cap_VTS = ov5647_get_VTS(); + cap_HTS = ov5647_get_HTS(); + cap_sysclk = ov5647_get_sysclk(); + + /* calculate capture shutter/gain16 */ + cap_shutter = pre_shutter * cap_sysclk/pre_sysclk * pre_HTS / cap_HTS; + + if (cap_shutter < 16) { + cap_gain16_shutter = pre_shutter * pre_gain16 * + cap_sysclk / pre_sysclk * pre_HTS / cap_HTS; + cap_shutter = ((int)(cap_gain16_shutter / 16)); + if (cap_shutter < 1) + cap_shutter = 1; + cap_gain16 = ((int)(cap_gain16_shutter / cap_shutter)); + if (cap_gain16 < 16) + cap_gain16 = 16; + } else + cap_gain16 = pre_gain16; + + /* gain to shutter */ + while ((cap_gain16 > 32) && + (cap_shutter < ((int)((cap_VTS - 4) / 2)))) { + cap_gain16 = cap_gain16 / 2; + cap_shutter = cap_shutter * 2; + } + /* write capture gain */ + ov5647_set_gain16(cap_gain16); + + /* write capture shutter */ + if (cap_shutter > (cap_VTS - 4)) { + cap_VTS = cap_shutter + 4; + ov5647_set_VTS(cap_VTS); + } + ov5647_set_shutter(cap_shutter); + + ov5647_stream_on(); + +err: + return retval; +} + +/* if sensor changes inside scaling or subsampling + * change mode directly + * */ +static int ov5647_change_mode_direct(enum ov5647_frame_rate frame_rate, + enum ov5647_mode mode) +{ + struct reg_value *pModeSetting = NULL; + s32 ArySize = 0; + int retval = 0; + + /* check if the input mode and frame rate is valid */ + pModeSetting = + ov5647_mode_info_data[frame_rate][mode].init_data_ptr; + ArySize = + ov5647_mode_info_data[frame_rate][mode].init_data_size; + + ov5647_data.pix.width = + ov5647_mode_info_data[frame_rate][mode].width; + ov5647_data.pix.height = + ov5647_mode_info_data[frame_rate][mode].height; + + if (ov5647_data.pix.width == 0 || ov5647_data.pix.height == 0 || + pModeSetting == NULL || ArySize == 0) + return -EINVAL; + + /* turn off AE/AG */ + ov5647_turn_on_AE_AG(0); + + ov5647_stream_off(); + + /* Write capture setting */ + retval = ov5647_download_firmware(pModeSetting, ArySize); + if (retval < 0) + goto err; + + ov5647_stream_on(); + + ov5647_turn_on_AE_AG(1); + +err: + return retval; +} + +static int ov5647_init_mode(enum ov5647_frame_rate frame_rate, + enum ov5647_mode mode, enum ov5647_mode orig_mode) +{ + struct reg_value *pModeSetting = NULL; + s32 ArySize = 0; + int retval = 0; + u32 msec_wait4stable = 0; + enum ov5647_downsize_mode dn_mode, orig_dn_mode; + + if ((mode > ov5647_mode_MAX || mode < ov5647_mode_MIN) + && (mode != ov5647_mode_INIT)) { + pr_err("Wrong ov5647 mode detected!\n"); + return -1; + } + + dn_mode = ov5647_mode_info_data[frame_rate][mode].dn_mode; + orig_dn_mode = ov5647_mode_info_data[frame_rate][orig_mode].dn_mode; + if (mode == ov5647_mode_INIT) { + pModeSetting = ov5647_init_setting; + ArySize = ARRAY_SIZE(ov5647_init_setting); + retval = ov5647_download_firmware(pModeSetting, ArySize); + if (retval < 0) + goto err; + pModeSetting = ov5647_setting_60fps_VGA_640_480; + ArySize = ARRAY_SIZE(ov5647_setting_60fps_VGA_640_480); + retval = ov5647_download_firmware(pModeSetting, ArySize); + + ov5647_data.pix.width = 640; + ov5647_data.pix.height = 480; + } else if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) || + (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) { + /* change between subsampling and scaling + * go through exposure calucation */ + retval = ov5647_change_mode_exposure_calc(frame_rate, mode); + } else { + /* change inside subsampling or scaling + * download firmware directly */ + retval = ov5647_change_mode_direct(frame_rate, mode); + } + + if (retval < 0) + goto err; + + ov5647_set_AE_target(AE_Target); + ov5647_get_light_freq(); + ov5647_set_bandingfilter(); + ov5647_set_virtual_channel(ov5647_data.csi); + + /* add delay to wait for sensor stable */ + if (mode == ov5647_mode_QSXGA_2592_1944) { + /* dump the first two frames: 1/7.5*2 + * the frame rate of QSXGA is 7.5fps */ + msec_wait4stable = 267; + } else if (frame_rate == ov5647_15_fps) { + /* dump the first nine frames: 1/15*9 */ + msec_wait4stable = 600; + } else if (frame_rate == ov5647_30_fps) { + /* dump the first nine frames: 1/30*9 */ + msec_wait4stable = 300; + } + msleep(msec_wait4stable); + +err: + return retval; +} + +/*! + * ov5647_s_power - V4L2 sensor interface handler for VIDIOC_S_POWER ioctl + * @s: pointer to standard V4L2 device structure + * @on: indicates power mode (on or off) + * + * Turns the power on or off, depending on the value of on and returns the + * appropriate error code. + */ +static int ov5647_s_power(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5647 *sensor = to_ov5647(client); + + if (on && !sensor->on) { + if (io_regulator) + if (regulator_enable(io_regulator) != 0) + return -EIO; + if (core_regulator) + if (regulator_enable(core_regulator) != 0) + return -EIO; + if (gpo_regulator) + if (regulator_enable(gpo_regulator) != 0) + return -EIO; + if (analog_regulator) + if (regulator_enable(analog_regulator) != 0) + return -EIO; + } else if (!on && sensor->on) { + if (analog_regulator) + regulator_disable(analog_regulator); + if (core_regulator) + regulator_disable(core_regulator); + if (io_regulator) + regulator_disable(io_regulator); + if (gpo_regulator) + regulator_disable(gpo_regulator); + } + + sensor->on = on; + + return 0; +} + +/*! + * ov5647_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl + * @s: pointer to standard V4L2 sub device structure + * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure + * + * Returns the sensor's video CAPTURE parameters. + */ +static int ov5647_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5647 *sensor = to_ov5647(client); + struct v4l2_captureparm *cparm = &a->parm.capture; + int ret = 0; + + switch (a->type) { + /* This is the only case currently handled. */ + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + memset(a, 0, sizeof(*a)); + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + cparm->capability = sensor->streamcap.capability; + cparm->timeperframe = sensor->streamcap.timeperframe; + cparm->capturemode = sensor->streamcap.capturemode; + ret = 0; + break; + + /* These are all the possible cases. */ + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + ret = -EINVAL; + break; + + default: + pr_debug(" type is unknown - %d\n", a->type); + ret = -EINVAL; + break; + } + + return ret; +} + +/*! + * ov5460_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl + * @s: pointer to standard V4L2 sub device structure + * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure + * + * Configures the sensor to use the input parameters, if possible. If + * not possible, reverts to the old parameters and returns the + * appropriate error code. + */ +static int ov5647_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5647 *sensor = to_ov5647(client); + struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe; + u32 tgt_fps; /* target frames per secound */ + enum ov5647_frame_rate frame_rate; + enum ov5647_mode orig_mode; + int ret = 0; + + /* Make sure power on */ + ov5647_power_down(0); + + switch (a->type) { + /* This is the only case currently handled. */ + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + /* Check that the new frame rate is allowed. */ + if ((timeperframe->numerator == 0) || + (timeperframe->denominator == 0)) { + timeperframe->denominator = DEFAULT_FPS; + timeperframe->numerator = 1; + } + + tgt_fps = timeperframe->denominator / + timeperframe->numerator; + + if (tgt_fps > MAX_FPS) { + timeperframe->denominator = MAX_FPS; + timeperframe->numerator = 1; + } else if (tgt_fps < MIN_FPS) { + timeperframe->denominator = MIN_FPS; + timeperframe->numerator = 1; + } + + /* Actual frame rate we use */ + tgt_fps = timeperframe->denominator / + timeperframe->numerator; + + if (tgt_fps == 15) + frame_rate = ov5647_15_fps; + else if (tgt_fps == 30) + frame_rate = ov5647_30_fps; + else { + pr_err(" The camera frame rate is not supported!\n"); + return -EINVAL; + } + + orig_mode = sensor->streamcap.capturemode; + ret = ov5647_init_mode(frame_rate, + (u32)a->parm.capture.capturemode, orig_mode); + if (ret < 0) + return ret; + + sensor->streamcap.timeperframe = *timeperframe; + sensor->streamcap.capturemode = + (u32)a->parm.capture.capturemode; + + break; + + /* These are all the possible cases. */ + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + pr_debug("type is not " \ + "V4L2_BUF_TYPE_VIDEO_CAPTURE but %d\n", + a->type); + ret = -EINVAL; + break; + + default: + pr_debug("type is unknown - %d\n", a->type); + ret = -EINVAL; + break; + } + + return ret; +} + +static int ov5647_try_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + const struct ov5647_datafmt *fmt = ov5647_find_datafmt(mf->code); + + if (!fmt) { + mf->code = ov5647_colour_fmts[0].code; + mf->colorspace = ov5647_colour_fmts[0].colorspace; + } + + mf->field = V4L2_FIELD_NONE; + + return 0; +} + +static int ov5647_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5647 *sensor = to_ov5647(client); + + /* MIPI CSI could have changed the format, double-check */ + if (!ov5647_find_datafmt(mf->code)) + return -EINVAL; + + ov5647_try_fmt(sd, mf); + sensor->fmt = ov5647_find_datafmt(mf->code); + + return 0; +} + +static int ov5647_g_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5647 *sensor = to_ov5647(client); + + const struct ov5647_datafmt *fmt = sensor->fmt; + + mf->code = fmt->code; + mf->colorspace = fmt->colorspace; + mf->field = V4L2_FIELD_NONE; + + return 0; +} + +static int ov5647_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + u32 *code) +{ + if (index >= ARRAY_SIZE(ov5647_colour_fmts)) + return -EINVAL; + + *code = ov5647_colour_fmts[index].code; + return 0; +} + +/*! + * ov5647_enum_framesizes - V4L2 sensor interface handler for + * VIDIOC_ENUM_FRAMESIZES ioctl + * @s: pointer to standard V4L2 device structure + * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure + * + * Return 0 if successful, otherwise -EINVAL. + */ +static int ov5647_enum_framesizes(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index > ov5647_mode_MAX) + return -EINVAL; + + fse->max_width = + max(ov5647_mode_info_data[0][fse->index].width, + ov5647_mode_info_data[1][fse->index].width); + fse->min_width = fse->max_width; + fse->max_height = + max(ov5647_mode_info_data[0][fse->index].height, + ov5647_mode_info_data[1][fse->index].height); + fse->min_height = fse->max_height; + return 0; +} + +/*! + * ov5647_enum_frameintervals - V4L2 sensor interface handler for + * VIDIOC_ENUM_FRAMEINTERVALS ioctl + * @s: pointer to standard V4L2 device structure + * @fival: standard V4L2 VIDIOC_ENUM_FRAMEINTERVALS ioctl structure + * + * Return 0 if successful, otherwise -EINVAL. + */ +static int ov5647_enum_frameintervals(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_interval_enum *fie) +{ + int i, j, count; + + if (fie->index < 0 || fie->index > ov5647_mode_MAX) + return -EINVAL; + + if (fie->width == 0 || fie->height == 0 || + fie->code == 0) { + pr_warning("Please assign pixel format, width and height.\n"); + return -EINVAL; + } + + fie->interval.numerator = 1; + + count = 0; + for (i = 0; i < ARRAY_SIZE(ov5647_mode_info_data); i++) { + for (j = 0; j < (ov5647_mode_MAX + 1); j++) { + if (fie->width == ov5647_mode_info_data[i][j].width + && fie->height == ov5647_mode_info_data[i][j].height + && ov5647_mode_info_data[i][j].init_data_ptr != NULL) { + count++; + } + if (fie->index == (count - 1)) { + fie->interval.denominator = + ov5647_framerates[i]; + return 0; + } + } + } + + return -EINVAL; +} + +/*! + * dev_init - V4L2 sensor init + * @s: pointer to standard V4L2 device structure + * + */ +static int init_device(void) +{ + u32 tgt_xclk; /* target xclk */ + u32 tgt_fps; /* target frames per secound */ + enum ov5647_frame_rate frame_rate; + int ret; + + ov5647_data.on = true; + + /* mclk */ + tgt_xclk = ov5647_data.mclk; + tgt_xclk = min(tgt_xclk, (u32)OV5647_XCLK_MAX); + tgt_xclk = max(tgt_xclk, (u32)OV5647_XCLK_MIN); + ov5647_data.mclk = tgt_xclk; + + pr_debug(" Setting mclk to %d MHz\n", tgt_xclk / 1000000); + + /* Default camera frame rate is set in probe */ + tgt_fps = ov5647_data.streamcap.timeperframe.denominator / + ov5647_data.streamcap.timeperframe.numerator; + + if (tgt_fps == 15) + frame_rate = ov5647_15_fps; + else if (tgt_fps == 30) + frame_rate = ov5647_30_fps; + else + return -EINVAL; /* Only support 15fps or 30fps now. */ + + ret = ov5647_init_mode(frame_rate, ov5647_mode_INIT, ov5647_mode_INIT); + + ov5647_update_otp(); + return ret; +} + +static struct v4l2_subdev_video_ops ov5647_subdev_video_ops = { + .g_parm = ov5647_g_parm, + .s_parm = ov5647_s_parm, + + .s_mbus_fmt = ov5647_s_fmt, + .g_mbus_fmt = ov5647_g_fmt, + .try_mbus_fmt = ov5647_try_fmt, + .enum_mbus_fmt = ov5647_enum_fmt, +}; + +static const struct v4l2_subdev_pad_ops ov5647_subdev_pad_ops = { + .enum_frame_size = ov5647_enum_framesizes, + .enum_frame_interval = ov5647_enum_frameintervals, +}; + +static struct v4l2_subdev_core_ops ov5647_subdev_core_ops = { + .s_power = ov5647_s_power, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = ov5647_get_register, + .s_register = ov5647_set_register, +#endif +}; + +static struct v4l2_subdev_ops ov5647_subdev_ops = { + .core = &ov5647_subdev_core_ops, + .video = &ov5647_subdev_video_ops, + .pad = &ov5647_subdev_pad_ops, +}; + + +/*! + * ov5647 I2C probe function + * + * @param adapter struct i2c_adapter * + * @return Error code indicating success or failure + */ +static int ov5647_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pinctrl *pinctrl; + struct device *dev = &client->dev; + int retval; + u8 chip_id_high, chip_id_low; + + /* ov5647 pinctrl */ + pinctrl = devm_pinctrl_get_select_default(dev); + if (IS_ERR(pinctrl)) { + dev_warn(dev, "no pin available\n"); + } + + + /* request power down pin */ + pwn_gpio = of_get_named_gpio(dev->of_node, "pwn-gpios", 0); + if (!gpio_is_valid(pwn_gpio)) { + dev_warn(dev, "no sensor pwdn pin available\n"); + pwn_gpio = -1; + } else { + retval = devm_gpio_request_one(dev, pwn_gpio, GPIOF_OUT_INIT_HIGH, + "ov5647_mipi_pwdn"); + if (retval < 0) { + dev_warn(dev, "Failed to set power pin\n"); + return retval; + } + } + + /* request reset pin */ + rst_gpio = of_get_named_gpio(dev->of_node, "rst-gpios", 0); + if (!gpio_is_valid(rst_gpio)) { + dev_warn(dev, "no sensor reset pin available\n"); + rst_gpio = -1; + } else { + retval = devm_gpio_request_one(dev, rst_gpio, GPIOF_OUT_INIT_HIGH, + "ov5647_mipi_reset"); + if (retval < 0) { + dev_warn(dev, "Failed to set reset pin\n"); + return retval; + } + } + + /* Set initial values for the sensor struct. */ + memset(&ov5647_data, 0, sizeof(ov5647_data)); + ov5647_data.sensor_clk = devm_clk_get(dev, "csi_mclk"); + if (IS_ERR(ov5647_data.sensor_clk)) { + /* assuming clock enabled by default */ + ov5647_data.sensor_clk = NULL; + dev_err(dev, "clock-frequency missing or invalid\n"); + return PTR_ERR(ov5647_data.sensor_clk); + } + + retval = of_property_read_u32(dev->of_node, "mclk", + &(ov5647_data.mclk)); + if (retval) { + dev_err(dev, "mclk missing or invalid\n"); + return retval; + } + + retval = of_property_read_u32(dev->of_node, "mclk_source", + (u32 *) &(ov5647_data.mclk_source)); + if (retval) { + dev_err(dev, "mclk_source missing or invalid\n"); + return retval; + } + + retval = of_property_read_u32(dev->of_node, "csi_id", + &(ov5647_data.csi)); + if (retval) { + dev_err(dev, "csi id missing or invalid\n"); + return retval; + } + + clk_prepare_enable(ov5647_data.sensor_clk); + + ov5647_data.io_init = ov5647_reset; + ov5647_data.i2c_client = client; + ov5647_data.pix.pixelformat = V4L2_PIX_FMT_SBGGR8; + ov5647_data.pix.width = 640; + ov5647_data.pix.height = 480; + ov5647_data.streamcap.capability = V4L2_MODE_HIGHQUALITY | + V4L2_CAP_TIMEPERFRAME; + ov5647_data.streamcap.capturemode = 0; + ov5647_data.streamcap.timeperframe.denominator = DEFAULT_FPS; + ov5647_data.streamcap.timeperframe.numerator = 1; + + ov5647_regulator_enable(&client->dev); + + ov5647_reset(); + + ov5647_power_down(0); + + retval = ov5647_read_reg(OV5647_CHIP_ID_HIGH_BYTE, &chip_id_high); + if (retval < 0 || chip_id_high != 0x56) { + pr_warning("camera ov5647_mipi is not found\n"); + clk_disable_unprepare(ov5647_data.sensor_clk); + return -ENODEV; + } + retval = ov5647_read_reg(OV5647_CHIP_ID_LOW_BYTE, &chip_id_low); + if (retval < 0 || chip_id_low != 0x47) { + pr_warning("camera ov5647_mipi is not found\n"); + clk_disable_unprepare(ov5647_data.sensor_clk); + return -ENODEV; + } + + retval = init_device(); + if (retval < 0) { + clk_disable_unprepare(ov5647_data.sensor_clk); + pr_warning("camera ov5647 init failed\n"); + ov5647_power_down(1); + return retval; + } + + v4l2_i2c_subdev_init(&ov5647_data.subdev, client, &ov5647_subdev_ops); + + ov5647_data.subdev.grp_id = 678; + retval = v4l2_async_register_subdev(&ov5647_data.subdev); + if (retval < 0) + dev_err(&client->dev, + "%s--Async register failed, ret=%d\n", __func__, retval); + + pr_info("camera ov5647_mipi is found\n"); + return retval; +} + +/*! + * ov5647 I2C detach function + * + * @param client struct i2c_client * + * @return Error code indicating success or failure + */ +static int ov5647_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + v4l2_async_unregister_subdev(sd); + + clk_disable_unprepare(ov5647_data.sensor_clk); + + ov5647_power_down(1); + + if (gpo_regulator) + regulator_disable(gpo_regulator); + + if (analog_regulator) + regulator_disable(analog_regulator); + + if (core_regulator) + regulator_disable(core_regulator); + + if (io_regulator) + regulator_disable(io_regulator); + + return 0; +} + +module_i2c_driver(ov5647_i2c_driver); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("OV5647 MIPI Camera Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("1.0"); +MODULE_ALIAS("CSI"); diff --git a/drivers/mxc/Kconfig b/drivers/mxc/Kconfig index 4d4c137dfc73..3dfa29bffdce 100644 --- a/drivers/mxc/Kconfig +++ b/drivers/mxc/Kconfig @@ -15,6 +15,7 @@ source "drivers/mxc/mlb/Kconfig" source "drivers/mxc/ipu3/Kconfig" source "drivers/mxc/gpu-viv/Kconfig" source "drivers/mxc/sim/Kconfig" +source "drivers/mxc/mipi/Kconfig" source "drivers/mxc/vpu/Kconfig" source "drivers/mxc/hdmi-cec/Kconfig" diff --git a/drivers/mxc/Makefile b/drivers/mxc/Makefile index e2ae1a010527..8374cfa5492a 100644 --- a/drivers/mxc/Makefile +++ b/drivers/mxc/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_MXC_VPU) += vpu/ obj-$(CONFIG_MXC_IPU_V3) += ipu3/ obj-$(CONFIG_MXC_HDMI_CEC) += hdmi-cec/ obj-$(CONFIG_MXC_GPU_VIV) += gpu-viv/ +obj-$(CONFIG_MXC_MIPI_CSI2) += mipi/ diff --git a/drivers/mxc/mipi/Kconfig b/drivers/mxc/mipi/Kconfig new file mode 100644 index 000000000000..a6a3c3306934 --- /dev/null +++ b/drivers/mxc/mipi/Kconfig @@ -0,0 +1,14 @@ +# +# MIPI configuration +# + +menu "MXC MIPI Support" + +config MXC_MIPI_CSI2 + tristate "MIPI CSI2 support" + depends on SOC_IMX6Q + default n + ---help--- + Say Y to get the MIPI CSI2 support. + +endmenu diff --git a/drivers/mxc/mipi/Makefile b/drivers/mxc/mipi/Makefile new file mode 100644 index 000000000000..98cda773bd28 --- /dev/null +++ b/drivers/mxc/mipi/Makefile @@ -0,0 +1,4 @@ +# +# Makefile for the mipi interface driver +# +obj-$(CONFIG_MXC_MIPI_CSI2) += mxc_mipi_csi2.o diff --git a/drivers/mxc/mipi/mxc_mipi_csi2.c b/drivers/mxc/mipi/mxc_mipi_csi2.c new file mode 100644 index 000000000000..df45c364f144 --- /dev/null +++ b/drivers/mxc/mipi/mxc_mipi_csi2.c @@ -0,0 +1,540 @@ +/* + * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "mxc_mipi_csi2.h" + +static struct mipi_csi2_info *gmipi_csi2; + +void _mipi_csi2_lock(struct mipi_csi2_info *info) +{ + if (!in_irq() && !in_softirq()) + mutex_lock(&info->mutex_lock); +} + +void _mipi_csi2_unlock(struct mipi_csi2_info *info) +{ + if (!in_irq() && !in_softirq()) + mutex_unlock(&info->mutex_lock); +} + +static inline void mipi_csi2_write(struct mipi_csi2_info *info, + unsigned value, unsigned offset) +{ + writel(value, info->mipi_csi2_base + offset); +} + +static inline unsigned int mipi_csi2_read(struct mipi_csi2_info *info, + unsigned offset) +{ + return readl(info->mipi_csi2_base + offset); +} + +/*! + * This function is called to enable the mipi csi2 interface. + * + * @param info mipi csi2 hander + * @return Returns setted value + */ +bool mipi_csi2_enable(struct mipi_csi2_info *info) +{ + bool status; + + _mipi_csi2_lock(info); + + if (!info->mipi_en) { + info->mipi_en = true; + clk_prepare_enable(info->cfg_clk); + clk_prepare_enable(info->dphy_clk); + } else + mipi_dbg("mipi csi2 already enabled!\n"); + + status = info->mipi_en; + + _mipi_csi2_unlock(info); + + return status; +} +EXPORT_SYMBOL(mipi_csi2_enable); + +/*! + * This function is called to disable the mipi csi2 interface. + * + * @param info mipi csi2 hander + * @return Returns setted value + */ +bool mipi_csi2_disable(struct mipi_csi2_info *info) +{ + bool status; + + _mipi_csi2_lock(info); + + if (info->mipi_en) { + info->mipi_en = false; + clk_disable_unprepare(info->dphy_clk); + clk_disable_unprepare(info->cfg_clk); + } else + mipi_dbg("mipi csi2 already disabled!\n"); + + status = info->mipi_en; + + _mipi_csi2_unlock(info); + + return status; +} +EXPORT_SYMBOL(mipi_csi2_disable); + +/*! + * This function is called to get mipi csi2 disable/enable status. + * + * @param info mipi csi2 hander + * @return Returns mipi csi2 status + */ +bool mipi_csi2_get_status(struct mipi_csi2_info *info) +{ + bool status; + + _mipi_csi2_lock(info); + status = info->mipi_en; + _mipi_csi2_unlock(info); + + return status; +} +EXPORT_SYMBOL(mipi_csi2_get_status); + +/*! + * This function is called to set mipi lanes. + * + * @param info mipi csi2 hander + * @return Returns setted value + */ +unsigned int mipi_csi2_set_lanes(struct mipi_csi2_info *info) +{ + unsigned int lanes; + + _mipi_csi2_lock(info); + mipi_csi2_write(info, info->lanes - 1, MIPI_CSI2_N_LANES); + lanes = mipi_csi2_read(info, MIPI_CSI2_N_LANES); + _mipi_csi2_unlock(info); + + return lanes; +} +EXPORT_SYMBOL(mipi_csi2_set_lanes); + +/*! + * This function is called to set mipi data type. + * + * @param info mipi csi2 hander + * @return Returns setted value + */ +unsigned int mipi_csi2_set_datatype(struct mipi_csi2_info *info, + unsigned int datatype) +{ + unsigned int dtype; + + _mipi_csi2_lock(info); + info->datatype = datatype; + dtype = info->datatype; + _mipi_csi2_unlock(info); + + return dtype; +} +EXPORT_SYMBOL(mipi_csi2_set_datatype); + +/*! + * This function is called to get mipi data type. + * + * @param info mipi csi2 hander + * @return Returns mipi data type + */ +unsigned int mipi_csi2_get_datatype(struct mipi_csi2_info *info) +{ + unsigned int dtype; + + _mipi_csi2_lock(info); + dtype = info->datatype; + _mipi_csi2_unlock(info); + + return dtype; +} +EXPORT_SYMBOL(mipi_csi2_get_datatype); + +/*! + * This function is called to get mipi csi2 dphy status. + * + * @param info mipi csi2 hander + * @return Returns dphy status + */ +unsigned int mipi_csi2_dphy_status(struct mipi_csi2_info *info) +{ + unsigned int status; + + _mipi_csi2_lock(info); + status = mipi_csi2_read(info, MIPI_CSI2_PHY_STATE); + _mipi_csi2_unlock(info); + + return status; +} +EXPORT_SYMBOL(mipi_csi2_dphy_status); + +/*! + * This function is called to get mipi csi2 error1 status. + * + * @param info mipi csi2 hander + * @return Returns error1 value + */ +unsigned int mipi_csi2_get_error1(struct mipi_csi2_info *info) +{ + unsigned int err1; + + _mipi_csi2_lock(info); + err1 = mipi_csi2_read(info, MIPI_CSI2_ERR1); + _mipi_csi2_unlock(info); + + return err1; +} +EXPORT_SYMBOL(mipi_csi2_get_error1); + +/*! + * This function is called to get mipi csi2 error1 status. + * + * @param info mipi csi2 hander + * @return Returns error1 value + */ +unsigned int mipi_csi2_get_error2(struct mipi_csi2_info *info) +{ + unsigned int err2; + + _mipi_csi2_lock(info); + err2 = mipi_csi2_read(info, MIPI_CSI2_ERR2); + _mipi_csi2_unlock(info); + + return err2; +} +EXPORT_SYMBOL(mipi_csi2_get_error2); + +/*! + * This function is called to enable mipi to ipu pixel clock. + * + * @param info mipi csi2 hander + * @return Returns 0 on success or negative error code on fail + */ +int mipi_csi2_pixelclk_enable(struct mipi_csi2_info *info) +{ + return clk_prepare_enable(info->pixel_clk); +} +EXPORT_SYMBOL(mipi_csi2_pixelclk_enable); + +/*! + * This function is called to disable mipi to ipu pixel clock. + * + * @param info mipi csi2 hander + * @return Returns 0 on success or negative error code on fail + */ +void mipi_csi2_pixelclk_disable(struct mipi_csi2_info *info) +{ + clk_disable_unprepare(info->pixel_clk); +} +EXPORT_SYMBOL(mipi_csi2_pixelclk_disable); + +/*! + * This function is called to power on mipi csi2. + * + * @param info mipi csi2 hander + * @return Returns 0 on success or negative error code on fail + */ +int mipi_csi2_reset(struct mipi_csi2_info *info) +{ + _mipi_csi2_lock(info); + + mipi_csi2_write(info, 0x0, MIPI_CSI2_PHY_SHUTDOWNZ); + mipi_csi2_write(info, 0x0, MIPI_CSI2_DPHY_RSTZ); + mipi_csi2_write(info, 0x0, MIPI_CSI2_CSI2_RESETN); + + mipi_csi2_write(info, 0x00000001, MIPI_CSI2_PHY_TST_CTRL0); + mipi_csi2_write(info, 0x00000000, MIPI_CSI2_PHY_TST_CTRL1); + mipi_csi2_write(info, 0x00000000, MIPI_CSI2_PHY_TST_CTRL0); + mipi_csi2_write(info, 0x00000002, MIPI_CSI2_PHY_TST_CTRL0); + mipi_csi2_write(info, 0x00010044, MIPI_CSI2_PHY_TST_CTRL1); + mipi_csi2_write(info, 0x00000000, MIPI_CSI2_PHY_TST_CTRL0); + mipi_csi2_write(info, 0x00000014, MIPI_CSI2_PHY_TST_CTRL1); + mipi_csi2_write(info, 0x00000002, MIPI_CSI2_PHY_TST_CTRL0); + mipi_csi2_write(info, 0x00000000, MIPI_CSI2_PHY_TST_CTRL0); + + mipi_csi2_write(info, 0xffffffff, MIPI_CSI2_PHY_SHUTDOWNZ); + mipi_csi2_write(info, 0xffffffff, MIPI_CSI2_DPHY_RSTZ); + mipi_csi2_write(info, 0xffffffff, MIPI_CSI2_CSI2_RESETN); + + _mipi_csi2_unlock(info); + + return 0; +} +EXPORT_SYMBOL(mipi_csi2_reset); + +/*! + * This function is called to get mipi csi2 info. + * + * @return Returns mipi csi2 info struct pointor + */ +struct mipi_csi2_info *mipi_csi2_get_info(void) +{ + return gmipi_csi2; +} +EXPORT_SYMBOL(mipi_csi2_get_info); + +/*! + * This function is called to get mipi csi2 bind ipu num. + * + * @return Returns mipi csi2 bind ipu num + */ +int mipi_csi2_get_bind_ipu(struct mipi_csi2_info *info) +{ + int ipu_id; + + _mipi_csi2_lock(info); + ipu_id = info->ipu_id; + _mipi_csi2_unlock(info); + + return ipu_id; +} +EXPORT_SYMBOL(mipi_csi2_get_bind_ipu); + +/*! + * This function is called to get mipi csi2 bind csi num. + * + * @return Returns mipi csi2 bind csi num + */ +unsigned int mipi_csi2_get_bind_csi(struct mipi_csi2_info *info) +{ + unsigned int csi_id; + + _mipi_csi2_lock(info); + csi_id = info->csi_id; + _mipi_csi2_unlock(info); + + return csi_id; +} +EXPORT_SYMBOL(mipi_csi2_get_bind_csi); + +/*! + * This function is called to get mipi csi2 virtual channel. + * + * @return Returns mipi csi2 virtual channel num + */ +unsigned int mipi_csi2_get_virtual_channel(struct mipi_csi2_info *info) +{ + unsigned int v_channel; + + _mipi_csi2_lock(info); + v_channel = info->v_channel; + _mipi_csi2_unlock(info); + + return v_channel; +} +EXPORT_SYMBOL(mipi_csi2_get_virtual_channel); + +/** + * This function is called by the driver framework to initialize the MIPI CSI2 + * device. + * + * @param pdev The device structure for the MIPI CSI2 passed in by the + * driver framework. + * + * @return Returns 0 on success or negative error code on error + */ +static int mipi_csi2_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = pdev->dev.of_node; + struct resource *res; + u32 mipi_csi2_dphy_ver; + int ret; + + gmipi_csi2 = kmalloc(sizeof(struct mipi_csi2_info), GFP_KERNEL); + if (!gmipi_csi2) { + ret = -ENOMEM; + goto alloc_failed; + } + + ret = of_property_read_u32(np, "ipu_id", &(gmipi_csi2->ipu_id)); + if (ret) { + dev_err(&pdev->dev, "ipu_id missing or invalid\n"); + goto err; + } + + ret = of_property_read_u32(np, "csi_id", &(gmipi_csi2->csi_id)); + if (ret) { + dev_err(&pdev->dev, "csi_id missing or invalid\n"); + goto err; + } + + ret = of_property_read_u32(np, "v_channel", &(gmipi_csi2->v_channel)); + if (ret) { + dev_err(&pdev->dev, "v_channel missing or invalid\n"); + goto err; + } + + ret = of_property_read_u32(np, "lanes", &(gmipi_csi2->lanes)); + if (ret) { + dev_err(&pdev->dev, "lanes missing or invalid\n"); + goto err; + } + + if ((gmipi_csi2->ipu_id < 0) || (gmipi_csi2->ipu_id > 1) || + (gmipi_csi2->csi_id > 1) || (gmipi_csi2->v_channel > 3) || + (gmipi_csi2->lanes > 4)) { + dev_err(&pdev->dev, "invalid param for mipi csi2!\n"); + ret = -EINVAL; + goto err; + } + + /* initialize mutex */ + mutex_init(&gmipi_csi2->mutex_lock); + + /* get mipi csi2 informaiton */ + gmipi_csi2->pdev = pdev; + gmipi_csi2->mipi_en = false; + + gmipi_csi2->cfg_clk = devm_clk_get(dev, "cfg_clk"); + if (IS_ERR(gmipi_csi2->cfg_clk)) { + dev_err(&pdev->dev, "failed to get cfg_clk\n"); + ret = PTR_ERR(gmipi_csi2->cfg_clk); + goto err; + } + + /* get mipi dphy clk */ + gmipi_csi2->dphy_clk = devm_clk_get(dev, "dphy_clk"); + if (IS_ERR(gmipi_csi2->dphy_clk)) { + dev_err(&pdev->dev, "failed to get dphy pll_ref_clk\n"); + ret = PTR_ERR(gmipi_csi2->dphy_clk); + goto err; + } + + /* get mipi to ipu pixel clk */ + gmipi_csi2->pixel_clk = devm_clk_get(dev, "pixel_clk"); + if (IS_ERR(gmipi_csi2->pixel_clk)) { + dev_err(&pdev->dev, "failed to get mipi pixel clk\n"); + ret = PTR_ERR(gmipi_csi2->pixel_clk); + goto err; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + ret = -ENODEV; + goto err; + } + + /* mipi register mapping */ + gmipi_csi2->mipi_csi2_base = ioremap(res->start, PAGE_SIZE); + if (!gmipi_csi2->mipi_csi2_base) { + ret = -ENOMEM; + goto err; + } + + /* mipi dphy clk enable for register access */ + clk_prepare_enable(gmipi_csi2->dphy_clk); + /* get mipi csi2 dphy version */ + mipi_csi2_dphy_ver = mipi_csi2_read(gmipi_csi2, MIPI_CSI2_VERSION); + + clk_disable_unprepare(gmipi_csi2->dphy_clk); + + platform_set_drvdata(pdev, gmipi_csi2); + + dev_info(&pdev->dev, "i.MX MIPI CSI2 driver probed\n"); + dev_info(&pdev->dev, "i.MX MIPI CSI2 dphy version is 0x%x\n", + mipi_csi2_dphy_ver); + + return 0; + +err: + kfree(gmipi_csi2); +alloc_failed: + dev_err(&pdev->dev, "i.MX MIPI CSI2 driver probed - error\n"); + return ret; +} + +static int mipi_csi2_remove(struct platform_device *pdev) +{ + /* unmapping mipi register */ + iounmap(gmipi_csi2->mipi_csi2_base); + + kfree(gmipi_csi2); + + dev_set_drvdata(&pdev->dev, NULL); + + return 0; +} + +static const struct of_device_id imx_mipi_csi2_dt_ids[] = { + { .compatible = "fsl,imx6q-mipi-csi2", }, + { /* sentinel */ } +}; + +static struct platform_driver mipi_csi2_driver = { + .driver = { + .name = "mxc_mipi_csi2", + .of_match_table = imx_mipi_csi2_dt_ids, + }, + .probe = mipi_csi2_probe, + .remove = mipi_csi2_remove, +}; + +static int __init mipi_csi2_init(void) +{ + int err; + + err = platform_driver_register(&mipi_csi2_driver); + if (err) { + pr_err("mipi_csi2_driver register failed\n"); + return -ENODEV; + } + + pr_info("MIPI CSI2 driver module loaded\n"); + + return 0; +} + +static void __exit mipi_csi2_cleanup(void) +{ + platform_driver_unregister(&mipi_csi2_driver); +} + +subsys_initcall(mipi_csi2_init); +module_exit(mipi_csi2_cleanup); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("i.MX MIPI CSI2 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mxc/mipi/mxc_mipi_csi2.h b/drivers/mxc/mipi/mxc_mipi_csi2.h new file mode 100644 index 000000000000..291d7e891e09 --- /dev/null +++ b/drivers/mxc/mipi/mxc_mipi_csi2.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __MXC_MIPI_CSI2_H__ +#define __MXC_MIPI_CSI2_H__ + +#ifdef DEBUG +#define mipi_dbg(fmt, ...) \ + printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) +#else +#define mipi_dbg(fmt, ...) +#endif + +/* driver private data */ +struct mipi_csi2_info { + bool mipi_en; + int ipu_id; + unsigned int csi_id; + unsigned int v_channel; + unsigned int lanes; + unsigned int datatype; + struct clk *cfg_clk; + struct clk *dphy_clk; + struct clk *pixel_clk; + void __iomem *mipi_csi2_base; + struct platform_device *pdev; + + struct mutex mutex_lock; +}; + +#endif diff --git a/include/linux/mipi_csi2.h b/include/linux/mipi_csi2.h new file mode 100644 index 000000000000..7dc76fd293f8 --- /dev/null +++ b/include/linux/mipi_csi2.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __INCLUDE_MIPI_CSI2_H +#define __INCLUDE_MIPI_CSI2_H + +/* MIPI CSI2 registers */ +#define MIPI_CSI2_REG(offset) (offset) + +#define MIPI_CSI2_VERSION MIPI_CSI2_REG(0x000) +#define MIPI_CSI2_N_LANES MIPI_CSI2_REG(0x004) +#define MIPI_CSI2_PHY_SHUTDOWNZ MIPI_CSI2_REG(0x008) +#define MIPI_CSI2_DPHY_RSTZ MIPI_CSI2_REG(0x00c) +#define MIPI_CSI2_CSI2_RESETN MIPI_CSI2_REG(0x010) +#define MIPI_CSI2_PHY_STATE MIPI_CSI2_REG(0x014) +#define MIPI_CSI2_DATA_IDS_1 MIPI_CSI2_REG(0x018) +#define MIPI_CSI2_DATA_IDS_2 MIPI_CSI2_REG(0x01c) +#define MIPI_CSI2_ERR1 MIPI_CSI2_REG(0x020) +#define MIPI_CSI2_ERR2 MIPI_CSI2_REG(0x024) +#define MIPI_CSI2_MASK1 MIPI_CSI2_REG(0x028) +#define MIPI_CSI2_MASK2 MIPI_CSI2_REG(0x02c) +#define MIPI_CSI2_PHY_TST_CTRL0 MIPI_CSI2_REG(0x030) +#define MIPI_CSI2_PHY_TST_CTRL1 MIPI_CSI2_REG(0x034) +#define MIPI_CSI2_SFT_RESET MIPI_CSI2_REG(0xf00) + +/* mipi data type */ +#define MIPI_DT_YUV420 0x18 /* YYY.../UYVY.... */ +#define MIPI_DT_YUV420_LEGACY 0x1a /* UYY.../VYY... */ +#define MIPI_DT_YUV422 0x1e /* UYVY... */ +#define MIPI_DT_RGB444 0x20 +#define MIPI_DT_RGB555 0x21 +#define MIPI_DT_RGB565 0x22 +#define MIPI_DT_RGB666 0x23 +#define MIPI_DT_RGB888 0x24 +#define MIPI_DT_RAW6 0x28 +#define MIPI_DT_RAW7 0x29 +#define MIPI_DT_RAW8 0x2a +#define MIPI_DT_RAW10 0x2b +#define MIPI_DT_RAW12 0x2c +#define MIPI_DT_RAW14 0x2d + + +struct mipi_csi2_info; +/* mipi csi2 API */ +struct mipi_csi2_info *mipi_csi2_get_info(void); + +bool mipi_csi2_enable(struct mipi_csi2_info *info); + +bool mipi_csi2_disable(struct mipi_csi2_info *info); + +bool mipi_csi2_get_status(struct mipi_csi2_info *info); + +int mipi_csi2_get_bind_ipu(struct mipi_csi2_info *info); + +unsigned int mipi_csi2_get_bind_csi(struct mipi_csi2_info *info); + +unsigned int mipi_csi2_get_virtual_channel(struct mipi_csi2_info *info); + +unsigned int mipi_csi2_set_lanes(struct mipi_csi2_info *info); + +unsigned int mipi_csi2_set_datatype(struct mipi_csi2_info *info, + unsigned int datatype); + +unsigned int mipi_csi2_get_datatype(struct mipi_csi2_info *info); + +unsigned int mipi_csi2_dphy_status(struct mipi_csi2_info *info); + +unsigned int mipi_csi2_get_error1(struct mipi_csi2_info *info); + +unsigned int mipi_csi2_get_error2(struct mipi_csi2_info *info); + +int mipi_csi2_pixelclk_enable(struct mipi_csi2_info *info); + +void mipi_csi2_pixelclk_disable(struct mipi_csi2_info *info); + +int mipi_csi2_reset(struct mipi_csi2_info *info); + +#endif diff --git a/include/uapi/linux/mxc_v4l2.h b/include/uapi/linux/mxc_v4l2.h index 5049eee461b4..f261b925a7ed 100644 --- a/include/uapi/linux/mxc_v4l2.h +++ b/include/uapi/linux/mxc_v4l2.h @@ -53,6 +53,11 @@ struct v4l2_mxc_offset { uint32_t v_offset; }; +struct v4l2_mxc_dest_crop { + __u32 type; /* enum v4l2_buf_type */ + struct v4l2_mxc_offset offset; +}; + /* * Private IOCTLs * @@ -63,5 +68,6 @@ struct v4l2_mxc_offset { _IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct v4l2_crop) #define VIDIOC_G_INPUT_CROP \ _IOWR('V', BASE_VIDIOC_PRIVATE + 2, struct v4l2_crop) - +#define VIDIOC_S_DEST_CROP \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 3, struct v4l2_mxc_dest_crop) #endif