linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/43] i.MX6 Video capture
@ 2014-06-07 21:56 Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 01/43] imx-drm: ipu-v3: Move imx-ipu-v3.h to include/linux/platform_data/ Steve Longerbeam
                   ` (44 more replies)
  0 siblings, 45 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Hi all,

This patch set adds video capture support for the Freescale i.MX6 SOC.

It is a from-scratch standardized driver that works with community
v4l2 utilities, such as v4l2-ctl, v4l2-cap, and the v4l2src gstreamer
plugin. It uses the latest v4l2 interfaces (subdev, videobuf2).
Please see Documentation/video4linux/mx6_camera.txt for it's full list
of features!

The first 38 patches:

- prepare the ipu-v3 driver for video capture support. The current driver
  contains only video display functionality to support the imx DRM drivers.
  At some point ipu-v3 should be moved out from under staging/imx-drm since
  it will no longer only support DRM.

- Adds the device tree nodes and OF graph bindings for video capture support
  on sabrelite, sabresd, and sabreauto reference platforms.

The new i.MX6 capture host interface driver is at patch 39.

To support the sensors found on the sabrelite, sabresd, and sabreauto,
three patches add sensor subdev's for parallel OV5642, MIPI CSI-2 OV5640,
and the ADV7180 decoder chip, beginning at patch 40.

There is an existing adv7180 subdev driver under drivers/media/i2c, but
it needs some extra functionality to work on the sabreauto. It will need
OF graph bindings support and gpio for a power-on pin on the sabreauto.
It would also need to send a new subdev notification to take advantage
of decoder status change handling provided by the host driver. This
feature makes it possible to correctly handle "hot" (while streaming)
signal lock/unlock and autodetected video standard changes.

Usage notes are found in Documentation/video4linux/mx6_camera.txt for the
above three reference platforms.

The driver source is under drivers/staging/media/imx6/capture/.


Steve Longerbeam (43):
  imx-drm: ipu-v3: Move imx-ipu-v3.h to include/linux/platform_data/
  ARM: dts: imx6qdl: Add ipu aliases
  imx-drm: ipu-v3: Add ipu_get_num()
  imx-drm: ipu-v3: Add solo/dual-lite IPU device type
  imx-drm: ipu-v3: Map IOMUXC registers
  imx-drm: ipu-v3: Add functions to set CSI/IC source muxes
  imx-drm: ipu-v3: Rename and add IDMAC channels
  imx-drm: ipu-v3: Add units required for video capture
  imx-drm: ipu-v3: Add ipu_mbus_code_to_colorspace()
  imx-drm: ipu-v3: Add rotation mode conversion utilities
  imx-drm: ipu-v3: Add helper function checking if pixfmt is planar
  imx-drm: ipu-v3: Move IDMAC channel names to imx-ipu-v3.h
  imx-drm: ipu-v3: Add ipu_idmac_buffer_is_ready()
  imx-drm: ipu-v3: Add ipu_idmac_clear_buffer()
  imx-drm: ipu-v3: Add ipu_idmac_current_buffer()
  imx-drm: ipu-v3: Add __ipu_idmac_reset_current_buffer()
  imx-drm: ipu-v3: Add ipu_stride_to_bytes()
  imx-drm: ipu-v3: Add ipu_idmac_enable_watermark()
  imx-drm: ipu-v3: Add ipu_idmac_lock_enable()
  imx-drm: ipu-v3: Add idmac channel linking support
  imx-drm: ipu-v3: Add ipu_bits_per_pixel()
  imx-drm: ipu-v3: Add ipu-cpmem unit
  imx-drm: ipu-cpmem: Add ipu_cpmem_set_block_mode()
  imx-drm: ipu-cpmem: Add ipu_cpmem_set_axi_id()
  imx-drm: ipu-cpmem: Add ipu_cpmem_set_rotation()
  imx-drm: ipu-cpmem: Add second buffer support to ipu_cpmem_set_image()
  imx-drm: ipu-v3: Add more planar formats support
  imx-drm: ipu-cpmem: Add ipu_cpmem_dump()
  imx-drm: ipu-v3: Add ipu_dump()
  ARM: dts: imx6: add pin groups for imx6q/dl for IPU1 CSI0
  ARM: dts: imx6qdl: Flesh out MIPI CSI2 receiver node
  ARM: dts: imx: sabrelite: add video capture ports and endpoints
  ARM: dts: imx6-sabresd: add video capture ports and endpoints
  ARM: dts: imx6-sabreauto: add video capture ports and endpoints
  ARM: dts: imx6qdl: Add simple-bus to ipu compatibility
  gpio: pca953x: Add reset-gpios property
  ARM: imx6q: clk: Add video 27m clock
  media: imx6: Add device tree binding documentation
  media: Add new camera interface driver for i.MX6
  media: imx6: Add support for MIPI CSI-2 OV5640
  media: imx6: Add support for Parallel OV5642
  media: imx6: Add support for ADV7180 Video Decoder
  ARM: imx_v6_v7_defconfig: Enable video4linux drivers

 .../devicetree/bindings/clock/imx6q-clock.txt      |    1 +
 Documentation/devicetree/bindings/media/imx6.txt   |  433 ++
 .../bindings/staging/imx-drm/fsl-imx-drm.txt       |    6 +-
 .../devicetree/bindings/vendor-prefixes.txt        |    1 +
 Documentation/video4linux/mx6_camera.txt           |  188 +
 arch/arm/boot/dts/imx6q.dtsi                       |    3 +-
 arch/arm/boot/dts/imx6qdl-sabreauto.dtsi           |  149 +
 arch/arm/boot/dts/imx6qdl-sabrelite.dtsi           |   91 +
 arch/arm/boot/dts/imx6qdl-sabresd.dtsi             |  116 +
 arch/arm/boot/dts/imx6qdl.dtsi                     |   62 +-
 arch/arm/configs/imx_v6_v7_defconfig               |    4 +
 arch/arm/mach-imx/clk-imx6q.c                      |    3 +-
 drivers/gpio/gpio-pca953x.c                        |   26 +
 drivers/staging/imx-drm/imx-hdmi.c                 |    2 +-
 drivers/staging/imx-drm/imx-tve.c                  |    2 +-
 drivers/staging/imx-drm/ipu-v3/Makefile            |    3 +-
 drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h        |  326 --
 drivers/staging/imx-drm/ipu-v3/ipu-common.c        | 1151 ++++--
 drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c         |  814 ++++
 drivers/staging/imx-drm/ipu-v3/ipu-csi.c           |  821 ++++
 drivers/staging/imx-drm/ipu-v3/ipu-dc.c            |    2 +-
 drivers/staging/imx-drm/ipu-v3/ipu-di.c            |    2 +-
 drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c          |    2 +-
 drivers/staging/imx-drm/ipu-v3/ipu-dp.c            |    2 +-
 drivers/staging/imx-drm/ipu-v3/ipu-ic.c            |  835 ++++
 drivers/staging/imx-drm/ipu-v3/ipu-irt.c           |  103 +
 drivers/staging/imx-drm/ipu-v3/ipu-prv.h           |  126 +-
 drivers/staging/imx-drm/ipu-v3/ipu-smfc.c          |  348 ++
 drivers/staging/imx-drm/ipuv3-crtc.c               |    2 +-
 drivers/staging/imx-drm/ipuv3-plane.c              |   18 +-
 drivers/staging/media/Kconfig                      |    2 +
 drivers/staging/media/Makefile                     |    1 +
 drivers/staging/media/imx6/Kconfig                 |   25 +
 drivers/staging/media/imx6/Makefile                |    1 +
 drivers/staging/media/imx6/capture/Kconfig         |   33 +
 drivers/staging/media/imx6/capture/Makefile        |    7 +
 drivers/staging/media/imx6/capture/adv7180.c       | 1298 ++++++
 drivers/staging/media/imx6/capture/mipi-csi2.c     |  322 ++
 drivers/staging/media/imx6/capture/mx6-camif.c     | 2235 ++++++++++
 drivers/staging/media/imx6/capture/mx6-camif.h     |  197 +
 drivers/staging/media/imx6/capture/mx6-encode.c    |  775 ++++
 drivers/staging/media/imx6/capture/mx6-preview.c   |  748 ++++
 drivers/staging/media/imx6/capture/ov5640-mipi.c   | 2158 ++++++++++
 drivers/staging/media/imx6/capture/ov5642.c        | 4258 ++++++++++++++++++++
 include/linux/platform_data/imx-ipu-v3.h           |  425 ++
 include/media/imx6.h                               |   18 +
 46 files changed, 17340 insertions(+), 805 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/media/imx6.txt
 create mode 100644 Documentation/video4linux/mx6_camera.txt
 delete mode 100644 drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
 create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c
 create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-csi.c
 create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-ic.c
 create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-irt.c
 create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-smfc.c
 create mode 100644 drivers/staging/media/imx6/Kconfig
 create mode 100644 drivers/staging/media/imx6/Makefile
 create mode 100644 drivers/staging/media/imx6/capture/Kconfig
 create mode 100644 drivers/staging/media/imx6/capture/Makefile
 create mode 100644 drivers/staging/media/imx6/capture/adv7180.c
 create mode 100644 drivers/staging/media/imx6/capture/mipi-csi2.c
 create mode 100644 drivers/staging/media/imx6/capture/mx6-camif.c
 create mode 100644 drivers/staging/media/imx6/capture/mx6-camif.h
 create mode 100644 drivers/staging/media/imx6/capture/mx6-encode.c
 create mode 100644 drivers/staging/media/imx6/capture/mx6-preview.c
 create mode 100644 drivers/staging/media/imx6/capture/ov5640-mipi.c
 create mode 100644 drivers/staging/media/imx6/capture/ov5642.c
 create mode 100644 include/linux/platform_data/imx-ipu-v3.h
 create mode 100644 include/media/imx6.h

-- 
1.7.9.5


^ permalink raw reply	[flat|nested] 79+ messages in thread

* [PATCH 01/43] imx-drm: ipu-v3: Move imx-ipu-v3.h to include/linux/platform_data/
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-11 11:22   ` Philipp Zabel
  2014-06-07 21:56 ` [PATCH 02/43] ARM: dts: imx6qdl: Add ipu aliases Steve Longerbeam
                   ` (43 subsequent siblings)
  44 siblings, 1 reply; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

In subsequent patches, the video capture units will be added (csi, smfc,
ic, irt). So the IPU prototypes are no longer needed only by imx-drm,
so we need to export them to a common include path.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/imx-hdmi.c                 |    2 +-
 drivers/staging/imx-drm/imx-tve.c                  |    2 +-
 drivers/staging/imx-drm/ipu-v3/ipu-common.c        |    2 +-
 drivers/staging/imx-drm/ipu-v3/ipu-dc.c            |    2 +-
 drivers/staging/imx-drm/ipu-v3/ipu-di.c            |    2 +-
 drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c          |    2 +-
 drivers/staging/imx-drm/ipu-v3/ipu-dp.c            |    2 +-
 drivers/staging/imx-drm/ipu-v3/ipu-prv.h           |    2 +-
 drivers/staging/imx-drm/ipuv3-crtc.c               |    2 +-
 drivers/staging/imx-drm/ipuv3-plane.c              |    2 +-
 .../linux/platform_data}/imx-ipu-v3.h              |    9 +++++----
 11 files changed, 15 insertions(+), 14 deletions(-)
 rename {drivers/staging/imx-drm/ipu-v3 => include/linux/platform_data}/imx-ipu-v3.h (99%)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index d47dedd..f0710a4 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -28,7 +28,7 @@
 #include <drm/drm_edid.h>
 #include <drm/drm_encoder_slave.h>
 
-#include "ipu-v3/imx-ipu-v3.h"
+#include <linux/platform_data/imx-ipu-v3.h>
 #include "imx-hdmi.h"
 #include "imx-drm.h"
 
diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c
index a23f4f7..8b91588 100644
--- a/drivers/staging/imx-drm/imx-tve.c
+++ b/drivers/staging/imx-drm/imx-tve.c
@@ -31,7 +31,7 @@
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_crtc_helper.h>
 
-#include "ipu-v3/imx-ipu-v3.h"
+#include <linux/platform_data/imx-ipu-v3.h>
 #include "imx-drm.h"
 
 #define TVE_COM_CONF_REG	0x00
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index ca85d3d..2aca7dd 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -31,7 +31,7 @@
 
 #include <drm/drm_fourcc.h>
 
-#include "imx-ipu-v3.h"
+#include <linux/platform_data/imx-ipu-v3.h>
 #include "ipu-prv.h"
 
 static inline u32 ipu_cm_read(struct ipu_soc *ipu, unsigned offset)
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
index d5de8bb..e86010b 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c
@@ -21,7 +21,7 @@
 #include <linux/io.h>
 
 #include "../imx-drm.h"
-#include "imx-ipu-v3.h"
+#include <linux/platform_data/imx-ipu-v3.h>
 #include "ipu-prv.h"
 
 #define DC_MAP_CONF_PTR(n)	(0x108 + ((n) & ~0x1) * 2)
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-di.c b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
index 82a9eba..1e54c00 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-di.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
@@ -20,7 +20,7 @@
 #include <linux/err.h>
 #include <linux/platform_device.h>
 
-#include "imx-ipu-v3.h"
+#include <linux/platform_data/imx-ipu-v3.h>
 #include "ipu-prv.h"
 
 struct ipu_di {
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c
index 4521301..3c24111 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c
@@ -17,7 +17,7 @@
 #include <linux/errno.h>
 #include <linux/io.h>
 
-#include "imx-ipu-v3.h"
+#include <linux/platform_data/imx-ipu-v3.h>
 #include "ipu-prv.h"
 
 #define DMFC_RD_CHAN		0x0000
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dp.c b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
index 58f87c8..27d9a81 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c
@@ -19,7 +19,7 @@
 #include <linux/io.h>
 #include <linux/err.h>
 
-#include "imx-ipu-v3.h"
+#include <linux/platform_data/imx-ipu-v3.h>
 #include "ipu-prv.h"
 
 #define DP_SYNC 0
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
index 4df0050..40211f6 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
@@ -22,7 +22,7 @@ struct ipu_soc;
 #include <linux/clk.h>
 #include <linux/platform_device.h>
 
-#include "imx-ipu-v3.h"
+#include <linux/platform_data/imx-ipu-v3.h>
 
 #define IPUV3_CHANNEL_CSI0			 0
 #define IPUV3_CHANNEL_CSI1			 1
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index c48f640..9b707aa 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -30,7 +30,7 @@
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 
-#include "ipu-v3/imx-ipu-v3.h"
+#include <linux/platform_data/imx-ipu-v3.h>
 #include "imx-drm.h"
 #include "ipuv3-plane.h"
 
diff --git a/drivers/staging/imx-drm/ipuv3-plane.c b/drivers/staging/imx-drm/ipuv3-plane.c
index 27a8d73..e9e4e7a 100644
--- a/drivers/staging/imx-drm/ipuv3-plane.c
+++ b/drivers/staging/imx-drm/ipuv3-plane.c
@@ -17,7 +17,7 @@
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
-#include "ipu-v3/imx-ipu-v3.h"
+#include <linux/platform_data/imx-ipu-v3.h>
 #include "ipuv3-plane.h"
 
 #define to_ipu_plane(x)	container_of(x, struct ipu_plane, base)
diff --git a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h b/include/linux/platform_data/imx-ipu-v3.h
similarity index 99%
rename from drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
rename to include/linux/platform_data/imx-ipu-v3.h
index c4d14ea..c083a2a 100644
--- a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
+++ b/include/linux/platform_data/imx-ipu-v3.h
@@ -9,8 +9,8 @@
  * http://www.gnu.org/copyleft/lgpl.html
  */
 
-#ifndef __DRM_IPU_H__
-#define __DRM_IPU_H__
+#ifndef __IMX_IPU_H__
+#define __IMX_IPU_H__
 
 #include <linux/types.h>
 #include <linux/videodev2.h>
@@ -230,7 +230,8 @@ struct ipu_ch_param {
 	struct ipu_cpmem_word word[2];
 };
 
-void ipu_ch_param_write_field(struct ipu_ch_param __iomem *base, u32 wbs, u32 v);
+void ipu_ch_param_write_field(struct ipu_ch_param __iomem *base,
+			      u32 wbs, u32 v);
 u32 ipu_ch_param_read_field(struct ipu_ch_param __iomem *base, u32 wbs);
 struct ipu_ch_param __iomem *ipu_get_cpmem(struct ipuv3_channel *channel);
 void ipu_ch_param_dump(struct ipu_ch_param __iomem *p);
@@ -323,4 +324,4 @@ struct ipu_client_platformdata {
 	int dma[2];
 };
 
-#endif /* __DRM_IPU_H__ */
+#endif /* __IMX_IPU_H__ */
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 02/43] ARM: dts: imx6qdl: Add ipu aliases
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 01/43] imx-drm: ipu-v3: Move imx-ipu-v3.h to include/linux/platform_data/ Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-11 11:21   ` Philipp Zabel
  2014-06-07 21:56 ` [PATCH 03/43] imx-drm: ipu-v3: Add ipu_get_num() Steve Longerbeam
                   ` (42 subsequent siblings)
  44 siblings, 1 reply; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Add ipu0 (and ipu1 for quad) aliases to ipu1/ipu2 nodes respectively.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 arch/arm/boot/dts/imx6q.dtsi   |    1 +
 arch/arm/boot/dts/imx6qdl.dtsi |    1 +
 2 files changed, 2 insertions(+)

diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index addd3f8..c7544f0 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -15,6 +15,7 @@
 / {
 	aliases {
 		spi4 = &ecspi5;
+		ipu1 = &ipu2;
 	};
 
 	cpus {
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index eca0971..04c978c 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -43,6 +43,7 @@
 		spi3 = &ecspi4;
 		usbphy0 = &usbphy1;
 		usbphy1 = &usbphy2;
+		ipu0 = &ipu1;
 	};
 
 	intc: interrupt-controller@00a01000 {
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 03/43] imx-drm: ipu-v3: Add ipu_get_num()
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 01/43] imx-drm: ipu-v3: Move imx-ipu-v3.h to include/linux/platform_data/ Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 02/43] ARM: dts: imx6qdl: Add ipu aliases Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-11 11:22   ` Philipp Zabel
  2014-06-07 21:56 ` [PATCH 04/43] imx-drm: ipu-v3: Add solo/dual-lite IPU device type Steve Longerbeam
                   ` (41 subsequent siblings)
  44 siblings, 1 reply; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Adds of-alias id to ipu_soc and retrieve with ipu_get_num().

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/ipu-common.c |    8 ++++++++
 drivers/staging/imx-drm/ipu-v3/ipu-prv.h    |    1 +
 include/linux/platform_data/imx-ipu-v3.h    |    5 +++++
 3 files changed, 14 insertions(+)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index 2aca7dd..f8e8c56 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -55,6 +55,12 @@ static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value,
 	writel(value, ipu->idmac_reg + offset);
 }
 
+int ipu_get_num(struct ipu_soc *ipu)
+{
+	return ipu->id;
+}
+EXPORT_SYMBOL_GPL(ipu_get_num);
+
 void ipu_srm_dp_sync_update(struct ipu_soc *ipu)
 {
 	u32 val;
@@ -1104,6 +1110,7 @@ static int ipu_probe(struct platform_device *pdev)
 {
 	const struct of_device_id *of_id =
 			of_match_device(imx_ipu_dt_ids, &pdev->dev);
+	struct device_node *np = pdev->dev.of_node;
 	struct ipu_soc *ipu;
 	struct resource *res;
 	unsigned long ipu_base;
@@ -1132,6 +1139,7 @@ static int ipu_probe(struct platform_device *pdev)
 		ipu->channel[i].ipu = ipu;
 	ipu->devtype = devtype;
 	ipu->ipu_type = devtype->type;
+	ipu->id = of_alias_get_id(np, "ipu");
 
 	spin_lock_init(&ipu->lock);
 	mutex_init(&ipu->channel_lock);
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
index 40211f6..9e4cf4b 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
@@ -164,6 +164,7 @@ struct ipu_soc {
 	void __iomem		*idmac_reg;
 	struct ipu_ch_param __iomem	*cpmem_base;
 
+	int			id;
 	int			usecount;
 
 	struct clk		*clk;
diff --git a/include/linux/platform_data/imx-ipu-v3.h b/include/linux/platform_data/imx-ipu-v3.h
index c083a2a..ca91dd9 100644
--- a/include/linux/platform_data/imx-ipu-v3.h
+++ b/include/linux/platform_data/imx-ipu-v3.h
@@ -92,6 +92,11 @@ int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
 #define IPU_IRQ_VSYNC_PRE_1		(448 + 15)
 
 /*
+ * IPU Common functions
+ */
+int ipu_get_num(struct ipu_soc *ipu);
+
+/*
  * IPU Image DMA Controller (idmac) functions
  */
 struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned channel);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 04/43] imx-drm: ipu-v3: Add solo/dual-lite IPU device type
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (2 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 03/43] imx-drm: ipu-v3: Add ipu_get_num() Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-11  5:37   ` Sascha Hauer
  2014-06-11 11:38   ` Philipp Zabel
  2014-06-07 21:56 ` [PATCH 05/43] imx-drm: ipu-v3: Map IOMUXC registers Steve Longerbeam
                   ` (40 subsequent siblings)
  44 siblings, 2 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam, Jiada Wang

Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/ipu-common.c |   18 ++++++++++++++++++
 include/linux/platform_data/imx-ipu-v3.h    |    1 +
 2 files changed, 19 insertions(+)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index f8e8c56..2d95a7c 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -829,10 +829,28 @@ static struct ipu_devtype ipu_type_imx6q = {
 	.type = IPUV3H,
 };
 
+static struct ipu_devtype ipu_type_imx6dl = {
+	.name = "IPUv3HDL",
+	.cm_ofs = 0x00200000,
+	.cpmem_ofs = 0x00300000,
+	.srm_ofs = 0x00340000,
+	.tpm_ofs = 0x00360000,
+	.csi0_ofs = 0x00230000,
+	.csi1_ofs = 0x00238000,
+	.disp0_ofs = 0x00240000,
+	.disp1_ofs = 0x00248000,
+	.smfc_ofs =  0x00250000,
+	.ic_ofs = 0x00220000,
+	.vdi_ofs = 0x00268000,
+	.dc_tmpl_ofs = 0x00380000,
+	.type = IPUV3HDL,
+};
+
 static const struct of_device_id imx_ipu_dt_ids[] = {
 	{ .compatible = "fsl,imx51-ipu", .data = &ipu_type_imx51, },
 	{ .compatible = "fsl,imx53-ipu", .data = &ipu_type_imx53, },
 	{ .compatible = "fsl,imx6q-ipu", .data = &ipu_type_imx6q, },
+	{ .compatible = "fsl,imx6dl-ipu", .data = &ipu_type_imx6dl, },
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, imx_ipu_dt_ids);
diff --git a/include/linux/platform_data/imx-ipu-v3.h b/include/linux/platform_data/imx-ipu-v3.h
index ca91dd9..8050277 100644
--- a/include/linux/platform_data/imx-ipu-v3.h
+++ b/include/linux/platform_data/imx-ipu-v3.h
@@ -23,6 +23,7 @@ enum ipuv3_type {
 	IPUV3EX,
 	IPUV3M,
 	IPUV3H,
+	IPUV3HDL,
 };
 
 #define IPU_PIX_FMT_GBR24	v4l2_fourcc('G', 'B', 'R', '3')
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 05/43] imx-drm: ipu-v3: Map IOMUXC registers
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (3 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 04/43] imx-drm: ipu-v3: Add solo/dual-lite IPU device type Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-11 13:11   ` Philipp Zabel
  2014-06-07 21:56 ` [PATCH 06/43] imx-drm: ipu-v3: Add functions to set CSI/IC source muxes Steve Longerbeam
                   ` (39 subsequent siblings)
  44 siblings, 1 reply; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Map the IOMUXC registers, which will be needed by ipu-csi for mux
control.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/ipu-common.c |    8 ++++++++
 drivers/staging/imx-drm/ipu-v3/ipu-prv.h    |    4 ++++
 2 files changed, 12 insertions(+)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index 2d95a7c..635dafe 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -1196,6 +1196,14 @@ static int ipu_probe(struct platform_device *pdev)
 	if (!ipu->cm_reg || !ipu->idmac_reg || !ipu->cpmem_base)
 		return -ENOMEM;
 
+	ipu->gp_reg = syscon_regmap_lookup_by_compatible(
+		"fsl,imx6q-iomuxc-gpr");
+	if (IS_ERR(ipu->gp_reg)) {
+		ret = PTR_ERR(ipu->gp_reg);
+		dev_err(&pdev->dev, "failed to map iomuxc regs with %d\n", ret);
+		return ret;
+	}
+
 	ipu->clk = devm_clk_get(&pdev->dev, "bus");
 	if (IS_ERR(ipu->clk)) {
 		ret = PTR_ERR(ipu->clk);
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
index 9e4cf4b..90c0c50 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
@@ -21,6 +21,9 @@ struct ipu_soc;
 #include <linux/device.h>
 #include <linux/clk.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
 
 #include <linux/platform_data/imx-ipu-v3.h>
 
@@ -163,6 +166,7 @@ struct ipu_soc {
 	void __iomem		*cm_reg;
 	void __iomem		*idmac_reg;
 	struct ipu_ch_param __iomem	*cpmem_base;
+	struct regmap		*gp_reg;
 
 	int			id;
 	int			usecount;
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 06/43] imx-drm: ipu-v3: Add functions to set CSI/IC source muxes
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (4 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 05/43] imx-drm: ipu-v3: Map IOMUXC registers Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-11 11:22   ` Philipp Zabel
  2014-06-07 21:56 ` [PATCH 07/43] imx-drm: ipu-v3: Rename and add IDMAC channels Steve Longerbeam
                   ` (38 subsequent siblings)
  44 siblings, 1 reply; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Adds two new functions, ipu_set_csi_src_mux() and ipu_set_ic_src_mux(),
that select the inputs to the CSI and IC respectively. Both muxes are
programmed in the IPU_CONF register.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/ipu-common.c |   51 +++++++++++++++++++++++++++
 drivers/staging/imx-drm/ipu-v3/ipu-prv.h    |    3 ++
 2 files changed, 54 insertions(+)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index 635dafe..1c606b5 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -777,6 +777,57 @@ static int ipu_memory_reset(struct ipu_soc *ipu)
 	return 0;
 }
 
+/*
+ * Set the source mux for the given CSI. Selects either parallel or
+ * MIPI CSI2 sources. This is not exported because it is used only
+ * by ipu.
+ */
+void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2)
+{
+	unsigned long flags;
+	u32 val, mask;
+
+	mask = (csi_id == 1) ? IPU_CONF_CSI1_DATA_SOURCE :
+		IPU_CONF_CSI0_DATA_SOURCE;
+
+	spin_lock_irqsave(&ipu->lock, flags);
+
+	val = ipu_cm_read(ipu, IPU_CONF);
+	if (mipi_csi2)
+		val |= mask;
+	else
+		val &= ~mask;
+	ipu_cm_write(ipu, val, IPU_CONF);
+
+	spin_unlock_irqrestore(&ipu->lock, flags);
+}
+
+/*
+ * Set the source mux for the IC. Selects either CSI[01] or the VDI.
+ * This is not exported because it is used only by ipu.
+ */
+void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi)
+{
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&ipu->lock, flags);
+
+	val = ipu_cm_read(ipu, IPU_CONF);
+	if (vdi) {
+		val |= IPU_CONF_IC_INPUT;
+	} else {
+		val &= ~IPU_CONF_IC_INPUT;
+		if (csi_id == 1)
+			val |= IPU_CONF_CSI_SEL;
+		else
+			val &= ~IPU_CONF_CSI_SEL;
+	}
+	ipu_cm_write(ipu, val, IPU_CONF);
+
+	spin_unlock_irqrestore(&ipu->lock, flags);
+}
+
 struct ipu_devtype {
 	const char *name;
 	unsigned long cm_ofs;
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
index 90c0c50..69d99b0 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
@@ -190,6 +190,9 @@ void ipu_srm_dp_sync_update(struct ipu_soc *ipu);
 int ipu_module_enable(struct ipu_soc *ipu, u32 mask);
 int ipu_module_disable(struct ipu_soc *ipu, u32 mask);
 
+void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2);
+void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi);
+
 int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
 		unsigned long base, u32 module, struct clk *ipu_clk);
 void ipu_di_exit(struct ipu_soc *ipu, int id);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 07/43] imx-drm: ipu-v3: Rename and add IDMAC channels
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (5 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 06/43] imx-drm: ipu-v3: Add functions to set CSI/IC source muxes Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-11 11:22   ` Philipp Zabel
  2014-06-07 21:56 ` [PATCH 08/43] imx-drm: ipu-v3: Add units required for video capture Steve Longerbeam
                   ` (37 subsequent siblings)
  44 siblings, 1 reply; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Rename the ENC/VF/PP rotation channel names, to be more consistent
with the convention that *_MEM is write-to-memory channels and
MEM_* is read-from-memory channels. Also add the channels who's
source and destination is the IC.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/ipu-prv.h |   20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
index 69d99b0..1398752 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
@@ -31,17 +31,25 @@ struct ipu_soc;
 #define IPUV3_CHANNEL_CSI1			 1
 #define IPUV3_CHANNEL_CSI2			 2
 #define IPUV3_CHANNEL_CSI3			 3
+#define IPUV3_CHANNEL_VDI_MEM_IC_VF              5
+#define IPUV3_CHANNEL_MEM_IC_PP                 11
+#define IPUV3_CHANNEL_MEM_IC_PRP_VF             12
+#define IPUV3_CHANNEL_G_MEM_IC_PRP_VF           14
+#define IPUV3_CHANNEL_G_MEM_IC_PP               15
+#define IPUV3_CHANNEL_IC_PRP_ENC_MEM            20
+#define IPUV3_CHANNEL_IC_PRP_VF_MEM             21
+#define IPUV3_CHANNEL_IC_PP_MEM                 22
 #define IPUV3_CHANNEL_MEM_BG_SYNC		23
 #define IPUV3_CHANNEL_MEM_FG_SYNC		27
 #define IPUV3_CHANNEL_MEM_DC_SYNC		28
 #define IPUV3_CHANNEL_MEM_FG_SYNC_ALPHA		31
 #define IPUV3_CHANNEL_MEM_DC_ASYNC		41
-#define IPUV3_CHANNEL_ROT_ENC_MEM		45
-#define IPUV3_CHANNEL_ROT_VF_MEM		46
-#define IPUV3_CHANNEL_ROT_PP_MEM		47
-#define IPUV3_CHANNEL_ROT_ENC_MEM_OUT		48
-#define IPUV3_CHANNEL_ROT_VF_MEM_OUT		49
-#define IPUV3_CHANNEL_ROT_PP_MEM_OUT		50
+#define IPUV3_CHANNEL_MEM_ROT_ENC		45
+#define IPUV3_CHANNEL_MEM_ROT_VF		46
+#define IPUV3_CHANNEL_MEM_ROT_PP		47
+#define IPUV3_CHANNEL_ROT_ENC_MEM		48
+#define IPUV3_CHANNEL_ROT_VF_MEM		49
+#define IPUV3_CHANNEL_ROT_PP_MEM		50
 #define IPUV3_CHANNEL_MEM_BG_SYNC_ALPHA		51
 
 #define IPU_MCU_T_DEFAULT	8
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 08/43] imx-drm: ipu-v3: Add units required for video capture
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (6 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 07/43] imx-drm: ipu-v3: Rename and add IDMAC channels Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-11  6:18   ` Sascha Hauer
  2014-06-11 14:09   ` Philipp Zabel
  2014-06-07 21:56 ` [PATCH 09/43] imx-drm: ipu-v3: Add ipu_mbus_code_to_colorspace() Steve Longerbeam
                   ` (36 subsequent siblings)
  44 siblings, 2 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Adds the following new IPU units:

- Camera Sensor Interface (csi)
- Sensor Multi FIFO Controller (smfc)
- Image Converter (ic)
- Image Rotator (irt)

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/Makefile     |    3 +-
 drivers/staging/imx-drm/ipu-v3/ipu-common.c |   67 ++-
 drivers/staging/imx-drm/ipu-v3/ipu-csi.c    |  821 ++++++++++++++++++++++++++
 drivers/staging/imx-drm/ipu-v3/ipu-ic.c     |  835 +++++++++++++++++++++++++++
 drivers/staging/imx-drm/ipu-v3/ipu-irt.c    |  103 ++++
 drivers/staging/imx-drm/ipu-v3/ipu-prv.h    |   24 +
 drivers/staging/imx-drm/ipu-v3/ipu-smfc.c   |  348 +++++++++++
 include/linux/platform_data/imx-ipu-v3.h    |  151 +++++
 8 files changed, 2350 insertions(+), 2 deletions(-)
 create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-csi.c
 create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-ic.c
 create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-irt.c
 create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-smfc.c

diff --git a/drivers/staging/imx-drm/ipu-v3/Makefile b/drivers/staging/imx-drm/ipu-v3/Makefile
index 28ed72e..79c0c88 100644
--- a/drivers/staging/imx-drm/ipu-v3/Makefile
+++ b/drivers/staging/imx-drm/ipu-v3/Makefile
@@ -1,3 +1,4 @@
 obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += imx-ipu-v3.o
 
-imx-ipu-v3-objs := ipu-common.o ipu-dc.o ipu-di.o ipu-dp.o ipu-dmfc.o
+imx-ipu-v3-objs := ipu-common.o ipu-csi.o ipu-dc.o ipu-di.o \
+	ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-irt.o ipu-smfc.o
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index 1c606b5..3d7e28d 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -834,6 +834,10 @@ struct ipu_devtype {
 	unsigned long cpmem_ofs;
 	unsigned long srm_ofs;
 	unsigned long tpm_ofs;
+	unsigned long csi0_ofs;
+	unsigned long csi1_ofs;
+	unsigned long smfc_ofs;
+	unsigned long ic_ofs;
 	unsigned long disp0_ofs;
 	unsigned long disp1_ofs;
 	unsigned long dc_tmpl_ofs;
@@ -873,8 +877,12 @@ static struct ipu_devtype ipu_type_imx6q = {
 	.cpmem_ofs = 0x00300000,
 	.srm_ofs = 0x00340000,
 	.tpm_ofs = 0x00360000,
+	.csi0_ofs = 0x00230000,
+	.csi1_ofs = 0x00238000,
 	.disp0_ofs = 0x00240000,
 	.disp1_ofs = 0x00248000,
+	.smfc_ofs =  0x00250000,
+	.ic_ofs = 0x00220000,
 	.dc_tmpl_ofs = 0x00380000,
 	.vdi_ofs = 0x00268000,
 	.type = IPUV3H,
@@ -915,8 +923,44 @@ static int ipu_submodules_init(struct ipu_soc *ipu,
 	struct device *dev = &pdev->dev;
 	const struct ipu_devtype *devtype = ipu->devtype;
 
+	ret = ipu_csi_init(ipu, dev, 0, ipu_base + devtype->csi0_ofs,
+			   IPU_CONF_CSI0_EN, ipu_clk);
+	if (ret) {
+		unit = "csi0";
+		goto err_csi_0;
+	}
+
+	ret = ipu_csi_init(ipu, dev, 1, ipu_base + devtype->csi1_ofs,
+			   IPU_CONF_CSI1_EN, ipu_clk);
+	if (ret) {
+		unit = "csi1";
+		goto err_csi_1;
+	}
+
+	ret = ipu_smfc_init(ipu, dev, ipu_base + devtype->smfc_ofs,
+			    IPU_CONF_SMFC_EN);
+	if (ret) {
+		unit = "smfc";
+		goto err_smfc;
+	}
+
+	ret = ipu_ic_init(ipu, dev,
+			  ipu_base + devtype->ic_ofs,
+			  ipu_base + devtype->tpm_ofs,
+			  IPU_CONF_IC_EN);
+	if (ret) {
+		unit = "ic";
+		goto err_ic;
+	}
+
+	ret = ipu_irt_init(ipu, dev, IPU_CONF_ROT_EN);
+	if (ret) {
+		unit = "irt";
+		goto err_irt;
+	}
+
 	ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs,
-			IPU_CONF_DI0_EN, ipu_clk);
+			  IPU_CONF_DI0_EN, ipu_clk);
 	if (ret) {
 		unit = "di0";
 		goto err_di_0;
@@ -960,6 +1004,16 @@ err_dc:
 err_di_1:
 	ipu_di_exit(ipu, 0);
 err_di_0:
+	ipu_irt_exit(ipu);
+err_irt:
+	ipu_ic_exit(ipu);
+err_ic:
+	ipu_smfc_exit(ipu);
+err_smfc:
+	ipu_csi_exit(ipu, 1);
+err_csi_1:
+	ipu_csi_exit(ipu, 0);
+err_csi_0:
 	dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret);
 	return ret;
 }
@@ -1027,6 +1081,11 @@ static void ipu_submodules_exit(struct ipu_soc *ipu)
 	ipu_dc_exit(ipu);
 	ipu_di_exit(ipu, 1);
 	ipu_di_exit(ipu, 0);
+	ipu_irt_exit(ipu);
+	ipu_ic_exit(ipu);
+	ipu_smfc_exit(ipu);
+	ipu_csi_exit(ipu, 1);
+	ipu_csi_exit(ipu, 0);
 }
 
 static int platform_remove_devices_fn(struct device *dev, void *unused)
@@ -1219,6 +1278,12 @@ static int ipu_probe(struct platform_device *pdev)
 			ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS);
 	dev_dbg(&pdev->dev, "cpmem:    0x%08lx\n",
 			ipu_base + devtype->cpmem_ofs);
+	dev_dbg(&pdev->dev, "csi0:    0x%08lx\n",
+			ipu_base + devtype->csi0_ofs);
+	dev_dbg(&pdev->dev, "csi1:    0x%08lx\n",
+			ipu_base + devtype->csi1_ofs);
+	dev_dbg(&pdev->dev, "smfc:    0x%08lx\n",
+			ipu_base + devtype->smfc_ofs);
 	dev_dbg(&pdev->dev, "disp0:    0x%08lx\n",
 			ipu_base + devtype->disp0_ofs);
 	dev_dbg(&pdev->dev, "disp1:    0x%08lx\n",
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-csi.c b/drivers/staging/imx-drm/ipu-v3/ipu-csi.c
new file mode 100644
index 0000000..fa54b30
--- /dev/null
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-csi.c
@@ -0,0 +1,821 @@
+/*
+ * Copyright (C) 2012-2014 Mentor Graphics Inc.
+ * Copyright (C) 2005-2009 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.
+ */
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <uapi/linux/v4l2-mediabus.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+
+#include "ipu-prv.h"
+
+struct ipu_csi {
+	void __iomem *base;
+	int id;
+	u32 module;
+	struct clk *clk_ipu;    /* IPU bus clock */
+	spinlock_t lock;
+	int use_count;
+	struct ipu_soc *ipu;
+};
+
+/* CSI Register Offsets */
+#define CSI_SENS_CONF           0x0000
+#define CSI_SENS_FRM_SIZE       0x0004
+#define CSI_ACT_FRM_SIZE        0x0008
+#define CSI_OUT_FRM_CTRL        0x000C
+#define CSI_TST_CTRL            0x0010
+#define CSI_CCIR_CODE_1         0x0014
+#define CSI_CCIR_CODE_2         0x0018
+#define CSI_CCIR_CODE_3         0x001C
+#define CSI_MIPI_DI             0x0020
+#define CSI_SKIP                0x0024
+#define CSI_CPD_CTRL            0x0028
+#define CSI_CPD_RC(n)           (0x002C + ((n)*4))
+#define CSI_CPD_RS(n)           (0x004C + ((n)*4))
+#define CSI_CPD_GRC(n)          (0x005C + ((n)*4))
+#define CSI_CPD_GRS(n)          (0x007C + ((n)*4))
+#define CSI_CPD_GBC(n)          (0x008C + ((n)*4))
+#define CSI_CPD_GBS(n)          (0x00AC + ((n)*4))
+#define CSI_CPD_BC(n)           (0x00BC + ((n)*4))
+#define CSI_CPD_BS(n)           (0x00DC + ((n)*4))
+#define CSI_CPD_OFFSET1         0x00EC
+#define CSI_CPD_OFFSET2         0x00F0
+
+/* CSI Register Fields */
+#define CSI_SENS_CONF_DATA_FMT_SHIFT       8
+#define CSI_SENS_CONF_DATA_FMT_MASK        0x00000700
+#define CSI_SENS_CONF_DATA_FMT_RGB_YUV444  0L
+#define CSI_SENS_CONF_DATA_FMT_YUV422_YUYV 1L
+#define CSI_SENS_CONF_DATA_FMT_YUV422_UYVY 2L
+#define CSI_SENS_CONF_DATA_FMT_BAYER       3L
+#define CSI_SENS_CONF_DATA_FMT_RGB565      4L
+#define CSI_SENS_CONF_DATA_FMT_RGB555      5L
+#define CSI_SENS_CONF_DATA_FMT_RGB444      6L
+#define CSI_SENS_CONF_DATA_FMT_JPEG        7L
+
+#define CSI_SENS_CONF_VSYNC_POL_SHIFT      0
+#define CSI_SENS_CONF_HSYNC_POL_SHIFT      1
+#define CSI_SENS_CONF_DATA_POL_SHIFT       2
+#define CSI_SENS_CONF_PIX_CLK_POL_SHIFT    3
+#define CSI_SENS_CONF_SENS_PRTCL_MASK      0x00000070L
+#define CSI_SENS_CONF_SENS_PRTCL_SHIFT     4
+#define CSI_SENS_CONF_PACK_TIGHT_SHIFT     7
+#define CSI_SENS_CONF_DATA_WIDTH_SHIFT     11
+#define CSI_SENS_CONF_EXT_VSYNC_SHIFT      15
+#define CSI_SENS_CONF_DIVRATIO_SHIFT       16
+
+#define CSI_SENS_CONF_DIVRATIO_MASK        0x00FF0000L
+#define CSI_SENS_CONF_DATA_DEST_SHIFT      24
+#define CSI_SENS_CONF_DATA_DEST_MASK       0x07000000L
+#define CSI_SENS_CONF_JPEG8_EN_SHIFT       27
+#define CSI_SENS_CONF_JPEG_EN_SHIFT        28
+#define CSI_SENS_CONF_FORCE_EOF_SHIFT      29
+#define CSI_SENS_CONF_DATA_EN_POL_SHIFT    31
+
+#define CSI_DATA_DEST_ISP                  1L
+#define CSI_DATA_DEST_IC                   2L
+#define CSI_DATA_DEST_IDMAC                4L
+
+#define CSI_CCIR_ERR_DET_EN                0x01000000L
+#define CSI_HORI_DOWNSIZE_EN               0x80000000L
+#define CSI_VERT_DOWNSIZE_EN               0x40000000L
+#define CSI_TEST_GEN_MODE_EN               0x01000000L
+
+#define CSI_HSC_MASK                       0x1FFF0000
+#define CSI_HSC_SHIFT                      16
+#define CSI_VSC_MASK                       0x00000FFF
+#define CSI_VSC_SHIFT                      0
+
+#define CSI_TEST_GEN_R_MASK                0x000000FFL
+#define CSI_TEST_GEN_R_SHIFT               0
+#define CSI_TEST_GEN_G_MASK                0x0000FF00L
+#define CSI_TEST_GEN_G_SHIFT               8
+#define CSI_TEST_GEN_B_MASK                0x00FF0000L
+#define CSI_TEST_GEN_B_SHIFT               16
+
+#define CSI_MAX_RATIO_SKIP_ISP_MASK        0x00070000L
+#define CSI_MAX_RATIO_SKIP_ISP_SHIFT       16
+#define CSI_SKIP_ISP_MASK                  0x00F80000L
+#define CSI_SKIP_ISP_SHIFT                 19
+#define CSI_MAX_RATIO_SKIP_SMFC_MASK       0x00000007L
+#define CSI_MAX_RATIO_SKIP_SMFC_SHIFT      0
+#define CSI_SKIP_SMFC_MASK                 0x000000F8L
+#define CSI_SKIP_SMFC_SHIFT                3
+#define CSI_ID_2_SKIP_MASK                 0x00000300L
+#define CSI_ID_2_SKIP_SHIFT                8
+
+#define CSI_COLOR_FIRST_ROW_MASK           0x00000002L
+#define CSI_COLOR_FIRST_COMP_MASK          0x00000001L
+
+/* MIPI CSI-2 data types */
+#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
+
+
+static inline u32 ipu_csi_read(struct ipu_csi *csi, unsigned offset)
+{
+	return readl(csi->base + offset);
+}
+
+static inline void ipu_csi_write(struct ipu_csi *csi, u32 value,
+				 unsigned offset)
+{
+	writel(value, csi->base + offset);
+}
+
+/*
+ * Set mclk division ratio for generating test mode mclk. Only used
+ * for test generator.
+ */
+static int ipu_csi_set_testgen_mclk(struct ipu_csi *csi, u32 pixel_clk,
+				    u32 ipu_clk)
+{
+	u32 temp;
+	u32 div_ratio;
+
+	div_ratio = (ipu_clk / pixel_clk) - 1;
+
+	if (div_ratio > 0xFF || div_ratio < 0) {
+		dev_err(csi->ipu->dev,
+			"value of pixel_clk extends normal range\n");
+		return -EINVAL;
+	}
+
+	temp = ipu_csi_read(csi, CSI_SENS_CONF);
+	temp &= ~CSI_SENS_CONF_DIVRATIO_MASK;
+	ipu_csi_write(csi, temp | (div_ratio << CSI_SENS_CONF_DIVRATIO_SHIFT),
+		      CSI_SENS_CONF);
+
+	return 0;
+}
+
+/*
+ * Enable error detection and correction for CCIR interlaced mode.
+ */
+static void ipu_csi_ccir_err_detection_enable(struct ipu_csi *csi)
+{
+	u32 temp;
+
+	temp = ipu_csi_read(csi, CSI_CCIR_CODE_1);
+	temp |= CSI_CCIR_ERR_DET_EN;
+	ipu_csi_write(csi, temp, CSI_CCIR_CODE_1);
+
+}
+
+/*
+ * Disable error detection and correction for CCIR interlaced mode.
+ */
+static void ipu_csi_ccir_err_detection_disable(struct ipu_csi *csi)
+{
+	u32 temp;
+
+	temp = ipu_csi_read(csi, CSI_CCIR_CODE_1);
+	temp &= ~CSI_CCIR_ERR_DET_EN;
+	ipu_csi_write(csi, temp, CSI_CCIR_CODE_1);
+
+}
+
+#define GPR1_IPU_CSI_MUX_CTL_SHIFT 19
+#define GPR13_IPUV3HDL_CSI_MUX_CTL_SHIFT 0
+
+int ipu_csi_set_src(struct ipu_csi *csi, u32 vc, bool select_mipi_csi2)
+{
+	struct ipu_soc *ipu = csi->ipu;
+	int ipu_id = ipu_get_num(ipu);
+	u32 val, bit;
+
+	/*
+	 * Set the muxes that choose between mipi-csi2 and parallel inputs
+	 * to the CSI's.
+	 */
+	if (csi->ipu->ipu_type == IPUV3HDL) {
+		/*
+		 * On D/L, the mux is in GPR13. The TRM is unclear,
+		 * but it appears the mux allows selecting the MIPI
+		 * CSI-2 virtual channel number to route to the CSIs.
+		 */
+		bit = GPR13_IPUV3HDL_CSI_MUX_CTL_SHIFT + csi->id * 3;
+		val = select_mipi_csi2 ? vc << bit : 4 << bit;
+		regmap_update_bits(ipu->gp_reg, IOMUXC_GPR13,
+				   0x7 << bit, val);
+	} else if (csi->ipu->ipu_type == IPUV3H) {
+		/*
+		 * For Q/D, the mux only exists on IPU0-CSI0 and IPU1-CSI1,
+		 * and the routed virtual channel numbers are fixed at 0 and
+		 * 3 respectively.
+		 */
+		if ((ipu_id == 0 && csi->id == 0) ||
+		    (ipu_id == 1 && csi->id == 1)) {
+			bit = GPR1_IPU_CSI_MUX_CTL_SHIFT + csi->ipu->id;
+			val = select_mipi_csi2 ? 0 : 1 << bit;
+			regmap_update_bits(ipu->gp_reg, IOMUXC_GPR1,
+					   0x1 << bit, val);
+		}
+	} else {
+		dev_err(csi->ipu->dev,
+			"ERROR: %s: unsupported CPU version!\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	/*
+	 * there is another mux in the IPU config register that
+	 * must be set as well
+	 */
+	ipu_set_csi_src_mux(ipu, csi->id, select_mipi_csi2);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_set_src);
+
+int ipu_csi_init_interface(struct ipu_csi *csi, u16 width, u16 height,
+			   struct ipu_csi_signal_cfg *cfg)
+{
+	unsigned long flags;
+	u32 data = 0;
+	u32 ipu_clk;
+
+	/* Set the CSI_SENS_CONF register remaining fields */
+	data |= cfg->data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT |
+		cfg->data_fmt << CSI_SENS_CONF_DATA_FMT_SHIFT |
+		cfg->data_pol << CSI_SENS_CONF_DATA_POL_SHIFT |
+		cfg->vsync_pol << CSI_SENS_CONF_VSYNC_POL_SHIFT |
+		cfg->hsync_pol << CSI_SENS_CONF_HSYNC_POL_SHIFT |
+		cfg->pixclk_pol << CSI_SENS_CONF_PIX_CLK_POL_SHIFT |
+		cfg->ext_vsync << CSI_SENS_CONF_EXT_VSYNC_SHIFT |
+		cfg->clk_mode << CSI_SENS_CONF_SENS_PRTCL_SHIFT |
+		cfg->pack_tight << CSI_SENS_CONF_PACK_TIGHT_SHIFT |
+		cfg->force_eof << CSI_SENS_CONF_FORCE_EOF_SHIFT |
+		cfg->data_en_pol << CSI_SENS_CONF_DATA_EN_POL_SHIFT;
+
+	ipu_clk = clk_get_rate(csi->clk_ipu);
+
+	spin_lock_irqsave(&csi->lock, flags);
+
+	ipu_csi_write(csi, data, CSI_SENS_CONF);
+
+	/* Setup sensor frame size */
+	ipu_csi_write(csi, (width - 1) | (height - 1) << 16, CSI_SENS_FRM_SIZE);
+
+	/* Set CCIR registers */
+	if (cfg->clk_mode == IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE) {
+		ipu_csi_write(csi, 0x40030, CSI_CCIR_CODE_1);
+		ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
+	} else if (cfg->clk_mode == IPU_CSI_CLK_MODE_CCIR656_INTERLACED) {
+		if (width == 720 && height == 625) {
+			/*
+			 * PAL case
+			 *
+			 * Field0BlankEnd = 0x6, Field0BlankStart = 0x2,
+			 * Field0ActiveEnd = 0x4, Field0ActiveStart = 0
+			 * Field1BlankEnd = 0x7, Field1BlankStart = 0x3,
+			 * Field1ActiveEnd = 0x5, Field1ActiveStart = 0x1
+			 */
+			ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_1);
+			ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2);
+			ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
+
+		} else if (width == 720 && height == 525) {
+			/*
+			 * NTSC case
+			 *
+			 * Field0BlankEnd = 0x7, Field0BlankStart = 0x3,
+			 * Field0ActiveEnd = 0x5, Field0ActiveStart = 0x1
+			 * Field1BlankEnd = 0x6, Field1BlankStart = 0x2,
+			 * Field1ActiveEnd = 0x4, Field1ActiveStart = 0
+			 */
+			ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_1);
+			ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2);
+			ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
+		} else {
+			dev_err(csi->ipu->dev,
+				"Unsupported CCIR656 interlaced video mode\n");
+			spin_unlock_irqrestore(&csi->lock, flags);
+			return -EINVAL;
+		}
+		ipu_csi_ccir_err_detection_enable(csi);
+	} else if ((cfg->clk_mode ==
+		    IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR) ||
+		   (cfg->clk_mode ==
+		    IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR) ||
+		   (cfg->clk_mode ==
+		    IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR) ||
+		   (cfg->clk_mode ==
+		    IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR)) {
+		ipu_csi_write(csi, 0x40030, CSI_CCIR_CODE_1);
+		ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3);
+		ipu_csi_ccir_err_detection_enable(csi);
+	} else if ((cfg->clk_mode == IPU_CSI_CLK_MODE_GATED_CLK) ||
+		   (cfg->clk_mode == IPU_CSI_CLK_MODE_NONGATED_CLK)) {
+		ipu_csi_ccir_err_detection_disable(csi);
+	}
+
+	dev_dbg(csi->ipu->dev, "CSI_SENS_CONF = 0x%08X\n",
+		ipu_csi_read(csi, CSI_SENS_CONF));
+	dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE = 0x%08X\n",
+		ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
+
+	spin_unlock_irqrestore(&csi->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_init_interface);
+
+/*
+ * Find the CSI data format and data width codes for the given V4L2 media
+ * bus pixel format code.
+ */
+int ipu_csi_mbus_fmt_to_sig_cfg(struct ipu_csi_signal_cfg *cfg, u32 mbus_code)
+{
+	switch (mbus_code) {
+	case V4L2_MBUS_FMT_BGR565_2X8_BE:
+	case V4L2_MBUS_FMT_BGR565_2X8_LE:
+	case V4L2_MBUS_FMT_RGB565_2X8_BE:
+	case V4L2_MBUS_FMT_RGB565_2X8_LE:
+		cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565;
+		cfg->mipi_dt = MIPI_DT_RGB565;
+		cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+		break;
+	case V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE:
+	case V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE:
+		cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB444;
+		cfg->mipi_dt = MIPI_DT_RGB444;
+		cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+		break;
+	case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
+	case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
+		cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB555;
+		cfg->mipi_dt = MIPI_DT_RGB555;
+		cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+		break;
+	case V4L2_MBUS_FMT_UYVY8_2X8:
+		cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
+		cfg->mipi_dt = MIPI_DT_YUV422;
+		cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+		break;
+	case V4L2_MBUS_FMT_YUYV8_2X8:
+		cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
+		cfg->mipi_dt = MIPI_DT_YUV422;
+		cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+		break;
+	case V4L2_MBUS_FMT_UYVY8_1X16:
+		cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
+		cfg->mipi_dt = MIPI_DT_YUV422;
+		cfg->data_width = IPU_CSI_DATA_WIDTH_16;
+		break;
+	case V4L2_MBUS_FMT_YUYV8_1X16:
+		cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
+		cfg->mipi_dt = MIPI_DT_YUV422;
+		cfg->data_width = IPU_CSI_DATA_WIDTH_16;
+		break;
+	case V4L2_MBUS_FMT_SBGGR8_1X8:
+	case V4L2_MBUS_FMT_SGBRG8_1X8:
+	case V4L2_MBUS_FMT_SGRBG8_1X8:
+	case V4L2_MBUS_FMT_SRGGB8_1X8:
+		cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+		cfg->mipi_dt = MIPI_DT_RAW8;
+		cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+		break;
+	case V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8:
+	case V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8:
+	case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
+	case V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8:
+	case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE:
+	case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE:
+	case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE:
+	case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE:
+		cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+		cfg->mipi_dt = MIPI_DT_RAW10;
+		cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+		break;
+	case V4L2_MBUS_FMT_SBGGR10_1X10:
+	case V4L2_MBUS_FMT_SGBRG10_1X10:
+	case V4L2_MBUS_FMT_SGRBG10_1X10:
+	case V4L2_MBUS_FMT_SRGGB10_1X10:
+		cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+		cfg->mipi_dt = MIPI_DT_RAW10;
+		cfg->data_width = IPU_CSI_DATA_WIDTH_10;
+		break;
+	case V4L2_MBUS_FMT_SBGGR12_1X12:
+	case V4L2_MBUS_FMT_SGBRG12_1X12:
+	case V4L2_MBUS_FMT_SGRBG12_1X12:
+	case V4L2_MBUS_FMT_SRGGB12_1X12:
+		cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+		cfg->mipi_dt = MIPI_DT_RAW12;
+		cfg->data_width = IPU_CSI_DATA_WIDTH_12;
+		break;
+	case V4L2_MBUS_FMT_JPEG_1X8:
+		/* TODO */
+		cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_JPEG;
+		cfg->mipi_dt = MIPI_DT_RAW8;
+		cfg->data_width = IPU_CSI_DATA_WIDTH_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_mbus_fmt_to_sig_cfg);
+
+int ipu_csi_get_sensor_protocol(struct ipu_csi *csi)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&csi->lock, flags);
+	ret = (ipu_csi_read(csi, CSI_SENS_CONF) &
+	       CSI_SENS_CONF_SENS_PRTCL_MASK) >>
+		CSI_SENS_CONF_SENS_PRTCL_SHIFT;
+	spin_unlock_irqrestore(&csi->lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_get_sensor_protocol);
+
+bool ipu_csi_is_interlaced(struct ipu_csi *csi)
+{
+	int sensor_protocol = ipu_csi_get_sensor_protocol(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:
+		return 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:
+		return true;
+		break;
+	default:
+		dev_err(csi->ipu->dev,
+			"CSI %d sensor protocol unsupported\n", csi->id);
+		return false;
+	}
+}
+EXPORT_SYMBOL_GPL(ipu_csi_is_interlaced);
+
+void ipu_csi_get_window_size(struct ipu_csi *csi, u32 *width, u32 *height)
+{
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&csi->lock, flags);
+
+	reg = ipu_csi_read(csi, CSI_ACT_FRM_SIZE);
+	*width = (reg & 0xFFFF) + 1;
+	*height = (reg >> 16 & 0xFFFF) + 1;
+
+	spin_unlock_irqrestore(&csi->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_csi_get_window_size);
+
+void ipu_csi_set_window_size(struct ipu_csi *csi, u32 width, u32 height)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&csi->lock, flags);
+
+	ipu_csi_write(csi, (width - 1) | (height - 1) << 16, CSI_ACT_FRM_SIZE);
+
+	spin_unlock_irqrestore(&csi->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_csi_set_window_size);
+
+void ipu_csi_set_window_pos(struct ipu_csi *csi, u32 left, u32 top)
+{
+	unsigned long flags;
+	u32 temp;
+
+	spin_lock_irqsave(&csi->lock, flags);
+	temp = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
+	temp &= ~(CSI_HSC_MASK | CSI_VSC_MASK);
+	temp |= ((top << CSI_VSC_SHIFT) | (left << CSI_HSC_SHIFT));
+	ipu_csi_write(csi, temp, CSI_OUT_FRM_CTRL);
+	spin_unlock_irqrestore(&csi->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_csi_set_window_pos);
+
+void ipu_csi_horizontal_downsize_enable(struct ipu_csi *csi)
+{
+	unsigned long flags;
+	u32 temp;
+
+	spin_lock_irqsave(&csi->lock, flags);
+	temp = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
+	temp |= CSI_HORI_DOWNSIZE_EN;
+	ipu_csi_write(csi, temp, CSI_OUT_FRM_CTRL);
+	spin_unlock_irqrestore(&csi->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_csi_horizontal_downsize_enable);
+
+void ipu_csi_horizontal_downsize_disable(struct ipu_csi *csi)
+{
+	unsigned long flags;
+	u32 temp;
+
+	spin_lock_irqsave(&csi->lock, flags);
+	temp = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
+	temp &= ~CSI_HORI_DOWNSIZE_EN;
+	ipu_csi_write(csi, temp, CSI_OUT_FRM_CTRL);
+	spin_unlock_irqrestore(&csi->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_csi_horizontal_downsize_disable);
+
+void ipu_csi_vertical_downsize_enable(struct ipu_csi *csi)
+{
+	unsigned long flags;
+	u32 temp;
+
+	spin_lock_irqsave(&csi->lock, flags);
+	temp = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
+	temp |= CSI_VERT_DOWNSIZE_EN;
+	ipu_csi_write(csi, temp, CSI_OUT_FRM_CTRL);
+	spin_unlock_irqrestore(&csi->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_csi_vertical_downsize_enable);
+
+void ipu_csi_vertical_downsize_disable(struct ipu_csi *csi)
+{
+	unsigned long flags;
+	u32 temp;
+
+	spin_lock_irqsave(&csi->lock, flags);
+	temp = ipu_csi_read(csi, CSI_OUT_FRM_CTRL);
+	temp &= ~CSI_VERT_DOWNSIZE_EN;
+	ipu_csi_write(csi, temp, CSI_OUT_FRM_CTRL);
+	spin_unlock_irqrestore(&csi->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_csi_vertical_downsize_disable);
+
+void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active,
+				u32 r_value, u32 g_value, u32 b_value,
+				u32 pix_clk)
+{
+	unsigned long flags;
+	u32 ipu_clk = clk_get_rate(csi->clk_ipu);
+	u32 temp;
+
+	spin_lock_irqsave(&csi->lock, flags);
+
+	temp = ipu_csi_read(csi, CSI_TST_CTRL);
+
+	if (active == false) {
+		temp &= ~CSI_TEST_GEN_MODE_EN;
+		ipu_csi_write(csi, temp, CSI_TST_CTRL);
+	} else {
+		/* Set sensb_mclk div_ratio*/
+		ipu_csi_set_testgen_mclk(csi, pix_clk, ipu_clk);
+
+		temp &= ~(CSI_TEST_GEN_R_MASK | CSI_TEST_GEN_G_MASK |
+			  CSI_TEST_GEN_B_MASK);
+		temp |= CSI_TEST_GEN_MODE_EN;
+		temp |= (r_value << CSI_TEST_GEN_R_SHIFT) |
+			(g_value << CSI_TEST_GEN_G_SHIFT) |
+			(b_value << CSI_TEST_GEN_B_SHIFT);
+		ipu_csi_write(csi, temp, CSI_TST_CTRL);
+	}
+
+	spin_unlock_irqrestore(&csi->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_csi_set_test_generator);
+
+int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc,
+			      struct ipu_csi_signal_cfg *cfg)
+{
+	unsigned long flags;
+	u32 temp;
+
+	if (vc > 3)
+		return -EINVAL;
+
+	spin_lock_irqsave(&csi->lock, flags);
+
+	temp = ipu_csi_read(csi, CSI_MIPI_DI);
+	temp &= ~(0xff << (vc * 8));
+	temp |= (cfg->mipi_dt << (vc * 8));
+	ipu_csi_write(csi, temp, CSI_MIPI_DI);
+
+	spin_unlock_irqrestore(&csi->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_set_mipi_datatype);
+
+int ipu_csi_set_skip_isp(struct ipu_csi *csi, u32 skip, u32 max_ratio)
+{
+	unsigned long flags;
+	u32 temp;
+
+	if (max_ratio > 5)
+		return -EINVAL;
+
+	spin_lock_irqsave(&csi->lock, flags);
+
+	temp = ipu_csi_read(csi, CSI_SKIP);
+	temp &= ~(CSI_MAX_RATIO_SKIP_ISP_MASK | CSI_SKIP_ISP_MASK);
+	temp |= (max_ratio << CSI_MAX_RATIO_SKIP_ISP_SHIFT) |
+		(skip << CSI_SKIP_ISP_SHIFT);
+	ipu_csi_write(csi, temp, CSI_SKIP);
+
+	spin_unlock_irqrestore(&csi->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_set_skip_isp);
+
+int ipu_csi_set_skip_smfc(struct ipu_csi *csi, u32 skip,
+			  u32 max_ratio, u32 id)
+{
+	unsigned long flags;
+	u32 temp;
+
+	if (max_ratio > 5 || id > 3)
+		return -EINVAL;
+
+	spin_lock_irqsave(&csi->lock, flags);
+
+	temp = ipu_csi_read(csi, CSI_SKIP);
+	temp &= ~(CSI_MAX_RATIO_SKIP_SMFC_MASK | CSI_ID_2_SKIP_MASK |
+		  CSI_SKIP_SMFC_MASK);
+	temp |= (max_ratio << CSI_MAX_RATIO_SKIP_SMFC_SHIFT) |
+		(id << CSI_ID_2_SKIP_SHIFT) |
+		(skip << CSI_SKIP_SMFC_SHIFT);
+	ipu_csi_write(csi, temp, CSI_SKIP);
+
+	spin_unlock_irqrestore(&csi->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_set_skip_smfc);
+
+int ipu_csi_set_dest(struct ipu_csi *csi, bool ic)
+{
+	unsigned long flags;
+	u32 csi_sens_conf, csi_dest;
+
+	csi_dest = ic ? CSI_DATA_DEST_IC : CSI_DATA_DEST_IDMAC;
+
+	spin_lock_irqsave(&csi->lock, flags);
+
+	csi_sens_conf = ipu_csi_read(csi, CSI_SENS_CONF);
+	csi_sens_conf &= ~CSI_SENS_CONF_DATA_DEST_MASK;
+	csi_sens_conf |= (csi_dest << CSI_SENS_CONF_DATA_DEST_SHIFT);
+	ipu_csi_write(csi, csi_sens_conf, CSI_SENS_CONF);
+
+	spin_unlock_irqrestore(&csi->lock, flags);
+
+	/* also need to set the IC source mux */
+	if (ic)
+		ipu_set_ic_src_mux(csi->ipu, csi->id, false);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_set_dest);
+
+int ipu_csi_enable(struct ipu_csi *csi)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&csi->lock, flags);
+
+	if (!csi->use_count)
+		ipu_module_enable(csi->ipu, csi->module);
+
+	csi->use_count++;
+
+	spin_unlock_irqrestore(&csi->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_enable);
+
+int ipu_csi_disable(struct ipu_csi *csi)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&csi->lock, flags);
+
+	csi->use_count--;
+
+	if (!csi->use_count)
+		ipu_module_disable(csi->ipu, csi->module);
+
+	if (csi->use_count < 0)
+		csi->use_count = 0;
+
+	spin_unlock_irqrestore(&csi->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_disable);
+
+int ipu_csi_get_num(struct ipu_csi *csi)
+{
+	return csi->id;
+}
+EXPORT_SYMBOL_GPL(ipu_csi_get_num);
+
+struct ipu_csi *ipu_csi_get(struct ipu_soc *ipu, int id)
+{
+	if (id > 1)
+		return ERR_PTR(-EINVAL);
+
+	return ipu->csi_priv[id];
+}
+EXPORT_SYMBOL_GPL(ipu_csi_get);
+
+void ipu_csi_put(struct ipu_csi *csi)
+{
+}
+EXPORT_SYMBOL_GPL(ipu_csi_put);
+
+int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id,
+		 unsigned long base, u32 module, struct clk *clk_ipu)
+{
+	struct ipu_csi *csi;
+
+	if (id > 1)
+		return -ENODEV;
+
+	csi = devm_kzalloc(dev, sizeof(*csi), GFP_KERNEL);
+	if (!csi)
+		return -ENOMEM;
+
+	ipu->csi_priv[id] = csi;
+
+	spin_lock_init(&csi->lock);
+	csi->module = module;
+	csi->id = id;
+	csi->clk_ipu = clk_ipu;
+	csi->base = devm_ioremap(dev, base, PAGE_SIZE);
+	if (!csi->base)
+		return -ENOMEM;
+
+	dev_dbg(dev, "CSI%d base: 0x%08lx remapped to %p\n",
+		id, base, csi->base);
+	csi->ipu = ipu;
+
+	return 0;
+}
+
+void ipu_csi_exit(struct ipu_soc *ipu, int id)
+{
+}
+
+void ipu_csi_dump(struct ipu_csi *csi)
+{
+	dev_dbg(csi->ipu->dev, "CSI_SENS_CONF:     %08x\n",
+		ipu_csi_read(csi, CSI_SENS_CONF));
+	dev_dbg(csi->ipu->dev, "CSI_SENS_FRM_SIZE: %08x\n",
+		ipu_csi_read(csi, CSI_SENS_FRM_SIZE));
+	dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE:  %08x\n",
+		ipu_csi_read(csi, CSI_ACT_FRM_SIZE));
+	dev_dbg(csi->ipu->dev, "CSI_OUT_FRM_CTRL:  %08x\n",
+		ipu_csi_read(csi, CSI_OUT_FRM_CTRL));
+	dev_dbg(csi->ipu->dev, "CSI_TST_CTRL:      %08x\n",
+		ipu_csi_read(csi, CSI_TST_CTRL));
+	dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_1:   %08x\n",
+		ipu_csi_read(csi, CSI_CCIR_CODE_1));
+	dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_2:   %08x\n",
+		ipu_csi_read(csi, CSI_CCIR_CODE_2));
+	dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_3:   %08x\n",
+		ipu_csi_read(csi, CSI_CCIR_CODE_3));
+	dev_dbg(csi->ipu->dev, "CSI_MIPI_DI:       %08x\n",
+		ipu_csi_read(csi, CSI_MIPI_DI));
+	dev_dbg(csi->ipu->dev, "CSI_SKIP:          %08x\n",
+		ipu_csi_read(csi, CSI_SKIP));
+}
+EXPORT_SYMBOL_GPL(ipu_csi_dump);
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-ic.c b/drivers/staging/imx-drm/ipu-v3/ipu-ic.c
new file mode 100644
index 0000000..7ec40f7
--- /dev/null
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-ic.c
@@ -0,0 +1,835 @@
+/*
+ * Copyright (C) 2012-2014 Mentor Graphics Inc.
+ * Copyright 2005-2012 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 <linux/types.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <linux/bitrev.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+
+#include "ipu-prv.h"
+
+/* IC Register Offsets */
+#define IC_CONF                 0x0000
+#define IC_PRP_ENC_RSC          0x0004
+#define IC_PRP_VF_RSC           0x0008
+#define IC_PP_RSC               0x000C
+#define IC_CMBP_1               0x0010
+#define IC_CMBP_2               0x0014
+#define IC_IDMAC_1              0x0018
+#define IC_IDMAC_2              0x001C
+#define IC_IDMAC_3              0x0020
+#define IC_IDMAC_4              0x0024
+
+/* IC Register Fields */
+#define IC_CONF_PRPENC_EN       (1 << 0)
+#define IC_CONF_PRPENC_CSC1     (1 << 1)
+#define IC_CONF_PRPENC_ROT_EN   (1 << 2)
+#define IC_CONF_PRPVF_EN        (1 << 8)
+#define IC_CONF_PRPVF_CSC1      (1 << 9)
+#define IC_CONF_PRPVF_CSC2      (1 << 10)
+#define IC_CONF_PRPVF_CMB       (1 << 11)
+#define IC_CONF_PRPVF_ROT_EN    (1 << 12)
+#define IC_CONF_PP_EN           (1 << 16)
+#define IC_CONF_PP_CSC1         (1 << 17)
+#define IC_CONF_PP_CSC2         (1 << 18)
+#define IC_CONF_PP_CMB          (1 << 19)
+#define IC_CONF_PP_ROT_EN       (1 << 20)
+#define IC_CONF_IC_GLB_LOC_A    (1 << 28)
+#define IC_CONF_KEY_COLOR_EN    (1 << 29)
+#define IC_CONF_RWS_EN          (1 << 30)
+#define IC_CONF_CSI_MEM_WR_EN   (1 << 31)
+
+#define IC_IDMAC_1_CB0_BURST_16         (1 << 0)
+#define IC_IDMAC_1_CB1_BURST_16         (1 << 1)
+#define IC_IDMAC_1_CB2_BURST_16         (1 << 2)
+#define IC_IDMAC_1_CB3_BURST_16         (1 << 3)
+#define IC_IDMAC_1_CB4_BURST_16         (1 << 4)
+#define IC_IDMAC_1_CB5_BURST_16         (1 << 5)
+#define IC_IDMAC_1_CB6_BURST_16         (1 << 6)
+#define IC_IDMAC_1_CB7_BURST_16         (1 << 7)
+#define IC_IDMAC_1_PRPENC_ROT_MASK      (0x7 << 11)
+#define IC_IDMAC_1_PRPENC_ROT_OFFSET    11
+#define IC_IDMAC_1_PRPVF_ROT_MASK       (0x7 << 14)
+#define IC_IDMAC_1_PRPVF_ROT_OFFSET     14
+#define IC_IDMAC_1_PP_ROT_MASK          (0x7 << 17)
+#define IC_IDMAC_1_PP_ROT_OFFSET        17
+#define IC_IDMAC_1_PP_FLIP_RS           (1 << 22)
+#define IC_IDMAC_1_PRPVF_FLIP_RS        (1 << 21)
+#define IC_IDMAC_1_PRPENC_FLIP_RS       (1 << 20)
+
+#define IC_IDMAC_2_PRPENC_HEIGHT_MASK   (0x3ff << 0)
+#define IC_IDMAC_2_PRPENC_HEIGHT_OFFSET 0
+#define IC_IDMAC_2_PRPVF_HEIGHT_MASK    (0x3ff << 10)
+#define IC_IDMAC_2_PRPVF_HEIGHT_OFFSET  10
+#define IC_IDMAC_2_PP_HEIGHT_MASK       (0x3ff << 20)
+#define IC_IDMAC_2_PP_HEIGHT_OFFSET     20
+
+#define IC_IDMAC_3_PRPENC_WIDTH_MASK    (0x3ff << 0)
+#define IC_IDMAC_3_PRPENC_WIDTH_OFFSET  0
+#define IC_IDMAC_3_PRPVF_WIDTH_MASK     (0x3ff << 10)
+#define IC_IDMAC_3_PRPVF_WIDTH_OFFSET   10
+#define IC_IDMAC_3_PP_WIDTH_MASK        (0x3ff << 20)
+#define IC_IDMAC_3_PP_WIDTH_OFFSET      20
+
+struct ic_task_regoffs {
+	u32 rsc;
+	u32 tpmem_csc[2];
+};
+
+struct ic_task_bitfields {
+	u32 ic_conf_en;
+	u32 ic_conf_rot_en;
+	u32 ic_conf_cmb_en;
+	u32 ic_conf_csc1_en;
+	u32 ic_conf_csc2_en;
+	u32 ic_cmb_galpha_bit;
+};
+
+static const struct ic_task_regoffs ic_task_reg[IC_NUM_TASKS] = {
+	[IC_TASK_ENCODER] = {
+		.rsc = IC_PRP_ENC_RSC,
+		.tpmem_csc = {0x2008, 0},
+	},
+	[IC_TASK_VIEWFINDER] = {
+		.rsc = IC_PRP_VF_RSC,
+		.tpmem_csc = {0x4028, 0x4040},
+	},
+	[IC_TASK_POST_PROCESSOR] = {
+		.rsc = IC_PP_RSC,
+		.tpmem_csc = {0x6060, 0x6078},
+	},
+};
+
+static const struct ic_task_bitfields ic_task_bit[IC_NUM_TASKS] = {
+	[IC_TASK_ENCODER] = {
+		.ic_conf_en = IC_CONF_PRPENC_EN,
+		.ic_conf_rot_en = IC_CONF_PRPENC_ROT_EN,
+		.ic_conf_cmb_en = 0,    /* NA */
+		.ic_conf_csc1_en = IC_CONF_PRPENC_CSC1,
+		.ic_conf_csc2_en = 0,   /* NA */
+		.ic_cmb_galpha_bit = 0, /* NA */
+	},
+	[IC_TASK_VIEWFINDER] = {
+		.ic_conf_en = IC_CONF_PRPVF_EN,
+		.ic_conf_rot_en = IC_CONF_PRPVF_ROT_EN,
+		.ic_conf_cmb_en = IC_CONF_PRPVF_CMB,
+		.ic_conf_csc1_en = IC_CONF_PRPVF_CSC1,
+		.ic_conf_csc2_en = IC_CONF_PRPVF_CSC2,
+		.ic_cmb_galpha_bit = 0,
+	},
+	[IC_TASK_POST_PROCESSOR] = {
+		.ic_conf_en = IC_CONF_PP_EN,
+		.ic_conf_rot_en = IC_CONF_PP_ROT_EN,
+		.ic_conf_cmb_en = IC_CONF_PP_CMB,
+		.ic_conf_csc1_en = IC_CONF_PP_CSC1,
+		.ic_conf_csc2_en = IC_CONF_PP_CSC2,
+		.ic_cmb_galpha_bit = 8,
+	},
+};
+
+struct ipu_ic_priv;
+
+struct ipu_ic {
+	enum ipu_ic_task task;
+	const struct ic_task_regoffs *reg;
+	const struct ic_task_bitfields *bit;
+
+	enum ipu_color_space in_cs, g_in_cs;
+	enum ipu_color_space out_cs;
+	bool graphics;
+	bool rotation;
+	bool in_use;
+
+	struct ipu_ic_priv *priv;
+};
+
+struct ipu_ic_priv {
+	void __iomem *base;
+	void __iomem *tpmem_base;
+	u32 module;
+	spinlock_t lock;
+	struct ipu_soc *ipu;
+	int use_count;
+	struct ipu_ic task[IC_NUM_TASKS];
+};
+
+static int init_csc(struct ipu_ic *ic,
+		    enum ipu_color_space in_format,
+		    enum ipu_color_space out_format,
+		    int csc_index);
+static int calc_resize_coeffs(struct ipu_ic *ic,
+			      u32 in_size, u32 out_size,
+			      u32 *resize_coeff,
+			      u32 *downsize_coeff);
+
+static inline u32 ipu_ic_read(struct ipu_ic *ic, unsigned offset)
+{
+	return readl(ic->priv->base + offset);
+}
+
+static inline void ipu_ic_write(struct ipu_ic *ic, u32 value,
+				unsigned offset)
+{
+	writel(value, ic->priv->base + offset);
+}
+
+void ipu_ic_dump(struct ipu_ic *ic)
+{
+	struct ipu_ic_priv *priv = ic->priv;
+	struct ipu_soc *ipu = priv->ipu;
+
+	dev_dbg(ipu->dev, "IC_CONF = \t0x%08X\n",
+		ipu_ic_read(ic, IC_CONF));
+	dev_dbg(ipu->dev, "IC_PRP_ENC_RSC = \t0x%08X\n",
+		ipu_ic_read(ic, IC_PRP_ENC_RSC));
+	dev_dbg(ipu->dev, "IC_PRP_VF_RSC = \t0x%08X\n",
+		ipu_ic_read(ic, IC_PRP_VF_RSC));
+	dev_dbg(ipu->dev, "IC_PP_RSC = \t0x%08X\n",
+		ipu_ic_read(ic, IC_PP_RSC));
+	dev_dbg(ipu->dev, "IC_CMBP_1 = \t0x%08X\n",
+		ipu_ic_read(ic, IC_CMBP_1));
+	dev_dbg(ipu->dev, "IC_CMBP_2 = \t0x%08X\n",
+		ipu_ic_read(ic, IC_CMBP_2));
+	dev_dbg(ipu->dev, "IC_IDMAC_1 = \t0x%08X\n",
+		ipu_ic_read(ic, IC_IDMAC_1));
+	dev_dbg(ipu->dev, "IC_IDMAC_2 = \t0x%08X\n",
+		ipu_ic_read(ic, IC_IDMAC_2));
+	dev_dbg(ipu->dev, "IC_IDMAC_3 = \t0x%08X\n",
+		ipu_ic_read(ic, IC_IDMAC_3));
+	dev_dbg(ipu->dev, "IC_IDMAC_4 = \t0x%08X\n",
+		ipu_ic_read(ic, IC_IDMAC_4));
+}
+EXPORT_SYMBOL_GPL(ipu_ic_dump);
+
+void ipu_ic_task_enable(struct ipu_ic *ic)
+{
+	struct ipu_ic_priv *priv = ic->priv;
+	unsigned long flags;
+	u32 ic_conf;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	ic_conf = ipu_ic_read(ic, IC_CONF);
+
+	ic_conf |= ic->bit->ic_conf_en;
+
+	if (ic->rotation)
+		ic_conf |= ic->bit->ic_conf_rot_en;
+
+	if (ic->in_cs != ic->out_cs)
+		ic_conf |= ic->bit->ic_conf_csc1_en;
+
+	if (ic->graphics) {
+		ic_conf |= ic->bit->ic_conf_cmb_en;
+		ic_conf |= ic->bit->ic_conf_csc1_en;
+
+		if (ic->g_in_cs != ic->out_cs)
+			ic_conf |= ic->bit->ic_conf_csc2_en;
+	}
+
+	ipu_ic_write(ic, ic_conf, IC_CONF);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_ic_task_enable);
+
+void ipu_ic_task_disable(struct ipu_ic *ic)
+{
+	struct ipu_ic_priv *priv = ic->priv;
+	unsigned long flags;
+	u32 ic_conf;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	ic_conf = ipu_ic_read(ic, IC_CONF);
+
+	ic_conf &= ~(ic->bit->ic_conf_en |
+		     ic->bit->ic_conf_csc1_en |
+		     ic->bit->ic_conf_rot_en);
+	if (ic->bit->ic_conf_csc2_en)
+		ic_conf &= ~ic->bit->ic_conf_csc2_en;
+	if (ic->bit->ic_conf_cmb_en)
+		ic_conf &= ~ic->bit->ic_conf_cmb_en;
+
+	ipu_ic_write(ic, ic_conf, IC_CONF);
+
+	ic->rotation = ic->graphics = false;
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_ic_task_disable);
+
+int ipu_ic_task_graphics_init(struct ipu_ic *ic,
+			      enum ipu_color_space in_g_cs,
+			      bool galpha_en, u32 galpha,
+			      bool colorkey_en, u32 colorkey)
+{
+	struct ipu_ic_priv *priv = ic->priv;
+	unsigned long flags;
+	u32 reg, ic_conf;
+	int ret = 0;
+
+	if (ic->task == IC_TASK_ENCODER)
+		return -EINVAL;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	ic_conf = ipu_ic_read(ic, IC_CONF);
+
+	if (!(ic_conf & ic->bit->ic_conf_csc1_en)) {
+		/* need transparent CSC1 conversion */
+		ret = init_csc(ic, IPUV3_COLORSPACE_RGB,
+			       IPUV3_COLORSPACE_RGB, 0);
+		if (ret)
+			goto unlock;
+	}
+
+	ic->g_in_cs = in_g_cs;
+
+	if (ic->g_in_cs != ic->out_cs) {
+		ret = init_csc(ic, ic->g_in_cs, ic->out_cs, 1);
+		if (ret)
+			goto unlock;
+	}
+
+	if (galpha_en) {
+		ic_conf |= IC_CONF_IC_GLB_LOC_A;
+		reg = ipu_ic_read(ic, IC_CMBP_1);
+		reg &= ~(0xff << ic->bit->ic_cmb_galpha_bit);
+		reg |= (galpha << ic->bit->ic_cmb_galpha_bit);
+		ipu_ic_write(ic, reg, IC_CMBP_1);
+	} else
+		ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
+
+	if (colorkey_en) {
+		ic_conf |= IC_CONF_KEY_COLOR_EN;
+		ipu_ic_write(ic, colorkey, IC_CMBP_2);
+	} else
+		ic_conf &= ~IC_CONF_KEY_COLOR_EN;
+
+	ipu_ic_write(ic, ic_conf, IC_CONF);
+
+	ic->graphics = true;
+unlock:
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_ic_task_graphics_init);
+
+int ipu_ic_task_init(struct ipu_ic *ic,
+		     int in_width, int in_height,
+		     int out_width, int out_height,
+		     enum ipu_color_space in_cs,
+		     enum ipu_color_space out_cs)
+{
+	struct ipu_ic_priv *priv = ic->priv;
+	u32 reg, downsize_coeff, resize_coeff;
+	unsigned long flags;
+	int ret = 0;
+
+	/* Setup vertical resizing */
+	ret = calc_resize_coeffs(ic, in_height, out_height,
+				 &resize_coeff, &downsize_coeff);
+	if (ret)
+		return ret;
+
+	reg = (downsize_coeff << 30) | (resize_coeff << 16);
+
+	/* Setup horizontal resizing */
+	ret = calc_resize_coeffs(ic, in_width, out_width,
+				 &resize_coeff, &downsize_coeff);
+	if (ret)
+		return ret;
+
+	reg |= (downsize_coeff << 14) | resize_coeff;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	ipu_ic_write(ic, reg, ic->reg->rsc);
+
+	/* Setup color space conversion */
+	ic->in_cs = in_cs;
+	ic->out_cs = out_cs;
+
+	if (ic->in_cs != ic->out_cs) {
+		ret = init_csc(ic, ic->in_cs, ic->out_cs, 0);
+		if (ret)
+			goto unlock;
+	}
+
+unlock:
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_ic_task_init);
+
+int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel,
+			  u32 width, u32 height, int burst_size,
+			  enum ipu_rotate_mode rot)
+{
+	struct ipu_ic_priv *priv = ic->priv;
+	struct ipu_soc *ipu = priv->ipu;
+	u32 ic_idmac_1, ic_idmac_2, ic_idmac_3;
+	u32 temp_rot = bitrev8(rot) >> 5;
+	bool need_hor_flip = false;
+	unsigned long flags;
+	int ret = 0;
+
+	if ((burst_size != 8) && (burst_size != 16)) {
+		dev_err(ipu->dev, "Illegal burst length for IC\n");
+		return -EINVAL;
+	}
+
+	width--;
+	height--;
+
+	if (temp_rot & 0x2)	/* Need horizontal flip */
+		need_hor_flip = true;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	ic_idmac_1 = ipu_ic_read(ic, IC_IDMAC_1);
+	ic_idmac_2 = ipu_ic_read(ic, IC_IDMAC_2);
+	ic_idmac_3 = ipu_ic_read(ic, IC_IDMAC_3);
+
+	switch (channel->num) {
+	case IPUV3_CHANNEL_IC_PP_MEM:
+		if (burst_size == 16)
+			ic_idmac_1 |= IC_IDMAC_1_CB2_BURST_16;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_CB2_BURST_16;
+
+		if (need_hor_flip)
+			ic_idmac_1 |= IC_IDMAC_1_PP_FLIP_RS;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_PP_FLIP_RS;
+
+		ic_idmac_2 &= ~IC_IDMAC_2_PP_HEIGHT_MASK;
+		ic_idmac_2 |= height << IC_IDMAC_2_PP_HEIGHT_OFFSET;
+
+		ic_idmac_3 &= ~IC_IDMAC_3_PP_WIDTH_MASK;
+		ic_idmac_3 |= width << IC_IDMAC_3_PP_WIDTH_OFFSET;
+		break;
+	case IPUV3_CHANNEL_MEM_IC_PP:
+		if (burst_size == 16)
+			ic_idmac_1 |= IC_IDMAC_1_CB5_BURST_16;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_CB5_BURST_16;
+		break;
+	case IPUV3_CHANNEL_MEM_ROT_PP:
+		ic_idmac_1 &= ~IC_IDMAC_1_PP_ROT_MASK;
+		ic_idmac_1 |= temp_rot << IC_IDMAC_1_PP_ROT_OFFSET;
+		break;
+	case IPUV3_CHANNEL_MEM_IC_PRP_VF:
+		if (burst_size == 16)
+			ic_idmac_1 |= IC_IDMAC_1_CB6_BURST_16;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_CB6_BURST_16;
+		break;
+	case IPUV3_CHANNEL_IC_PRP_ENC_MEM:
+		if (burst_size == 16)
+			ic_idmac_1 |= IC_IDMAC_1_CB0_BURST_16;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_CB0_BURST_16;
+
+		if (need_hor_flip)
+			ic_idmac_1 |= IC_IDMAC_1_PRPENC_FLIP_RS;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_FLIP_RS;
+
+		ic_idmac_2 &= ~IC_IDMAC_2_PRPENC_HEIGHT_MASK;
+		ic_idmac_2 |= height << IC_IDMAC_2_PRPENC_HEIGHT_OFFSET;
+
+		ic_idmac_3 &= ~IC_IDMAC_3_PRPENC_WIDTH_MASK;
+		ic_idmac_3 |= width << IC_IDMAC_3_PRPENC_WIDTH_OFFSET;
+		break;
+	case IPUV3_CHANNEL_MEM_ROT_ENC:
+		ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_ROT_MASK;
+		ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPENC_ROT_OFFSET;
+		break;
+	case IPUV3_CHANNEL_IC_PRP_VF_MEM:
+		if (burst_size == 16)
+			ic_idmac_1 |= IC_IDMAC_1_CB1_BURST_16;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_CB1_BURST_16;
+
+		if (need_hor_flip)
+			ic_idmac_1 |= IC_IDMAC_1_PRPVF_FLIP_RS;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_FLIP_RS;
+
+		ic_idmac_2 &= ~IC_IDMAC_2_PRPVF_HEIGHT_MASK;
+		ic_idmac_2 |= height << IC_IDMAC_2_PRPVF_HEIGHT_OFFSET;
+
+		ic_idmac_3 &= ~IC_IDMAC_3_PRPVF_WIDTH_MASK;
+		ic_idmac_3 |= width << IC_IDMAC_3_PRPVF_WIDTH_OFFSET;
+		break;
+	case IPUV3_CHANNEL_MEM_ROT_VF:
+		ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_ROT_MASK;
+		ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPVF_ROT_OFFSET;
+		break;
+	case IPUV3_CHANNEL_G_MEM_IC_PRP_VF:
+		if (burst_size == 16)
+			ic_idmac_1 |= IC_IDMAC_1_CB3_BURST_16;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_CB3_BURST_16;
+		break;
+	case IPUV3_CHANNEL_G_MEM_IC_PP:
+		if (burst_size == 16)
+			ic_idmac_1 |= IC_IDMAC_1_CB4_BURST_16;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_CB4_BURST_16;
+		break;
+	case IPUV3_CHANNEL_VDI_MEM_IC_VF:
+		if (burst_size == 16)
+			ic_idmac_1 |= IC_IDMAC_1_CB7_BURST_16;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_CB7_BURST_16;
+		break;
+	default:
+		goto unlock;
+	}
+
+	ipu_ic_write(ic, ic_idmac_1, IC_IDMAC_1);
+	ipu_ic_write(ic, ic_idmac_2, IC_IDMAC_2);
+	ipu_ic_write(ic, ic_idmac_3, IC_IDMAC_3);
+
+	if (rot >= IPU_ROTATE_90_RIGHT)
+		ic->rotation = true;
+
+unlock:
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_ic_task_idma_init);
+
+
+/*
+ * Y = R *  .299 + G *  .587 + B *  .114;
+ * U = R * -.169 + G * -.332 + B *  .500 + 128.;
+ * V = R *  .500 + G * -.419 + B * -.0813 + 128.;
+ */
+static const u32 rgb2ycbcr_coeff[4][3] = {
+	{0x004D, 0x0096, 0x001D},
+	{0x01D5, 0x01AB, 0x0080},
+	{0x0080, 0x0195, 0x01EB},
+	{0x0000, 0x0200, 0x0200},	/* A0, A1, A2 */
+};
+
+/* transparent RGB->RGB matrix for graphics combining */
+static const u32 rgb2rgb_coeff[4][3] = {
+	{0x0080, 0x0000, 0x0000},
+	{0x0000, 0x0080, 0x0000},
+	{0x0000, 0x0000, 0x0080},
+	{0x0000, 0x0000, 0x0000},	/* A0, A1, A2 */
+};
+
+/*
+ * R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
+ * G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
+ * B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128);
+ */
+static const u32 ycbcr2rgb_coeff[4][3] = {
+	{149, 0, 204},
+	{149, 462, 408},
+	{149, 255, 0},
+	{8192 - 446, 266, 8192 - 554},	/* A0, A1, A2 */
+};
+
+static int init_csc(struct ipu_ic *ic,
+		    enum ipu_color_space in_format,
+		    enum ipu_color_space out_format,
+		    int csc_index)
+{
+	struct ipu_ic_priv *priv = ic->priv;
+	u32 __iomem *base;
+	u32 param;
+
+	base = (u32 __iomem *)
+		(priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
+
+	if (in_format == IPUV3_COLORSPACE_YUV &&
+	    out_format == IPUV3_COLORSPACE_RGB) {
+		/* Init CSC (YCbCr->RGB) */
+		param = (ycbcr2rgb_coeff[3][0] << 27) |
+			(ycbcr2rgb_coeff[0][0] << 18) |
+			(ycbcr2rgb_coeff[1][1] << 9) |
+			ycbcr2rgb_coeff[2][2];
+		writel(param, base++);
+
+		/* scale = 2, sat = 0 */
+		param = (ycbcr2rgb_coeff[3][0] >> 5) |
+			(2L << (40 - 32));
+		writel(param, base++);
+
+		param = (ycbcr2rgb_coeff[3][1] << 27) |
+			(ycbcr2rgb_coeff[0][1] << 18) |
+			(ycbcr2rgb_coeff[1][0] << 9) |
+			ycbcr2rgb_coeff[2][0];
+		writel(param, base++);
+
+		param = (ycbcr2rgb_coeff[3][1] >> 5);
+		writel(param, base++);
+
+		param = (ycbcr2rgb_coeff[3][2] << 27) |
+			(ycbcr2rgb_coeff[0][2] << 18) |
+			(ycbcr2rgb_coeff[1][2] << 9) |
+			ycbcr2rgb_coeff[2][1];
+		writel(param, base++);
+
+		param = (ycbcr2rgb_coeff[3][2] >> 5);
+		writel(param, base++);
+	} else if (in_format == IPUV3_COLORSPACE_RGB &&
+		   out_format == IPUV3_COLORSPACE_YUV) {
+		/* Init CSC (RGB->YCbCr) */
+		param = (rgb2ycbcr_coeff[3][0] << 27) |
+			(rgb2ycbcr_coeff[0][0] << 18) |
+			(rgb2ycbcr_coeff[1][1] << 9) |
+			rgb2ycbcr_coeff[2][2];
+		writel(param, base++);
+
+		/* scale = 1, sat = 0 */
+		param = (rgb2ycbcr_coeff[3][0] >> 5) | (1UL << 8);
+		writel(param, base++);
+
+		param = (rgb2ycbcr_coeff[3][1] << 27) |
+			(rgb2ycbcr_coeff[0][1] << 18) |
+			(rgb2ycbcr_coeff[1][0] << 9) |
+			rgb2ycbcr_coeff[2][0];
+		writel(param, base++);
+
+		param = (rgb2ycbcr_coeff[3][1] >> 5);
+		writel(param, base++);
+
+		param = (rgb2ycbcr_coeff[3][2] << 27) |
+			(rgb2ycbcr_coeff[0][2] << 18) |
+			(rgb2ycbcr_coeff[1][2] << 9) |
+			rgb2ycbcr_coeff[2][1];
+		writel(param, base++);
+
+		param = (rgb2ycbcr_coeff[3][2] >> 5);
+		writel(param, base++);
+	} else if (in_format == IPUV3_COLORSPACE_RGB &&
+		   out_format == IPUV3_COLORSPACE_RGB) {
+		/* Init CSC */
+		param = (rgb2rgb_coeff[3][0] << 27) |
+			(rgb2rgb_coeff[0][0] << 18) |
+			(rgb2rgb_coeff[1][1] << 9) |
+			rgb2rgb_coeff[2][2];
+		writel(param, base++);
+
+		/* scale = 2, sat = 0 */
+		param = (rgb2rgb_coeff[3][0] >> 5) | (2UL << 8);
+		writel(param, base++);
+
+		param = (rgb2rgb_coeff[3][1] << 27) |
+			(rgb2rgb_coeff[0][1] << 18) |
+			(rgb2rgb_coeff[1][0] << 9) |
+			rgb2rgb_coeff[2][0];
+		writel(param, base++);
+
+		param = (rgb2rgb_coeff[3][1] >> 5);
+		writel(param, base++);
+
+		param = (rgb2rgb_coeff[3][2] << 27) |
+			(rgb2rgb_coeff[0][2] << 18) |
+			(rgb2rgb_coeff[1][2] << 9) |
+			rgb2rgb_coeff[2][1];
+		writel(param, base++);
+
+		param = (rgb2rgb_coeff[3][2] >> 5);
+		writel(param, base++);
+	} else {
+		dev_err(priv->ipu->dev, "Unsupported color space conversion\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int calc_resize_coeffs(struct ipu_ic *ic,
+			      u32 in_size, u32 out_size,
+			      u32 *resize_coeff,
+			      u32 *downsize_coeff)
+{
+	struct ipu_ic_priv *priv = ic->priv;
+	struct ipu_soc *ipu = priv->ipu;
+	u32 temp_size, temp_downsize;
+
+	/*
+	 * Input size cannot be more than 4096, and output size cannot
+	 * be more than 1024
+	 */
+	if (in_size > 4096) {
+		dev_err(ipu->dev, "Unsupported resize (in_size > 4096)\n");
+		return -EINVAL;
+	}
+	if (out_size > 1024) {
+		dev_err(ipu->dev, "Unsupported resize (out_size > 1024)\n");
+		return -EINVAL;
+	}
+
+	/* Cannot downsize more than 8:1 */
+	if ((out_size << 3) < in_size) {
+		dev_err(ipu->dev, "Unsupported downsize\n");
+		return -EINVAL;
+	}
+
+	/* Compute downsizing coefficient */
+	temp_downsize = 0;
+	temp_size = in_size;
+	while (((temp_size > 1024) || (temp_size >= out_size * 2)) &&
+	       (temp_downsize < 2)) {
+		temp_size >>= 1;
+		temp_downsize++;
+	}
+	*downsize_coeff = temp_downsize;
+
+	/*
+	 * compute resizing coefficient using the following equation:
+	 * resize_coeff = M * (SI - 1) / (SO - 1)
+	 * where M = 2^13, SI = input size, SO = output size
+	 */
+	*resize_coeff = (8192L * (temp_size - 1)) / (out_size - 1);
+	if (*resize_coeff >= 16384L) {
+		dev_err(ipu->dev, "Warning! Overflow on resize coeff.\n");
+		*resize_coeff = 0x3FFF;
+	}
+
+	return 0;
+}
+
+
+int ipu_ic_enable(struct ipu_ic *ic)
+{
+	struct ipu_ic_priv *priv = ic->priv;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	if (!priv->use_count)
+		ipu_module_enable(priv->ipu, priv->module);
+
+	priv->use_count++;
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_ic_enable);
+
+int ipu_ic_disable(struct ipu_ic *ic)
+{
+	struct ipu_ic_priv *priv = ic->priv;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	priv->use_count--;
+
+	if (!priv->use_count)
+		ipu_module_disable(priv->ipu, priv->module);
+
+	if (priv->use_count < 0)
+		priv->use_count = 0;
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_ic_disable);
+
+struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task)
+{
+	struct ipu_ic_priv *priv = ipu->ic_priv;
+	unsigned long flags;
+	struct ipu_ic *ic, *ret;
+
+	if (task >= IC_NUM_TASKS)
+		return ERR_PTR(-EINVAL);
+
+	ic = &priv->task[task];
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	if (ic->in_use) {
+		ret = ERR_PTR(-EBUSY);
+		goto unlock;
+	}
+
+	ic->in_use = true;
+	ret = ic;
+
+unlock:
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_ic_get);
+
+void ipu_ic_put(struct ipu_ic *ic)
+{
+	struct ipu_ic_priv *priv = ic->priv;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	ic->in_use = false;
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_ic_put);
+
+int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
+		unsigned long base, unsigned long tpmem_base,
+		u32 module)
+{
+	struct ipu_ic_priv *priv;
+	int i;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	ipu->ic_priv = priv;
+
+	spin_lock_init(&priv->lock);
+	priv->module = module;
+	priv->base = devm_ioremap(dev, base, PAGE_SIZE);
+	if (!priv->base)
+		return -ENOMEM;
+	priv->tpmem_base = devm_ioremap(dev, tpmem_base, SZ_64K);
+	if (!priv->tpmem_base)
+		return -ENOMEM;
+
+	dev_dbg(dev, "IC base: 0x%08lx remapped to %p\n", base, priv->base);
+
+	priv->ipu = ipu;
+
+	for (i = 0; i < IC_NUM_TASKS; i++) {
+		priv->task[i].task = i;
+		priv->task[i].priv = priv;
+		priv->task[i].reg = &ic_task_reg[i];
+		priv->task[i].bit = &ic_task_bit[i];
+	}
+
+	return 0;
+}
+
+void ipu_ic_exit(struct ipu_soc *ipu)
+{
+}
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-irt.c b/drivers/staging/imx-drm/ipu-v3/ipu-irt.c
new file mode 100644
index 0000000..fff8188
--- /dev/null
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-irt.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2012 Mentor Graphics 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.
+ */
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+
+#include "ipu-prv.h"
+
+struct ipu_irt {
+	u32 module;
+	spinlock_t lock;
+	int use_count;
+	struct ipu_soc *ipu;
+};
+
+
+int ipu_irt_enable(struct ipu_irt *irt)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&irt->lock, flags);
+
+	if (!irt->use_count)
+		ipu_module_enable(irt->ipu, irt->module);
+
+	irt->use_count++;
+
+	spin_unlock_irqrestore(&irt->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_irt_enable);
+
+int ipu_irt_disable(struct ipu_irt *irt)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&irt->lock, flags);
+
+	irt->use_count--;
+
+	if (!irt->use_count)
+		ipu_module_disable(irt->ipu, irt->module);
+
+	if (irt->use_count < 0)
+		irt->use_count = 0;
+
+	spin_unlock_irqrestore(&irt->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_irt_disable);
+
+struct ipu_irt *ipu_irt_get(struct ipu_soc *ipu)
+{
+	return ipu->irt_priv;
+}
+EXPORT_SYMBOL_GPL(ipu_irt_get);
+
+void ipu_irt_put(struct ipu_irt *irt)
+{
+}
+EXPORT_SYMBOL_GPL(ipu_irt_put);
+
+int ipu_irt_init(struct ipu_soc *ipu, struct device *dev, u32 module)
+{
+	struct ipu_irt *irt;
+
+	irt = devm_kzalloc(dev, sizeof(*irt), GFP_KERNEL);
+	if (!irt)
+		return -ENOMEM;
+
+	ipu->irt_priv = irt;
+
+	spin_lock_init(&irt->lock);
+	irt->module = module;
+	irt->ipu = ipu;
+
+	return 0;
+}
+
+void ipu_irt_exit(struct ipu_soc *ipu)
+{
+}
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
index 1398752..211d6f2 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
@@ -163,6 +163,10 @@ struct ipu_dc_priv;
 struct ipu_dmfc_priv;
 struct ipu_di;
 struct ipu_devtype;
+struct ipu_csi;
+struct ipu_smfc;
+struct ipu_ic_priv;
+struct ipu_irt;
 
 struct ipu_soc {
 	struct device		*dev;
@@ -191,6 +195,10 @@ struct ipu_soc {
 	struct ipu_dp_priv	*dp_priv;
 	struct ipu_dmfc_priv	*dmfc_priv;
 	struct ipu_di		*di_priv[2];
+	struct ipu_csi		*csi_priv[2];
+	struct ipu_smfc		*smfc_priv;
+	struct ipu_ic_priv	*ic_priv;
+	struct ipu_irt		*irt_priv;
 };
 
 void ipu_srm_dp_sync_update(struct ipu_soc *ipu);
@@ -201,6 +209,22 @@ int ipu_module_disable(struct ipu_soc *ipu, u32 mask);
 void ipu_set_csi_src_mux(struct ipu_soc *ipu, int csi_id, bool mipi_csi2);
 void ipu_set_ic_src_mux(struct ipu_soc *ipu, int csi_id, bool vdi);
 
+int ipu_csi_init(struct ipu_soc *ipu, struct device *dev, int id,
+		 unsigned long base, u32 module, struct clk *clk_ipu);
+void ipu_csi_exit(struct ipu_soc *ipu, int id);
+
+int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev,
+		  unsigned long base, u32 module);
+void ipu_smfc_exit(struct ipu_soc *ipu);
+
+int ipu_ic_init(struct ipu_soc *ipu, struct device *dev,
+		unsigned long base, unsigned long tpmem_base,
+		u32 module);
+void ipu_ic_exit(struct ipu_soc *ipu);
+
+int ipu_irt_init(struct ipu_soc *ipu, struct device *dev, u32 module);
+void ipu_irt_exit(struct ipu_soc *ipu);
+
 int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
 		unsigned long base, u32 module, struct clk *ipu_clk);
 void ipu_di_exit(struct ipu_soc *ipu, int id);
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-smfc.c b/drivers/staging/imx-drm/ipu-v3/ipu-smfc.c
new file mode 100644
index 0000000..0e4881b
--- /dev/null
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-smfc.c
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2012 Mentor Graphics Inc.
+ * Copyright (C) 2005-2009 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.
+ */
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+
+#include "ipu-prv.h"
+
+struct ipu_smfc {
+	void __iomem *base;
+	u32 module;
+	spinlock_t lock;
+	int use_count;
+	struct ipu_soc *ipu;
+};
+
+
+/* SMFC Register Offsets */
+#define SMFC_MAP                0x0000
+#define SMFC_WMC                0x0004
+#define SMFC_BS                 0x0008
+
+/* SMFC Register Fields */
+#define SMFC_MAP_CH0_MASK                  0x00000007L
+#define SMFC_MAP_CH0_SHIFT                 0
+#define SMFC_MAP_CH1_MASK                  0x00000038L
+#define SMFC_MAP_CH1_SHIFT                 3
+#define SMFC_MAP_CH2_MASK                  0x000001C0L
+#define SMFC_MAP_CH2_SHIFT                 6
+#define SMFC_MAP_CH3_MASK                  0x00000E00L
+#define SMFC_MAP_CH3_SHIFT                 9
+
+#define SMFC_WM0_SET_MASK                  0x00000007L
+#define SMFC_WM0_SET_SHIFT                 0
+#define SMFC_WM1_SET_MASK                  0x000001C0L
+#define SMFC_WM1_SET_SHIFT                 6
+#define SMFC_WM2_SET_MASK                  0x00070000L
+#define SMFC_WM2_SET_SHIFT                 16
+#define SMFC_WM3_SET_MASK                  0x01C00000L
+#define SMFC_WM3_SET_SHIFT                 22
+
+#define SMFC_WM0_CLR_MASK                  0x00000038L
+#define SMFC_WM0_CLR_SHIFT                 3
+#define SMFC_WM1_CLR_MASK                  0x00000E00L
+#define SMFC_WM1_CLR_SHIFT                 9
+#define SMFC_WM2_CLR_MASK                  0x00380000L
+#define SMFC_WM2_CLR_SHIFT                 19
+#define SMFC_WM3_CLR_MASK                  0x0E000000L
+#define SMFC_WM3_CLR_SHIFT                 25
+
+#define SMFC_BS0_MASK                      0x0000000FL
+#define SMFC_BS0_SHIFT                     0
+#define SMFC_BS1_MASK                      0x000000F0L
+#define SMFC_BS1_SHIFT                     4
+#define SMFC_BS2_MASK                      0x00000F00L
+#define SMFC_BS2_SHIFT                     8
+#define SMFC_BS3_MASK                      0x0000F000L
+#define SMFC_BS3_SHIFT                     12
+
+static inline u32 ipu_smfc_read(struct ipu_smfc *smfc, unsigned offset)
+{
+	return readl(smfc->base + offset);
+}
+
+static inline void ipu_smfc_write(struct ipu_smfc *smfc, u32 value,
+				 unsigned offset)
+{
+	writel(value, smfc->base + offset);
+}
+
+void ipu_smfc_dump(struct ipu_smfc *smfc)
+{
+	dev_dbg(smfc->ipu->dev, "SMFC_MAP: %08x\n",
+		ipu_smfc_read(smfc, SMFC_MAP));
+	dev_dbg(smfc->ipu->dev, "SMFC_WMC: %08x\n",
+		ipu_smfc_read(smfc, SMFC_WMC));
+	dev_dbg(smfc->ipu->dev, "SMFC_BS: %08x\n",
+		ipu_smfc_read(smfc, SMFC_BS));
+}
+EXPORT_SYMBOL_GPL(ipu_smfc_dump);
+
+/*
+ * Maps frames from given CSI and MIPI CSI2 virtual channel to given
+ * IDMAC channel.
+ */
+void ipu_smfc_map(struct ipu_smfc *smfc, struct ipuv3_channel *channel,
+		  int csi_id, int mipi_vc)
+{
+	unsigned long flags;
+	u32 temp;
+
+	spin_lock_irqsave(&smfc->lock, flags);
+
+	temp = ipu_smfc_read(smfc, SMFC_MAP);
+
+	switch (channel->num) {
+	case IPUV3_CHANNEL_CSI0:
+		temp &= ~SMFC_MAP_CH0_MASK;
+		temp |= ((csi_id << 2) | mipi_vc) << SMFC_MAP_CH0_SHIFT;
+		break;
+	case IPUV3_CHANNEL_CSI1:
+		temp &= ~SMFC_MAP_CH1_MASK;
+		temp |= ((csi_id << 2) | mipi_vc) << SMFC_MAP_CH1_SHIFT;
+		break;
+	case IPUV3_CHANNEL_CSI2:
+		temp &= ~SMFC_MAP_CH2_MASK;
+		temp |= ((csi_id << 2) | mipi_vc) << SMFC_MAP_CH2_SHIFT;
+		break;
+	case IPUV3_CHANNEL_CSI3:
+		temp &= ~SMFC_MAP_CH3_MASK;
+		temp |= ((csi_id << 2) | mipi_vc) << SMFC_MAP_CH3_SHIFT;
+		break;
+	default:
+		goto out;
+	}
+
+	ipu_smfc_write(smfc, temp, SMFC_MAP);
+out:
+	spin_unlock_irqrestore(&smfc->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_smfc_map);
+
+/*
+ * Setup the SMFC FIFO watermark set and clear levels.
+ */
+void ipu_smfc_set_wmc(struct ipu_smfc *smfc,
+		      struct ipuv3_channel *channel,
+		      bool set, u32 level)
+{
+	unsigned long flags;
+	u32 temp;
+
+	spin_lock_irqsave(&smfc->lock, flags);
+
+	temp = ipu_smfc_read(smfc, SMFC_WMC);
+
+	switch (channel->num) {
+	case IPUV3_CHANNEL_CSI0:
+		if (set) {
+			temp &= ~SMFC_WM0_SET_MASK;
+			temp |= level << SMFC_WM0_SET_SHIFT;
+		} else {
+			temp &= ~SMFC_WM0_CLR_MASK;
+			temp |= level << SMFC_WM0_CLR_SHIFT;
+		}
+		break;
+	case IPUV3_CHANNEL_CSI1:
+		if (set) {
+			temp &= ~SMFC_WM1_SET_MASK;
+			temp |= level << SMFC_WM1_SET_SHIFT;
+		} else {
+			temp &= ~SMFC_WM1_CLR_MASK;
+			temp |= level << SMFC_WM1_CLR_SHIFT;
+		}
+		break;
+	case IPUV3_CHANNEL_CSI2:
+		if (set) {
+			temp &= ~SMFC_WM2_SET_MASK;
+			temp |= level << SMFC_WM2_SET_SHIFT;
+		} else {
+			temp &= ~SMFC_WM2_CLR_MASK;
+			temp |= level << SMFC_WM2_CLR_SHIFT;
+		}
+		break;
+	case IPUV3_CHANNEL_CSI3:
+		if (set) {
+			temp &= ~SMFC_WM3_SET_MASK;
+			temp |= level << SMFC_WM3_SET_SHIFT;
+		} else {
+			temp &= ~SMFC_WM3_CLR_MASK;
+			temp |= level << SMFC_WM3_CLR_SHIFT;
+		}
+		break;
+	default:
+		goto out;
+	}
+
+	ipu_smfc_write(smfc, temp, SMFC_WMC);
+out:
+	spin_unlock_irqrestore(&smfc->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_smfc_set_wmc);
+
+void ipu_smfc_set_burst_size(struct ipu_smfc *smfc,
+			     struct ipuv3_channel *channel,
+			     u32 burst_size, bool passthrough_16)
+{
+	unsigned long flags;
+	u32 fifo_acc_per_burst;
+	u32 temp, bs;
+
+	/*
+	 * The imx6 TRM states that SMFC_BS register
+	 * should be set to NPB[6:4] for 8 and 16 bit-per-pixel,
+	 * when generic "passthrough" pixel format is used (PFS=6).
+	 *
+	 * The TRM goes on to say that the register holds
+	 * "the number of IDMAC's active accesses that will done
+	 * for each IDMAC's burst.".
+	 *
+	 * It's not too clear what that means, but an educated
+	 * guess is that the SMFC_BS register holds the
+	 * number of SMFC FIFO lines accessed per burst by
+	 * the IDMAC.
+	 *
+	 * If true, and assuming a FIFO line holds 128 bits,
+	 * then SMFC_BS register should be set to
+	 *
+	 *     NPB * bpp / 128
+	 *
+	 * So for 16 bpp, that would mean NPB[6:3], not NPB[6:4].
+	 * Only for 8 bpp, would it correctly be NPB[6:4].
+	 *
+	 * We don't support 8-bit generic, so ignore that.
+	 */
+
+	if (passthrough_16)
+		fifo_acc_per_burst = burst_size >> 3;
+	else
+		fifo_acc_per_burst = burst_size >> 2;
+
+	bs = fifo_acc_per_burst - 1;
+
+	spin_lock_irqsave(&smfc->lock, flags);
+
+	temp = ipu_smfc_read(smfc, SMFC_BS);
+
+	switch (channel->num) {
+	case IPUV3_CHANNEL_CSI0:
+		temp &= ~SMFC_BS0_MASK;
+		temp |= bs << SMFC_BS0_SHIFT;
+		break;
+	case IPUV3_CHANNEL_CSI1:
+		temp &= ~SMFC_BS1_MASK;
+		temp |= bs << SMFC_BS1_SHIFT;
+		break;
+	case IPUV3_CHANNEL_CSI2:
+		temp &= ~SMFC_BS2_MASK;
+		temp |= bs << SMFC_BS2_SHIFT;
+		break;
+	case IPUV3_CHANNEL_CSI3:
+		temp &= ~SMFC_BS3_MASK;
+		temp |= bs << SMFC_BS3_SHIFT;
+		break;
+	default:
+		goto out;
+	}
+
+	ipu_smfc_write(smfc, temp, SMFC_BS);
+out:
+	spin_unlock_irqrestore(&smfc->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_smfc_set_burst_size);
+
+int ipu_smfc_enable(struct ipu_smfc *smfc)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&smfc->lock, flags);
+
+	if (!smfc->use_count)
+		ipu_module_enable(smfc->ipu, smfc->module);
+
+	smfc->use_count++;
+
+	spin_unlock_irqrestore(&smfc->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_smfc_enable);
+
+int ipu_smfc_disable(struct ipu_smfc *smfc)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&smfc->lock, flags);
+
+	smfc->use_count--;
+
+	if (!smfc->use_count)
+		ipu_module_disable(smfc->ipu, smfc->module);
+
+	if (smfc->use_count < 0)
+		smfc->use_count = 0;
+
+	spin_unlock_irqrestore(&smfc->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_smfc_disable);
+
+struct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu)
+{
+	return ipu->smfc_priv;
+}
+EXPORT_SYMBOL_GPL(ipu_smfc_get);
+
+void ipu_smfc_put(struct ipu_smfc *smfc)
+{
+}
+EXPORT_SYMBOL_GPL(ipu_smfc_put);
+
+int ipu_smfc_init(struct ipu_soc *ipu, struct device *dev,
+		  unsigned long base, u32 module)
+{
+	struct ipu_smfc *smfc;
+
+	smfc = devm_kzalloc(dev, sizeof(*smfc), GFP_KERNEL);
+	if (!smfc)
+		return -ENOMEM;
+
+	ipu->smfc_priv = smfc;
+
+	spin_lock_init(&smfc->lock);
+	smfc->module = module;
+	smfc->base = devm_ioremap(dev, base, PAGE_SIZE);
+	if (!smfc->base)
+		return -ENOMEM;
+
+	dev_dbg(dev, "SMFC base: 0x%08lx remapped to %p\n", base, smfc->base);
+	smfc->ipu = ipu;
+
+	return 0;
+}
+
+void ipu_smfc_exit(struct ipu_soc *ipu)
+{
+}
diff --git a/include/linux/platform_data/imx-ipu-v3.h b/include/linux/platform_data/imx-ipu-v3.h
index 8050277..b4bc549 100644
--- a/include/linux/platform_data/imx-ipu-v3.h
+++ b/include/linux/platform_data/imx-ipu-v3.h
@@ -62,6 +62,65 @@ struct ipu_di_signal_cfg {
 	u8 vsync_pin;
 };
 
+/*
+ * Bitfield of CSI signal polarities and modes.
+ */
+struct ipu_csi_signal_cfg {
+	unsigned data_width:4;
+	unsigned clk_mode:3;
+	unsigned ext_vsync:1;
+	unsigned vsync_pol:1;
+	unsigned hsync_pol:1;
+	unsigned pixclk_pol:1;
+	unsigned data_pol:1;
+	unsigned sens_clksrc:1;
+	unsigned pack_tight:1;
+	unsigned force_eof:1;
+	unsigned data_en_pol:1;
+
+	unsigned data_fmt;
+	unsigned mipi_dt;
+};
+
+/*
+ * Enumeration of CSI data bus widths.
+ */
+enum ipu_csi_data_width {
+	IPU_CSI_DATA_WIDTH_4   = 0,
+	IPU_CSI_DATA_WIDTH_8   = 1,
+	IPU_CSI_DATA_WIDTH_10  = 3,
+	IPU_CSI_DATA_WIDTH_12  = 5,
+	IPU_CSI_DATA_WIDTH_16  = 9,
+};
+
+/*
+ * Enumeration of CSI clock modes.
+ */
+enum ipu_csi_clk_mode {
+	IPU_CSI_CLK_MODE_GATED_CLK,
+	IPU_CSI_CLK_MODE_NONGATED_CLK,
+	IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE,
+	IPU_CSI_CLK_MODE_CCIR656_INTERLACED,
+	IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR,
+	IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR,
+	IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR,
+	IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR,
+};
+
+/*
+ * Enumeration of IPU rotation modes
+ */
+enum ipu_rotate_mode {
+	IPU_ROTATE_NONE = 0,
+	IPU_ROTATE_VERT_FLIP,
+	IPU_ROTATE_HORIZ_FLIP,
+	IPU_ROTATE_180,
+	IPU_ROTATE_90_RIGHT,
+	IPU_ROTATE_90_RIGHT_VFLIP,
+	IPU_ROTATE_90_RIGHT_HFLIP,
+	IPU_ROTATE_90_LEFT,
+};
+
 enum ipu_color_space {
 	IPUV3_COLORSPACE_RGB,
 	IPUV3_COLORSPACE_YUV,
@@ -166,6 +225,98 @@ int ipu_dp_set_window_pos(struct ipu_dp *, u16 x_pos, u16 y_pos);
 int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable, u8 alpha,
 		bool bg_chan);
 
+/*
+ * IPU Camera Sensor Interface (csi) functions
+ */
+struct ipu_csi;
+int ipu_csi_set_src(struct ipu_csi *csi, u32 vc, bool select_mipi_csi2);
+int ipu_csi_mbus_fmt_to_sig_cfg(struct ipu_csi_signal_cfg *cfg,
+				u32 mbus_code);
+int ipu_csi_init_interface(struct ipu_csi *csi, u16 width, u16 height,
+			   struct ipu_csi_signal_cfg *cfg);
+int ipu_csi_get_sensor_protocol(struct ipu_csi *csi);
+bool ipu_csi_is_interlaced(struct ipu_csi *csi);
+void ipu_csi_get_window_size(struct ipu_csi *csi, u32 *width, u32 *height);
+void ipu_csi_set_window_size(struct ipu_csi *csi, u32 width, u32 height);
+void ipu_csi_set_window_pos(struct ipu_csi *csi, u32 left, u32 top);
+void ipu_csi_horizontal_downsize_enable(struct ipu_csi *csi);
+void ipu_csi_horizontal_downsize_disable(struct ipu_csi *csi);
+void ipu_csi_vertical_downsize_enable(struct ipu_csi *csi);
+void ipu_csi_vertical_downsize_disable(struct ipu_csi *csi);
+void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active,
+				u32 r_value, u32 g_value, u32 b_value,
+				u32 pix_clk);
+int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc,
+			      struct ipu_csi_signal_cfg *cfg);
+int ipu_csi_set_skip_isp(struct ipu_csi *csi, u32 skip, u32 max_ratio);
+int ipu_csi_set_skip_smfc(struct ipu_csi *csi, u32 skip,
+			  u32 max_ratio, u32 id);
+int ipu_csi_set_dest(struct ipu_csi *csi, bool ic);
+int ipu_csi_enable(struct ipu_csi *csi);
+int ipu_csi_disable(struct ipu_csi *csi);
+int ipu_csi_get_num(struct ipu_csi *csi);
+struct ipu_csi *ipu_csi_get(struct ipu_soc *ipu, int id);
+void ipu_csi_put(struct ipu_csi *csi);
+void ipu_csi_dump(struct ipu_csi *csi);
+
+/*
+ * IPU Sensor Multi-Fifo Controller (smfc) functions
+ */
+struct ipu_smfc;
+void ipu_smfc_map(struct ipu_smfc *smfc, struct ipuv3_channel *channel,
+		  int csi_id, int mipi_vc);
+void ipu_smfc_set_wmc(struct ipu_smfc *smfc,
+		      struct ipuv3_channel *channel,
+		      bool set, u32 level);
+void ipu_smfc_set_burst_size(struct ipu_smfc *smfc,
+			     struct ipuv3_channel *channel,
+			     u32 burst_size, bool passthrough_16);
+int ipu_smfc_enable(struct ipu_smfc *smfc);
+int ipu_smfc_disable(struct ipu_smfc *smfc);
+struct ipu_smfc *ipu_smfc_get(struct ipu_soc *ipu);
+void ipu_smfc_put(struct ipu_smfc *smfc);
+void ipu_smfc_dump(struct ipu_smfc *smfc);
+
+/*
+ * IPU Image Converter (ic) functions
+ */
+enum ipu_ic_task {
+	IC_TASK_ENCODER,
+	IC_TASK_VIEWFINDER,
+	IC_TASK_POST_PROCESSOR,
+	IC_NUM_TASKS,
+};
+
+struct ipu_ic;
+int ipu_ic_task_init(struct ipu_ic *ic,
+		     int in_width, int in_height,
+		     int out_width, int out_height,
+		     enum ipu_color_space in_cs,
+		     enum ipu_color_space out_cs);
+int ipu_ic_task_graphics_init(struct ipu_ic *ic,
+			      enum ipu_color_space in_g_cs,
+			      bool galpha_en, u32 galpha,
+			      bool colorkey_en, u32 colorkey);
+void ipu_ic_task_enable(struct ipu_ic *ic);
+void ipu_ic_task_disable(struct ipu_ic *ic);
+int ipu_ic_task_idma_init(struct ipu_ic *ic, struct ipuv3_channel *channel,
+			  u32 width, u32 height, int burst_size,
+			  enum ipu_rotate_mode rot);
+int ipu_ic_enable(struct ipu_ic *ic);
+int ipu_ic_disable(struct ipu_ic *ic);
+struct ipu_ic *ipu_ic_get(struct ipu_soc *ipu, enum ipu_ic_task task);
+void ipu_ic_put(struct ipu_ic *ic);
+void ipu_ic_dump(struct ipu_ic *ic);
+
+/*
+ * IPU Image Rotator (irt) functions
+ */
+struct ipu_irt;
+int ipu_irt_enable(struct ipu_irt *irt);
+int ipu_irt_disable(struct ipu_irt *irt);
+struct ipu_irt *ipu_irt_get(struct ipu_soc *ipu);
+void ipu_irt_put(struct ipu_irt *irt);
+
 #define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size))
 
 #define IPU_FIELD_UBO		IPU_CPMEM_WORD(0, 46, 22)
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 09/43] imx-drm: ipu-v3: Add ipu_mbus_code_to_colorspace()
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (7 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 08/43] imx-drm: ipu-v3: Add units required for video capture Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 10/43] imx-drm: ipu-v3: Add rotation mode conversion utilities Steve Longerbeam
                   ` (35 subsequent siblings)
  44 siblings, 0 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Add ipu_mbus_code_to_colorspace() to find ipu_color_space from a
media bus pixel format code.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/ipu-common.c |   13 +++++++++++++
 include/linux/platform_data/imx-ipu-v3.h    |    1 +
 2 files changed, 14 insertions(+)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index 3d7e28d..9c29e19 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -551,6 +551,19 @@ enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat)
 }
 EXPORT_SYMBOL_GPL(ipu_pixelformat_to_colorspace);
 
+enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code)
+{
+	switch (mbus_code & 0xf000) {
+	case 0x1000:
+		return IPUV3_COLORSPACE_RGB;
+	case 0x2000:
+		return IPUV3_COLORSPACE_YUV;
+	default:
+		return IPUV3_COLORSPACE_UNKNOWN;
+	}
+}
+EXPORT_SYMBOL_GPL(ipu_mbus_code_to_colorspace);
+
 struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num)
 {
 	struct ipuv3_channel *channel;
diff --git a/include/linux/platform_data/imx-ipu-v3.h b/include/linux/platform_data/imx-ipu-v3.h
index b4bc549..21226a2 100644
--- a/include/linux/platform_data/imx-ipu-v3.h
+++ b/include/linux/platform_data/imx-ipu-v3.h
@@ -466,6 +466,7 @@ int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem,
 
 enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc);
 enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat);
+enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code);
 
 static inline void ipu_cpmem_set_burstsize(struct ipu_ch_param __iomem *p,
 		int burstsize)
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 10/43] imx-drm: ipu-v3: Add rotation mode conversion utilities
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (8 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 09/43] imx-drm: ipu-v3: Add ipu_mbus_code_to_colorspace() Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 11/43] imx-drm: ipu-v3: Add helper function checking if pixfmt is planar Steve Longerbeam
                   ` (34 subsequent siblings)
  44 siblings, 0 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Add two functions:

- ipu_degrees_to_rot_mode(): converts a degrees, hflip, and vflip setting
  to an IPU rotation mode.
- ipu_rot_mode_to_degrees(): converts an IPU rotation mode with given hflip
  and vflip settings to degrees.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/ipu-common.c |   64 +++++++++++++++++++++++++++
 include/linux/platform_data/imx-ipu-v3.h    |    4 ++
 2 files changed, 68 insertions(+)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index 9c29e19..02577cc 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -564,6 +564,70 @@ enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code)
 }
 EXPORT_SYMBOL_GPL(ipu_mbus_code_to_colorspace);
 
+int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees,
+			    bool hflip, bool vflip)
+{
+	u32 r90, vf, hf;
+
+	switch (degrees) {
+	case 0:
+		vf = hf = r90 = 0;
+		break;
+	case 90:
+		vf = hf = 0;
+		r90 = 1;
+		break;
+	case 180:
+		vf = hf = 1;
+		r90 = 0;
+		break;
+	case 270:
+		vf = hf = r90 = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	hf ^= (u32)hflip;
+	vf ^= (u32)vflip;
+
+	*mode = (enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_degrees_to_rot_mode);
+
+int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode,
+			    bool hflip, bool vflip)
+{
+	u32 r90, vf, hf;
+
+	r90 = ((u32)mode >> 2) & 0x1;
+	hf = ((u32)mode >> 1) & 0x1;
+	vf = ((u32)mode >> 0) & 0x1;
+	hf ^= (u32)hflip;
+	vf ^= (u32)vflip;
+
+	switch ((enum ipu_rotate_mode)((r90 << 2) | (hf << 1) | vf)) {
+	case IPU_ROTATE_NONE:
+		*degrees = 0;
+		break;
+	case IPU_ROTATE_90_RIGHT:
+		*degrees = 90;
+		break;
+	case IPU_ROTATE_180:
+		*degrees = 180;
+		break;
+	case IPU_ROTATE_90_LEFT:
+		*degrees = 270;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_rot_mode_to_degrees);
+
 struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num)
 {
 	struct ipuv3_channel *channel;
diff --git a/include/linux/platform_data/imx-ipu-v3.h b/include/linux/platform_data/imx-ipu-v3.h
index 21226a2..ffcfe20 100644
--- a/include/linux/platform_data/imx-ipu-v3.h
+++ b/include/linux/platform_data/imx-ipu-v3.h
@@ -467,6 +467,10 @@ int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem,
 enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc);
 enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat);
 enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code);
+int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees,
+			    bool hflip, bool vflip);
+int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode,
+			    bool hflip, bool vflip);
 
 static inline void ipu_cpmem_set_burstsize(struct ipu_ch_param __iomem *p,
 		int burstsize)
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 11/43] imx-drm: ipu-v3: Add helper function checking if pixfmt is planar
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (9 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 10/43] imx-drm: ipu-v3: Add rotation mode conversion utilities Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 12/43] imx-drm: ipu-v3: Move IDMAC channel names to imx-ipu-v3.h Steve Longerbeam
                   ` (33 subsequent siblings)
  44 siblings, 0 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam, Dmitry Eremin-Solenikov

Add simple helper function returning true if passed pixel format is one
of supported planar ones.

Signed-off-by: Dmitry Eremin-Solenikov <dmitry_eremin@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/ipu-common.c |   12 ++++++++++++
 include/linux/platform_data/imx-ipu-v3.h    |    1 +
 2 files changed, 13 insertions(+)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index 02577cc..d005ed5 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -551,6 +551,18 @@ enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat)
 }
 EXPORT_SYMBOL_GPL(ipu_pixelformat_to_colorspace);
 
+bool ipu_pixelformat_is_planar(u32 pixelformat)
+{
+	switch (pixelformat) {
+	case V4L2_PIX_FMT_YUV420:
+	case V4L2_PIX_FMT_YVU420:
+		return true;
+	}
+
+	return false;
+}
+EXPORT_SYMBOL_GPL(ipu_pixelformat_is_planar);
+
 enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code)
 {
 	switch (mbus_code & 0xf000) {
diff --git a/include/linux/platform_data/imx-ipu-v3.h b/include/linux/platform_data/imx-ipu-v3.h
index ffcfe20..dcf2c57 100644
--- a/include/linux/platform_data/imx-ipu-v3.h
+++ b/include/linux/platform_data/imx-ipu-v3.h
@@ -467,6 +467,7 @@ int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem,
 enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc);
 enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat);
 enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code);
+bool ipu_pixelformat_is_planar(u32 pixelformat);
 int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees,
 			    bool hflip, bool vflip);
 int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode,
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 12/43] imx-drm: ipu-v3: Move IDMAC channel names to imx-ipu-v3.h
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (10 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 11/43] imx-drm: ipu-v3: Add helper function checking if pixfmt is planar Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 13/43] imx-drm: ipu-v3: Add ipu_idmac_buffer_is_ready() Steve Longerbeam
                   ` (32 subsequent siblings)
  44 siblings, 0 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Move the IDMAC channel names to imx-ipu-v3.h, to make the names
available outside IPU. Add a couple new channels in the process
(async display BG/FG, channels 24 and 29).

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/ipu-prv.h |   25 -------------------------
 include/linux/platform_data/imx-ipu-v3.h |   30 ++++++++++++++++++++++++++++++
 2 files changed, 30 insertions(+), 25 deletions(-)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
index 211d6f2..104e296 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
@@ -27,31 +27,6 @@ struct ipu_soc;
 
 #include <linux/platform_data/imx-ipu-v3.h>
 
-#define IPUV3_CHANNEL_CSI0			 0
-#define IPUV3_CHANNEL_CSI1			 1
-#define IPUV3_CHANNEL_CSI2			 2
-#define IPUV3_CHANNEL_CSI3			 3
-#define IPUV3_CHANNEL_VDI_MEM_IC_VF              5
-#define IPUV3_CHANNEL_MEM_IC_PP                 11
-#define IPUV3_CHANNEL_MEM_IC_PRP_VF             12
-#define IPUV3_CHANNEL_G_MEM_IC_PRP_VF           14
-#define IPUV3_CHANNEL_G_MEM_IC_PP               15
-#define IPUV3_CHANNEL_IC_PRP_ENC_MEM            20
-#define IPUV3_CHANNEL_IC_PRP_VF_MEM             21
-#define IPUV3_CHANNEL_IC_PP_MEM                 22
-#define IPUV3_CHANNEL_MEM_BG_SYNC		23
-#define IPUV3_CHANNEL_MEM_FG_SYNC		27
-#define IPUV3_CHANNEL_MEM_DC_SYNC		28
-#define IPUV3_CHANNEL_MEM_FG_SYNC_ALPHA		31
-#define IPUV3_CHANNEL_MEM_DC_ASYNC		41
-#define IPUV3_CHANNEL_MEM_ROT_ENC		45
-#define IPUV3_CHANNEL_MEM_ROT_VF		46
-#define IPUV3_CHANNEL_MEM_ROT_PP		47
-#define IPUV3_CHANNEL_ROT_ENC_MEM		48
-#define IPUV3_CHANNEL_ROT_VF_MEM		49
-#define IPUV3_CHANNEL_ROT_PP_MEM		50
-#define IPUV3_CHANNEL_MEM_BG_SYNC_ALPHA		51
-
 #define IPU_MCU_T_DEFAULT	8
 #define IPU_CM_IDMAC_REG_OFS	0x00008000
 #define IPU_CM_IC_REG_OFS	0x00020000
diff --git a/include/linux/platform_data/imx-ipu-v3.h b/include/linux/platform_data/imx-ipu-v3.h
index dcf2c57..65ff5ce 100644
--- a/include/linux/platform_data/imx-ipu-v3.h
+++ b/include/linux/platform_data/imx-ipu-v3.h
@@ -136,6 +136,36 @@ enum ipu_channel_irq {
 	IPU_IRQ_EOS = 192,
 };
 
+/*
+ * Enumeration of IDMAC channels
+ */
+#define IPUV3_CHANNEL_CSI0			 0
+#define IPUV3_CHANNEL_CSI1			 1
+#define IPUV3_CHANNEL_CSI2			 2
+#define IPUV3_CHANNEL_CSI3			 3
+#define IPUV3_CHANNEL_VDI_MEM_IC_VF              5
+#define IPUV3_CHANNEL_MEM_IC_PP                 11
+#define IPUV3_CHANNEL_MEM_IC_PRP_VF             12
+#define IPUV3_CHANNEL_G_MEM_IC_PRP_VF           14
+#define IPUV3_CHANNEL_G_MEM_IC_PP               15
+#define IPUV3_CHANNEL_IC_PRP_ENC_MEM            20
+#define IPUV3_CHANNEL_IC_PRP_VF_MEM             21
+#define IPUV3_CHANNEL_IC_PP_MEM                 22
+#define IPUV3_CHANNEL_MEM_BG_SYNC		23
+#define IPUV3_CHANNEL_MEM_BG_ASYNC		24
+#define IPUV3_CHANNEL_MEM_FG_SYNC		27
+#define IPUV3_CHANNEL_MEM_DC_SYNC		28
+#define IPUV3_CHANNEL_MEM_FG_ASYNC		29
+#define IPUV3_CHANNEL_MEM_FG_SYNC_ALPHA		31
+#define IPUV3_CHANNEL_MEM_DC_ASYNC		41
+#define IPUV3_CHANNEL_MEM_ROT_ENC		45
+#define IPUV3_CHANNEL_MEM_ROT_VF		46
+#define IPUV3_CHANNEL_MEM_ROT_PP		47
+#define IPUV3_CHANNEL_ROT_ENC_MEM		48
+#define IPUV3_CHANNEL_ROT_VF_MEM		49
+#define IPUV3_CHANNEL_ROT_PP_MEM		50
+#define IPUV3_CHANNEL_MEM_BG_SYNC_ALPHA		51
+
 int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
 		enum ipu_channel_irq irq);
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 13/43] imx-drm: ipu-v3: Add ipu_idmac_buffer_is_ready()
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (11 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 12/43] imx-drm: ipu-v3: Move IDMAC channel names to imx-ipu-v3.h Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 14/43] imx-drm: ipu-v3: Add ipu_idmac_clear_buffer() Steve Longerbeam
                   ` (31 subsequent siblings)
  44 siblings, 0 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Add ipu_idmac_buffer_is_ready(), returns true if the given buffer in
the given channel is set ready (owned by IPU), or false if not ready
(owned by CPU core).

Support has been added for third buffer, there is no support yet for
triple-buffering in idmac channels, but this function checks
buffer-ready for third buffer in case this support is added later.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/ipu-common.c |   26 +++++++++++++++++++++++++-
 drivers/staging/imx-drm/ipu-v3/ipu-prv.h    |    1 +
 include/linux/platform_data/imx-ipu-v3.h    |    1 +
 3 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index d005ed5..3ff55da 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -682,7 +682,7 @@ void ipu_idmac_put(struct ipuv3_channel *channel)
 }
 EXPORT_SYMBOL_GPL(ipu_idmac_put);
 
-#define idma_mask(ch)			(1 << (ch & 0x1f))
+#define idma_mask(ch)			(1 << ((ch) & 0x1f))
 
 void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
 		bool doublebuffer)
@@ -756,6 +756,30 @@ int ipu_module_disable(struct ipu_soc *ipu, u32 mask)
 }
 EXPORT_SYMBOL_GPL(ipu_module_disable);
 
+bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num)
+{
+	struct ipu_soc *ipu = channel->ipu;
+	unsigned long flags;
+	u32 reg = 0;
+
+	spin_lock_irqsave(&ipu->lock, flags);
+	switch (buf_num) {
+	case 0:
+		reg = ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(channel->num));
+		break;
+	case 1:
+		reg = ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(channel->num));
+		break;
+	case 2:
+		reg = ipu_cm_read(ipu, IPU_CHA_BUF2_RDY(channel->num));
+		break;
+	}
+	spin_unlock_irqrestore(&ipu->lock, flags);
+
+	return ((reg & idma_mask(channel->num)) != 0);
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_buffer_is_ready);
+
 void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num)
 {
 	struct ipu_soc *ipu = channel->ipu;
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
index 104e296..43ac6c3 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
@@ -71,6 +71,7 @@ struct ipu_soc;
 #define IPU_DISP_TASK_STAT		IPU_CM_REG(0x0254)
 #define IPU_CHA_BUF0_RDY(ch)		IPU_CM_REG(0x0268 + 4 * ((ch) / 32))
 #define IPU_CHA_BUF1_RDY(ch)		IPU_CM_REG(0x0270 + 4 * ((ch) / 32))
+#define IPU_CHA_BUF2_RDY(ch)		IPU_CM_REG(0x0288 + 4 * ((ch) / 32))
 #define IPU_ALT_CHA_BUF0_RDY(ch)	IPU_CM_REG(0x0278 + 4 * ((ch) / 32))
 #define IPU_ALT_CHA_BUF1_RDY(ch)	IPU_CM_REG(0x0280 + 4 * ((ch) / 32))
 
diff --git a/include/linux/platform_data/imx-ipu-v3.h b/include/linux/platform_data/imx-ipu-v3.h
index 65ff5ce..0128667 100644
--- a/include/linux/platform_data/imx-ipu-v3.h
+++ b/include/linux/platform_data/imx-ipu-v3.h
@@ -199,6 +199,7 @@ int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms);
 void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
 		bool doublebuffer);
 void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num);
+bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num);
 
 /*
  * IPU Display Controller (dc) functions
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 14/43] imx-drm: ipu-v3: Add ipu_idmac_clear_buffer()
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (12 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 13/43] imx-drm: ipu-v3: Add ipu_idmac_buffer_is_ready() Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 15/43] imx-drm: ipu-v3: Add ipu_idmac_current_buffer() Steve Longerbeam
                   ` (30 subsequent siblings)
  44 siblings, 0 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Add the reverse of ipu_idmac_select_buffer(), that is, clear a buffer
ready status in a channel.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/ipu-common.c |   28 +++++++++++++++++++++++++++
 include/linux/platform_data/imx-ipu-v3.h    |    1 +
 2 files changed, 29 insertions(+)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index 3ff55da..fd15eae 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -798,6 +798,34 @@ void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num)
 }
 EXPORT_SYMBOL_GPL(ipu_idmac_select_buffer);
 
+void ipu_idmac_clear_buffer(struct ipuv3_channel *channel, u32 buf_num)
+{
+	struct ipu_soc *ipu = channel->ipu;
+	unsigned int chno = channel->num;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ipu->lock, flags);
+
+	ipu_cm_write(ipu, 0xF0300000, IPU_GPR); /* write one to clear */
+	switch (buf_num) {
+	case 0:
+		ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
+		break;
+	case 1:
+		ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
+		break;
+	case 2:
+		ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF2_RDY(chno));
+		break;
+	default:
+		break;
+	}
+	ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
+
+	spin_unlock_irqrestore(&ipu->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_clear_buffer);
+
 int ipu_idmac_enable_channel(struct ipuv3_channel *channel)
 {
 	struct ipu_soc *ipu = channel->ipu;
diff --git a/include/linux/platform_data/imx-ipu-v3.h b/include/linux/platform_data/imx-ipu-v3.h
index 0128667..480c30d 100644
--- a/include/linux/platform_data/imx-ipu-v3.h
+++ b/include/linux/platform_data/imx-ipu-v3.h
@@ -199,6 +199,7 @@ int ipu_idmac_wait_busy(struct ipuv3_channel *channel, int ms);
 void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
 		bool doublebuffer);
 void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num);
+void ipu_idmac_clear_buffer(struct ipuv3_channel *channel, u32 buf_num);
 bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num);
 
 /*
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 15/43] imx-drm: ipu-v3: Add ipu_idmac_current_buffer()
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (13 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 14/43] imx-drm: ipu-v3: Add ipu_idmac_clear_buffer() Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-11 11:22   ` Philipp Zabel
  2014-06-07 21:56 ` [PATCH 16/43] imx-drm: ipu-v3: Add __ipu_idmac_reset_current_buffer() Steve Longerbeam
                   ` (29 subsequent siblings)
  44 siblings, 1 reply; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Add ipu_idmac_current_buffer(), returns the currently active
buffer number in the given channel.

Checks for third buffer ready in case triple-buffer support is
added later.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/ipu-common.c |   27 +++++++++++++++++++++++++++
 drivers/staging/imx-drm/ipu-v3/ipu-prv.h    |    2 ++
 include/linux/platform_data/imx-ipu-v3.h    |    1 +
 3 files changed, 30 insertions(+)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index fd15eae..4839893 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -683,6 +683,8 @@ void ipu_idmac_put(struct ipuv3_channel *channel)
 EXPORT_SYMBOL_GPL(ipu_idmac_put);
 
 #define idma_mask(ch)			(1 << ((ch) & 0x1f))
+#define tri_cur_buf_mask(ch)		(idma_mask((ch) * 2) * 3)
+#define tri_cur_buf_shift(ch)		(ffs(idma_mask((ch) * 2)) - 1)
 
 void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
 		bool doublebuffer)
@@ -780,6 +782,31 @@ bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num)
 }
 EXPORT_SYMBOL_GPL(ipu_idmac_buffer_is_ready);
 
+int ipu_idmac_current_buffer(struct ipuv3_channel *channel)
+{
+	struct ipu_soc *ipu = channel->ipu;
+	unsigned long flags;
+	int bufnum;
+	u32 reg;
+
+	spin_lock_irqsave(&ipu->lock, flags);
+
+	reg = ipu_cm_read(ipu, IPU_CHA_TRB_MODE_SEL(channel->num));
+	if (reg & idma_mask(channel->num)) {
+		reg = ipu_cm_read(ipu, IPU_CHA_TRIPLE_CUR_BUF(channel->num));
+		bufnum = (reg & tri_cur_buf_mask(channel->num)) >>
+			tri_cur_buf_shift(channel->num);
+	} else {
+		reg = ipu_cm_read(ipu, IPU_CHA_CUR_BUF(channel->num));
+		bufnum = (reg & idma_mask(channel->num)) ? 1 : 0;
+	}
+
+	spin_unlock_irqrestore(&ipu->lock, flags);
+
+	return bufnum;
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_current_buffer);
+
 void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num)
 {
 	struct ipu_soc *ipu = channel->ipu;
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
index 43ac6c3..446ed20 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
@@ -62,8 +62,10 @@ struct ipu_soc;
 #define IPU_PM				IPU_CM_REG(0x00e0)
 #define IPU_GPR				IPU_CM_REG(0x00e4)
 #define IPU_CHA_DB_MODE_SEL(ch)		IPU_CM_REG(0x0150 + 4 * ((ch) / 32))
+#define IPU_CHA_TRB_MODE_SEL(ch)	IPU_CM_REG(0x0178 + 4 * ((ch) / 32))
 #define IPU_ALT_CHA_DB_MODE_SEL(ch)	IPU_CM_REG(0x0168 + 4 * ((ch) / 32))
 #define IPU_CHA_CUR_BUF(ch)		IPU_CM_REG(0x023C + 4 * ((ch) / 32))
+#define IPU_CHA_TRIPLE_CUR_BUF(ch)	IPU_CM_REG(0x0258 + 4 * ((ch) / 32))
 #define IPU_ALT_CUR_BUF0		IPU_CM_REG(0x0244)
 #define IPU_ALT_CUR_BUF1		IPU_CM_REG(0x0248)
 #define IPU_SRM_STAT			IPU_CM_REG(0x024C)
diff --git a/include/linux/platform_data/imx-ipu-v3.h b/include/linux/platform_data/imx-ipu-v3.h
index 480c30d..6f2c408 100644
--- a/include/linux/platform_data/imx-ipu-v3.h
+++ b/include/linux/platform_data/imx-ipu-v3.h
@@ -201,6 +201,7 @@ void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
 void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num);
 void ipu_idmac_clear_buffer(struct ipuv3_channel *channel, u32 buf_num);
 bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num);
+int ipu_idmac_current_buffer(struct ipuv3_channel *channel);
 
 /*
  * IPU Display Controller (dc) functions
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 16/43] imx-drm: ipu-v3: Add __ipu_idmac_reset_current_buffer()
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (14 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 15/43] imx-drm: ipu-v3: Add ipu_idmac_current_buffer() Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 17/43] imx-drm: ipu-v3: Add ipu_stride_to_bytes() Steve Longerbeam
                   ` (28 subsequent siblings)
  44 siblings, 0 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Adds __ipu_idmac_reset_current_buffer() that resets a channel's
internal current buffer pointer so that transfers start from buffer
0 on the next channel enable.

This operation is required for channel linking to work correctly,
for instance video capture pipelines that carry out image rotations
will fail after the first streaming unless this function is called
for each channel before re-enabling the channels.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/ipu-common.c |   23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index 4839893..07b025f 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -686,6 +686,25 @@ EXPORT_SYMBOL_GPL(ipu_idmac_put);
 #define tri_cur_buf_mask(ch)		(idma_mask((ch) * 2) * 3)
 #define tri_cur_buf_shift(ch)		(ffs(idma_mask((ch) * 2)) - 1)
 
+/*
+ * This is an undocumented feature, a write one to a channel bit in
+ * IPU_CHA_CUR_BUF and IPU_CHA_TRIPLE_CUR_BUF will reset the channel's
+ * internal current buffer pointer so that transfers start from buffer
+ * 0 on the next channel enable (that's the theory anyway, the imx6 TRM
+ * only says these are read-only registers). This operation is required
+ * for channel linking to work correctly, for instance video capture
+ * pipelines that carry out image rotations will fail after the first
+ * streaming unless this function is called for each channel before
+ * re-enabling the channels.
+ */
+static void __ipu_idmac_reset_current_buffer(struct ipuv3_channel *channel)
+{
+	struct ipu_soc *ipu = channel->ipu;
+	unsigned int chno = channel->num;
+
+	ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_CUR_BUF(chno));
+}
+
 void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
 		bool doublebuffer)
 {
@@ -702,6 +721,8 @@ void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
 		reg &= ~idma_mask(channel->num);
 	ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(channel->num));
 
+	__ipu_idmac_reset_current_buffer(channel);
+
 	spin_unlock_irqrestore(&ipu->lock, flags);
 }
 EXPORT_SYMBOL_GPL(ipu_idmac_set_double_buffer);
@@ -901,6 +922,8 @@ int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
 	val &= ~idma_mask(channel->num);
 	ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
 
+	__ipu_idmac_reset_current_buffer(channel);
+
 	/* Set channel buffers NOT to be ready */
 	ipu_cm_write(ipu, 0xf0000000, IPU_GPR); /* write one to clear */
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 17/43] imx-drm: ipu-v3: Add ipu_stride_to_bytes()
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (15 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 16/43] imx-drm: ipu-v3: Add __ipu_idmac_reset_current_buffer() Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 18/43] imx-drm: ipu-v3: Add ipu_idmac_enable_watermark() Steve Longerbeam
                   ` (27 subsequent siblings)
  44 siblings, 0 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Adds ipu_stride_to_bytes(), which converts a pixel stride to bytes,
suitable for passing to cpmem.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/ipu-common.c |   30 +++++++++++++++++++++++++++
 include/linux/platform_data/imx-ipu-v3.h    |    1 +
 2 files changed, 31 insertions(+)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index 07b025f..32a51d6 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -576,6 +576,36 @@ enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code)
 }
 EXPORT_SYMBOL_GPL(ipu_mbus_code_to_colorspace);
 
+int ipu_stride_to_bytes(u32 pixel_stride, u32 pixelformat)
+{
+	switch (pixelformat) {
+	case V4L2_PIX_FMT_YUV420:
+	case V4L2_PIX_FMT_YVU420:
+		/*
+		 * for the planar YUV formats, the stride passed to
+		 * cpmem must be the stride in bytes of the Y plane.
+		 * And all the planar YUV formats have an 8-bit
+		 * Y component.
+		 */
+		return (8 * pixel_stride) >> 3;
+	case V4L2_PIX_FMT_RGB565:
+	case V4L2_PIX_FMT_YUYV:
+	case V4L2_PIX_FMT_UYVY:
+		return (16 * pixel_stride) >> 3;
+	case V4L2_PIX_FMT_BGR24:
+	case V4L2_PIX_FMT_RGB24:
+		return (24 * pixel_stride) >> 3;
+	case V4L2_PIX_FMT_BGR32:
+	case V4L2_PIX_FMT_RGB32:
+		return (32 * pixel_stride) >> 3;
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(ipu_stride_to_bytes);
+
 int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees,
 			    bool hflip, bool vflip)
 {
diff --git a/include/linux/platform_data/imx-ipu-v3.h b/include/linux/platform_data/imx-ipu-v3.h
index 6f2c408..681b9fd 100644
--- a/include/linux/platform_data/imx-ipu-v3.h
+++ b/include/linux/platform_data/imx-ipu-v3.h
@@ -500,6 +500,7 @@ int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem,
 enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc);
 enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat);
 enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code);
+int ipu_stride_to_bytes(u32 pixel_stride, u32 pixelformat);
 bool ipu_pixelformat_is_planar(u32 pixelformat);
 int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees,
 			    bool hflip, bool vflip);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 18/43] imx-drm: ipu-v3: Add ipu_idmac_enable_watermark()
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (16 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 17/43] imx-drm: ipu-v3: Add ipu_stride_to_bytes() Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 19/43] imx-drm: ipu-v3: Add ipu_idmac_lock_enable() Steve Longerbeam
                   ` (26 subsequent siblings)
  44 siblings, 0 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Adds the function ipu_idmac_enable_watermark(), which enables or disables
watermarking in the IDMAC channel. Enabling watermarking can increase a
channel's AXI bus arbitration priority.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/ipu-common.c |   25 +++++++++++++++++++++++++
 include/linux/platform_data/imx-ipu-v3.h    |    1 +
 2 files changed, 26 insertions(+)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index 32a51d6..8c5b8d3 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -982,6 +982,31 @@ int ipu_idmac_disable_channel(struct ipuv3_channel *channel)
 }
 EXPORT_SYMBOL_GPL(ipu_idmac_disable_channel);
 
+/*
+ * The imx6 rev. D TRM says that enabling the WM feature will increase
+ * a channel's priority. Refer to Table 36-8 Calculated priority value.
+ * The sub-module that is the sink or source for the channel must enable
+ * watermark signal for this to take effect (SMFC_WM for instance).
+ */
+void ipu_idmac_enable_watermark(struct ipuv3_channel *channel, bool enable)
+{
+	struct ipu_soc *ipu = channel->ipu;
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&ipu->lock, flags);
+
+	val = ipu_idmac_read(ipu, IDMAC_WM_EN(channel->num));
+	if (enable)
+		val |= 1 << (channel->num % 32);
+	else
+		val &= ~(1 << (channel->num % 32));
+	ipu_idmac_write(ipu, val, IDMAC_WM_EN(channel->num));
+
+	spin_unlock_irqrestore(&ipu->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_enable_watermark);
+
 static int ipu_memory_reset(struct ipu_soc *ipu)
 {
 	unsigned long timeout;
diff --git a/include/linux/platform_data/imx-ipu-v3.h b/include/linux/platform_data/imx-ipu-v3.h
index 681b9fd..d1def4d 100644
--- a/include/linux/platform_data/imx-ipu-v3.h
+++ b/include/linux/platform_data/imx-ipu-v3.h
@@ -202,6 +202,7 @@ void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num);
 void ipu_idmac_clear_buffer(struct ipuv3_channel *channel, u32 buf_num);
 bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num);
 int ipu_idmac_current_buffer(struct ipuv3_channel *channel);
+void ipu_idmac_enable_watermark(struct ipuv3_channel *channel, bool enable);
 
 /*
  * IPU Display Controller (dc) functions
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 19/43] imx-drm: ipu-v3: Add ipu_idmac_lock_enable()
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (17 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 18/43] imx-drm: ipu-v3: Add ipu_idmac_enable_watermark() Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 20/43] imx-drm: ipu-v3: Add idmac channel linking support Steve Longerbeam
                   ` (25 subsequent siblings)
  44 siblings, 0 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Adds ipu_idmac_lock_enable(), which enables or disables channel
burst locking.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/ipu-common.c |   69 +++++++++++++++++++++++++++
 include/linux/platform_data/imx-ipu-v3.h    |    1 +
 2 files changed, 70 insertions(+)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index 8c5b8d3..dfa6cf3 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -757,6 +757,75 @@ void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel,
 }
 EXPORT_SYMBOL_GPL(ipu_idmac_set_double_buffer);
 
+static const struct {
+	int chnum;
+	u32 reg;
+	int shift;
+} idmac_lock_en_info[] = {
+	{ .chnum =  5, .reg = IDMAC_CH_LOCK_EN_1, .shift =  0, },
+	{ .chnum = 11, .reg = IDMAC_CH_LOCK_EN_1, .shift =  2, },
+	{ .chnum = 12, .reg = IDMAC_CH_LOCK_EN_1, .shift =  4, },
+	{ .chnum = 14, .reg = IDMAC_CH_LOCK_EN_1, .shift =  6, },
+	{ .chnum = 15, .reg = IDMAC_CH_LOCK_EN_1, .shift =  8, },
+	{ .chnum = 20, .reg = IDMAC_CH_LOCK_EN_1, .shift = 10, },
+	{ .chnum = 21, .reg = IDMAC_CH_LOCK_EN_1, .shift = 12, },
+	{ .chnum = 22, .reg = IDMAC_CH_LOCK_EN_1, .shift = 14, },
+	{ .chnum = 23, .reg = IDMAC_CH_LOCK_EN_1, .shift = 16, },
+	{ .chnum = 27, .reg = IDMAC_CH_LOCK_EN_1, .shift = 18, },
+	{ .chnum = 28, .reg = IDMAC_CH_LOCK_EN_1, .shift = 20, },
+	{ .chnum = 45, .reg = IDMAC_CH_LOCK_EN_2, .shift =  0, },
+	{ .chnum = 46, .reg = IDMAC_CH_LOCK_EN_2, .shift =  2, },
+	{ .chnum = 47, .reg = IDMAC_CH_LOCK_EN_2, .shift =  4, },
+	{ .chnum = 48, .reg = IDMAC_CH_LOCK_EN_2, .shift =  6, },
+	{ .chnum = 49, .reg = IDMAC_CH_LOCK_EN_2, .shift =  8, },
+	{ .chnum = 50, .reg = IDMAC_CH_LOCK_EN_2, .shift = 10, },
+};
+
+int ipu_idmac_lock_enable(struct ipuv3_channel *channel, int num_bursts)
+{
+	struct ipu_soc *ipu = channel->ipu;
+	unsigned long flags;
+	u32 bursts, regval;
+	int i;
+
+	switch (num_bursts) {
+	case 0:
+	case 1:
+		bursts = 0x00; /* locking disabled */
+		break;
+	case 2:
+		bursts = 0x01;
+		break;
+	case 4:
+		bursts = 0x02;
+		break;
+	case 8:
+		bursts = 0x03;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(idmac_lock_en_info); i++) {
+		if (channel->num == idmac_lock_en_info[i].chnum)
+			break;
+	}
+	if (i >= ARRAY_SIZE(idmac_lock_en_info))
+		return -EINVAL;
+
+	spin_lock_irqsave(&ipu->lock, flags);
+
+	regval = ipu_idmac_read(ipu, idmac_lock_en_info[i].reg);
+	regval &= ~(0x03 << idmac_lock_en_info[i].shift);
+	regval |= (bursts << idmac_lock_en_info[i].shift);
+	ipu_idmac_write(ipu, regval, idmac_lock_en_info[i].reg);
+
+	spin_unlock_irqrestore(&ipu->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_lock_enable);
+
 int ipu_module_enable(struct ipu_soc *ipu, u32 mask)
 {
 	unsigned long lock_flags;
diff --git a/include/linux/platform_data/imx-ipu-v3.h b/include/linux/platform_data/imx-ipu-v3.h
index d1def4d..949beec 100644
--- a/include/linux/platform_data/imx-ipu-v3.h
+++ b/include/linux/platform_data/imx-ipu-v3.h
@@ -203,6 +203,7 @@ void ipu_idmac_clear_buffer(struct ipuv3_channel *channel, u32 buf_num);
 bool ipu_idmac_buffer_is_ready(struct ipuv3_channel *channel, u32 buf_num);
 int ipu_idmac_current_buffer(struct ipuv3_channel *channel);
 void ipu_idmac_enable_watermark(struct ipuv3_channel *channel, bool enable);
+int ipu_idmac_lock_enable(struct ipuv3_channel *channel, int num_bursts);
 
 /*
  * IPU Display Controller (dc) functions
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 20/43] imx-drm: ipu-v3: Add idmac channel linking support
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (18 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 19/43] imx-drm: ipu-v3: Add ipu_idmac_lock_enable() Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 21/43] imx-drm: ipu-v3: Add ipu_bits_per_pixel() Steve Longerbeam
                   ` (24 subsequent siblings)
  44 siblings, 0 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Add idmac channel linking/unlinking functions for specific IPU
client use cases. The following linkings are currently needed:

- ipu_link_prp_enc_rot_enc():

Link IPUV3_CHANNEL_IC_PRP_ENC_MEM to IPUV3_CHANNEL_MEM_ROT_ENC.

- ipu_link_prpvf_rot_prpvf():

Links IPUV3_CHANNEL_IC_PRP_VF_MEM to IPUV3_CHANNEL_MEM_ROT_VF.

- ipu_link_pp_rot_pp():

Links IPUV3_CHANNEL_IC_PP_MEM to IPUV3_CHANNEL_MEM_ROT_PP.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/ipu-common.c |  159 +++++++++++++++++++++++++++
 drivers/staging/imx-drm/ipu-v3/ipu-prv.h    |   58 ++++++++++
 include/linux/platform_data/imx-ipu-v3.h    |    7 ++
 3 files changed, 224 insertions(+)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index dfa6cf3..de66d02 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -973,6 +973,165 @@ void ipu_idmac_clear_buffer(struct ipuv3_channel *channel, u32 buf_num)
 }
 EXPORT_SYMBOL_GPL(ipu_idmac_clear_buffer);
 
+/*
+ * Links IPUV3_CHANNEL_IC_PRP_ENC_MEM to IPUV3_CHANNEL_MEM_ROT_ENC
+ */
+int ipu_link_prp_enc_rot_enc(struct ipu_soc *ipu)
+{
+	unsigned long flags;
+	u32 fs_proc_flow1;
+	u32 fs_proc_flow2;
+
+	spin_lock_irqsave(&ipu->lock, flags);
+
+	fs_proc_flow1 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+	fs_proc_flow2 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW2);
+
+	fs_proc_flow1 &= ~FS_PRPENC_ROT_SRC_SEL_MASK;
+	fs_proc_flow1 |= (0x07 << FS_PRPENC_ROT_SRC_SEL_OFFSET);
+
+	fs_proc_flow2 &= ~FS_PRPENC_DEST_SEL_MASK;
+	fs_proc_flow2 |= (0x01 << FS_PRPENC_DEST_SEL_OFFSET);
+
+	ipu_cm_write(ipu, fs_proc_flow1, IPU_FS_PROC_FLOW1);
+	ipu_cm_write(ipu, fs_proc_flow2, IPU_FS_PROC_FLOW2);
+
+	spin_unlock_irqrestore(&ipu->lock, flags);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_link_prp_enc_rot_enc);
+
+/*
+ * Unlinks IPUV3_CHANNEL_IC_PRP_ENC_MEM from IPUV3_CHANNEL_MEM_ROT_ENC
+ */
+int ipu_unlink_prp_enc_rot_enc(struct ipu_soc *ipu)
+{
+	unsigned long flags;
+	u32 fs_proc_flow1;
+	u32 fs_proc_flow2;
+
+	spin_lock_irqsave(&ipu->lock, flags);
+
+	fs_proc_flow1 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+	fs_proc_flow2 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW2);
+
+	fs_proc_flow1 &= ~FS_PRPENC_ROT_SRC_SEL_MASK;
+	fs_proc_flow2 &= ~FS_PRPENC_DEST_SEL_MASK;
+
+	ipu_cm_write(ipu, fs_proc_flow1, IPU_FS_PROC_FLOW1);
+	ipu_cm_write(ipu, fs_proc_flow2, IPU_FS_PROC_FLOW2);
+
+	spin_unlock_irqrestore(&ipu->lock, flags);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_unlink_prp_enc_rot_enc);
+
+/*
+ * Links IPUV3_CHANNEL_IC_PRP_VF_MEM to IPUV3_CHANNEL_MEM_ROT_VF
+ */
+int ipu_link_prpvf_rot_prpvf(struct ipu_soc *ipu)
+{
+	unsigned long flags;
+	u32 fs_proc_flow1;
+	u32 fs_proc_flow2;
+
+	spin_lock_irqsave(&ipu->lock, flags);
+
+	fs_proc_flow1 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+	fs_proc_flow2 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW2);
+
+	fs_proc_flow1 &= ~FS_PRPVF_ROT_SRC_SEL_MASK;
+	fs_proc_flow1 |= (0x08 << FS_PRPVF_ROT_SRC_SEL_OFFSET);
+
+	fs_proc_flow2 &= ~FS_PRPVF_DEST_SEL_MASK;
+	fs_proc_flow2 |= (0x01 << FS_PRPVF_DEST_SEL_OFFSET);
+
+	ipu_cm_write(ipu, fs_proc_flow1, IPU_FS_PROC_FLOW1);
+	ipu_cm_write(ipu, fs_proc_flow2, IPU_FS_PROC_FLOW2);
+
+	spin_unlock_irqrestore(&ipu->lock, flags);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_link_prpvf_rot_prpvf);
+
+/*
+ * Unlinks IPUV3_CHANNEL_IC_PRP_VF_MEM from IPUV3_CHANNEL_MEM_ROT_VF
+ */
+int ipu_unlink_prpvf_rot_prpvf(struct ipu_soc *ipu)
+{
+	unsigned long flags;
+	u32 fs_proc_flow1;
+	u32 fs_proc_flow2;
+
+	spin_lock_irqsave(&ipu->lock, flags);
+
+	fs_proc_flow1 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+	fs_proc_flow2 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW2);
+
+	fs_proc_flow1 &= ~FS_PRPVF_ROT_SRC_SEL_MASK;
+	fs_proc_flow2 &= ~FS_PRPVF_DEST_SEL_MASK;
+
+	ipu_cm_write(ipu, fs_proc_flow1, IPU_FS_PROC_FLOW1);
+	ipu_cm_write(ipu, fs_proc_flow2, IPU_FS_PROC_FLOW2);
+
+	spin_unlock_irqrestore(&ipu->lock, flags);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_unlink_prpvf_rot_prpvf);
+
+/*
+ * Links IPUV3_CHANNEL_IC_PP_MEM to IPUV3_CHANNEL_MEM_ROT_PP
+ */
+int ipu_link_pp_rot_pp(struct ipu_soc *ipu)
+{
+	unsigned long flags;
+	u32 fs_proc_flow1;
+	u32 fs_proc_flow2;
+
+	spin_lock_irqsave(&ipu->lock, flags);
+
+	fs_proc_flow1 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+	fs_proc_flow2 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW2);
+
+	fs_proc_flow1 &= ~FS_PP_ROT_SRC_SEL_MASK;
+	fs_proc_flow1 |= (0x05 << FS_PP_ROT_SRC_SEL_OFFSET);
+
+	fs_proc_flow2 &= ~FS_PP_DEST_SEL_MASK;
+	fs_proc_flow2 |= (0x03 << FS_PP_DEST_SEL_OFFSET);
+
+	ipu_cm_write(ipu, fs_proc_flow1, IPU_FS_PROC_FLOW1);
+	ipu_cm_write(ipu, fs_proc_flow2, IPU_FS_PROC_FLOW2);
+
+	spin_unlock_irqrestore(&ipu->lock, flags);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_link_pp_rot_pp);
+
+/*
+ * Unlinks IPUV3_CHANNEL_IC_PP_MEM from IPUV3_CHANNEL_MEM_ROT_PP
+ */
+int ipu_unlink_pp_rot_pp(struct ipu_soc *ipu)
+{
+	unsigned long flags;
+	u32 fs_proc_flow1;
+	u32 fs_proc_flow2;
+
+	spin_lock_irqsave(&ipu->lock, flags);
+
+	fs_proc_flow1 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+	fs_proc_flow2 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW2);
+
+	fs_proc_flow1 &= ~FS_PP_ROT_SRC_SEL_MASK;
+	fs_proc_flow2 &= ~FS_PP_DEST_SEL_MASK;
+
+	ipu_cm_write(ipu, fs_proc_flow1, IPU_FS_PROC_FLOW1);
+	ipu_cm_write(ipu, fs_proc_flow2, IPU_FS_PROC_FLOW2);
+
+	spin_unlock_irqrestore(&ipu->lock, flags);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_unlink_pp_rot_pp);
+
 int ipu_idmac_enable_channel(struct ipuv3_channel *channel)
 {
 	struct ipu_soc *ipu = channel->ipu;
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
index 446ed20..d10e624 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
@@ -83,6 +83,64 @@ struct ipu_soc;
 #define IPU_DI0_COUNTER_RELEASE			(1 << 24)
 #define IPU_DI1_COUNTER_RELEASE			(1 << 25)
 
+#define FS_PRPENC_ROT_SRC_SEL_MASK     (0xf << 0)
+#define FS_PRPENC_ROT_SRC_SEL_OFFSET   0
+#define FS_PRPVF_ROT_SRC_SEL_MASK      (0xf << 8)
+#define FS_PRPVF_ROT_SRC_SEL_OFFSET    8
+#define FS_PP_ROT_SRC_SEL_MASK         (0xf << 16)
+#define FS_PP_ROT_SRC_SEL_OFFSET       16
+#define FS_PP_SRC_SEL_MASK             (0xf << 12)
+#define FS_PP_SRC_SEL_OFFSET           12
+#define FS_PP_SRC_SEL_VDOA             (1 << 15)
+#define FS_PRP_SRC_SEL_MASK            (0xf << 24)
+#define FS_PRP_SRC_SEL_OFFSET          24
+#define FS_VF_IN_VALID                 (1 << 31)
+#define FS_ENC_IN_VALID                (1 << 30)
+#define FS_VDI_SRC_SEL_MASK            (0x3 << 28)
+#define FS_VDI_SRC_SEL_VDOA            (0x2 << 28)
+#define FS_VDOA_DEST_SEL_MASK          (0x3 << 16)
+#define FS_VDOA_DEST_SEL_VDI           (0x2 << 16)
+#define FS_VDOA_DEST_SEL_IC            (0x1 << 16)
+#define FS_VDI_SRC_SEL_OFFSET          28
+
+#define FS_PRPENC_DEST_SEL_MASK        (0xf << 0)
+#define FS_PRPENC_DEST_SEL_OFFSET      0
+#define FS_PRPVF_DEST_SEL_MASK         (0xf << 4)
+#define FS_PRPVF_DEST_SEL_OFFSET       4
+#define FS_PRPVF_ROT_DEST_SEL_MASK     (0xf << 8)
+#define FS_PRPVF_ROT_DEST_SEL_OFFSET   8
+#define FS_PP_DEST_SEL_MASK            (0xf << 12)
+#define FS_PP_DEST_SEL_OFFSET          12
+#define FS_PP_ROT_DEST_SEL_MASK        (0xf << 16)
+#define FS_PP_ROT_DEST_SEL_OFFSET      16
+#define FS_PRPENC_ROT_DEST_SEL_MASK    (0xf << 20)
+#define FS_PRPENC_ROT_DEST_SEL_OFFSET  20
+
+#define FS_SMFC0_DEST_SEL_MASK         (0xf << 0)
+#define FS_SMFC0_DEST_SEL_OFFSET       0
+#define FS_SMFC1_DEST_SEL_MASK         (0x7 << 4)
+#define FS_SMFC1_DEST_SEL_OFFSET       4
+#define FS_SMFC2_DEST_SEL_MASK         (0xf << 7)
+#define FS_SMFC2_DEST_SEL_OFFSET       7
+#define FS_SMFC3_DEST_SEL_MASK         (0x7 << 11)
+#define FS_SMFC3_DEST_SEL_OFFSET       11
+
+#define FS_DC1_SRC_SEL_MASK            (0xf << 20)
+#define FS_DC1_SRC_SEL_OFFSET          20
+#define FS_DC2_SRC_SEL_MASK            (0xf << 16)
+#define FS_DC2_SRC_SEL_OFFSET          16
+#define FS_DP_SYNC0_SRC_SEL_MASK       (0xf << 0)
+#define FS_DP_SYNC0_SRC_SEL_OFFSET     0
+#define FS_DP_SYNC1_SRC_SEL_MASK       (0xf << 4)
+#define FS_DP_SYNC1_SRC_SEL_OFFSET     4
+#define FS_DP_ASYNC0_SRC_SEL_MASK      (0xf << 8)
+#define FS_DP_ASYNC0_SRC_SEL_OFFSET    8
+#define FS_DP_ASYNC1_SRC_SEL_MASK      (0xf << 12)
+#define FS_DP_ASYNC1_SRC_SEL_OFFSET    12
+
+#define FS_AUTO_REF_PER_MASK           0
+#define FS_AUTO_REF_PER_OFFSET         16
+
 #define IPU_IDMAC_REG(offset)	(offset)
 
 #define IDMAC_CONF			IPU_IDMAC_REG(0x0000)
diff --git a/include/linux/platform_data/imx-ipu-v3.h b/include/linux/platform_data/imx-ipu-v3.h
index 949beec..75a6a5d 100644
--- a/include/linux/platform_data/imx-ipu-v3.h
+++ b/include/linux/platform_data/imx-ipu-v3.h
@@ -205,6 +205,13 @@ int ipu_idmac_current_buffer(struct ipuv3_channel *channel);
 void ipu_idmac_enable_watermark(struct ipuv3_channel *channel, bool enable);
 int ipu_idmac_lock_enable(struct ipuv3_channel *channel, int num_bursts);
 
+int ipu_link_prp_enc_rot_enc(struct ipu_soc *ipu);
+int ipu_unlink_prp_enc_rot_enc(struct ipu_soc *ipu);
+int ipu_link_prpvf_rot_prpvf(struct ipu_soc *ipu);
+int ipu_unlink_prpvf_rot_prpvf(struct ipu_soc *ipu);
+int ipu_link_pp_rot_pp(struct ipu_soc *ipu);
+int ipu_unlink_pp_rot_pp(struct ipu_soc *ipu);
+
 /*
  * IPU Display Controller (dc) functions
  */
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 21/43] imx-drm: ipu-v3: Add ipu_bits_per_pixel()
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (19 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 20/43] imx-drm: ipu-v3: Add idmac channel linking support Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-11 11:23   ` Philipp Zabel
  2014-06-07 21:56 ` [PATCH 22/43] imx-drm: ipu-v3: Add ipu-cpmem unit Steve Longerbeam
                   ` (23 subsequent siblings)
  44 siblings, 1 reply; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Add simple conversion from pixelformat to total bits-per-pixel.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/ipu-common.c |   27 +++++++++++++++++++++++++++
 include/linux/platform_data/imx-ipu-v3.h    |    1 +
 2 files changed, 28 insertions(+)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index de66d02..8a03ad2 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -606,6 +606,33 @@ int ipu_stride_to_bytes(u32 pixel_stride, u32 pixelformat)
 }
 EXPORT_SYMBOL_GPL(ipu_stride_to_bytes);
 
+/*
+ * Standard bpp from pixel format.
+ */
+int ipu_bits_per_pixel(u32 pixelformat)
+{
+	switch (pixelformat) {
+	case V4L2_PIX_FMT_YUV420:
+	case V4L2_PIX_FMT_YVU420:
+		return 12;
+	case V4L2_PIX_FMT_RGB565:
+	case V4L2_PIX_FMT_YUYV:
+	case V4L2_PIX_FMT_UYVY:
+		return 16;
+	case V4L2_PIX_FMT_BGR24:
+	case V4L2_PIX_FMT_RGB24:
+		return 24;
+	case V4L2_PIX_FMT_BGR32:
+	case V4L2_PIX_FMT_RGB32:
+		return 32;
+	default:
+		break;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_bits_per_pixel);
+
 int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees,
 			    bool hflip, bool vflip)
 {
diff --git a/include/linux/platform_data/imx-ipu-v3.h b/include/linux/platform_data/imx-ipu-v3.h
index 75a6a5d..49e69a9 100644
--- a/include/linux/platform_data/imx-ipu-v3.h
+++ b/include/linux/platform_data/imx-ipu-v3.h
@@ -510,6 +510,7 @@ enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc);
 enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat);
 enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code);
 int ipu_stride_to_bytes(u32 pixel_stride, u32 pixelformat);
+int ipu_bits_per_pixel(u32 pixelformat);
 bool ipu_pixelformat_is_planar(u32 pixelformat);
 int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees,
 			    bool hflip, bool vflip);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 22/43] imx-drm: ipu-v3: Add ipu-cpmem unit
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (20 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 21/43] imx-drm: ipu-v3: Add ipu_bits_per_pixel() Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-11 11:23   ` Philipp Zabel
  2014-06-07 21:56 ` [PATCH 23/43] imx-drm: ipu-cpmem: Add ipu_cpmem_set_block_mode() Steve Longerbeam
                   ` (22 subsequent siblings)
  44 siblings, 1 reply; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam, Drew Moseley

Move channel parameter memory setup functions and macros into a new
submodule ipu-cpmem. In the process, cleanup arguments to the functions
to take a channel pointer instead of a pointer into cpmem for that
channel. That allows the structure of the parameter memory to be
private to ipu-cpmem.c.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
Signed-off-by: Drew Moseley <drew_moseley@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/Makefile     |    2 +-
 drivers/staging/imx-drm/ipu-v3/ipu-common.c |  457 +-------------------
 drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c  |  595 +++++++++++++++++++++++++++
 drivers/staging/imx-drm/ipu-v3/ipu-prv.h    |   14 +-
 drivers/staging/imx-drm/ipuv3-plane.c       |   16 +-
 include/linux/platform_data/imx-ipu-v3.h    |  190 ++-------
 6 files changed, 662 insertions(+), 612 deletions(-)
 create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c

diff --git a/drivers/staging/imx-drm/ipu-v3/Makefile b/drivers/staging/imx-drm/ipu-v3/Makefile
index 79c0c88..147a1b7 100644
--- a/drivers/staging/imx-drm/ipu-v3/Makefile
+++ b/drivers/staging/imx-drm/ipu-v3/Makefile
@@ -1,4 +1,4 @@
 obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += imx-ipu-v3.o
 
-imx-ipu-v3-objs := ipu-common.o ipu-csi.o ipu-dc.o ipu-di.o \
+imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-csi.o ipu-dc.o ipu-di.o \
 	ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-irt.o ipu-smfc.o
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index 8a03ad2..b9d759d 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -44,17 +44,6 @@ static inline void ipu_cm_write(struct ipu_soc *ipu, u32 value, unsigned offset)
 	writel(value, ipu->cm_reg + offset);
 }
 
-static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset)
-{
-	return readl(ipu->idmac_reg + offset);
-}
-
-static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value,
-		unsigned offset)
-{
-	writel(value, ipu->idmac_reg + offset);
-}
-
 int ipu_get_num(struct ipu_soc *ipu)
 {
 	return ipu->id;
@@ -71,379 +60,6 @@ void ipu_srm_dp_sync_update(struct ipu_soc *ipu)
 }
 EXPORT_SYMBOL_GPL(ipu_srm_dp_sync_update);
 
-struct ipu_ch_param __iomem *ipu_get_cpmem(struct ipuv3_channel *channel)
-{
-	struct ipu_soc *ipu = channel->ipu;
-
-	return ipu->cpmem_base + channel->num;
-}
-EXPORT_SYMBOL_GPL(ipu_get_cpmem);
-
-void ipu_cpmem_set_high_priority(struct ipuv3_channel *channel)
-{
-	struct ipu_soc *ipu = channel->ipu;
-	struct ipu_ch_param __iomem *p = ipu_get_cpmem(channel);
-	u32 val;
-
-	if (ipu->ipu_type == IPUV3EX)
-		ipu_ch_param_write_field(p, IPU_FIELD_ID, 1);
-
-	val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(channel->num));
-	val |= 1 << (channel->num % 32);
-	ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(channel->num));
-};
-EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority);
-
-void ipu_ch_param_write_field(struct ipu_ch_param __iomem *base, u32 wbs, u32 v)
-{
-	u32 bit = (wbs >> 8) % 160;
-	u32 size = wbs & 0xff;
-	u32 word = (wbs >> 8) / 160;
-	u32 i = bit / 32;
-	u32 ofs = bit % 32;
-	u32 mask = (1 << size) - 1;
-	u32 val;
-
-	pr_debug("%s %d %d %d\n", __func__, word, bit , size);
-
-	val = readl(&base->word[word].data[i]);
-	val &= ~(mask << ofs);
-	val |= v << ofs;
-	writel(val, &base->word[word].data[i]);
-
-	if ((bit + size - 1) / 32 > i) {
-		val = readl(&base->word[word].data[i + 1]);
-		val &= ~(mask >> (ofs ? (32 - ofs) : 0));
-		val |= v >> (ofs ? (32 - ofs) : 0);
-		writel(val, &base->word[word].data[i + 1]);
-	}
-}
-EXPORT_SYMBOL_GPL(ipu_ch_param_write_field);
-
-u32 ipu_ch_param_read_field(struct ipu_ch_param __iomem *base, u32 wbs)
-{
-	u32 bit = (wbs >> 8) % 160;
-	u32 size = wbs & 0xff;
-	u32 word = (wbs >> 8) / 160;
-	u32 i = bit / 32;
-	u32 ofs = bit % 32;
-	u32 mask = (1 << size) - 1;
-	u32 val = 0;
-
-	pr_debug("%s %d %d %d\n", __func__, word, bit , size);
-
-	val = (readl(&base->word[word].data[i]) >> ofs) & mask;
-
-	if ((bit + size - 1) / 32 > i) {
-		u32 tmp;
-		tmp = readl(&base->word[word].data[i + 1]);
-		tmp &= mask >> (ofs ? (32 - ofs) : 0);
-		val |= tmp << (ofs ? (32 - ofs) : 0);
-	}
-
-	return val;
-}
-EXPORT_SYMBOL_GPL(ipu_ch_param_read_field);
-
-int ipu_cpmem_set_format_rgb(struct ipu_ch_param __iomem *p,
-		const struct ipu_rgb *rgb)
-{
-	int bpp = 0, npb = 0, ro, go, bo, to;
-
-	ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset;
-	go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset;
-	bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset;
-	to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset;
-
-	ipu_ch_param_write_field(p, IPU_FIELD_WID0, rgb->red.length - 1);
-	ipu_ch_param_write_field(p, IPU_FIELD_OFS0, ro);
-	ipu_ch_param_write_field(p, IPU_FIELD_WID1, rgb->green.length - 1);
-	ipu_ch_param_write_field(p, IPU_FIELD_OFS1, go);
-	ipu_ch_param_write_field(p, IPU_FIELD_WID2, rgb->blue.length - 1);
-	ipu_ch_param_write_field(p, IPU_FIELD_OFS2, bo);
-
-	if (rgb->transp.length) {
-		ipu_ch_param_write_field(p, IPU_FIELD_WID3,
-				rgb->transp.length - 1);
-		ipu_ch_param_write_field(p, IPU_FIELD_OFS3, to);
-	} else {
-		ipu_ch_param_write_field(p, IPU_FIELD_WID3, 7);
-		ipu_ch_param_write_field(p, IPU_FIELD_OFS3,
-				rgb->bits_per_pixel);
-	}
-
-	switch (rgb->bits_per_pixel) {
-	case 32:
-		bpp = 0;
-		npb = 15;
-		break;
-	case 24:
-		bpp = 1;
-		npb = 19;
-		break;
-	case 16:
-		bpp = 3;
-		npb = 31;
-		break;
-	case 8:
-		bpp = 5;
-		npb = 63;
-		break;
-	default:
-		return -EINVAL;
-	}
-	ipu_ch_param_write_field(p, IPU_FIELD_BPP, bpp);
-	ipu_ch_param_write_field(p, IPU_FIELD_NPB, npb);
-	ipu_ch_param_write_field(p, IPU_FIELD_PFS, 7); /* rgb mode */
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb);
-
-int ipu_cpmem_set_format_passthrough(struct ipu_ch_param __iomem *p,
-		int width)
-{
-	int bpp = 0, npb = 0;
-
-	switch (width) {
-	case 32:
-		bpp = 0;
-		npb = 15;
-		break;
-	case 24:
-		bpp = 1;
-		npb = 19;
-		break;
-	case 16:
-		bpp = 3;
-		npb = 31;
-		break;
-	case 8:
-		bpp = 5;
-		npb = 63;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	ipu_ch_param_write_field(p, IPU_FIELD_BPP, bpp);
-	ipu_ch_param_write_field(p, IPU_FIELD_NPB, npb);
-	ipu_ch_param_write_field(p, IPU_FIELD_PFS, 6); /* raw mode */
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough);
-
-void ipu_cpmem_set_yuv_interleaved(struct ipu_ch_param __iomem *p,
-				   u32 pixel_format)
-{
-	switch (pixel_format) {
-	case V4L2_PIX_FMT_UYVY:
-		ipu_ch_param_write_field(p, IPU_FIELD_BPP, 3);    /* bits/pixel */
-		ipu_ch_param_write_field(p, IPU_FIELD_PFS, 0xA);  /* pix format */
-		ipu_ch_param_write_field(p, IPU_FIELD_NPB, 31);   /* burst size */
-		break;
-	case V4L2_PIX_FMT_YUYV:
-		ipu_ch_param_write_field(p, IPU_FIELD_BPP, 3);    /* bits/pixel */
-		ipu_ch_param_write_field(p, IPU_FIELD_PFS, 0x8);  /* pix format */
-		ipu_ch_param_write_field(p, IPU_FIELD_NPB, 31);   /* burst size */
-		break;
-	}
-}
-EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved);
-
-void ipu_cpmem_set_yuv_planar_full(struct ipu_ch_param __iomem *p,
-		u32 pixel_format, int stride, int u_offset, int v_offset)
-{
-	switch (pixel_format) {
-	case V4L2_PIX_FMT_YUV420:
-		ipu_ch_param_write_field(p, IPU_FIELD_SLUV, (stride / 2) - 1);
-		ipu_ch_param_write_field(p, IPU_FIELD_UBO, u_offset / 8);
-		ipu_ch_param_write_field(p, IPU_FIELD_VBO, v_offset / 8);
-		break;
-	case V4L2_PIX_FMT_YVU420:
-		ipu_ch_param_write_field(p, IPU_FIELD_SLUV, (stride / 2) - 1);
-		ipu_ch_param_write_field(p, IPU_FIELD_UBO, v_offset / 8);
-		ipu_ch_param_write_field(p, IPU_FIELD_VBO, u_offset / 8);
-		break;
-	}
-}
-EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
-
-void ipu_cpmem_set_yuv_planar(struct ipu_ch_param __iomem *p, u32 pixel_format,
-		int stride, int height)
-{
-	int u_offset, v_offset;
-	int uv_stride = 0;
-
-	switch (pixel_format) {
-	case V4L2_PIX_FMT_YUV420:
-	case V4L2_PIX_FMT_YVU420:
-		uv_stride = stride / 2;
-		u_offset = stride * height;
-		v_offset = u_offset + (uv_stride * height / 2);
-		ipu_cpmem_set_yuv_planar_full(p, pixel_format, stride,
-				u_offset, v_offset);
-		break;
-	}
-}
-EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar);
-
-static const struct ipu_rgb def_rgb_32 = {
-	.red	= { .offset = 16, .length = 8, },
-	.green	= { .offset =  8, .length = 8, },
-	.blue	= { .offset =  0, .length = 8, },
-	.transp = { .offset = 24, .length = 8, },
-	.bits_per_pixel = 32,
-};
-
-static const struct ipu_rgb def_bgr_32 = {
-	.red	= { .offset =  0, .length = 8, },
-	.green	= { .offset =  8, .length = 8, },
-	.blue	= { .offset = 16, .length = 8, },
-	.transp = { .offset = 24, .length = 8, },
-	.bits_per_pixel = 32,
-};
-
-static const struct ipu_rgb def_rgb_24 = {
-	.red	= { .offset = 16, .length = 8, },
-	.green	= { .offset =  8, .length = 8, },
-	.blue	= { .offset =  0, .length = 8, },
-	.transp = { .offset =  0, .length = 0, },
-	.bits_per_pixel = 24,
-};
-
-static const struct ipu_rgb def_bgr_24 = {
-	.red	= { .offset =  0, .length = 8, },
-	.green	= { .offset =  8, .length = 8, },
-	.blue	= { .offset = 16, .length = 8, },
-	.transp = { .offset =  0, .length = 0, },
-	.bits_per_pixel = 24,
-};
-
-static const struct ipu_rgb def_rgb_16 = {
-	.red	= { .offset = 11, .length = 5, },
-	.green	= { .offset =  5, .length = 6, },
-	.blue	= { .offset =  0, .length = 5, },
-	.transp = { .offset =  0, .length = 0, },
-	.bits_per_pixel = 16,
-};
-
-static const struct ipu_rgb def_bgr_16 = {
-	.red	= { .offset =  0, .length = 5, },
-	.green	= { .offset =  5, .length = 6, },
-	.blue	= { .offset = 11, .length = 5, },
-	.transp = { .offset =  0, .length = 0, },
-	.bits_per_pixel = 16,
-};
-
-#define Y_OFFSET(pix, x, y)	((x) + pix->width * (y))
-#define U_OFFSET(pix, x, y)	((pix->width * pix->height) + \
-					(pix->width * (y) / 4) + (x) / 2)
-#define V_OFFSET(pix, x, y)	((pix->width * pix->height) + \
-					(pix->width * pix->height / 4) + \
-					(pix->width * (y) / 4) + (x) / 2)
-
-int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 drm_fourcc)
-{
-	switch (drm_fourcc) {
-	case DRM_FORMAT_YUV420:
-	case DRM_FORMAT_YVU420:
-		/* pix format */
-		ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 2);
-		/* burst size */
-		ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 63);
-		break;
-	case DRM_FORMAT_UYVY:
-		/* bits/pixel */
-		ipu_ch_param_write_field(cpmem, IPU_FIELD_BPP, 3);
-		/* pix format */
-		ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 0xA);
-		/* burst size */
-		ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 31);
-		break;
-	case DRM_FORMAT_YUYV:
-		/* bits/pixel */
-		ipu_ch_param_write_field(cpmem, IPU_FIELD_BPP, 3);
-		/* pix format */
-		ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 0x8);
-		/* burst size */
-		ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 31);
-		break;
-	case DRM_FORMAT_ABGR8888:
-	case DRM_FORMAT_XBGR8888:
-		ipu_cpmem_set_format_rgb(cpmem, &def_bgr_32);
-		break;
-	case DRM_FORMAT_ARGB8888:
-	case DRM_FORMAT_XRGB8888:
-		ipu_cpmem_set_format_rgb(cpmem, &def_rgb_32);
-		break;
-	case DRM_FORMAT_BGR888:
-		ipu_cpmem_set_format_rgb(cpmem, &def_bgr_24);
-		break;
-	case DRM_FORMAT_RGB888:
-		ipu_cpmem_set_format_rgb(cpmem, &def_rgb_24);
-		break;
-	case DRM_FORMAT_RGB565:
-		ipu_cpmem_set_format_rgb(cpmem, &def_rgb_16);
-		break;
-	case DRM_FORMAT_BGR565:
-		ipu_cpmem_set_format_rgb(cpmem, &def_bgr_16);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
-
-/*
- * The V4L2 spec defines packed RGB formats in memory byte order, which from
- * point of view of the IPU corresponds to little-endian words with the first
- * component in the least significant bits.
- * The DRM pixel formats and IPU internal representation are ordered the other
- * way around, with the first named component ordered at the most significant
- * bits. Further, V4L2 formats are not well defined:
- *     http://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html
- * We choose the interpretation which matches GStreamer behavior.
- */
-static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat)
-{
-	switch (pixelformat) {
-	case V4L2_PIX_FMT_RGB565:
-		/*
-		 * Here we choose the 'corrected' interpretation of RGBP, a
-		 * little-endian 16-bit word with the red component at the most
-		 * significant bits:
-		 * g[2:0]b[4:0] r[4:0]g[5:3] <=> [16:0] R:G:B
-		 */
-		return DRM_FORMAT_RGB565;
-	case V4L2_PIX_FMT_BGR24:
-		/* B G R <=> [24:0] R:G:B */
-		return DRM_FORMAT_RGB888;
-	case V4L2_PIX_FMT_RGB24:
-		/* R G B <=> [24:0] B:G:R */
-		return DRM_FORMAT_BGR888;
-	case V4L2_PIX_FMT_BGR32:
-		/* B G R A <=> [32:0] A:B:G:R */
-		return DRM_FORMAT_XRGB8888;
-	case V4L2_PIX_FMT_RGB32:
-		/* R G B A <=> [32:0] A:B:G:R */
-		return DRM_FORMAT_XBGR8888;
-	case V4L2_PIX_FMT_UYVY:
-		return DRM_FORMAT_UYVY;
-	case V4L2_PIX_FMT_YUYV:
-		return DRM_FORMAT_YUYV;
-	case V4L2_PIX_FMT_YUV420:
-		return DRM_FORMAT_YUV420;
-	case V4L2_PIX_FMT_YVU420:
-		return DRM_FORMAT_YVU420;
-	}
-
-	return -EINVAL;
-}
-
 enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc)
 {
 	switch (drm_fourcc) {
@@ -471,66 +87,6 @@ enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc)
 }
 EXPORT_SYMBOL_GPL(ipu_drm_fourcc_to_colorspace);
 
-int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem,
-		struct ipu_image *image)
-{
-	struct v4l2_pix_format *pix = &image->pix;
-	int y_offset, u_offset, v_offset;
-
-	pr_debug("%s: resolution: %dx%d stride: %d\n",
-			__func__, pix->width, pix->height,
-			pix->bytesperline);
-
-	ipu_cpmem_set_resolution(cpmem, image->rect.width,
-			image->rect.height);
-	ipu_cpmem_set_stride(cpmem, pix->bytesperline);
-
-	ipu_cpmem_set_fmt(cpmem, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat));
-
-	switch (pix->pixelformat) {
-	case V4L2_PIX_FMT_YUV420:
-	case V4L2_PIX_FMT_YVU420:
-		y_offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
-		u_offset = U_OFFSET(pix, image->rect.left,
-				image->rect.top) - y_offset;
-		v_offset = V_OFFSET(pix, image->rect.left,
-				image->rect.top) - y_offset;
-
-		ipu_cpmem_set_yuv_planar_full(cpmem, pix->pixelformat,
-				pix->bytesperline, u_offset, v_offset);
-		ipu_cpmem_set_buffer(cpmem, 0, image->phys + y_offset);
-		break;
-	case V4L2_PIX_FMT_UYVY:
-	case V4L2_PIX_FMT_YUYV:
-		ipu_cpmem_set_buffer(cpmem, 0, image->phys +
-				image->rect.left * 2 +
-				image->rect.top * image->pix.bytesperline);
-		break;
-	case V4L2_PIX_FMT_RGB32:
-	case V4L2_PIX_FMT_BGR32:
-		ipu_cpmem_set_buffer(cpmem, 0, image->phys +
-				image->rect.left * 4 +
-				image->rect.top * image->pix.bytesperline);
-		break;
-	case V4L2_PIX_FMT_RGB565:
-		ipu_cpmem_set_buffer(cpmem, 0, image->phys +
-				image->rect.left * 2 +
-				image->rect.top * image->pix.bytesperline);
-		break;
-	case V4L2_PIX_FMT_RGB24:
-	case V4L2_PIX_FMT_BGR24:
-		ipu_cpmem_set_buffer(cpmem, 0, image->phys +
-				image->rect.left * 3 +
-				image->rect.top * image->pix.bytesperline);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
-
 enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat)
 {
 	switch (pixelformat) {
@@ -1424,6 +980,12 @@ static int ipu_submodules_init(struct ipu_soc *ipu,
 	struct device *dev = &pdev->dev;
 	const struct ipu_devtype *devtype = ipu->devtype;
 
+	ret = ipu_cpmem_init(ipu, dev, ipu_base + devtype->cpmem_ofs);
+	if (ret) {
+		unit = "cpmem";
+		goto err_cpmem;
+	}
+
 	ret = ipu_csi_init(ipu, dev, 0, ipu_base + devtype->csi0_ofs,
 			   IPU_CONF_CSI0_EN, ipu_clk);
 	if (ret) {
@@ -1515,6 +1077,8 @@ err_smfc:
 err_csi_1:
 	ipu_csi_exit(ipu, 0);
 err_csi_0:
+	ipu_cpmem_exit(ipu);
+err_cpmem:
 	dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret);
 	return ret;
 }
@@ -1587,6 +1151,7 @@ static void ipu_submodules_exit(struct ipu_soc *ipu)
 	ipu_smfc_exit(ipu);
 	ipu_csi_exit(ipu, 1);
 	ipu_csi_exit(ipu, 0);
+	ipu_cpmem_exit(ipu);
 }
 
 static int platform_remove_devices_fn(struct device *dev, void *unused)
@@ -1807,10 +1372,8 @@ static int ipu_probe(struct platform_device *pdev)
 	ipu->idmac_reg = devm_ioremap(&pdev->dev,
 			ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS,
 			PAGE_SIZE);
-	ipu->cpmem_base = devm_ioremap(&pdev->dev,
-			ipu_base + devtype->cpmem_ofs, PAGE_SIZE);
 
-	if (!ipu->cm_reg || !ipu->idmac_reg || !ipu->cpmem_base)
+	if (!ipu->cm_reg || !ipu->idmac_reg)
 		return -ENOMEM;
 
 	ipu->gp_reg = syscon_regmap_lookup_by_compatible(
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c b/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c
new file mode 100644
index 0000000..06471ee
--- /dev/null
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c
@@ -0,0 +1,595 @@
+/*
+ * Copyright (C) 2012 Mentor Graphics Inc.
+ * Copyright 2005-2012 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 <linux/types.h>
+#include <linux/bitrev.h>
+#include <linux/io.h>
+#include <drm/drm_fourcc.h>
+#include "ipu-prv.h"
+
+struct ipu_cpmem_word {
+	u32 data[5];
+	u32 res[3];
+};
+
+struct ipu_ch_param {
+	struct ipu_cpmem_word word[2];
+};
+
+struct ipu_cpmem {
+	struct ipu_ch_param __iomem *base;
+	u32 module;
+	spinlock_t lock;
+	int use_count;
+	struct ipu_soc *ipu;
+};
+
+#define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size))
+
+#define IPU_FIELD_UBO		IPU_CPMEM_WORD(0, 46, 22)
+#define IPU_FIELD_VBO		IPU_CPMEM_WORD(0, 68, 22)
+#define IPU_FIELD_IOX		IPU_CPMEM_WORD(0, 90, 4)
+#define IPU_FIELD_RDRW		IPU_CPMEM_WORD(0, 94, 1)
+#define IPU_FIELD_SO		IPU_CPMEM_WORD(0, 113, 1)
+#define IPU_FIELD_SLY		IPU_CPMEM_WORD(1, 102, 14)
+#define IPU_FIELD_SLUV		IPU_CPMEM_WORD(1, 128, 14)
+
+#define IPU_FIELD_XV		IPU_CPMEM_WORD(0, 0, 10)
+#define IPU_FIELD_YV		IPU_CPMEM_WORD(0, 10, 9)
+#define IPU_FIELD_XB		IPU_CPMEM_WORD(0, 19, 13)
+#define IPU_FIELD_YB		IPU_CPMEM_WORD(0, 32, 12)
+#define IPU_FIELD_NSB_B		IPU_CPMEM_WORD(0, 44, 1)
+#define IPU_FIELD_CF		IPU_CPMEM_WORD(0, 45, 1)
+#define IPU_FIELD_SX		IPU_CPMEM_WORD(0, 46, 12)
+#define IPU_FIELD_SY		IPU_CPMEM_WORD(0, 58, 11)
+#define IPU_FIELD_NS		IPU_CPMEM_WORD(0, 69, 10)
+#define IPU_FIELD_SDX		IPU_CPMEM_WORD(0, 79, 7)
+#define IPU_FIELD_SM		IPU_CPMEM_WORD(0, 86, 10)
+#define IPU_FIELD_SCC		IPU_CPMEM_WORD(0, 96, 1)
+#define IPU_FIELD_SCE		IPU_CPMEM_WORD(0, 97, 1)
+#define IPU_FIELD_SDY		IPU_CPMEM_WORD(0, 98, 7)
+#define IPU_FIELD_SDRX		IPU_CPMEM_WORD(0, 105, 1)
+#define IPU_FIELD_SDRY		IPU_CPMEM_WORD(0, 106, 1)
+#define IPU_FIELD_BPP		IPU_CPMEM_WORD(0, 107, 3)
+#define IPU_FIELD_DEC_SEL	IPU_CPMEM_WORD(0, 110, 2)
+#define IPU_FIELD_DIM		IPU_CPMEM_WORD(0, 112, 1)
+#define IPU_FIELD_BNDM		IPU_CPMEM_WORD(0, 114, 3)
+#define IPU_FIELD_BM		IPU_CPMEM_WORD(0, 117, 2)
+#define IPU_FIELD_ROT		IPU_CPMEM_WORD(0, 119, 1)
+#define IPU_FIELD_HF		IPU_CPMEM_WORD(0, 120, 1)
+#define IPU_FIELD_VF		IPU_CPMEM_WORD(0, 121, 1)
+#define IPU_FIELD_THE		IPU_CPMEM_WORD(0, 122, 1)
+#define IPU_FIELD_CAP		IPU_CPMEM_WORD(0, 123, 1)
+#define IPU_FIELD_CAE		IPU_CPMEM_WORD(0, 124, 1)
+#define IPU_FIELD_FW		IPU_CPMEM_WORD(0, 125, 13)
+#define IPU_FIELD_FH		IPU_CPMEM_WORD(0, 138, 12)
+#define IPU_FIELD_EBA0		IPU_CPMEM_WORD(1, 0, 29)
+#define IPU_FIELD_EBA1		IPU_CPMEM_WORD(1, 29, 29)
+#define IPU_FIELD_ILO		IPU_CPMEM_WORD(1, 58, 20)
+#define IPU_FIELD_NPB		IPU_CPMEM_WORD(1, 78, 7)
+#define IPU_FIELD_PFS		IPU_CPMEM_WORD(1, 85, 4)
+#define IPU_FIELD_ALU		IPU_CPMEM_WORD(1, 89, 1)
+#define IPU_FIELD_ALBM		IPU_CPMEM_WORD(1, 90, 3)
+#define IPU_FIELD_ID		IPU_CPMEM_WORD(1, 93, 2)
+#define IPU_FIELD_TH		IPU_CPMEM_WORD(1, 95, 7)
+#define IPU_FIELD_SL		IPU_CPMEM_WORD(1, 102, 14)
+#define IPU_FIELD_WID0		IPU_CPMEM_WORD(1, 116, 3)
+#define IPU_FIELD_WID1		IPU_CPMEM_WORD(1, 119, 3)
+#define IPU_FIELD_WID2		IPU_CPMEM_WORD(1, 122, 3)
+#define IPU_FIELD_WID3		IPU_CPMEM_WORD(1, 125, 3)
+#define IPU_FIELD_OFS0		IPU_CPMEM_WORD(1, 128, 5)
+#define IPU_FIELD_OFS1		IPU_CPMEM_WORD(1, 133, 5)
+#define IPU_FIELD_OFS2		IPU_CPMEM_WORD(1, 138, 5)
+#define IPU_FIELD_OFS3		IPU_CPMEM_WORD(1, 143, 5)
+#define IPU_FIELD_SXYS		IPU_CPMEM_WORD(1, 148, 1)
+#define IPU_FIELD_CRE		IPU_CPMEM_WORD(1, 149, 1)
+#define IPU_FIELD_DEC_SEL2	IPU_CPMEM_WORD(1, 150, 1)
+
+static inline struct ipu_ch_param __iomem *
+ipu_get_cpmem(struct ipuv3_channel *ch)
+{
+	struct ipu_cpmem *cpmem = ch->ipu->cpmem_priv;
+	return cpmem->base + ch->num;
+}
+
+static void ipu_ch_param_write_field(struct ipuv3_channel *ch, u32 wbs, u32 v)
+{
+	struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch);
+	u32 bit = (wbs >> 8) % 160;
+	u32 size = wbs & 0xff;
+	u32 word = (wbs >> 8) / 160;
+	u32 i = bit / 32;
+	u32 ofs = bit % 32;
+	u32 mask = (1 << size) - 1;
+	u32 val;
+
+	pr_debug("%s %d %d %d\n", __func__, word, bit , size);
+
+	val = readl(&base->word[word].data[i]);
+	val &= ~(mask << ofs);
+	val |= v << ofs;
+	writel(val, &base->word[word].data[i]);
+
+	if ((bit + size - 1) / 32 > i) {
+		val = readl(&base->word[word].data[i + 1]);
+		val &= ~(mask >> (ofs ? (32 - ofs) : 0));
+		val |= v >> (ofs ? (32 - ofs) : 0);
+		writel(val, &base->word[word].data[i + 1]);
+	}
+}
+
+static u32 ipu_ch_param_read_field(struct ipuv3_channel *ch, u32 wbs)
+{
+	struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch);
+	u32 bit = (wbs >> 8) % 160;
+	u32 size = wbs & 0xff;
+	u32 word = (wbs >> 8) / 160;
+	u32 i = bit / 32;
+	u32 ofs = bit % 32;
+	u32 mask = (1 << size) - 1;
+	u32 val = 0;
+
+	pr_debug("%s %d %d %d\n", __func__, word, bit , size);
+
+	val = (readl(&base->word[word].data[i]) >> ofs) & mask;
+
+	if ((bit + size - 1) / 32 > i) {
+		u32 tmp;
+		tmp = readl(&base->word[word].data[i + 1]);
+		tmp &= mask >> (ofs ? (32 - ofs) : 0);
+		val |= tmp << (ofs ? (32 - ofs) : 0);
+	}
+
+	return val;
+}
+
+/*
+ * The V4L2 spec defines packed RGB formats in memory byte order, which from
+ * point of view of the IPU corresponds to little-endian words with the first
+ * component in the least significant bits.
+ * The DRM pixel formats and IPU internal representation are ordered the other
+ * way around, with the first named component ordered at the most significant
+ * bits. Further, V4L2 formats are not well defined:
+ *     http://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html
+ * We choose the interpretation which matches GStreamer behavior.
+ */
+static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat)
+{
+	switch (pixelformat) {
+	case V4L2_PIX_FMT_RGB565:
+		/*
+		 * Here we choose the 'corrected' interpretation of RGBP, a
+		 * little-endian 16-bit word with the red component at the most
+		 * significant bits:
+		 * g[2:0]b[4:0] r[4:0]g[5:3] <=> [16:0] R:G:B
+		 */
+		return DRM_FORMAT_RGB565;
+	case V4L2_PIX_FMT_BGR24:
+		/* B G R <=> [24:0] R:G:B */
+		return DRM_FORMAT_RGB888;
+	case V4L2_PIX_FMT_RGB24:
+		/* R G B <=> [24:0] B:G:R */
+		return DRM_FORMAT_BGR888;
+	case V4L2_PIX_FMT_BGR32:
+		/* B G R A <=> [32:0] A:B:G:R */
+		return DRM_FORMAT_XRGB8888;
+	case V4L2_PIX_FMT_RGB32:
+		/* R G B A <=> [32:0] A:B:G:R */
+		return DRM_FORMAT_XBGR8888;
+	case V4L2_PIX_FMT_UYVY:
+		return DRM_FORMAT_UYVY;
+	case V4L2_PIX_FMT_YUYV:
+		return DRM_FORMAT_YUYV;
+	case V4L2_PIX_FMT_YUV420:
+		return DRM_FORMAT_YUV420;
+	case V4L2_PIX_FMT_YVU420:
+		return DRM_FORMAT_YVU420;
+	}
+
+	return -EINVAL;
+}
+
+void ipu_cpmem_zero(struct ipuv3_channel *ch)
+{
+	struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
+	void __iomem *base = p;
+	int i;
+
+	for (i = 0; i < sizeof(*p) / sizeof(u32); i++)
+		writel(0, base + i * sizeof(u32));
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_zero);
+
+void ipu_cpmem_set_resolution(struct ipuv3_channel *ch, int xres, int yres)
+{
+	ipu_ch_param_write_field(ch, IPU_FIELD_FW, xres - 1);
+	ipu_ch_param_write_field(ch, IPU_FIELD_FH, yres - 1);
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_resolution);
+
+void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride)
+{
+	ipu_ch_param_write_field(ch, IPU_FIELD_SLY, stride - 1);
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_stride);
+
+void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch)
+{
+	struct ipu_soc *ipu = ch->ipu;
+	u32 val;
+
+	if (ipu->ipu_type == IPUV3EX)
+		ipu_ch_param_write_field(ch, IPU_FIELD_ID, 1);
+
+	val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(ch->num));
+	val |= 1 << (ch->num % 32);
+	ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(ch->num));
+};
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority);
+
+void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf)
+{
+	if (bufnum)
+		ipu_ch_param_write_field(ch, IPU_FIELD_EBA1, buf >> 3);
+	else
+		ipu_ch_param_write_field(ch, IPU_FIELD_EBA0, buf >> 3);
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer);
+
+void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride)
+{
+	ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1);
+	ipu_ch_param_write_field(ch, IPU_FIELD_ILO, stride / 8);
+	ipu_ch_param_write_field(ch, IPU_FIELD_SLY, (stride * 2) - 1);
+};
+EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
+
+void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize)
+{
+	ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1);
+};
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_burstsize);
+
+int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
+			     const struct ipu_rgb *rgb)
+{
+	int bpp = 0, npb = 0, ro, go, bo, to;
+
+	ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset;
+	go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset;
+	bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset;
+	to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset;
+
+	ipu_ch_param_write_field(ch, IPU_FIELD_WID0, rgb->red.length - 1);
+	ipu_ch_param_write_field(ch, IPU_FIELD_OFS0, ro);
+	ipu_ch_param_write_field(ch, IPU_FIELD_WID1, rgb->green.length - 1);
+	ipu_ch_param_write_field(ch, IPU_FIELD_OFS1, go);
+	ipu_ch_param_write_field(ch, IPU_FIELD_WID2, rgb->blue.length - 1);
+	ipu_ch_param_write_field(ch, IPU_FIELD_OFS2, bo);
+
+	if (rgb->transp.length) {
+		ipu_ch_param_write_field(ch, IPU_FIELD_WID3,
+				rgb->transp.length - 1);
+		ipu_ch_param_write_field(ch, IPU_FIELD_OFS3, to);
+	} else {
+		ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7);
+		ipu_ch_param_write_field(ch, IPU_FIELD_OFS3,
+				rgb->bits_per_pixel);
+	}
+
+	switch (rgb->bits_per_pixel) {
+	case 32:
+		bpp = 0;
+		npb = 15;
+		break;
+	case 24:
+		bpp = 1;
+		npb = 19;
+		break;
+	case 16:
+		bpp = 3;
+		npb = 31;
+		break;
+	case 8:
+		bpp = 5;
+		npb = 63;
+		break;
+	default:
+		return -EINVAL;
+	}
+	ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
+	ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
+	ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 7); /* rgb mode */
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb);
+
+int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width)
+{
+	int bpp = 0, npb = 0;
+
+	switch (width) {
+	case 32:
+		bpp = 0;
+		npb = 15;
+		break;
+	case 24:
+		bpp = 1;
+		npb = 19;
+		break;
+	case 16:
+		bpp = 3;
+		npb = 31;
+		break;
+	case 8:
+		bpp = 5;
+		npb = 63;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp);
+	ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb);
+	ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 6); /* raw mode */
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough);
+
+void ipu_cpmem_set_yuv_interleaved(struct ipuv3_channel *ch, u32 pixel_format)
+{
+	switch (pixel_format) {
+	case V4L2_PIX_FMT_UYVY:
+		ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
+		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);/* pix fmt */
+		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
+		break;
+	case V4L2_PIX_FMT_YUYV:
+		ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */
+		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);/* pix fmt */
+		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */
+		break;
+	}
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved);
+
+void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
+				   u32 pixel_format, int stride,
+				   int u_offset, int v_offset)
+{
+	switch (pixel_format) {
+	case V4L2_PIX_FMT_YUV420:
+		ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, (stride / 2) - 1);
+		ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8);
+		ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8);
+		break;
+	case V4L2_PIX_FMT_YVU420:
+		ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, (stride / 2) - 1);
+		ipu_ch_param_write_field(ch, IPU_FIELD_UBO, v_offset / 8);
+		ipu_ch_param_write_field(ch, IPU_FIELD_VBO, u_offset / 8);
+		break;
+	}
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
+
+void ipu_cpmem_set_yuv_planar(struct ipuv3_channel *ch,
+			      u32 pixel_format, int stride, int height)
+{
+	int u_offset, v_offset;
+	int uv_stride = 0;
+
+	switch (pixel_format) {
+	case V4L2_PIX_FMT_YUV420:
+	case V4L2_PIX_FMT_YVU420:
+		uv_stride = stride / 2;
+		u_offset = stride * height;
+		v_offset = u_offset + (uv_stride * height / 2);
+		ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride,
+					      u_offset, v_offset);
+		break;
+	}
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar);
+
+static const struct ipu_rgb def_rgb_32 = {
+	.red	= { .offset = 16, .length = 8, },
+	.green	= { .offset =  8, .length = 8, },
+	.blue	= { .offset =  0, .length = 8, },
+	.transp = { .offset = 24, .length = 8, },
+	.bits_per_pixel = 32,
+};
+
+static const struct ipu_rgb def_bgr_32 = {
+	.red	= { .offset =  0, .length = 8, },
+	.green	= { .offset =  8, .length = 8, },
+	.blue	= { .offset = 16, .length = 8, },
+	.transp = { .offset = 24, .length = 8, },
+	.bits_per_pixel = 32,
+};
+
+static const struct ipu_rgb def_rgb_24 = {
+	.red	= { .offset = 16, .length = 8, },
+	.green	= { .offset =  8, .length = 8, },
+	.blue	= { .offset =  0, .length = 8, },
+	.transp = { .offset =  0, .length = 0, },
+	.bits_per_pixel = 24,
+};
+
+static const struct ipu_rgb def_bgr_24 = {
+	.red	= { .offset =  0, .length = 8, },
+	.green	= { .offset =  8, .length = 8, },
+	.blue	= { .offset = 16, .length = 8, },
+	.transp = { .offset =  0, .length = 0, },
+	.bits_per_pixel = 24,
+};
+
+static const struct ipu_rgb def_rgb_16 = {
+	.red	= { .offset = 11, .length = 5, },
+	.green	= { .offset =  5, .length = 6, },
+	.blue	= { .offset =  0, .length = 5, },
+	.transp = { .offset =  0, .length = 0, },
+	.bits_per_pixel = 16,
+};
+
+static const struct ipu_rgb def_bgr_16 = {
+	.red	= { .offset =  0, .length = 5, },
+	.green	= { .offset =  5, .length = 6, },
+	.blue	= { .offset = 11, .length = 5, },
+	.transp = { .offset =  0, .length = 0, },
+	.bits_per_pixel = 16,
+};
+
+#define Y_OFFSET(pix, x, y)	((x) + pix->width * (y))
+#define U_OFFSET(pix, x, y)	((pix->width * pix->height) + \
+					(pix->width * (y) / 4) + (x) / 2)
+#define V_OFFSET(pix, x, y)	((pix->width * pix->height) + \
+					(pix->width * pix->height / 4) + \
+					(pix->width * (y) / 4) + (x) / 2)
+
+int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc)
+{
+	switch (drm_fourcc) {
+	case DRM_FORMAT_YUV420:
+	case DRM_FORMAT_YVU420:
+		/* pix format */
+		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 2);
+		/* burst size */
+		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+		break;
+	case DRM_FORMAT_UYVY:
+		/* bits/pixel */
+		ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
+		/* pix format */
+		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);
+		/* burst size */
+		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+		break;
+	case DRM_FORMAT_YUYV:
+		/* bits/pixel */
+		ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
+		/* pix format */
+		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);
+		/* burst size */
+		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+		break;
+	case DRM_FORMAT_ABGR8888:
+	case DRM_FORMAT_XBGR8888:
+		ipu_cpmem_set_format_rgb(ch, &def_bgr_32);
+		break;
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_XRGB8888:
+		ipu_cpmem_set_format_rgb(ch, &def_rgb_32);
+		break;
+	case DRM_FORMAT_BGR888:
+		ipu_cpmem_set_format_rgb(ch, &def_bgr_24);
+		break;
+	case DRM_FORMAT_RGB888:
+		ipu_cpmem_set_format_rgb(ch, &def_rgb_24);
+		break;
+	case DRM_FORMAT_RGB565:
+		ipu_cpmem_set_format_rgb(ch, &def_rgb_16);
+		break;
+	case DRM_FORMAT_BGR565:
+		ipu_cpmem_set_format_rgb(ch, &def_bgr_16);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
+
+int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
+{
+	struct v4l2_pix_format *pix = &image->pix;
+	int y_offset, u_offset, v_offset;
+
+	pr_debug("%s: resolution: %dx%d stride: %d\n",
+		 __func__, pix->width, pix->height,
+		 pix->bytesperline);
+
+	ipu_cpmem_set_resolution(ch, image->rect.width, image->rect.height);
+	ipu_cpmem_set_stride(ch, pix->bytesperline);
+
+	ipu_cpmem_set_fmt(ch, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat));
+
+	switch (pix->pixelformat) {
+	case V4L2_PIX_FMT_YUV420:
+	case V4L2_PIX_FMT_YVU420:
+		y_offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+		u_offset = U_OFFSET(pix, image->rect.left,
+				    image->rect.top) - y_offset;
+		v_offset = V_OFFSET(pix, image->rect.left,
+				    image->rect.top) - y_offset;
+
+		ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
+				pix->bytesperline, u_offset, v_offset);
+		ipu_cpmem_set_buffer(ch, 0, image->phys + y_offset);
+		break;
+	case V4L2_PIX_FMT_UYVY:
+	case V4L2_PIX_FMT_YUYV:
+		ipu_cpmem_set_buffer(ch, 0, image->phys +
+				     image->rect.left * 2 +
+				     image->rect.top * image->pix.bytesperline);
+		break;
+	case V4L2_PIX_FMT_RGB32:
+	case V4L2_PIX_FMT_BGR32:
+		ipu_cpmem_set_buffer(ch, 0, image->phys +
+				     image->rect.left * 4 +
+				     image->rect.top * image->pix.bytesperline);
+		break;
+	case V4L2_PIX_FMT_RGB565:
+		ipu_cpmem_set_buffer(ch, 0, image->phys +
+				     image->rect.left * 2 +
+				     image->rect.top * image->pix.bytesperline);
+		break;
+	case V4L2_PIX_FMT_RGB24:
+	case V4L2_PIX_FMT_BGR24:
+		ipu_cpmem_set_buffer(ch, 0, image->phys +
+				     image->rect.left * 3 +
+				     image->rect.top * image->pix.bytesperline);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
+
+int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
+{
+	struct ipu_cpmem *cpmem;
+
+	cpmem = devm_kzalloc(dev, sizeof(*cpmem), GFP_KERNEL);
+	if (!cpmem)
+		return -ENOMEM;
+
+	ipu->cpmem_priv = cpmem;
+
+	spin_lock_init(&cpmem->lock);
+	cpmem->base = devm_ioremap(dev, base, SZ_128K);
+	if (!cpmem->base)
+		return -ENOMEM;
+
+	dev_dbg(dev, "CPMEM base: 0x%08lx remapped to %p\n",
+		base, cpmem->base);
+	cpmem->ipu = ipu;
+
+	return 0;
+}
+
+void ipu_cpmem_exit(struct ipu_soc *ipu)
+{
+}
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
index d10e624..f56b3fd 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h
@@ -195,6 +195,7 @@ struct ipuv3_channel {
 	struct ipu_soc *ipu;
 };
 
+struct ipu_cpmem;
 struct ipu_dc_priv;
 struct ipu_dmfc_priv;
 struct ipu_di;
@@ -213,7 +214,6 @@ struct ipu_soc {
 
 	void __iomem		*cm_reg;
 	void __iomem		*idmac_reg;
-	struct ipu_ch_param __iomem	*cpmem_base;
 	struct regmap		*gp_reg;
 
 	int			id;
@@ -227,6 +227,7 @@ struct ipu_soc {
 	int			irq_err;
 	struct irq_domain	*domain;
 
+	struct ipu_cpmem	*cpmem_priv;
 	struct ipu_dc_priv	*dc_priv;
 	struct ipu_dp_priv	*dp_priv;
 	struct ipu_dmfc_priv	*dmfc_priv;
@@ -237,6 +238,17 @@ struct ipu_soc {
 	struct ipu_irt		*irt_priv;
 };
 
+static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset)
+{
+	return readl(ipu->idmac_reg + offset);
+}
+
+static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value,
+		unsigned offset)
+{
+	writel(value, ipu->idmac_reg + offset);
+}
+
 void ipu_srm_dp_sync_update(struct ipu_soc *ipu);
 
 int ipu_module_enable(struct ipu_soc *ipu, u32 mask);
diff --git a/drivers/staging/imx-drm/ipuv3-plane.c b/drivers/staging/imx-drm/ipuv3-plane.c
index e9e4e7a..f962cc8 100644
--- a/drivers/staging/imx-drm/ipuv3-plane.c
+++ b/drivers/staging/imx-drm/ipuv3-plane.c
@@ -62,7 +62,6 @@ static inline int calc_bandwidth(int width, int height, unsigned int vref)
 int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
 		       int x, int y)
 {
-	struct ipu_ch_param __iomem *cpmem;
 	struct drm_gem_cma_object *cma_obj;
 	unsigned long eba;
 
@@ -75,13 +74,12 @@ int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
 	dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d",
 		&cma_obj->paddr, x, y);
 
-	cpmem = ipu_get_cpmem(ipu_plane->ipu_ch);
-	ipu_cpmem_set_stride(cpmem, fb->pitches[0]);
+	ipu_cpmem_set_stride(ipu_plane->ipu_ch, fb->pitches[0]);
 
 	eba = cma_obj->paddr + fb->offsets[0] +
 	      fb->pitches[0] * y + (fb->bits_per_pixel >> 3) * x;
-	ipu_cpmem_set_buffer(cpmem, 0, eba);
-	ipu_cpmem_set_buffer(cpmem, 1, eba);
+	ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 0, eba);
+	ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba);
 
 	/* cache offsets for subsequent pageflips */
 	ipu_plane->x = x;
@@ -97,7 +95,6 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
 		       uint32_t src_x, uint32_t src_y,
 		       uint32_t src_w, uint32_t src_h)
 {
-	struct ipu_ch_param __iomem *cpmem;
 	struct device *dev = ipu_plane->base.dev->dev;
 	int ret;
 
@@ -175,10 +172,9 @@ int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
 		return ret;
 	}
 
-	cpmem = ipu_get_cpmem(ipu_plane->ipu_ch);
-	ipu_ch_param_zero(cpmem);
-	ipu_cpmem_set_resolution(cpmem, src_w, src_h);
-	ret = ipu_cpmem_set_fmt(cpmem, fb->pixel_format);
+	ipu_cpmem_zero(ipu_plane->ipu_ch);
+	ipu_cpmem_set_resolution(ipu_plane->ipu_ch, src_w, src_h);
+	ret = ipu_cpmem_set_fmt(ipu_plane->ipu_ch, fb->pixel_format);
 	if (ret < 0) {
 		dev_err(dev, "unsupported pixel format 0x%08x\n",
 			fb->pixel_format);
diff --git a/include/linux/platform_data/imx-ipu-v3.h b/include/linux/platform_data/imx-ipu-v3.h
index 49e69a9..91986ed 100644
--- a/include/linux/platform_data/imx-ipu-v3.h
+++ b/include/linux/platform_data/imx-ipu-v3.h
@@ -205,6 +205,43 @@ int ipu_idmac_current_buffer(struct ipuv3_channel *channel);
 void ipu_idmac_enable_watermark(struct ipuv3_channel *channel, bool enable);
 int ipu_idmac_lock_enable(struct ipuv3_channel *channel, int num_bursts);
 
+/*
+ * IPU Channel Parameter Memory (cpmem) functions
+ */
+struct ipu_rgb {
+	struct fb_bitfield	red;
+	struct fb_bitfield	green;
+	struct fb_bitfield	blue;
+	struct fb_bitfield	transp;
+	int			bits_per_pixel;
+};
+
+struct ipu_image {
+	struct v4l2_pix_format pix;
+	struct v4l2_rect rect;
+	dma_addr_t phys;
+};
+
+void ipu_cpmem_zero(struct ipuv3_channel *ch);
+void ipu_cpmem_set_resolution(struct ipuv3_channel *ch, int xres, int yres);
+void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride);
+void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch);
+void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf);
+void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride);
+void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize);
+int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
+			     const struct ipu_rgb *rgb);
+int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width);
+void ipu_cpmem_set_yuv_interleaved(struct ipuv3_channel *ch, u32 pixel_format);
+void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
+				   u32 pixel_format, int stride,
+				   int u_offset, int v_offset);
+void ipu_cpmem_set_yuv_planar(struct ipuv3_channel *ch,
+			      u32 pixel_format, int stride, int height);
+int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc);
+int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image);
+
+/* Channel linking functions */
 int ipu_link_prp_enc_rot_enc(struct ipu_soc *ipu);
 int ipu_unlink_prp_enc_rot_enc(struct ipu_soc *ipu);
 int ipu_link_prpvf_rot_prpvf(struct ipu_soc *ipu);
@@ -359,153 +396,6 @@ int ipu_irt_disable(struct ipu_irt *irt);
 struct ipu_irt *ipu_irt_get(struct ipu_soc *ipu);
 void ipu_irt_put(struct ipu_irt *irt);
 
-#define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size))
-
-#define IPU_FIELD_UBO		IPU_CPMEM_WORD(0, 46, 22)
-#define IPU_FIELD_VBO		IPU_CPMEM_WORD(0, 68, 22)
-#define IPU_FIELD_IOX		IPU_CPMEM_WORD(0, 90, 4)
-#define IPU_FIELD_RDRW		IPU_CPMEM_WORD(0, 94, 1)
-#define IPU_FIELD_SO		IPU_CPMEM_WORD(0, 113, 1)
-#define IPU_FIELD_SLY		IPU_CPMEM_WORD(1, 102, 14)
-#define IPU_FIELD_SLUV		IPU_CPMEM_WORD(1, 128, 14)
-
-#define IPU_FIELD_XV		IPU_CPMEM_WORD(0, 0, 10)
-#define IPU_FIELD_YV		IPU_CPMEM_WORD(0, 10, 9)
-#define IPU_FIELD_XB		IPU_CPMEM_WORD(0, 19, 13)
-#define IPU_FIELD_YB		IPU_CPMEM_WORD(0, 32, 12)
-#define IPU_FIELD_NSB_B		IPU_CPMEM_WORD(0, 44, 1)
-#define IPU_FIELD_CF		IPU_CPMEM_WORD(0, 45, 1)
-#define IPU_FIELD_SX		IPU_CPMEM_WORD(0, 46, 12)
-#define IPU_FIELD_SY		IPU_CPMEM_WORD(0, 58, 11)
-#define IPU_FIELD_NS		IPU_CPMEM_WORD(0, 69, 10)
-#define IPU_FIELD_SDX		IPU_CPMEM_WORD(0, 79, 7)
-#define IPU_FIELD_SM		IPU_CPMEM_WORD(0, 86, 10)
-#define IPU_FIELD_SCC		IPU_CPMEM_WORD(0, 96, 1)
-#define IPU_FIELD_SCE		IPU_CPMEM_WORD(0, 97, 1)
-#define IPU_FIELD_SDY		IPU_CPMEM_WORD(0, 98, 7)
-#define IPU_FIELD_SDRX		IPU_CPMEM_WORD(0, 105, 1)
-#define IPU_FIELD_SDRY		IPU_CPMEM_WORD(0, 106, 1)
-#define IPU_FIELD_BPP		IPU_CPMEM_WORD(0, 107, 3)
-#define IPU_FIELD_DEC_SEL	IPU_CPMEM_WORD(0, 110, 2)
-#define IPU_FIELD_DIM		IPU_CPMEM_WORD(0, 112, 1)
-#define IPU_FIELD_BNDM		IPU_CPMEM_WORD(0, 114, 3)
-#define IPU_FIELD_BM		IPU_CPMEM_WORD(0, 117, 2)
-#define IPU_FIELD_ROT		IPU_CPMEM_WORD(0, 119, 1)
-#define IPU_FIELD_HF		IPU_CPMEM_WORD(0, 120, 1)
-#define IPU_FIELD_VF		IPU_CPMEM_WORD(0, 121, 1)
-#define IPU_FIELD_THE		IPU_CPMEM_WORD(0, 122, 1)
-#define IPU_FIELD_CAP		IPU_CPMEM_WORD(0, 123, 1)
-#define IPU_FIELD_CAE		IPU_CPMEM_WORD(0, 124, 1)
-#define IPU_FIELD_FW		IPU_CPMEM_WORD(0, 125, 13)
-#define IPU_FIELD_FH		IPU_CPMEM_WORD(0, 138, 12)
-#define IPU_FIELD_EBA0		IPU_CPMEM_WORD(1, 0, 29)
-#define IPU_FIELD_EBA1		IPU_CPMEM_WORD(1, 29, 29)
-#define IPU_FIELD_ILO		IPU_CPMEM_WORD(1, 58, 20)
-#define IPU_FIELD_NPB		IPU_CPMEM_WORD(1, 78, 7)
-#define IPU_FIELD_PFS		IPU_CPMEM_WORD(1, 85, 4)
-#define IPU_FIELD_ALU		IPU_CPMEM_WORD(1, 89, 1)
-#define IPU_FIELD_ALBM		IPU_CPMEM_WORD(1, 90, 3)
-#define IPU_FIELD_ID		IPU_CPMEM_WORD(1, 93, 2)
-#define IPU_FIELD_TH		IPU_CPMEM_WORD(1, 95, 7)
-#define IPU_FIELD_SL		IPU_CPMEM_WORD(1, 102, 14)
-#define IPU_FIELD_WID0		IPU_CPMEM_WORD(1, 116, 3)
-#define IPU_FIELD_WID1		IPU_CPMEM_WORD(1, 119, 3)
-#define IPU_FIELD_WID2		IPU_CPMEM_WORD(1, 122, 3)
-#define IPU_FIELD_WID3		IPU_CPMEM_WORD(1, 125, 3)
-#define IPU_FIELD_OFS0		IPU_CPMEM_WORD(1, 128, 5)
-#define IPU_FIELD_OFS1		IPU_CPMEM_WORD(1, 133, 5)
-#define IPU_FIELD_OFS2		IPU_CPMEM_WORD(1, 138, 5)
-#define IPU_FIELD_OFS3		IPU_CPMEM_WORD(1, 143, 5)
-#define IPU_FIELD_SXYS		IPU_CPMEM_WORD(1, 148, 1)
-#define IPU_FIELD_CRE		IPU_CPMEM_WORD(1, 149, 1)
-#define IPU_FIELD_DEC_SEL2	IPU_CPMEM_WORD(1, 150, 1)
-
-struct ipu_cpmem_word {
-	u32 data[5];
-	u32 res[3];
-};
-
-struct ipu_ch_param {
-	struct ipu_cpmem_word word[2];
-};
-
-void ipu_ch_param_write_field(struct ipu_ch_param __iomem *base,
-			      u32 wbs, u32 v);
-u32 ipu_ch_param_read_field(struct ipu_ch_param __iomem *base, u32 wbs);
-struct ipu_ch_param __iomem *ipu_get_cpmem(struct ipuv3_channel *channel);
-void ipu_ch_param_dump(struct ipu_ch_param __iomem *p);
-
-static inline void ipu_ch_param_zero(struct ipu_ch_param __iomem *p)
-{
-	int i;
-	void __iomem *base = p;
-
-	for (i = 0; i < sizeof(*p) / sizeof(u32); i++)
-		writel(0, base + i * sizeof(u32));
-}
-
-static inline void ipu_cpmem_set_buffer(struct ipu_ch_param __iomem *p,
-		int bufnum, dma_addr_t buf)
-{
-	if (bufnum)
-		ipu_ch_param_write_field(p, IPU_FIELD_EBA1, buf >> 3);
-	else
-		ipu_ch_param_write_field(p, IPU_FIELD_EBA0, buf >> 3);
-}
-
-static inline void ipu_cpmem_set_resolution(struct ipu_ch_param __iomem *p,
-		int xres, int yres)
-{
-	ipu_ch_param_write_field(p, IPU_FIELD_FW, xres - 1);
-	ipu_ch_param_write_field(p, IPU_FIELD_FH, yres - 1);
-}
-
-static inline void ipu_cpmem_set_stride(struct ipu_ch_param __iomem *p,
-		int stride)
-{
-	ipu_ch_param_write_field(p, IPU_FIELD_SLY, stride - 1);
-}
-
-void ipu_cpmem_set_high_priority(struct ipuv3_channel *channel);
-
-struct ipu_rgb {
-	struct fb_bitfield	red;
-	struct fb_bitfield	green;
-	struct fb_bitfield	blue;
-	struct fb_bitfield	transp;
-	int			bits_per_pixel;
-};
-
-struct ipu_image {
-	struct v4l2_pix_format pix;
-	struct v4l2_rect rect;
-	dma_addr_t phys;
-};
-
-int ipu_cpmem_set_format_passthrough(struct ipu_ch_param __iomem *p,
-		int width);
-
-int ipu_cpmem_set_format_rgb(struct ipu_ch_param __iomem *,
-		const struct ipu_rgb *rgb);
-
-static inline void ipu_cpmem_interlaced_scan(struct ipu_ch_param *p,
-		int stride)
-{
-	ipu_ch_param_write_field(p, IPU_FIELD_SO, 1);
-	ipu_ch_param_write_field(p, IPU_FIELD_ILO, stride / 8);
-	ipu_ch_param_write_field(p, IPU_FIELD_SLY, (stride * 2) - 1);
-};
-
-void ipu_cpmem_set_yuv_planar(struct ipu_ch_param __iomem *p, u32 pixel_format,
-			int stride, int height);
-void ipu_cpmem_set_yuv_interleaved(struct ipu_ch_param __iomem *p,
-				   u32 pixel_format);
-void ipu_cpmem_set_yuv_planar_full(struct ipu_ch_param __iomem *p,
-		u32 pixel_format, int stride, int u_offset, int v_offset);
-int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 pixelformat);
-int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem,
-		struct ipu_image *image);
-
 enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc);
 enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat);
 enum ipu_color_space ipu_mbus_code_to_colorspace(u32 mbus_code);
@@ -517,12 +407,6 @@ int ipu_degrees_to_rot_mode(enum ipu_rotate_mode *mode, int degrees,
 int ipu_rot_mode_to_degrees(int *degrees, enum ipu_rotate_mode mode,
 			    bool hflip, bool vflip);
 
-static inline void ipu_cpmem_set_burstsize(struct ipu_ch_param __iomem *p,
-		int burstsize)
-{
-	ipu_ch_param_write_field(p, IPU_FIELD_NPB, burstsize - 1);
-};
-
 struct ipu_client_platformdata {
 	int di;
 	int dc;
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 23/43] imx-drm: ipu-cpmem: Add ipu_cpmem_set_block_mode()
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (21 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 22/43] imx-drm: ipu-v3: Add ipu-cpmem unit Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 24/43] imx-drm: ipu-cpmem: Add ipu_cpmem_set_axi_id() Steve Longerbeam
                   ` (21 subsequent siblings)
  44 siblings, 0 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Adds ipu_cpmem_set_block_mode().

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c |    6 ++++++
 include/linux/platform_data/imx-ipu-v3.h   |    1 +
 2 files changed, 7 insertions(+)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c b/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c
index 06471ee..c7910cc 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c
@@ -258,6 +258,12 @@ void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize)
 };
 EXPORT_SYMBOL_GPL(ipu_cpmem_set_burstsize);
 
+void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch)
+{
+	ipu_ch_param_write_field(ch, IPU_FIELD_BM, 1);
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_block_mode);
+
 int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
 			     const struct ipu_rgb *rgb)
 {
diff --git a/include/linux/platform_data/imx-ipu-v3.h b/include/linux/platform_data/imx-ipu-v3.h
index 91986ed..beb2e4b 100644
--- a/include/linux/platform_data/imx-ipu-v3.h
+++ b/include/linux/platform_data/imx-ipu-v3.h
@@ -229,6 +229,7 @@ void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch);
 void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf);
 void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride);
 void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize);
+void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch);
 int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
 			     const struct ipu_rgb *rgb);
 int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 24/43] imx-drm: ipu-cpmem: Add ipu_cpmem_set_axi_id()
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (22 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 23/43] imx-drm: ipu-cpmem: Add ipu_cpmem_set_block_mode() Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 25/43] imx-drm: ipu-cpmem: Add ipu_cpmem_set_rotation() Steve Longerbeam
                   ` (20 subsequent siblings)
  44 siblings, 0 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Adds ipu_cpmem_set_axi_id() to set which AXI bus master the channel
will use to transfer data onto AXI bus.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c |    7 +++++++
 include/linux/platform_data/imx-ipu-v3.h   |    1 +
 2 files changed, 8 insertions(+)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c b/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c
index c7910cc..4d5a9fe 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c
@@ -252,6 +252,13 @@ void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride)
 };
 EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan);
 
+void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id)
+{
+	id &= 0x3;
+	ipu_ch_param_write_field(ch, IPU_FIELD_ID, id);
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_axi_id);
+
 void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize)
 {
 	ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1);
diff --git a/include/linux/platform_data/imx-ipu-v3.h b/include/linux/platform_data/imx-ipu-v3.h
index beb2e4b..6486217 100644
--- a/include/linux/platform_data/imx-ipu-v3.h
+++ b/include/linux/platform_data/imx-ipu-v3.h
@@ -228,6 +228,7 @@ void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride);
 void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch);
 void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf);
 void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride);
+void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id);
 void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize);
 void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch);
 int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 25/43] imx-drm: ipu-cpmem: Add ipu_cpmem_set_rotation()
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (23 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 24/43] imx-drm: ipu-cpmem: Add ipu_cpmem_set_axi_id() Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 26/43] imx-drm: ipu-cpmem: Add second buffer support to ipu_cpmem_set_image() Steve Longerbeam
                   ` (19 subsequent siblings)
  44 siblings, 0 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Adds ipu_cpmem_set_rotation().

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c |    9 +++++++++
 include/linux/platform_data/imx-ipu-v3.h   |    2 ++
 2 files changed, 11 insertions(+)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c b/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c
index 4d5a9fe..bd76a38 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c
@@ -64,6 +64,7 @@ struct ipu_cpmem {
 #define IPU_FIELD_BNDM		IPU_CPMEM_WORD(0, 114, 3)
 #define IPU_FIELD_BM		IPU_CPMEM_WORD(0, 117, 2)
 #define IPU_FIELD_ROT		IPU_CPMEM_WORD(0, 119, 1)
+#define IPU_FIELD_ROT_HF_VF	IPU_CPMEM_WORD(0, 119, 3)
 #define IPU_FIELD_HF		IPU_CPMEM_WORD(0, 120, 1)
 #define IPU_FIELD_VF		IPU_CPMEM_WORD(0, 121, 1)
 #define IPU_FIELD_THE		IPU_CPMEM_WORD(0, 122, 1)
@@ -271,6 +272,14 @@ void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch)
 }
 EXPORT_SYMBOL_GPL(ipu_cpmem_set_block_mode);
 
+void ipu_cpmem_set_rotation(struct ipuv3_channel *ch,
+			    enum ipu_rotate_mode rot)
+{
+	u32 temp_rot = bitrev8(rot) >> 5;
+	ipu_ch_param_write_field(ch, IPU_FIELD_ROT_HF_VF, temp_rot);
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_set_rotation);
+
 int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
 			     const struct ipu_rgb *rgb)
 {
diff --git a/include/linux/platform_data/imx-ipu-v3.h b/include/linux/platform_data/imx-ipu-v3.h
index 6486217..53aab16 100644
--- a/include/linux/platform_data/imx-ipu-v3.h
+++ b/include/linux/platform_data/imx-ipu-v3.h
@@ -231,6 +231,8 @@ void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride);
 void ipu_cpmem_set_axi_id(struct ipuv3_channel *ch, u32 id);
 void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize);
 void ipu_cpmem_set_block_mode(struct ipuv3_channel *ch);
+void ipu_cpmem_set_rotation(struct ipuv3_channel *ch,
+			    enum ipu_rotate_mode rot);
 int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch,
 			     const struct ipu_rgb *rgb);
 int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 26/43] imx-drm: ipu-cpmem: Add second buffer support to ipu_cpmem_set_image()
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (24 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 25/43] imx-drm: ipu-cpmem: Add ipu_cpmem_set_rotation() Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 27/43] imx-drm: ipu-v3: Add more planar formats support Steve Longerbeam
                   ` (18 subsequent siblings)
  44 siblings, 0 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Add a second buffer physaddr to struct ipu_image, for double-buffering
support.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c |   32 ++++++++++++++--------------
 include/linux/platform_data/imx-ipu-v3.h   |    3 ++-
 2 files changed, 18 insertions(+), 17 deletions(-)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c b/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c
index bd76a38..70e90b40 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c
@@ -535,7 +535,7 @@ EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt);
 int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
 {
 	struct v4l2_pix_format *pix = &image->pix;
-	int y_offset, u_offset, v_offset;
+	int offset, y_offset, u_offset, v_offset;
 
 	pr_debug("%s: resolution: %dx%d stride: %d\n",
 		 __func__, pix->width, pix->height,
@@ -557,30 +557,30 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
 
 		ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
 				pix->bytesperline, u_offset, v_offset);
-		ipu_cpmem_set_buffer(ch, 0, image->phys + y_offset);
+		ipu_cpmem_set_buffer(ch, 0, image->phys0 + y_offset);
+		ipu_cpmem_set_buffer(ch, 1, image->phys1 + y_offset);
 		break;
 	case V4L2_PIX_FMT_UYVY:
 	case V4L2_PIX_FMT_YUYV:
-		ipu_cpmem_set_buffer(ch, 0, image->phys +
-				     image->rect.left * 2 +
-				     image->rect.top * image->pix.bytesperline);
+	case V4L2_PIX_FMT_RGB565:
+		offset = image->rect.left * 2 +
+			image->rect.top * pix->bytesperline;
+		ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset);
+		ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset);
 		break;
 	case V4L2_PIX_FMT_RGB32:
 	case V4L2_PIX_FMT_BGR32:
-		ipu_cpmem_set_buffer(ch, 0, image->phys +
-				     image->rect.left * 4 +
-				     image->rect.top * image->pix.bytesperline);
-		break;
-	case V4L2_PIX_FMT_RGB565:
-		ipu_cpmem_set_buffer(ch, 0, image->phys +
-				     image->rect.left * 2 +
-				     image->rect.top * image->pix.bytesperline);
+		offset = image->rect.left * 4 +
+			image->rect.top * pix->bytesperline;
+		ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset);
+		ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset);
 		break;
 	case V4L2_PIX_FMT_RGB24:
 	case V4L2_PIX_FMT_BGR24:
-		ipu_cpmem_set_buffer(ch, 0, image->phys +
-				     image->rect.left * 3 +
-				     image->rect.top * image->pix.bytesperline);
+		offset = image->rect.left * 3 +
+			image->rect.top * pix->bytesperline;
+		ipu_cpmem_set_buffer(ch, 0, image->phys0 + offset);
+		ipu_cpmem_set_buffer(ch, 1, image->phys1 + offset);
 		break;
 	default:
 		return -EINVAL;
diff --git a/include/linux/platform_data/imx-ipu-v3.h b/include/linux/platform_data/imx-ipu-v3.h
index 53aab16..4575657 100644
--- a/include/linux/platform_data/imx-ipu-v3.h
+++ b/include/linux/platform_data/imx-ipu-v3.h
@@ -219,7 +219,8 @@ struct ipu_rgb {
 struct ipu_image {
 	struct v4l2_pix_format pix;
 	struct v4l2_rect rect;
-	dma_addr_t phys;
+	dma_addr_t phys0;
+	dma_addr_t phys1;
 };
 
 void ipu_cpmem_zero(struct ipuv3_channel *ch);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 27/43] imx-drm: ipu-v3: Add more planar formats support
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (25 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 26/43] imx-drm: ipu-cpmem: Add second buffer support to ipu_cpmem_set_image() Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 28/43] imx-drm: ipu-cpmem: Add ipu_cpmem_dump() Steve Longerbeam
                   ` (17 subsequent siblings)
  44 siblings, 0 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam, Dmitry Eremin-Solenikov, Mohsin Kazmi

Adds support for the following planar and partial-planar formats:

YUV422
NV12
NV21
NV16
NV61

Signed-off-by: Dmitry Eremin-Solenikov <dmitry_eremin@mentor.com>
Signed-off-by: Mohsin Kazmi <mohsin_kazmi@mentor.com>
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/ipu-common.c |   26 +++++
 drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c  |  146 +++++++++++++++++++++++++--
 2 files changed, 166 insertions(+), 6 deletions(-)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index b9d759d..2ee6370 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -80,6 +80,12 @@ enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc)
 	case DRM_FORMAT_UYVY:
 	case DRM_FORMAT_YUV420:
 	case DRM_FORMAT_YVU420:
+	case DRM_FORMAT_YUV422:
+	case DRM_FORMAT_YVU422:
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV21:
+	case DRM_FORMAT_NV16:
+	case DRM_FORMAT_NV61:
 		return IPUV3_COLORSPACE_YUV;
 	default:
 		return IPUV3_COLORSPACE_UNKNOWN;
@@ -92,8 +98,13 @@ enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat)
 	switch (pixelformat) {
 	case V4L2_PIX_FMT_YUV420:
 	case V4L2_PIX_FMT_YVU420:
+	case V4L2_PIX_FMT_YUV422P:
 	case V4L2_PIX_FMT_UYVY:
 	case V4L2_PIX_FMT_YUYV:
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV21:
+	case V4L2_PIX_FMT_NV16:
+	case V4L2_PIX_FMT_NV61:
 		return IPUV3_COLORSPACE_YUV;
 	case V4L2_PIX_FMT_RGB32:
 	case V4L2_PIX_FMT_BGR32:
@@ -112,6 +123,11 @@ bool ipu_pixelformat_is_planar(u32 pixelformat)
 	switch (pixelformat) {
 	case V4L2_PIX_FMT_YUV420:
 	case V4L2_PIX_FMT_YVU420:
+	case V4L2_PIX_FMT_YUV422P:
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV21:
+	case V4L2_PIX_FMT_NV16:
+	case V4L2_PIX_FMT_NV61:
 		return true;
 	}
 
@@ -137,6 +153,11 @@ int ipu_stride_to_bytes(u32 pixel_stride, u32 pixelformat)
 	switch (pixelformat) {
 	case V4L2_PIX_FMT_YUV420:
 	case V4L2_PIX_FMT_YVU420:
+	case V4L2_PIX_FMT_YUV422P:
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV21:
+	case V4L2_PIX_FMT_NV16:
+	case V4L2_PIX_FMT_NV61:
 		/*
 		 * for the planar YUV formats, the stride passed to
 		 * cpmem must be the stride in bytes of the Y plane.
@@ -170,10 +191,15 @@ int ipu_bits_per_pixel(u32 pixelformat)
 	switch (pixelformat) {
 	case V4L2_PIX_FMT_YUV420:
 	case V4L2_PIX_FMT_YVU420:
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV21:
 		return 12;
+	case V4L2_PIX_FMT_YUV422P:
 	case V4L2_PIX_FMT_RGB565:
 	case V4L2_PIX_FMT_YUYV:
 	case V4L2_PIX_FMT_UYVY:
+	case V4L2_PIX_FMT_NV16:
+	case V4L2_PIX_FMT_NV61:
 		return 16;
 	case V4L2_PIX_FMT_BGR24:
 	case V4L2_PIX_FMT_RGB24:
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c b/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c
index 70e90b40..1ee5e11 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c
@@ -191,8 +191,18 @@ static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat)
 		return DRM_FORMAT_YUYV;
 	case V4L2_PIX_FMT_YUV420:
 		return DRM_FORMAT_YUV420;
+	case V4L2_PIX_FMT_YUV422P:
+		return DRM_FORMAT_YUV422;
 	case V4L2_PIX_FMT_YVU420:
 		return DRM_FORMAT_YVU420;
+	case V4L2_PIX_FMT_NV12:
+		return DRM_FORMAT_NV12;
+	case V4L2_PIX_FMT_NV21:
+		return DRM_FORMAT_NV21;
+	case V4L2_PIX_FMT_NV16:
+		return DRM_FORMAT_NV16;
+	case V4L2_PIX_FMT_NV61:
+		return DRM_FORMAT_NV61;
 	}
 
 	return -EINVAL;
@@ -391,6 +401,7 @@ void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
 {
 	switch (pixel_format) {
 	case V4L2_PIX_FMT_YUV420:
+	case V4L2_PIX_FMT_YUV422P:
 		ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, (stride / 2) - 1);
 		ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8);
 		ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8);
@@ -400,6 +411,18 @@ void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch,
 		ipu_ch_param_write_field(ch, IPU_FIELD_UBO, v_offset / 8);
 		ipu_ch_param_write_field(ch, IPU_FIELD_VBO, u_offset / 8);
 		break;
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV16:
+		ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, stride - 1);
+		ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8);
+		ipu_ch_param_write_field(ch, IPU_FIELD_VBO, u_offset / 8);
+		break;
+	case V4L2_PIX_FMT_NV21:
+	case V4L2_PIX_FMT_NV61:
+		ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, stride - 1);
+		ipu_ch_param_write_field(ch, IPU_FIELD_UBO, v_offset / 8);
+		ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8);
+		break;
 	}
 }
 EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full);
@@ -419,6 +442,25 @@ void ipu_cpmem_set_yuv_planar(struct ipuv3_channel *ch,
 		ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride,
 					      u_offset, v_offset);
 		break;
+	case V4L2_PIX_FMT_YUV422P:
+		uv_stride = stride / 2;
+		u_offset = stride * height;
+		v_offset = u_offset + (uv_stride * height);
+		ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride,
+					      u_offset, v_offset);
+		break;
+	case V4L2_PIX_FMT_NV12:
+	case V4L2_PIX_FMT_NV16:
+		u_offset = stride * height;
+		ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride,
+					      u_offset, 0);
+		break;
+	case V4L2_PIX_FMT_NV21:
+	case V4L2_PIX_FMT_NV61:
+		v_offset = stride * height;
+		ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride,
+					      0, v_offset);
+		break;
 	}
 }
 EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar);
@@ -472,11 +514,20 @@ static const struct ipu_rgb def_bgr_16 = {
 };
 
 #define Y_OFFSET(pix, x, y)	((x) + pix->width * (y))
-#define U_OFFSET(pix, x, y)	((pix->width * pix->height) + \
-					(pix->width * (y) / 4) + (x) / 2)
-#define V_OFFSET(pix, x, y)	((pix->width * pix->height) + \
-					(pix->width * pix->height / 4) + \
-					(pix->width * (y) / 4) + (x) / 2)
+#define U_OFFSET(pix, x, y)	((pix->width * pix->height) +		\
+				 (pix->width * (y) / 4) + (x) / 2)
+#define V_OFFSET(pix, x, y)	((pix->width * pix->height) +		\
+				 (pix->width * pix->height / 4) +	\
+				 (pix->width * (y) / 4) + (x) / 2)
+#define U2_OFFSET(pix, x, y)	((pix->width * pix->height) +		\
+				 (pix->width * (y) / 2) + (x) / 2)
+#define V2_OFFSET(pix, x, y)	((pix->width * pix->height) +		\
+				 (pix->width * pix->height / 2) +	\
+				 (pix->width * (y) / 2) + (x) / 2)
+#define UV_OFFSET(pix, x, y)	((pix->width * pix->height) +	\
+				 (pix->width * (y) / 2) + (x))
+#define UV2_OFFSET(pix, x, y)	((pix->width * pix->height) +	\
+				 (pix->width * y) + (x))
 
 int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc)
 {
@@ -488,6 +539,27 @@ int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc)
 		/* burst size */
 		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
 		break;
+	case DRM_FORMAT_YUV422:
+	case DRM_FORMAT_YVU422:
+		/* pix format */
+		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 1);
+		/* burst size */
+		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+		break;
+	case DRM_FORMAT_NV12:
+	case DRM_FORMAT_NV21:
+		/* pix format */
+		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 4);
+		/* burst size */
+		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+		break;
+	case DRM_FORMAT_NV16:
+	case DRM_FORMAT_NV61:
+		/* pix format */
+		ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 3);
+		/* burst size */
+		ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);
+		break;
 	case DRM_FORMAT_UYVY:
 		/* bits/pixel */
 		ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3);
@@ -556,7 +628,69 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
 				    image->rect.top) - y_offset;
 
 		ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
-				pix->bytesperline, u_offset, v_offset);
+					      pix->bytesperline,
+					      u_offset, v_offset);
+		ipu_cpmem_set_buffer(ch, 0, image->phys0 + y_offset);
+		ipu_cpmem_set_buffer(ch, 1, image->phys1 + y_offset);
+		break;
+	case V4L2_PIX_FMT_YUV422P:
+		y_offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+		u_offset = U2_OFFSET(pix, image->rect.left,
+				     image->rect.top) - y_offset;
+		v_offset = V2_OFFSET(pix, image->rect.left,
+				     image->rect.top) - y_offset;
+
+		ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
+					      pix->bytesperline,
+					      u_offset, v_offset);
+		ipu_cpmem_set_buffer(ch, 0, image->phys0 + y_offset);
+		ipu_cpmem_set_buffer(ch, 1, image->phys1 + y_offset);
+		break;
+	case V4L2_PIX_FMT_NV12:
+		y_offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+		u_offset = UV_OFFSET(pix, image->rect.left,
+				     image->rect.top) - y_offset;
+		v_offset = 0;
+
+		ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
+					      pix->bytesperline,
+					      u_offset, v_offset);
+		ipu_cpmem_set_buffer(ch, 0, image->phys0 + y_offset);
+		ipu_cpmem_set_buffer(ch, 1, image->phys1 + y_offset);
+		break;
+	case V4L2_PIX_FMT_NV21:
+		y_offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+		u_offset = 0;
+		v_offset = UV_OFFSET(pix, image->rect.left,
+				     image->rect.top) - y_offset;
+
+		ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
+					      pix->bytesperline,
+					      u_offset, v_offset);
+		ipu_cpmem_set_buffer(ch, 0, image->phys0 + y_offset);
+		ipu_cpmem_set_buffer(ch, 1, image->phys1 + y_offset);
+		break;
+	case V4L2_PIX_FMT_NV16:
+		y_offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+		u_offset = UV2_OFFSET(pix, image->rect.left,
+				      image->rect.top) - y_offset;
+		v_offset = 0;
+
+		ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
+					      pix->bytesperline,
+					      u_offset, v_offset);
+		ipu_cpmem_set_buffer(ch, 0, image->phys0 + y_offset);
+		ipu_cpmem_set_buffer(ch, 1, image->phys1 + y_offset);
+		break;
+	case V4L2_PIX_FMT_NV61:
+		y_offset = Y_OFFSET(pix, image->rect.left, image->rect.top);
+		u_offset = 0;
+		v_offset = UV2_OFFSET(pix, image->rect.left,
+				      image->rect.top) - y_offset;
+
+		ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat,
+					      pix->bytesperline,
+					      u_offset, v_offset);
 		ipu_cpmem_set_buffer(ch, 0, image->phys0 + y_offset);
 		ipu_cpmem_set_buffer(ch, 1, image->phys1 + y_offset);
 		break;
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 28/43] imx-drm: ipu-cpmem: Add ipu_cpmem_dump()
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (26 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 27/43] imx-drm: ipu-v3: Add more planar formats support Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 29/43] imx-drm: ipu-v3: Add ipu_dump() Steve Longerbeam
                   ` (16 subsequent siblings)
  44 siblings, 0 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Adds ipu_cpmem_dump() which dumps a channel's cpmem to debug.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c |   63 ++++++++++++++++++++++++++++
 include/linux/platform_data/imx-ipu-v3.h   |    1 +
 2 files changed, 64 insertions(+)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c b/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c
index 1ee5e11..b1d7f60 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c
@@ -724,6 +724,69 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
 }
 EXPORT_SYMBOL_GPL(ipu_cpmem_set_image);
 
+void ipu_cpmem_dump(struct ipuv3_channel *ch)
+{
+	struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch);
+	struct ipu_soc *ipu = ch->ipu;
+	int chno = ch->num;
+
+	dev_dbg(ipu->dev, "ch %d word 0 - %08X %08X %08X %08X %08X\n", chno,
+		readl(&p->word[0].data[0]),
+		readl(&p->word[0].data[1]),
+		readl(&p->word[0].data[2]),
+		readl(&p->word[0].data[3]),
+		readl(&p->word[0].data[4]));
+	dev_dbg(ipu->dev, "ch %d word 1 - %08X %08X %08X %08X %08X\n", chno,
+		readl(&p->word[1].data[0]),
+		readl(&p->word[1].data[1]),
+		readl(&p->word[1].data[2]),
+		readl(&p->word[1].data[3]),
+		readl(&p->word[1].data[4]));
+	dev_dbg(ipu->dev, "PFS 0x%x, ",
+		 ipu_ch_param_read_field(ch, IPU_FIELD_PFS));
+	dev_dbg(ipu->dev, "BPP 0x%x, ",
+		ipu_ch_param_read_field(ch, IPU_FIELD_BPP));
+	dev_dbg(ipu->dev, "NPB 0x%x\n",
+		 ipu_ch_param_read_field(ch, IPU_FIELD_NPB));
+
+	dev_dbg(ipu->dev, "FW %d, ",
+		 ipu_ch_param_read_field(ch, IPU_FIELD_FW));
+	dev_dbg(ipu->dev, "FH %d, ",
+		 ipu_ch_param_read_field(ch, IPU_FIELD_FH));
+	dev_dbg(ipu->dev, "EBA0 0x%x\n",
+		 ipu_ch_param_read_field(ch, IPU_FIELD_EBA0) << 3);
+	dev_dbg(ipu->dev, "EBA1 0x%x\n",
+		 ipu_ch_param_read_field(ch, IPU_FIELD_EBA1) << 3);
+	dev_dbg(ipu->dev, "Stride %d\n",
+		 ipu_ch_param_read_field(ch, IPU_FIELD_SL));
+	dev_dbg(ipu->dev, "scan_order %d\n",
+		 ipu_ch_param_read_field(ch, IPU_FIELD_SO));
+	dev_dbg(ipu->dev, "uv_stride %d\n",
+		 ipu_ch_param_read_field(ch, IPU_FIELD_SLUV));
+	dev_dbg(ipu->dev, "u_offset 0x%x\n",
+		 ipu_ch_param_read_field(ch, IPU_FIELD_UBO) << 3);
+	dev_dbg(ipu->dev, "v_offset 0x%x\n",
+		 ipu_ch_param_read_field(ch, IPU_FIELD_VBO) << 3);
+
+	dev_dbg(ipu->dev, "Width0 %d+1, ",
+		 ipu_ch_param_read_field(ch, IPU_FIELD_WID0));
+	dev_dbg(ipu->dev, "Width1 %d+1, ",
+		 ipu_ch_param_read_field(ch, IPU_FIELD_WID1));
+	dev_dbg(ipu->dev, "Width2 %d+1, ",
+		 ipu_ch_param_read_field(ch, IPU_FIELD_WID2));
+	dev_dbg(ipu->dev, "Width3 %d+1, ",
+		 ipu_ch_param_read_field(ch, IPU_FIELD_WID3));
+	dev_dbg(ipu->dev, "Offset0 %d, ",
+		 ipu_ch_param_read_field(ch, IPU_FIELD_OFS0));
+	dev_dbg(ipu->dev, "Offset1 %d, ",
+		 ipu_ch_param_read_field(ch, IPU_FIELD_OFS1));
+	dev_dbg(ipu->dev, "Offset2 %d, ",
+		 ipu_ch_param_read_field(ch, IPU_FIELD_OFS2));
+	dev_dbg(ipu->dev, "Offset3 %d\n",
+		 ipu_ch_param_read_field(ch, IPU_FIELD_OFS3));
+}
+EXPORT_SYMBOL_GPL(ipu_cpmem_dump);
+
 int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base)
 {
 	struct ipu_cpmem *cpmem;
diff --git a/include/linux/platform_data/imx-ipu-v3.h b/include/linux/platform_data/imx-ipu-v3.h
index 4575657..811b93b 100644
--- a/include/linux/platform_data/imx-ipu-v3.h
+++ b/include/linux/platform_data/imx-ipu-v3.h
@@ -245,6 +245,7 @@ void ipu_cpmem_set_yuv_planar(struct ipuv3_channel *ch,
 			      u32 pixel_format, int stride, int height);
 int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc);
 int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image);
+void ipu_cpmem_dump(struct ipuv3_channel *ch);
 
 /* Channel linking functions */
 int ipu_link_prp_enc_rot_enc(struct ipu_soc *ipu);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 29/43] imx-drm: ipu-v3: Add ipu_dump()
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (27 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 28/43] imx-drm: ipu-cpmem: Add ipu_cpmem_dump() Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 30/43] ARM: dts: imx6: add pin groups for imx6q/dl for IPU1 CSI0 Steve Longerbeam
                   ` (15 subsequent siblings)
  44 siblings, 0 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Adds ipu_dump() which dumps IPU register state to debug.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/imx-drm/ipu-v3/ipu-common.c |   41 +++++++++++++++++++++++++++
 include/linux/platform_data/imx-ipu-v3.h    |    1 +
 2 files changed, 42 insertions(+)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index 2ee6370..1526cec 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -1326,6 +1326,47 @@ static void ipu_irq_exit(struct ipu_soc *ipu)
 	irq_domain_remove(ipu->domain);
 }
 
+void ipu_dump(struct ipu_soc *ipu)
+{
+	int i;
+	dev_dbg(ipu->dev, "IPU_CONF = \t0x%08X\n",
+		ipu_cm_read(ipu, IPU_CONF));
+	dev_dbg(ipu->dev, "IDMAC_CONF = \t0x%08X\n",
+		ipu_idmac_read(ipu, IDMAC_CONF));
+	dev_dbg(ipu->dev, "IDMAC_CHA_EN1 = \t0x%08X\n",
+		ipu_idmac_read(ipu, IDMAC_CHA_EN(0)));
+	dev_dbg(ipu->dev, "IDMAC_CHA_EN2 = \t0x%08X\n",
+		ipu_idmac_read(ipu, IDMAC_CHA_EN(32)));
+	dev_dbg(ipu->dev, "IDMAC_CHA_PRI1 = \t0x%08X\n",
+		ipu_idmac_read(ipu, IDMAC_CHA_PRI(0)));
+	dev_dbg(ipu->dev, "IDMAC_CHA_PRI2 = \t0x%08X\n",
+		ipu_idmac_read(ipu, IDMAC_CHA_PRI(32)));
+	dev_dbg(ipu->dev, "IDMAC_BAND_EN1 = \t0x%08X\n",
+		ipu_idmac_read(ipu, IDMAC_BAND_EN(0)));
+	dev_dbg(ipu->dev, "IDMAC_BAND_EN2 = \t0x%08X\n",
+		ipu_idmac_read(ipu, IDMAC_BAND_EN(32)));
+	dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL0 = \t0x%08X\n",
+		ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(0)));
+	dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL1 = \t0x%08X\n",
+		ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(32)));
+	dev_dbg(ipu->dev, "IPU_CHA_TRB_MODE_SEL0 = \t0x%08X\n",
+		ipu_cm_read(ipu, IPU_CHA_TRB_MODE_SEL(0)));
+	dev_dbg(ipu->dev, "IPU_CHA_TRB_MODE_SEL1 = \t0x%08X\n",
+		ipu_cm_read(ipu, IPU_CHA_TRB_MODE_SEL(32)));
+	dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW1 = \t0x%08X\n",
+		ipu_cm_read(ipu, IPU_FS_PROC_FLOW1));
+	dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW2 = \t0x%08X\n",
+		ipu_cm_read(ipu, IPU_FS_PROC_FLOW2));
+	dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW3 = \t0x%08X\n",
+		ipu_cm_read(ipu, IPU_FS_PROC_FLOW3));
+	dev_dbg(ipu->dev, "IPU_FS_DISP_FLOW1 = \t0x%08X\n",
+		ipu_cm_read(ipu, IPU_FS_DISP_FLOW1));
+	for (i = 0; i < 15; i++)
+		dev_dbg(ipu->dev, "IPU_INT_CTRL(%d) = \t%08X\n", i,
+			ipu_cm_read(ipu, IPU_INT_CTRL(i)));
+}
+EXPORT_SYMBOL_GPL(ipu_dump);
+
 static int ipu_probe(struct platform_device *pdev)
 {
 	const struct of_device_id *of_id =
diff --git a/include/linux/platform_data/imx-ipu-v3.h b/include/linux/platform_data/imx-ipu-v3.h
index 811b93b..1698d5d 100644
--- a/include/linux/platform_data/imx-ipu-v3.h
+++ b/include/linux/platform_data/imx-ipu-v3.h
@@ -185,6 +185,7 @@ int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel,
  * IPU Common functions
  */
 int ipu_get_num(struct ipu_soc *ipu);
+void ipu_dump(struct ipu_soc *ipu);
 
 /*
  * IPU Image DMA Controller (idmac) functions
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 30/43] ARM: dts: imx6: add pin groups for imx6q/dl for IPU1 CSI0
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (28 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 29/43] imx-drm: ipu-v3: Add ipu_dump() Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-11  5:56   ` Sascha Hauer
  2014-06-07 21:56 ` [PATCH 31/43] ARM: dts: imx6qdl: Flesh out MIPI CSI2 receiver node Steve Longerbeam
                   ` (14 subsequent siblings)
  44 siblings, 1 reply; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam, Jiada Wang

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
 arch/arm/boot/dts/imx6qdl.dtsi |   52 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 04c978c..d793cd6 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -664,6 +664,58 @@
 			iomuxc: iomuxc@020e0000 {
 				compatible = "fsl,imx6dl-iomuxc", "fsl,imx6q-iomuxc";
 				reg = <0x020e0000 0x4000>;
+
+				ipu1 {
+					pinctrl_ipu1_csi0_d4_d7: ipu1-csi0-d4-d7 {
+						fsl,pins = <
+							MX6QDL_PAD_CSI0_DAT4__IPU1_CSI0_DATA04 0x80000000
+							MX6QDL_PAD_CSI0_DAT5__IPU1_CSI0_DATA05 0x80000000
+							MX6QDL_PAD_CSI0_DAT6__IPU1_CSI0_DATA06 0x80000000
+							MX6QDL_PAD_CSI0_DAT7__IPU1_CSI0_DATA07 0x80000000
+						>;
+					};
+					pinctrl_ipu1_csi0_1: ipu1-csi0-1 {
+						fsl,pins = <
+							MX6QDL_PAD_CSI0_DAT8__IPU1_CSI0_DATA08 0x80000000
+							MX6QDL_PAD_CSI0_DAT9__IPU1_CSI0_DATA09 0x80000000
+							MX6QDL_PAD_CSI0_DAT10__IPU1_CSI0_DATA10 0x80000000
+							MX6QDL_PAD_CSI0_DAT11__IPU1_CSI0_DATA11 0x80000000
+							MX6QDL_PAD_CSI0_DAT12__IPU1_CSI0_DATA12 0x80000000
+							MX6QDL_PAD_CSI0_DAT13__IPU1_CSI0_DATA13 0x80000000
+							MX6QDL_PAD_CSI0_DAT14__IPU1_CSI0_DATA14 0x80000000
+							MX6QDL_PAD_CSI0_DAT15__IPU1_CSI0_DATA15 0x80000000
+							MX6QDL_PAD_CSI0_DAT16__IPU1_CSI0_DATA16 0x80000000
+							MX6QDL_PAD_CSI0_DAT17__IPU1_CSI0_DATA17 0x80000000
+							MX6QDL_PAD_CSI0_DAT18__IPU1_CSI0_DATA18 0x80000000
+							MX6QDL_PAD_CSI0_DAT19__IPU1_CSI0_DATA19 0x80000000
+							MX6QDL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC 0x80000000
+							MX6QDL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK 0x80000000
+							MX6QDL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC 0x80000000
+						>;
+					};
+
+					pinctrl_ipu1_csi0_2: ipu1-csi0-2 {
+						fsl,pins = <
+							MX6QDL_PAD_CSI0_DAT12__IPU1_CSI0_DATA12  0x80000000
+							MX6QDL_PAD_CSI0_DAT13__IPU1_CSI0_DATA13  0x80000000
+							MX6QDL_PAD_CSI0_DAT14__IPU1_CSI0_DATA14  0x80000000
+							MX6QDL_PAD_CSI0_DAT15__IPU1_CSI0_DATA15  0x80000000
+							MX6QDL_PAD_CSI0_DAT16__IPU1_CSI0_DATA16  0x80000000
+							MX6QDL_PAD_CSI0_DAT17__IPU1_CSI0_DATA17  0x80000000
+							MX6QDL_PAD_CSI0_DAT18__IPU1_CSI0_DATA18  0x80000000
+							MX6QDL_PAD_CSI0_DAT19__IPU1_CSI0_DATA19  0x80000000
+							MX6QDL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC    0x80000000
+							MX6QDL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK 0x80000000
+							MX6QDL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC   0x80000000
+						>;
+					};
+
+					pinctrl_ipu1_csi0_data_en: ipu1-csi0-data-en {
+						fsl,pins = <
+							MX6QDL_PAD_CSI0_DATA_EN__IPU1_CSI0_DATA_EN 0x80000000
+						>;
+					};
+				};
 			};
 
 			ldb: ldb@020e0008 {
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 31/43] ARM: dts: imx6qdl: Flesh out MIPI CSI2 receiver node
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (29 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 30/43] ARM: dts: imx6: add pin groups for imx6q/dl for IPU1 CSI0 Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-11 11:38   ` Philipp Zabel
  2014-06-07 21:56 ` [PATCH 32/43] ARM: dts: imx: sabrelite: add video capture ports and endpoints Steve Longerbeam
                   ` (13 subsequent siblings)
  44 siblings, 1 reply; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Add mode device info to the MIPI CSI2 receiver node: compatible string,
interrupt sources, clocks.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 arch/arm/boot/dts/imx6qdl.dtsi |    7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index d793cd6..00130a8 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -1011,8 +1011,13 @@
 				status = "disabled";
 			};
 
-			mipi_csi: mipi@021dc000 {
+			mipi_csi2: mipi@021dc000 {
+				compatible = "fsl,imx6-mipi-csi2";
 				reg = <0x021dc000 0x4000>;
+				interrupts = <0 100 0x04>, <0 101 0x04>;
+				clocks = <&clks 138>, <&clks 208>;
+				clock-names = "dphy_clk", "cfg_clk";
+				status = "disabled";
 			};
 
 			mipi_dsi: mipi@021e0000 {
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 32/43] ARM: dts: imx: sabrelite: add video capture ports and endpoints
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (30 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 31/43] ARM: dts: imx6qdl: Flesh out MIPI CSI2 receiver node Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-11 11:38   ` Philipp Zabel
  2014-06-07 21:56 ` [PATCH 33/43] ARM: dts: imx6-sabresd: " Steve Longerbeam
                   ` (12 subsequent siblings)
  44 siblings, 1 reply; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Defines the host v4l2-capture device node and an OV5642 camera sensor
node on i2c2. The host capture device is a child of ipu1. An OV5642
parallel-bus endpoint is defined that connects to the host parallel-bus
endpoint on CSI0, using the OF graph bindings described in
Documentation/devicetree/bindings/media/video-interfaces.txt.

Note there is a pin conflict with GPIO6. This pin functions as a power
input pin to the OV5642, but ENET requires it to wake-up the ARM cores
on normal RX and TX packet done events (see 6261c4c8). So by default,
capture is disabled, enable by uncommenting __OV5642_CAPTURE__ macro.
Ethernet will still work just not quite as well.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 .../devicetree/bindings/vendor-prefixes.txt        |    1 +
 arch/arm/boot/dts/imx6qdl-sabrelite.dtsi           |   91 ++++++++++++++++++++
 2 files changed, 92 insertions(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index abc3080..90d19f8 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -90,6 +90,7 @@ nvidia	NVIDIA
 nxp	NXP Semiconductors
 onnn	ON Semiconductor Corp.
 opencores	OpenCores.org
+ovti	OmniVision Technologies, Inc
 panasonic	Panasonic Corporation
 phytec	PHYTEC Messtechnik GmbH
 picochip	Picochip Ltd
diff --git a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
index 3bec128..ea5bd9c 100644
--- a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
@@ -12,6 +12,15 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/input/input.h>
 
+/*
+ * Uncomment the following macro to enable OV5642 video capture
+ * support. There is a pin conflict for GPIO6 between ENET wake-up
+ * interrupt function and power-down pin function for the OV5642.
+ * ENET will still work when enabling OV5642 capture, just not
+ * quite as well.
+ */
+/* #define __OV5642_CAPTURE__ */
+
 / {
 	memory {
 		reg = <0x10000000 0x40000000>;
@@ -164,8 +173,10 @@
 	txd1-skew-ps = <0>;
 	txd2-skew-ps = <0>;
 	txd3-skew-ps = <0>;
+#ifndef __OV5642_CAPTURE__
 	interrupts-extended = <&gpio1 6 IRQ_TYPE_LEVEL_HIGH>,
 			      <&intc 0 119 IRQ_TYPE_LEVEL_HIGH>;
+#endif
 	status = "okay";
 };
 
@@ -193,6 +204,12 @@
 			fsl,pins = <
 				/* SGTL5000 sys_mclk */
 				MX6QDL_PAD_GPIO_0__CCM_CLKO1    0x030b0
+#ifdef __OV5642_CAPTURE__
+				MX6QDL_PAD_SD1_DAT0__GPIO1_IO16 0x80000000
+				MX6QDL_PAD_GPIO_6__GPIO1_IO06 0x80000000
+				MX6QDL_PAD_GPIO_8__GPIO1_IO08 0x80000000
+				MX6QDL_PAD_GPIO_3__CCM_CLKO2 0x80000000
+#endif
 			>;
 		};
 
@@ -233,7 +250,9 @@
 				MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL	0x1b0b0
 				/* Phy reset */
 				MX6QDL_PAD_EIM_D23__GPIO3_IO23		0x000b0
+#ifndef __OV5642_CAPTURE__
 				MX6QDL_PAD_GPIO_6__ENET_IRQ		0x000b1
+#endif
 			>;
 		};
 
@@ -261,6 +280,13 @@
 			>;
 		};
 
+		pinctrl_i2c2: i2c2grp {
+			fsl,pins = <
+				MX6QDL_PAD_KEY_COL3__I2C2_SCL           0x4001b8b1
+				MX6QDL_PAD_KEY_ROW3__I2C2_SDA           0x4001b8b1
+			>;
+		};
+
 		pinctrl_pwm1: pwm1grp {
 			fsl,pins = <
 				MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1
@@ -421,3 +447,68 @@
 	vmmc-supply = <&reg_3p3v>;
 	status = "okay";
 };
+
+#ifdef __OV5642_CAPTURE__
+
+&i2c2 {
+	status = "okay";
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c2>;
+
+	camera: ov5642@3c {
+		compatible = "ovti,ov5642";
+		clocks = <&clks 200>;
+		clock-names = "xclk";
+		reg = <0x3c>;
+		xclk = <24000000>;
+		reset-gpios = <&gpio1 8 0>;
+		pwdn-gpios = <&gpio1 6 0>;
+		gp-gpios = <&gpio1 16 0>;
+
+		port {
+			/* With 1 endpoint per port no need for addresses. */
+			ov5642_1: endpoint {
+				remote-endpoint = <&csi0>;
+				bus-width = <12>;
+				hsync-active = <1>;
+				vsync-active = <1>;
+			};
+		};
+	};
+};
+
+&ipu1 {
+	status = "okay";
+
+	v4l2-capture {
+		compatible = "fsl,imx6-v4l2-capture";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "okay";
+		pinctrl-names = "default";
+		pinctrl-0 = <
+			&pinctrl_ipu1_csi0_1
+			&pinctrl_ipu1_csi0_data_en
+		>;
+
+		/* CSI0 */
+		port@0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			/* Parallel bus */
+			csi0: endpoint@0 {
+				reg = <0>;
+				remote-endpoint = <&ov5642_1>;
+				bus-width = <12>;
+				data-shift = <8>; /* Lines 19:8 used */
+				hsync-active = <1>;
+				vync-active = <1>;
+			};
+		};
+	};
+};
+
+#endif /* __OV5642_CAPTURE__ */
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 33/43] ARM: dts: imx6-sabresd: add video capture ports and endpoints
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (31 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 32/43] ARM: dts: imx: sabrelite: add video capture ports and endpoints Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 34/43] ARM: dts: imx6-sabreauto: " Steve Longerbeam
                   ` (11 subsequent siblings)
  44 siblings, 0 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Defines the host v4l2-capture device node and two camera sensors:
parallel-bus OV5642 and MIPI CSI-2 OV5640. The host capture device
is a child of ipu1. The MIPI CSI-2 receiver device is also defined.

The OV5642 is connected to the host parallel-bus endpoint on CSI0,
and the OV5640 is connected to the host MIPI CSI-2 endpoint on CSI1,
over virtual channel 0.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 arch/arm/boot/dts/imx6qdl-sabresd.dtsi |  116 ++++++++++++++++++++++++++++++++
 1 file changed, 116 insertions(+)

diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
index 0d816d3..2a932bb 100644
--- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
@@ -164,6 +164,30 @@
 			0x0000 /* 5:Default */
 		>;
        };
+
+	camera: ov5642@3c {
+		compatible = "ovti,ov5642";
+		clocks = <&clks 201>;
+		clock-names = "xclk";
+		reg = <0x3c>;
+		xclk = <24000000>;
+		DOVDD-supply = <&vgen4_reg>; /* 1.8v */
+		AVDD-supply = <&vgen5_reg>;  /* 2.8v, rev C board is VGEN3
+						rev B board is VGEN5 */
+		DVDD-supply = <&vgen2_reg>;  /* 1.5v*/
+		pwdn-gpios = <&gpio1 16 GPIO_ACTIVE_LOW>;   /* SD1_DAT0 */
+		reset-gpios = <&gpio1 17 GPIO_ACTIVE_HIGH>; /* SD1_DAT1 */
+
+		port {
+			/* With 1 endpoint per port no need for addresses. */
+			ov5642_1: endpoint {
+				remote-endpoint = <&csi0>;
+				bus-width = <12>;
+				hsync-active = <1>;
+				vsync-active = <1>;
+			};
+		};
+	};
 };
 
 &i2c2 {
@@ -270,6 +294,32 @@
 			};
 		};
 	};
+
+	mipi_camera: ov5640@3c {
+		compatible = "ovti,ov5640_mipi";
+		reg = <0x3c>;
+		clocks = <&clks 201>;
+		clock-names = "xclk";
+		xclk = <24000000>;
+		DOVDD-supply = <&vgen4_reg>; /* 1.8v */
+		AVDD-supply = <&vgen5_reg>;  /* 2.8v, rev C board is VGEN3
+						rev B board is VGEN5 */
+		DVDD-supply = <&vgen2_reg>;  /* 1.5v*/
+		pwdn-gpios = <&gpio1 19 GPIO_ACTIVE_HIGH>; /* SD1_DAT2 */
+		reset-gpios = <&gpio1 20 GPIO_ACTIVE_LOW>; /* SD1_CLK */
+
+		port {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			ov5640_1: endpoint@1 {
+				reg = <1>;
+				remote-endpoint = <&csi1_vc0>;
+				data-lanes = <0 1>;
+				clock-lanes = <2>;
+			};
+		};
+	};
 };
 
 &i2c3 {
@@ -303,6 +353,10 @@
 				MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000
 				MX6QDL_PAD_EIM_D22__GPIO3_IO22  0x80000000
 				MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x80000000
+				MX6QDL_PAD_SD1_DAT0__GPIO1_IO16 0x80000000
+				MX6QDL_PAD_SD1_DAT1__GPIO1_IO17 0x80000000
+				MX6QDL_PAD_SD1_DAT2__GPIO1_IO19 0x80000000
+				MX6QDL_PAD_SD1_CLK__GPIO1_IO20 0x80000000
 			>;
 		};
 
@@ -496,3 +550,65 @@
 	wp-gpios = <&gpio2 1 0>;
 	status = "okay";
 };
+
+&mipi_csi2 {
+	status = "okay";
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	/* Incoming port from sensor */
+	port {
+		mipi_csi2_0: endpoint {
+			remote-endpoint = <&ov5640_1>;
+			data-lanes = <0 1>;
+			clock-lanes = <2>;
+		};
+	};
+};
+
+&ipu1 { /* IPU1 */
+	status = "okay";
+
+	v4l2-capture {
+		compatible = "fsl,imx6-v4l2-capture";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "okay";
+		pinctrl-names = "default";
+		pinctrl-0 = <
+			&pinctrl_ipu1_csi0_2
+		>;
+
+		/* CSI0 */
+		port@0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			/* Parallel bus */
+			csi0: endpoint@0 {
+				reg = <0>;
+				remote-endpoint = <&ov5642_1>;
+				bus-width = <8>;
+				data-shift = <12>; /* Lines 19:12 used */
+				hsync-active = <1>;
+				vsync-active = <1>;
+			};
+		};
+
+		/* CSI1 */
+		port@1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			/* MIPI CSI-2 virtual channel 0 */
+			csi1_vc0: endpoint@0 {
+				reg = <0>;
+				remote-endpoint = <&ov5640_1>;
+				data-lanes = <0 1>;
+				clock-lanes = <2>;
+			};
+		};
+	};
+};
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 34/43] ARM: dts: imx6-sabreauto: add video capture ports and endpoints
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (32 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 33/43] ARM: dts: imx6-sabresd: " Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 35/43] ARM: dts: imx6qdl: Add simple-bus to ipu compatibility Steve Longerbeam
                   ` (10 subsequent siblings)
  44 siblings, 0 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Defines the host v4l2-capture device node and the ADV7180 decoder
sensor. The host capture device is a child of ipu1. The ADV7180 is
connected to the host parallel-bus endpoint on CSI0.

On the sabreauto, two analog video inputs are routed to the ADV7180,
composite on Ain1, and composite on Ain3. Those inputs are defined
via inputs and input-names under the host endpoint node on CSI0.

Regulators and port expanders are defined which are required for the
ADV7180 (power pin is via port expander gpio on i2c3). The reset pin
to the port expander chip (MAX7310) is controlled by a gpio, so define
the reset-gpios property to control it.

The sabreauto uses a steering pin to select between the SDA signal on
i2c3 bus, and a data-in pin for an SPI NOR chip. Use i2cmux to control
this steering pin. Idle state of the i2cmux selects SPI NOR. This is not
a classic way to use i2cmux, since one side of the mux selects something
other than an i2c bus, but it works and is probably the cleanest
solution. Note that if one thread is attempting to access SPI NOR while
another thread is accessing i2c3, the SPI NOR access will fail since the
i2cmux has selected the SDA pin rather than SPI NOR data-in. This couldn't
be avoided in any case, the board is not designed to allow concurrent
i2c3 and SPI NOR functions (and the default device-tree does not enable
SPI NOR anyway).

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 arch/arm/boot/dts/imx6qdl-sabreauto.dtsi |  149 ++++++++++++++++++++++++++++++
 1 file changed, 149 insertions(+)

diff --git a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
index 009abd6..27ac698 100644
--- a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
@@ -17,6 +17,39 @@
 		reg = <0x10000000 0x80000000>;
 	};
 
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		reg_2p5v: regulator@0 {
+			compatible = "regulator-fixed";
+			reg = <0>;
+			regulator-name = "2P5V";
+			regulator-min-microvolt = <2500000>;
+			regulator-max-microvolt = <2500000>;
+			regulator-always-on;
+		};
+
+		reg_3p3v: regulator@1 {
+			compatible = "regulator-fixed";
+			reg = <1>;
+			regulator-name = "3P3V";
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			regulator-always-on;
+		};
+
+		reg_2p8v: regulator@2 {
+			compatible = "regulator-fixed";
+			reg = <2>;
+			regulator-name = "2P8V";
+			regulator-min-microvolt = <2800000>;
+			regulator-max-microvolt = <2800000>;
+			regulator-always-on;
+		};
+	};
+
 	leds {
 		compatible = "gpio-leds";
 		pinctrl-names = "default";
@@ -43,6 +76,66 @@
 		default-brightness-level = <7>;
 		status = "okay";
 	};
+
+	i2cmux {
+		compatible = "i2c-mux-gpio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_i2c3mux>;
+		mux-gpios = <&gpio5 4 0>;
+		i2c-parent = <&i2c3>;
+		idle-state = <0>;
+
+		i2c@1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			camera: adv7180@21 {
+				compatible = "adi,adv7180";
+				reg = <0x21>;
+				DOVDD-supply = <&reg_3p3v>;
+				AVDD-supply = <&reg_3p3v>;
+				DVDD-supply = <&reg_3p3v>;
+				PVDD-supply = <&reg_3p3v>;
+				pwdn-gpio = <&port_exp_b 2 0>;
+				interrupt-parent = <&gpio1>;
+				interrupts = <27 0x8>;
+
+				port {
+					adv7180_1: endpoint {
+						remote-endpoint = <&csi0>;
+						bus-width = <16>;
+					};
+				};
+			};
+
+			port_exp_a: gpio_pca953x@30 {
+				compatible = "maxim,max7310";
+				gpio-controller;
+				#gpio-cells = <2>;
+				reg = <0x30>;
+				reset-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
+			};
+
+			port_exp_b: gpio_pca953x@32 {
+				compatible = "maxim,max7310";
+				gpio-controller;
+				#gpio-cells = <2>;
+				reg = <0x32>;
+				reset-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
+			};
+
+			port_exp_c: gpio_pca953x@34 {
+				compatible = "maxim,max7310";
+				gpio-controller;
+				#gpio-cells = <2>;
+				reg = <0x34>;
+				reset-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
+			};
+		};
+	};
 };
 
 &ecspi1 {
@@ -182,6 +275,13 @@
 	};
 };
 
+&i2c3 {
+	status = "okay";
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c3>;
+};
+
 &iomuxc {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_hog>;
@@ -192,6 +292,7 @@
 				MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x80000000
 				MX6QDL_PAD_SD2_DAT2__GPIO1_IO13  0x80000000
 				MX6QDL_PAD_GPIO_18__SD3_VSELECT 0x17059
+				MX6QDL_PAD_SD2_DAT0__GPIO1_IO15 0x80000000
 			>;
 		};
 
@@ -265,6 +366,19 @@
 			>;
 		};
 
+		pinctrl_i2c3: i2c3grp {
+			fsl,pins = <
+				MX6QDL_PAD_GPIO_3__I2C3_SCL	0x4001b8b1
+				MX6QDL_PAD_EIM_D18__I2C3_SDA	0x4001b8b1
+			>;
+		};
+
+		pinctrl_i2c3mux: i2c3muxgrp {
+			fsl,pins = <
+				MX6QDL_PAD_EIM_A24__GPIO5_IO04 0x80000000
+			>;
+		};
+
 		pinctrl_pwm3: pwm1grp {
 			fsl,pins = <
 				MX6QDL_PAD_SD4_DAT1__PWM3_OUT		0x1b0b1
@@ -456,3 +570,38 @@
 				0x0000c000 0x1404a38e 0x00000000>;
 	};
 };
+
+&ipu1 {
+	status = "okay";
+
+	v4l2-capture {
+		compatible = "fsl,imx6-v4l2-capture";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "okay";
+		pinctrl-names = "default";
+		pinctrl-0 = <
+			&pinctrl_ipu1_csi0_d4_d7
+			&pinctrl_ipu1_csi0_1
+		>;
+
+		/* CSI0 */
+		port@0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			/* Parallel bus */
+			csi0: endpoint@0 {
+				reg = <0>;
+				remote-endpoint = <&adv7180_1>;
+				bus-width = <16>;
+				data-shift = <4>; /* Lines 19:4 used */
+
+				inputs = <0x00 0x02>;
+				input-names = "ADV7180 Composite on Ain1",
+						"ADV7180 Composite on Ain3";
+			};
+		};
+	};
+};
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 35/43] ARM: dts: imx6qdl: Add simple-bus to ipu compatibility
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (33 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 34/43] ARM: dts: imx6-sabreauto: " Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-11 11:39   ` Philipp Zabel
  2014-06-07 21:56 ` [PATCH 36/43] gpio: pca953x: Add reset-gpios property Steve Longerbeam
                   ` (9 subsequent siblings)
  44 siblings, 1 reply; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

The IPU can have child devices now, so add "simple-bus" to
compatible list to ensure creation of the children.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 .../bindings/staging/imx-drm/fsl-imx-drm.txt       |    6 ++++--
 arch/arm/boot/dts/imx6q.dtsi                       |    2 +-
 arch/arm/boot/dts/imx6qdl.dtsi                     |    2 +-
 3 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
index 3be5ce7..dc759e4 100644
--- a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
+++ b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
@@ -21,7 +21,9 @@ Freescale i.MX IPUv3
 ====================
 
 Required properties:
-- compatible: Should be "fsl,<chip>-ipu"
+- compatible: Should be "fsl,<chip>-ipu". The IPU can also have child
+  devices, so also must include "simple-bus" to ensure creation of the
+  children.
 - reg: should be register base and length as documented in the
   datasheet
 - interrupts: Should contain sync interrupt and error interrupt,
@@ -39,7 +41,7 @@ example:
 ipu: ipu@18000000 {
 	#address-cells = <1>;
 	#size-cells = <0>;
-	compatible = "fsl,imx53-ipu";
+	compatible = "fsl,imx53-ipu", "simple-bus";
 	reg = <0x18000000 0x080000000>;
 	interrupts = <11 10>;
 	resets = <&src 2>;
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index c7544f0..50e2a32 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -149,7 +149,7 @@
 		ipu2: ipu@02800000 {
 			#address-cells = <1>;
 			#size-cells = <0>;
-			compatible = "fsl,imx6q-ipu";
+			compatible = "fsl,imx6q-ipu", "simple-bus";
 			reg = <0x02800000 0x400000>;
 			interrupts = <0 8 IRQ_TYPE_LEVEL_HIGH>,
 				     <0 7 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 00130a8..089a84a 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -1096,7 +1096,7 @@
 		ipu1: ipu@02400000 {
 			#address-cells = <1>;
 			#size-cells = <0>;
-			compatible = "fsl,imx6q-ipu";
+			compatible = "fsl,imx6q-ipu", "simple-bus";
 			reg = <0x02400000 0x400000>;
 			interrupts = <0 6 IRQ_TYPE_LEVEL_HIGH>,
 				     <0 5 IRQ_TYPE_LEVEL_HIGH>;
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 36/43] gpio: pca953x: Add reset-gpios property
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (34 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 35/43] ARM: dts: imx6qdl: Add simple-bus to ipu compatibility Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-11 11:39   ` Philipp Zabel
  2014-06-07 21:56 ` [PATCH 37/43] ARM: imx6q: clk: Add video 27m clock Steve Longerbeam
                   ` (8 subsequent siblings)
  44 siblings, 1 reply; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Add optional reset-gpios property. If present, de-assert the
specified reset gpio pin to bring the chip out of reset.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/gpio/gpio-pca953x.c |   26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index d550d8e..6e212f7 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -22,6 +22,7 @@
 #include <linux/slab.h>
 #ifdef CONFIG_OF_GPIO
 #include <linux/of_platform.h>
+#include <linux/of_gpio.h>
 #endif
 
 #define PCA953X_INPUT		0
@@ -98,6 +99,11 @@ struct pca953x_chip {
 	struct gpio_chip gpio_chip;
 	const char *const *names;
 	int	chip_type;
+
+#ifdef CONFIG_OF_GPIO
+	enum of_gpio_flags reset_gpio_flags;
+	int reset_gpio;
+#endif
 };
 
 static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val,
@@ -735,6 +741,26 @@ static int pca953x_probe(struct i2c_client *client,
 		/* If I2C node has no interrupts property, disable GPIO interrupts */
 		if (of_find_property(client->dev.of_node, "interrupts", NULL) == NULL)
 			irq_base = -1;
+
+		/* see if we need to de-assert a reset pin */
+		ret = of_get_named_gpio_flags(client->dev.of_node,
+					      "reset-gpios", 0,
+					      &chip->reset_gpio_flags);
+		if (gpio_is_valid(ret)) {
+			chip->reset_gpio = ret;
+			ret = devm_gpio_request_one(&client->dev,
+						    chip->reset_gpio,
+						    GPIOF_DIR_OUT,
+						    "pca953x_reset");
+			if (ret == 0) {
+				/* bring chip out of reset */
+				dev_info(&client->dev, "releasing reset\n");
+				gpio_set_value(chip->reset_gpio,
+					       (chip->reset_gpio_flags ==
+						OF_GPIO_ACTIVE_LOW) ? 1 : 0);
+			}
+		} else if (ret == -EPROBE_DEFER)
+			return ret;
 #endif
 	}
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 37/43] ARM: imx6q: clk: Add video 27m clock
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (35 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 36/43] gpio: pca953x: Add reset-gpios property Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 38/43] media: imx6: Add device tree binding documentation Steve Longerbeam
                   ` (7 subsequent siblings)
  44 siblings, 0 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam, Liu Ying

Adds a 27MHz clock that is a fixed /20 from the pll3_pfd1_540m clock.
The MIPI CSI2 receiver depends on this clock for its D-PHY operation.
Based on ENGR00275483-1 from Freescale.

Signed-off-by: Liu Ying <Ying.Liu@freescale.com>
Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 .../devicetree/bindings/clock/imx6q-clock.txt      |    1 +
 arch/arm/mach-imx/clk-imx6q.c                      |    3 ++-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/clock/imx6q-clock.txt b/Documentation/devicetree/bindings/clock/imx6q-clock.txt
index 6aab72b..32dc74f 100644
--- a/Documentation/devicetree/bindings/clock/imx6q-clock.txt
+++ b/Documentation/devicetree/bindings/clock/imx6q-clock.txt
@@ -220,6 +220,7 @@ clocks and IDs.
 	lvds2_sel		205
 	lvds1_gate		206
 	lvds2_gate		207
+	video_27m		208
 
 Examples:
 
diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c
index 2b4d6ac..ca87984 100644
--- a/arch/arm/mach-imx/clk-imx6q.c
+++ b/arch/arm/mach-imx/clk-imx6q.c
@@ -107,7 +107,7 @@ enum mx6q_clks {
 	sata_ref, sata_ref_100m, pcie_ref, pcie_ref_125m, enet_ref, usbphy1_gate,
 	usbphy2_gate, pll4_post_div, pll5_post_div, pll5_video_div, eim_slow,
 	spdif, cko2_sel, cko2_podf, cko2, cko, vdoa, pll4_audio_div,
-	lvds1_sel, lvds2_sel, lvds1_gate, lvds2_gate, clk_max
+	lvds1_sel, lvds2_sel, lvds1_gate, lvds2_gate, video_27m, clk_max
 };
 
 static struct clk *clk[clk_max];
@@ -226,6 +226,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
 	clk[pll3_80m]  = imx_clk_fixed_factor("pll3_80m",  "pll3_usb_otg",   1, 6);
 	clk[pll3_60m]  = imx_clk_fixed_factor("pll3_60m",  "pll3_usb_otg",   1, 8);
 	clk[twd]       = imx_clk_fixed_factor("twd",       "arm",            1, 2);
+	clk[video_27m] = imx_clk_fixed_factor("video_27m", "pll3_pfd1_540m", 1, 20);
 
 	clk[pll4_post_div] = clk_register_divider_table(NULL, "pll4_post_div", "pll4_audio", CLK_SET_RATE_PARENT, base + 0x70, 19, 2, 0, post_div_table, &imx_ccm_lock);
 	clk[pll4_audio_div] = clk_register_divider(NULL, "pll4_audio_div", "pll4_post_div", CLK_SET_RATE_PARENT, base + 0x170, 15, 1, 0, &imx_ccm_lock);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 38/43] media: imx6: Add device tree binding documentation
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (36 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 37/43] ARM: imx6q: clk: Add video 27m clock Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 39/43] media: Add new camera interface driver for i.MX6 Steve Longerbeam
                   ` (6 subsequent siblings)
  44 siblings, 0 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Add device tree binding documentation for i.MX6 media devices.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 Documentation/devicetree/bindings/media/imx6.txt |  433 ++++++++++++++++++++++
 1 file changed, 433 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/imx6.txt

diff --git a/Documentation/devicetree/bindings/media/imx6.txt b/Documentation/devicetree/bindings/media/imx6.txt
new file mode 100644
index 0000000..0a4d170
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/imx6.txt
@@ -0,0 +1,433 @@
+Freescale i.MX6 Video Capture
+
+v4l2-capture node
+-----------------
+
+This is the imx6 camera host interface node, and must be a child node
+of ipu1 and/or ipu2. The host node does not require reg or interrupt
+properties because it uses the facilities of its parent IPU. Only a
+compatible property is required.
+
+Required properties:
+- compatible	: "fsl,imx6-v4l2-capture";
+
+mipi_csi2 node
+--------------
+
+This is the device node for the MIPI CSI-2 Receiver, required for MIPI
+CSi-2 sensors.
+
+Required properties:
+- compatible	: "fsl,imx6-mipi-csi2";
+- reg           : physical base address and length of the register set;
+- clocks	: the MIPI CSI-2 receiver requires two clocks: hsi_tx
+                  (the DPHY clock, 138) and video_27m (208);
+- clock-names	: must contain "dphy_clk" followed by "cfg_clk";
+
+Optional properties:
+- interrupts	: must contain two level-triggered interrupts,
+                  in order: 100 and 101;
+
+
+Device tree nodes of the image sensors' controlled directly by the imx6
+camera host interface driver must be child nodes of their corresponding
+I2C bus controller node. The data link of these image sensors must be
+specified using the common video interfaces bindings, defined in
+video-interfaces.txt.
+
+The port nodes correspond to the IPU CSI to which sensor endpoints are
+connected, so the reg property specifies the CSI number (0 or 1).
+
+The reg property for endpoint nodes are ignored except for MIPI CSI-2
+endpoints, in which case the reg property specifies the virtual
+channel number the remote sensor is transmitting data over.
+
+Video capture is supported with the following imx6-based reference
+platforms:
+
+
+SabreLite with OV5642
+---------------------
+
+The OV5642 module is connected to CSI0 on IPU1 (the first IPU on imx6
+quad SabreLite). It's i2c bus connects to i2c bus 2, so the ov5642
+sensor node must be a child of i2c2.
+
+OV5642 Required properties:
+- compatible	: "ovti,ov5642";
+- clocks        : the OV5642 system clock (cko2, 200);
+- clock-names	: must be "xclk";
+- reg           : must be 0x3c;
+- xclk          : the system clock frequency, must be 24000000;
+- reset-gpios   : must be <&gpio1 8 0>;
+- pwdn-gpios    : must be <&gpio1 6 0>;
+
+OV5642 Endpoint Required properties:
+- remote-endpoint : must connect to camera interface endpoint on CSI0;
+- bus-width       : must be 12;
+- hsync-active    : must be 1;
+- vsync-active    : must be 1;
+
+The following is an example devicetree configuration for SabreLite:
+
+&i2c2 {
+	status = "okay";
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c2>;
+
+	camera: ov5642@3c {
+		compatible = "ovti,ov5642";
+		clocks = <&clks 200>;
+		clock-names = "xclk";
+		reg = <0x3c>;
+		xclk = <24000000>;
+		reset-gpios = <&gpio1 8 0>;
+		pwdn-gpios = <&gpio1 6 0>;
+		gp-gpios = <&gpio1 16 0>;
+
+		port {
+			ov5642_1: endpoint {
+				remote-endpoint = <&csi0>;
+				bus-width = <12>;
+				hsync-active = <1>;
+				vsync-active = <1>;
+			};
+		};
+	};
+};
+
+&ipu1 {
+	status = "okay";
+
+	v4l2-capture {
+		compatible = "fsl,imx6-v4l2-capture";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "okay";
+		pinctrl-names = "default";
+		pinctrl-0 = <
+			&pinctrl_ipu1_csi0_1
+			&pinctrl_ipu1_csi0_data_en
+		>;
+
+		/* CSI0 */
+		port@0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			/* Parallel bus */
+			csi0: endpoint@0 {
+				reg = <0>;
+				remote-endpoint = <&ov5642_1>;
+				bus-width = <12>;
+				data-shift = <8>; /* Lines 19:8 used */
+				hsync-active = <1>;
+				vync-active = <1>;
+			};
+		};
+	};
+};
+
+
+
+SabreAuto with ADV7180
+----------------------
+
+On the SabreAuto, an on-board ADV7180 SD decoder is connected via a
+parallel bus on IPU1 CSI0.
+
+Two analog video inputs are routed to the ADV7180 on the SabreAuto,
+composite on Ain1, and composite on Ain3. Those inputs are defined
+via inputs and input-names properties under the host endpoint node
+on CSI0.
+
+Regulators and port expanders are required for the ADV7180 (power pin
+is via port expander gpio on i2c3). The reset pin to the port expander
+chip (MAX7310) is controlled by a gpio, so a reset-gpios property must
+be defined under the port expander node to control it.
+
+The sabreauto uses a steering pin to select between the SDA signal on
+i2c3 bus, and a data-in pin for an SPI NOR chip. i2cmux can be used to
+control this steering pin. Idle state of the i2cmux selects SPI NOR.
+This is not classic way to use i2cmux, since one side of the mux selects
+something other than an i2c bus, but it works and is probably the cleanest
+solution. Note that if one thread is attempting to access SPI NOR while
+another thread is accessing i2c3, the SPI NOR access will fail since the
+i2cmux has selected the SDA pin rather than SPI NOR data-in. This couldn't
+be avoided in any case, the board is not designed to allow concurrent
+i2c3 and SPI NOR functions (and the default device-tree does not enable
+SPI NOR anyway).
+
+Host Interface Endpoint Required Properties:
+- inputs        : list of input mux values, must be 0x00 followed by
+                  0x02 on SabreAuto;
+- input-names   : names of the inputs;
+
+ADV7180 Required properties:
+- compatible    : "adi,adv7180";
+- reg           : must be 0x21;
+
+ADV7180 Optional properties:
+- DOVDD-supply  : DOVDD regulator supply;
+- AVDD-supply   : AVDD regulator supply;
+- DVDD-supply   : DVDD regulator supply;
+- PVDD-supply   : PVDD regulator supply;
+- pwdn-gpio     : gpio to control ADV7180 power pin, must be
+                  <&port_exp_b 2 0> on SabreAuto;
+- interrupts    : interrupt from ADV7180, must be <27 0x8> on SabreAuto;
+- interrupt-parent : must be <&gpio1> on SabreAuto;
+
+ADV7180 Endpoint Required properties:
+- remote-endpoint : must connect to camera interface endpoint on CSI0;
+- bus-width       : must be 16;
+
+
+The following is an example devicetree configuration for SabreAuto:
+
+/ {
+	i2cmux {
+		compatible = "i2c-mux-gpio";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_i2c3mux>;
+		mux-gpios = <&gpio5 4 0>;
+		i2c-parent = <&i2c3>;
+		idle-state = <0>;
+
+		i2c@1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			camera: adv7180@21 {
+				compatible = "adi,adv7180";
+				reg = <0x21>;
+				DOVDD-supply = <&reg_3p3v>;
+				AVDD-supply = <&reg_3p3v>;
+				DVDD-supply = <&reg_3p3v>;
+				PVDD-supply = <&reg_3p3v>;
+				pwdn-gpio = <&port_exp_b 2 0>;
+				interrupt-parent = <&gpio1>;
+				interrupts = <27 0x8>;
+
+				port {
+					adv7180_1: endpoint {
+						remote-endpoint = <&csi0>;
+						bus-width = <16>;
+					};
+				};
+			};
+
+			port_exp_b: gpio_pca953x@32 {
+				compatible = "maxim,max7310";
+				gpio-controller;
+				#gpio-cells = <2>;
+				reg = <0x32>;
+				reset-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
+			};
+
+		};
+	};
+};
+
+&ipu1 {
+	status = "okay";
+
+	v4l2-capture {
+		compatible = "fsl,imx6-v4l2-capture";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "okay";
+		pinctrl-names = "default";
+		pinctrl-0 = <
+			&pinctrl_ipu1_csi0_d4_d7
+			&pinctrl_ipu1_csi0_1
+		>;
+
+		/* CSI0 */
+		port@0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			/* Parallel bus */
+			csi0: endpoint@0 {
+				reg = <0>;
+				remote-endpoint = <&adv7180_1>;
+				bus-width = <16>;
+				data-shift = <4>; /* Lines 19:4 used */
+
+				inputs = <0x00 0x02>;
+				input-names = "ADV7180 Composite on Ain1",
+						"ADV7180 Composite on Ain3";
+			};
+		};
+	};
+};
+
+
+
+SabreSD with OV5642 and MIPI CSI-2 OV5640
+-----------------------------------------
+
+On the SabreSD, two camera sensors are supported: a parallel interface
+OV5642 on IPU1 CSI0, and a MIPI CSi-2 OV5640 on IPU1 CSI1. The OV5642
+connects to i2c bus 1 (i2c1) and the OV5640 to i2c bus 2 (i2c2).
+
+The mipi_csi2 receiver node must be enabled and connected via
+remote-endpoint to the OV5640 MIPI CSI-2 endpoint.
+
+OV5642 properties are as described above on SabreLite.
+
+OV5640 Required properties:
+- compatible	: "ovti,ov5640_mipi";
+- clocks        : the OV5640 system clock (cko, 201);
+- clock-names	: must be "xclk";
+- reg           : must be 0x3c;
+- xclk          : the system clock frequency, must be 24000000;
+- reset-gpios   : must be <&gpio1 20 1>;
+- pwdn-gpios    : must be <&gpio1 19 0>;
+
+OV5640 Optional properties:
+- DOVDD-supply  : DOVDD regulator supply;
+- AVDD-supply   : AVDD regulator supply;
+- DVDD-supply   : DVDD regulator supply;
+
+OV5640 MIPI CSI-2 Endpoint Required properties:
+- remote-endpoint : must connect to camera interface virtual channel 0
+                    endpoint on CSI1;
+- reg             : must be 1;
+- data-lanes      : must be <0 1>;
+- clock-lanes     : must be <2>;
+
+
+The following is an example devicetree configuration for SabreSD:
+
+&i2c1 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c1>;
+	status = "okay";
+
+	camera: ov5642@3c {
+		compatible = "ovti,ov5642";
+		clocks = <&clks 201>;
+		clock-names = "xclk";
+		reg = <0x3c>;
+		xclk = <24000000>;
+		DOVDD-supply = <&vgen4_reg>; /* 1.8v */
+		AVDD-supply = <&vgen5_reg>;  /* 2.8v, rev C board is VGEN3
+						rev B board is VGEN5 */
+		DVDD-supply = <&vgen2_reg>;  /* 1.5v*/
+		pwdn-gpios = <&gpio1 16 GPIO_ACTIVE_LOW>;   /* SD1_DAT0 */
+		reset-gpios = <&gpio1 17 GPIO_ACTIVE_HIGH>; /* SD1_DAT1 */
+
+		port {
+			ov5642_1: endpoint {
+				remote-endpoint = <&csi0>;
+				bus-width = <12>;
+				hsync-active = <1>;
+				vsync-active = <1>;
+			};
+		};
+	};
+};
+
+&i2c2 {
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c2>;
+	status = "okay";
+
+	mipi_camera: ov5640@3c {
+		compatible = "ovti,ov5640_mipi";
+		reg = <0x3c>;
+		clocks = <&clks 201>;
+		clock-names = "xclk";
+		xclk = <24000000>;
+		DOVDD-supply = <&vgen4_reg>; /* 1.8v */
+		AVDD-supply = <&vgen5_reg>;  /* 2.8v, rev C board is VGEN3
+						rev B board is VGEN5 */
+		DVDD-supply = <&vgen2_reg>;  /* 1.5v*/
+		pwdn-gpios = <&gpio1 19 GPIO_ACTIVE_HIGH>; /* SD1_DAT2 */
+		reset-gpios = <&gpio1 20 GPIO_ACTIVE_LOW>; /* SD1_CLK */
+
+		port {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			ov5640_1: endpoint@1 {
+				reg = <1>;
+				remote-endpoint = <&csi1_vc0>;
+				data-lanes = <0 1>;
+				clock-lanes = <2>;
+			};
+		};
+	};
+};
+
+&mipi_csi2 {
+	status = "okay";
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	port {
+		mipi_csi2_0: endpoint {
+			remote-endpoint = <&ov5640_1>;
+			data-lanes = <0 1>;
+			clock-lanes = <2>;
+		};
+	};
+};
+
+&ipu1 { /* IPU1 */
+	status = "okay";
+
+	v4l2-capture {
+		compatible = "fsl,imx6-v4l2-capture";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "okay";
+		pinctrl-names = "default";
+		pinctrl-0 = <
+			&pinctrl_ipu1_csi0_2
+		>;
+
+		/* CSI0 */
+		port@0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			/* Parallel bus */
+			csi0: endpoint@0 {
+				reg = <0>;
+				remote-endpoint = <&ov5642_1>;
+				bus-width = <8>;
+				data-shift = <12>; /* Lines 19:12 used */
+				hsync-active = <1>;
+				vsync-active = <1>;
+			};
+		};
+
+		/* CSI1 */
+		port@1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			/* MIPI CSI-2 virtual channel 0 */
+			csi1_vc0: endpoint@0 {
+				reg = <0>;
+				remote-endpoint = <&ov5640_1>;
+				data-lanes = <0 1>;
+				clock-lanes = <2>;
+			};
+		};
+	};
+};
+
+
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 39/43] media: Add new camera interface driver for i.MX6
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (37 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 38/43] media: imx6: Add device tree binding documentation Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-11 15:27   ` Philipp Zabel
  2014-06-07 21:56 ` [PATCH 40/43] media: imx6: Add support for MIPI CSI-2 OV5640 Steve Longerbeam
                   ` (5 subsequent siblings)
  44 siblings, 1 reply; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media
  Cc: Steve Longerbeam, Dmitry Eremin-Solenikov, Jiada Wang,
	Vladimir Zapolskiy

This is a V4L2 camera interface driver for i.MX6. See
Documentation/video4linux/mx6_camera.txt.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
Signed-off-by: Dmitry Eremin-Solenikov <dmitry_eremin@mentor.com>
Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
Signed-off-by: Vladimir Zapolskiy <vladimir_zapolskiy@mentor.com>
---
 Documentation/video4linux/mx6_camera.txt         |  188 ++
 drivers/staging/media/Kconfig                    |    2 +
 drivers/staging/media/Makefile                   |    1 +
 drivers/staging/media/imx6/Kconfig               |   25 +
 drivers/staging/media/imx6/Makefile              |    1 +
 drivers/staging/media/imx6/capture/Kconfig       |   11 +
 drivers/staging/media/imx6/capture/Makefile      |    4 +
 drivers/staging/media/imx6/capture/mipi-csi2.c   |  322 ++++
 drivers/staging/media/imx6/capture/mx6-camif.c   | 2235 ++++++++++++++++++++++
 drivers/staging/media/imx6/capture/mx6-camif.h   |  197 ++
 drivers/staging/media/imx6/capture/mx6-encode.c  |  775 ++++++++
 drivers/staging/media/imx6/capture/mx6-preview.c |  748 ++++++++
 include/media/imx6.h                             |   18 +
 13 files changed, 4527 insertions(+)
 create mode 100644 Documentation/video4linux/mx6_camera.txt
 create mode 100644 drivers/staging/media/imx6/Kconfig
 create mode 100644 drivers/staging/media/imx6/Makefile
 create mode 100644 drivers/staging/media/imx6/capture/Kconfig
 create mode 100644 drivers/staging/media/imx6/capture/Makefile
 create mode 100644 drivers/staging/media/imx6/capture/mipi-csi2.c
 create mode 100644 drivers/staging/media/imx6/capture/mx6-camif.c
 create mode 100644 drivers/staging/media/imx6/capture/mx6-camif.h
 create mode 100644 drivers/staging/media/imx6/capture/mx6-encode.c
 create mode 100644 drivers/staging/media/imx6/capture/mx6-preview.c
 create mode 100644 include/media/imx6.h

diff --git a/Documentation/video4linux/mx6_camera.txt b/Documentation/video4linux/mx6_camera.txt
new file mode 100644
index 0000000..d712f91
--- /dev/null
+++ b/Documentation/video4linux/mx6_camera.txt
@@ -0,0 +1,188 @@
+                         i.MX6 Video Capture Driver
+                         ==========================
+
+Introduction
+------------
+
+The Freescale i.MX6 contains an Image Processing Unit (IPU), which
+handles the flow of image frames to and from capture devices and
+display devices.
+
+For image capture, the IPU contains the following subunits:
+
+- Image DMA Controller (IDMAC)
+- Camera Serial Interface (CSI)
+- Image Converter (IC)
+- Sensor Multi-FIFO Controller (SMFC)
+- Image Rotator (IRT)
+- Video De-Interlace Controller (VDIC)
+
+The IDMAC is the DMA controller for transfer of image frames to and from
+memory. Various dedicated DMA channels exist for both video capture and
+display paths.
+
+The CSI is the frontend capture unit that interfaces directly with
+capture devices over Parallel, BT.656, and MIPI CSI-2 busses.
+
+The IC handles color-space conversion, resizing, and rotation
+operations.
+
+The SMFC is used to send image frames directly to memory, bypassing the
+IC. The SMFC is used when no color-space conversion or resizing is
+required, i.e. the requested V4L2 formats and color-space are identical
+to raw frames from the capture device.
+
+The IRT carries out 90 and 270 degree image rotation operations.
+
+Finally, the VDIC handles the conversion of interlaced video to
+progressive, with support for different motion compensation modes (low
+and high).
+
+For more info, refer to the latest versions of the i.MX6 reference
+manuals listed under References.
+
+
+Features
+--------
+
+Some of the features of this driver include:
+
+- Supports parallel, BT.565, and MIPI CSI-2 interfaces.
+
+- Camera Preview mode.
+
+- Multiple subdev sensors can be registered and controlled by a single
+  interface driver instance. Input enumeration will list every registered
+  sensor's inputs and input names, and setting an input will switch to
+  a different sensor if the input index is handled by a different sensor.
+
+- Simultaneous streaming from two separate sensors is possible with two
+  interface driver instances, each instance controlling a different
+  sensor. This is currently possible with the SabreSD reference board
+  with OV5642 and MIPI CSI-2 OV5640 sensors.
+
+- Separate rotation control for both streaming and preview. Streaming
+  rotation control is via main video device node, and preview rotation
+  control via subdevice node.
+
+- Scaling and color-space conversion for both streaming and preview.
+
+- Many pixel formats supported (RGB, packed and planar YUV, partial
+  planar YUV).
+
+- Full device-tree support using OF graph bindings.
+
+- Analog decoder input video source hot-swap support (during streaming)
+  via decoder status change subdev notification.
+
+- MMAP, USERPTR, and DMABUF importer/exporter buffers supported.
+
+- De-interlacing is supported via simple even/odd line interleaving
+  which is a facility of the IDMAC. The VDIC is not yet supported, but
+  plans are in the works to allow more advanced motion compensation.
+
+
+
+Usage Notes
+-----------
+
+The i.MX6 capture driver is a standardized driver that supports the
+following community V4L2 tools:
+
+- v4l2-ctl
+- v4l2-cap
+- v4l2src gstreamer plugin
+
+
+The following platforms have been tested:
+
+
+SabreLite with parallel-interface OV5642
+----------------------------------------
+
+This platform requires the OmniVision OV5642 module with a parallel
+camera interface from Boundary Devices for the SabreLite
+(http://boundarydevices.com/products/nit6x_5mp/).
+
+There is a pin conflict between OV5642 and ethernet devices on this
+platform, so by default video capture is disabled in the device tree. To
+enable video capture, edit arch/arm/boot/dts/imx6qdl-sabrelite.dtsi and
+uncomment the macro __OV5642_CAPTURE__.
+
+
+SabreAuto with ADV7180 decoder
+------------------------------
+
+This platform accepts Composite Video analog inputs on Ain1 (connector
+J42) and Ain3 (connector J43).
+
+To switch to Ain1:
+
+# v4l2-ctl -i0
+
+To switch to Ain3:
+
+# v4l2-ctl -i1
+
+
+SabreSD with MIPI CSI-2 OV5640
+------------------------------
+
+The default device tree for SabreSD includes endpoints for both the
+parallel OV5642 and the MIPI CSI-2 OV5640, but as of this writing only
+the MIPI CSI-2 OV5640 has been tested. The OV5640 module connects to
+MIPI connector J5 (sorry I don't have the compatible module part number
+or URL).
+
+Inputs are registered for both the OV5642 and OV5640, and by default the
+OV5642 is selected. To switch to the OV5640:
+
+# v4l2-ctl -i1
+
+
+Preview Notes
+-------------
+
+Preview accepts a framebuffer physaddr via standard VIDIOC_S_FBUF. The
+driver is agnostic about the source of this framebuffer, it could come
+from a DRM-based background or overlay plane, or from legacy fbdev.
+
+Preview is implemented as a sub-device, and exports controls to
+allow preview horizontal/vertical flip and rotation settings independent
+of the same settings for streaming. These controls are available on
+/dev/v4l-subdev0.
+
+
+Known Issues
+------------
+
+There is one currently known issue. When using 90 or 270 degree rotation
+control at capture resolutions near the IC resizer limit of 1024x1024,
+and combined with planar pixel formats (YUV420, YUV422p), frame capture
+will often fail with no end-of-frame interrupts from the IDMAC channel.
+To work around this, use lower resolution and/or packed formats (YUYV,
+RGB3, etc.) when 90 or 270 rotations are needed.
+
+
+File list
+---------
+
+drivers/staging/media/imx6/capture/
+include/media/imx6.h
+
+
+References
+----------
+
+[1] "i.MX 6Dual/6Quad Applications Processor Reference Manual"
+[2] "i.MX 6Solo/6DualLite Applications Processor Reference Manual"
+
+
+Authors
+-------
+Steve Longerbeam <steve_longerbeam@mentor.com>
+Dmitry Eremin-Solenikov <dmitry_eremin@mentor.com>
+Jiada Wang <jiada_wang@mentor.com>
+Vladimir Zapolskiy <vladimir_zapolskiy@mentor.com>
+
+Copyright (C) 2012-2014 Mentor Graphics Inc.
diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig
index a9f2e63..fd94c05 100644
--- a/drivers/staging/media/Kconfig
+++ b/drivers/staging/media/Kconfig
@@ -31,6 +31,8 @@ source "drivers/staging/media/dt3155v4l/Kconfig"
 
 source "drivers/staging/media/go7007/Kconfig"
 
+source "drivers/staging/media/imx6/Kconfig"
+
 source "drivers/staging/media/msi3101/Kconfig"
 
 source "drivers/staging/media/omap24xx/Kconfig"
diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile
index 8e2c5d2..6faee43 100644
--- a/drivers/staging/media/Makefile
+++ b/drivers/staging/media/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_LIRC_STAGING)	+= lirc/
 obj-$(CONFIG_SOLO6X10)		+= solo6x10/
 obj-$(CONFIG_VIDEO_DT3155)	+= dt3155v4l/
 obj-$(CONFIG_VIDEO_GO7007)	+= go7007/
+obj-$(CONFIG_VIDEO_IMX6)	+= imx6/
 obj-$(CONFIG_USB_MSI3101)	+= msi3101/
 obj-$(CONFIG_VIDEO_DM365_VPFE)	+= davinci_vpfe/
 obj-$(CONFIG_VIDEO_OMAP4)	+= omap4iss/
diff --git a/drivers/staging/media/imx6/Kconfig b/drivers/staging/media/imx6/Kconfig
new file mode 100644
index 0000000..6d94f3f
--- /dev/null
+++ b/drivers/staging/media/imx6/Kconfig
@@ -0,0 +1,25 @@
+config VIDEO_IMX6
+	tristate "i.MX6 V4L2 devices"
+	depends on VIDEO_V4L2 && ARCH_MXC && DRM_IMX_IPUV3_CORE
+	default y
+	---help---
+	  Say yes here to enable support for video4linux capture for
+	  the i.MX6 SOC.
+
+config VIDEO_IMX6_CAMERA
+	tristate "i.MX6 Camera Interface driver"
+	depends on VIDEO_IMX6 && VIDEO_DEV && I2C
+	select VIDEOBUF2_DMA_CONTIG
+	default y
+	---help---
+	  A video4linux capture driver for i.MX6 SOC. Some of the
+	  features of this driver include simultaneous streaming
+	  and preview (overlay) support, MIPI CSI-2 sensor support,
+	  separate rotation control for both streaming and preview,
+	  scaling and colorspace conversion, simultaneous capture
+	  from separate sensors, dmabuf importer/exporter, and full
+	  devicetree support.
+
+if VIDEO_IMX6_CAMERA
+source "drivers/staging/media/imx6/capture/Kconfig"
+endif
diff --git a/drivers/staging/media/imx6/Makefile b/drivers/staging/media/imx6/Makefile
new file mode 100644
index 0000000..e0ed058
--- /dev/null
+++ b/drivers/staging/media/imx6/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_VIDEO_IMX6_CAMERA) += capture/
diff --git a/drivers/staging/media/imx6/capture/Kconfig b/drivers/staging/media/imx6/capture/Kconfig
new file mode 100644
index 0000000..ee4f017
--- /dev/null
+++ b/drivers/staging/media/imx6/capture/Kconfig
@@ -0,0 +1,11 @@
+menu "i.MX6 Camera Sensors"
+
+config IMX6_MIPI_CSI2
+       tristate "MIPI CSI2 Receiver Driver"
+       depends on VIDEO_IMX6_CAMERA
+       default y
+       ---help---
+         MIPI CSI-2 Receiver driver support. This driver is required
+	 for sensor drivers with a MIPI CSI2 interface.
+
+endmenu
diff --git a/drivers/staging/media/imx6/capture/Makefile b/drivers/staging/media/imx6/capture/Makefile
new file mode 100644
index 0000000..832d75d
--- /dev/null
+++ b/drivers/staging/media/imx6/capture/Makefile
@@ -0,0 +1,4 @@
+mx6-camera-objs := mx6-camif.o mx6-encode.o mx6-preview.o
+
+obj-$(CONFIG_VIDEO_IMX6_CAMERA) += mx6-camera.o
+obj-$(CONFIG_IMX6_MIPI_CSI2) += mipi-csi2.o
diff --git a/drivers/staging/media/imx6/capture/mipi-csi2.c b/drivers/staging/media/imx6/capture/mipi-csi2.c
new file mode 100644
index 0000000..4e2aadd
--- /dev/null
+++ b/drivers/staging/media/imx6/capture/mipi-csi2.c
@@ -0,0 +1,322 @@
+/*
+ * MIPI CSI-2 Receiver Subdev for Freescale i.MX6 SOC.
+ *
+ * Copyright (c) 2012-2014 Mentor Graphics Inc.
+ * Copyright 2004-2012 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.
+ */
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/list.h>
+#include <linux/irq.h>
+#include <linux/of_device.h>
+#include <media/v4l2-of.h>
+#include <media/v4l2-subdev.h>
+#include <asm/mach/irq.h>
+#include <linux/platform_data/imx-ipu-v3.h>
+
+struct mx6csi2_dev {
+	struct device          *dev;
+	struct v4l2_subdev      sd;
+	struct clk             *dphy_clk;
+	struct clk             *cfg_clk;
+	void __iomem           *base;
+	int                     intr1;
+	int                     intr2;
+	struct v4l2_of_bus_mipi_csi2 bus;
+	spinlock_t              lock;
+	bool                    on;
+};
+
+#define DEVICE_NAME "imx6-mipi-csi2"
+
+/* Register offsets */
+#define CSI2_VERSION            0x000
+#define CSI2_N_LANES            0x004
+#define CSI2_PHY_SHUTDOWNZ      0x008
+#define CSI2_DPHY_RSTZ          0x00c
+#define CSI2_RESETN             0x010
+#define CSI2_PHY_STATE          0x014
+#define CSI2_DATA_IDS_1         0x018
+#define CSI2_DATA_IDS_2         0x01c
+#define CSI2_ERR1               0x020
+#define CSI2_ERR2               0x024
+#define CSI2_MSK1               0x028
+#define CSI2_MSK2               0x02c
+#define CSI2_PHY_TST_CTRL0      0x030
+#define CSI2_PHY_TST_CTRL1      0x034
+#define CSI2_SFT_RESET          0xf00
+
+static inline struct mx6csi2_dev *sd_to_dev(struct v4l2_subdev *sdev)
+{
+	return container_of(sdev, struct mx6csi2_dev, sd);
+}
+
+static inline u32 mx6csi2_read(struct mx6csi2_dev *csi2, unsigned regoff)
+{
+	return readl(csi2->base + regoff);
+}
+
+static inline void mx6csi2_write(struct mx6csi2_dev *csi2, u32 val,
+				 unsigned regoff)
+{
+	writel(val, csi2->base + regoff);
+}
+
+static void mx6csi2_set_lanes(struct mx6csi2_dev *csi2)
+{
+	int lanes = csi2->bus.num_data_lanes;
+	unsigned long flags;
+
+	spin_lock_irqsave(&csi2->lock, flags);
+
+	mx6csi2_write(csi2, lanes - 1, CSI2_N_LANES);
+
+	spin_unlock_irqrestore(&csi2->lock, flags);
+}
+
+static void __mx6csi2_enable(struct mx6csi2_dev *csi2, bool enable)
+{
+	if (enable) {
+		mx6csi2_write(csi2, 0xffffffff, CSI2_PHY_SHUTDOWNZ);
+		mx6csi2_write(csi2, 0xffffffff, CSI2_DPHY_RSTZ);
+		mx6csi2_write(csi2, 0xffffffff, CSI2_RESETN);
+	} else {
+		mx6csi2_write(csi2, 0x0, CSI2_PHY_SHUTDOWNZ);
+		mx6csi2_write(csi2, 0x0, CSI2_DPHY_RSTZ);
+		mx6csi2_write(csi2, 0x0, CSI2_RESETN);
+	}
+}
+
+static void mx6csi2_enable(struct mx6csi2_dev *csi2, bool enable)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&csi2->lock, flags);
+	__mx6csi2_enable(csi2, enable);
+	spin_unlock_irqrestore(&csi2->lock, flags);
+}
+
+static void mx6csi2_reset(struct mx6csi2_dev *csi2)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&csi2->lock, flags);
+
+	__mx6csi2_enable(csi2, false);
+
+	mx6csi2_write(csi2, 0x00000001, CSI2_PHY_TST_CTRL0);
+	mx6csi2_write(csi2, 0x00000000, CSI2_PHY_TST_CTRL1);
+	mx6csi2_write(csi2, 0x00000000, CSI2_PHY_TST_CTRL0);
+	mx6csi2_write(csi2, 0x00000002, CSI2_PHY_TST_CTRL0);
+	mx6csi2_write(csi2, 0x00010044, CSI2_PHY_TST_CTRL1);
+	mx6csi2_write(csi2, 0x00000000, CSI2_PHY_TST_CTRL0);
+	mx6csi2_write(csi2, 0x00000014, CSI2_PHY_TST_CTRL1);
+	mx6csi2_write(csi2, 0x00000002, CSI2_PHY_TST_CTRL0);
+	mx6csi2_write(csi2, 0x00000000, CSI2_PHY_TST_CTRL0);
+
+	__mx6csi2_enable(csi2, true);
+
+	spin_unlock_irqrestore(&csi2->lock, flags);
+}
+
+static int mx6csi2_dphy_wait(struct mx6csi2_dev *csi2)
+{
+	u32 reg;
+	int i;
+
+	/* wait for mipi sensor ready */
+	for (i = 0; i < 50; i++) {
+		reg = mx6csi2_read(csi2, CSI2_PHY_STATE);
+		if (reg != 0x200)
+			break;
+		usleep_range(10000, 10001);
+	}
+
+	if (i >= 50) {
+		v4l2_err(&csi2->sd,
+			"wait for clock lane timeout, phy_state = 0x%08x\n",
+			reg);
+		return -ETIME;
+	}
+
+	/* wait for mipi stable */
+	for (i = 0; i < 50; i++) {
+		reg = mx6csi2_read(csi2, CSI2_ERR1);
+		if (reg == 0x0)
+			break;
+		usleep_range(10000, 10001);
+	}
+
+	if (i >= 50) {
+		v4l2_err(&csi2->sd,
+			"wait for controller timeout, err1 = 0x%08x\n",
+			reg);
+		return -ETIME;
+	}
+
+	v4l2_info(&csi2->sd, "ready, dphy version 0x%x\n",
+		  mx6csi2_read(csi2, CSI2_VERSION));
+	return 0;
+}
+
+/*
+ * V4L2 subdev operations
+ */
+static int mx6csi2_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct mx6csi2_dev *csi2 = sd_to_dev(sd);
+	int ret = 0;
+
+	if (on && !csi2->on) {
+		v4l2_info(&csi2->sd, "power on\n");
+		clk_prepare_enable(csi2->cfg_clk);
+		clk_prepare_enable(csi2->dphy_clk);
+		mx6csi2_set_lanes(csi2);
+		mx6csi2_reset(csi2);
+		ret = mx6csi2_dphy_wait(csi2);
+	} else if (!on && csi2->on) {
+		v4l2_info(&csi2->sd, "power off\n");
+		mx6csi2_enable(csi2, false);
+		clk_disable_unprepare(csi2->dphy_clk);
+		clk_disable_unprepare(csi2->cfg_clk);
+	}
+
+	csi2->on = on;
+	return ret;
+}
+
+static struct v4l2_subdev_core_ops mx6csi2_core_ops = {
+	.s_power = mx6csi2_s_power,
+};
+
+static struct v4l2_subdev_ops mx6csi2_subdev_ops = {
+	.core = &mx6csi2_core_ops,
+};
+
+static int mx6csi2_parse_endpoints(struct mx6csi2_dev *csi2)
+{
+	struct device_node *node = csi2->dev->of_node;
+	struct device_node *epnode;
+	struct v4l2_of_endpoint ep;
+	int ret = 0;
+
+	epnode = of_graph_get_next_endpoint(node, NULL);
+	if (!epnode) {
+		v4l2_err(&csi2->sd, "failed to get endpoint node\n");
+		return -EINVAL;
+	}
+
+	v4l2_of_parse_endpoint(epnode, &ep);
+	if (ep.bus_type != V4L2_MBUS_CSI2) {
+		v4l2_err(&csi2->sd, "invalid bus type, must be MIPI CSI2\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	csi2->bus = ep.bus.mipi_csi2;
+
+	v4l2_info(&csi2->sd, "data lanes: %d\n", csi2->bus.num_data_lanes);
+	v4l2_info(&csi2->sd, "flags: 0x%08x\n", csi2->bus.flags);
+out:
+	of_node_put(epnode);
+	return ret;
+}
+
+static int mx6csi2_probe(struct platform_device *pdev)
+{
+	struct mx6csi2_dev *csi2;
+	struct resource *res;
+	int ret;
+
+	csi2 = devm_kzalloc(&pdev->dev, sizeof(*csi2), GFP_KERNEL);
+	if (!csi2)
+		return -ENOMEM;
+
+	csi2->dev = &pdev->dev;
+	spin_lock_init(&csi2->lock);
+
+	v4l2_subdev_init(&csi2->sd, &mx6csi2_subdev_ops);
+	csi2->sd.owner = THIS_MODULE;
+	strcpy(csi2->sd.name, DEVICE_NAME);
+
+	ret = mx6csi2_parse_endpoints(csi2);
+	if (ret)
+		return ret;
+
+	csi2->cfg_clk = devm_clk_get(&pdev->dev, "cfg_clk");
+	if (IS_ERR(csi2->cfg_clk)) {
+		v4l2_err(&csi2->sd, "failed to get cfg clock\n");
+		ret = PTR_ERR(csi2->cfg_clk);
+		return ret;
+	}
+
+	csi2->dphy_clk = devm_clk_get(&pdev->dev, "dphy_clk");
+	if (IS_ERR(csi2->dphy_clk)) {
+		v4l2_err(&csi2->sd, "failed to get dphy clock\n");
+		ret = PTR_ERR(csi2->dphy_clk);
+		return ret;
+	}
+
+	csi2->intr1 = platform_get_irq(pdev, 0);
+	csi2->intr2 = platform_get_irq(pdev, 1);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (!res || csi2->intr1 < 0 || csi2->intr2 < 0) {
+		v4l2_err(&csi2->sd, "failed to get platform resources\n");
+		return -ENODEV;
+	}
+
+	csi2->base = devm_ioremap(&pdev->dev, res->start, PAGE_SIZE);
+	if (!csi2->base) {
+		v4l2_err(&csi2->sd, "failed to map CSI-2 registers\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(pdev, &csi2->sd);
+
+	return 0;
+}
+
+static int mx6csi2_remove(struct platform_device *pdev)
+{
+	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+
+	return mx6csi2_s_power(sd, 0);
+}
+
+static const struct of_device_id mx6csi2_dt_ids[] = {
+	{ .compatible = "fsl,imx6-mipi-csi2", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mx6csi2_dt_ids);
+
+static struct platform_driver mx6csi2_driver = {
+	.driver = {
+		.name = DEVICE_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = mx6csi2_dt_ids,
+	},
+	.probe = mx6csi2_probe,
+	.remove = mx6csi2_remove,
+};
+
+module_platform_driver(mx6csi2_driver);
+
+MODULE_DESCRIPTION("i.MX6 MIPI CSI-2 Receiver driver");
+MODULE_AUTHOR("Mentor Graphics Inc.");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/staging/media/imx6/capture/mx6-camif.c b/drivers/staging/media/imx6/capture/mx6-camif.c
new file mode 100644
index 0000000..0c70aa9
--- /dev/null
+++ b/drivers/staging/media/imx6/capture/mx6-camif.c
@@ -0,0 +1,2235 @@
+/*
+ * Video Camera Capture driver for Freescale i.MX6 SOC
+ *
+ * Copyright (c) 2012-2014 Mentor Graphics Inc.
+ * Copyright 2004-2012 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.
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/of_platform.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-of.h>
+#include <media/v4l2-ctrls.h>
+#include <linux/platform_data/imx-ipu-v3.h>
+#include <media/imx6.h>
+#include "mx6-camif.h"
+
+/*
+ * Min/Max supported width and heights.
+ */
+#define MIN_W       176
+#define MIN_H       144
+#define MAX_W      4096
+#define MAX_H      4096
+#define MAX_W_IC   1024
+#define MAX_H_IC   1024
+
+#define H_ALIGN    1 /* multiple of 2 */
+#define S_ALIGN    1 /* multiple of 2 */
+
+#define DEVICE_NAME "mx6-camera"
+
+/* In bytes, per queue */
+#define VID_MEM_LIMIT	SZ_64M
+
+static struct vb2_ops mx6cam_qops;
+
+/*
+ * The Gstreamer v4l2src plugin appears to have a bug, it doesn't handle
+ * frame sizes of type V4L2_FRMSIZE_TYPE_STEPWISE correctly. Set this
+ * module param to get around this bug. We can remove once v4l2src handles
+ * stepwise frame sizes correctly.
+ */
+static int v4l2src_compat = 1;
+module_param(v4l2src_compat, int, 0644);
+MODULE_PARM_DESC(v4l2src_compat,
+		 "Gstreamer v4l2src plugin compatibility (default: 1)");
+
+static inline struct mx6cam_dev *sd2dev(struct v4l2_subdev *sd)
+{
+	return container_of(sd->v4l2_dev, struct mx6cam_dev, v4l2_dev);
+}
+
+static inline struct mx6cam_ctx *file2ctx(struct file *file)
+{
+	return container_of(file->private_data, struct mx6cam_ctx, fh);
+}
+
+/* Supported pixel formats */
+static struct mx6cam_pixfmt mx6cam_pixformats[] = {
+	{
+		.name	= "RGB565",
+		.fourcc	= V4L2_PIX_FMT_RGB565,
+		.depth  = 16,
+	}, {
+		.name	= "RGB24",
+		.fourcc	= V4L2_PIX_FMT_RGB24,
+		.depth  = 24,
+	}, {
+		.name	= "BGR24",
+		.fourcc	= V4L2_PIX_FMT_BGR24,
+		.depth  = 24,
+	}, {
+		.name	= "RGB32",
+		.fourcc	= V4L2_PIX_FMT_RGB32,
+		.depth  = 32,
+	}, {
+		.name	= "BGR32",
+		.fourcc	= V4L2_PIX_FMT_BGR32,
+		.depth  = 32,
+	}, {
+		.name	= "4:2:2 packed, YUYV",
+		.fourcc	= V4L2_PIX_FMT_YUYV,
+		.depth  = 16,
+	}, {
+		.name	= "4:2:2 packed, UYVY",
+		.fourcc	= V4L2_PIX_FMT_UYVY,
+		.depth  = 16,
+	}, {
+		.name	= "4:2:0 planar, YUV",
+		.fourcc	= V4L2_PIX_FMT_YUV420,
+		.depth  = 12,
+		.y_depth = 8,
+	}, {
+		.name   = "4:2:0 planar, YVU",
+		.fourcc = V4L2_PIX_FMT_YVU420,
+		.depth  = 12,
+		.y_depth = 8,
+	}, {
+		.name   = "4:2:2 planar, YUV",
+		.fourcc = V4L2_PIX_FMT_YUV422P,
+		.depth  = 16,
+		.y_depth = 8,
+	}, {
+		.name   = "4:2:0 planar, Y/CbCr",
+		.fourcc = V4L2_PIX_FMT_NV12,
+		.depth  = 12,
+		.y_depth = 8,
+	},
+};
+#define NUM_FORMATS ARRAY_SIZE(mx6cam_pixformats)
+
+static struct mx6cam_pixfmt *mx6cam_get_format(u32 fourcc)
+{
+	struct mx6cam_pixfmt *ret = NULL;
+	int i;
+
+	for (i = 0; i < NUM_FORMATS; i++) {
+		if (mx6cam_pixformats[i].fourcc == fourcc) {
+			ret = &mx6cam_pixformats[i];
+			break;
+		}
+	}
+
+	return ret;
+}
+
+/* Support functions */
+
+static const char *mx6cam_v4l2_std_to_string(v4l2_std_id std)
+{
+	switch (std) {
+	case V4L2_STD_PAL:
+		return "PAL";
+	case V4L2_STD_PAL_N:
+		return "PAL N";
+	case V4L2_STD_NTSC:
+		return "NTSC";
+	case V4L2_STD_NTSC_443:
+		return "NTSC 4.43";
+	case V4L2_STD_PAL_M:
+		return "PAL M";
+	case V4L2_STD_PAL_60:
+		return "PAL 60";
+	case V4L2_STD_UNKNOWN:
+		return "UNKNOWN";
+	case V4L2_STD_ALL:
+		return "ALL";
+	default:
+		return "Unsupported";
+	}
+}
+
+/* find the endpoint that is handling this input index */
+static struct mx6cam_endpoint *find_ep_by_input_index(struct mx6cam_dev *dev,
+						      int input_idx)
+{
+	struct mx6cam_endpoint *ep;
+	int i;
+
+	for (i = 0; i < dev->num_eps; i++) {
+		ep = &dev->eplist[i];
+		if (!ep->sd)
+			continue;
+
+		if (input_idx >= ep->sensor_input.first &&
+		    input_idx <= ep->sensor_input.last)
+			break;
+	}
+
+	return (i < dev->num_eps) ? ep : NULL;
+}
+
+/*
+ * Query sensor and update signal lock status. Returns true if lock
+ * status has changed.
+ */
+static bool update_signal_lock_status(struct mx6cam_dev *dev)
+{
+	bool locked, changed;
+	u32 status;
+	int ret;
+
+	ret = v4l2_subdev_call(dev->ep->sd, video, g_input_status, &status);
+	if (ret)
+		return false;
+
+	locked = ((status & V4L2_IN_ST_NO_SYNC) == 0);
+	changed = (dev->signal_locked != locked);
+	dev->signal_locked = locked;
+
+	return changed;
+}
+
+/*
+ * Return true if the current capture parameters require the use of
+ * the Image Converter. We need the IC for scaling, colorspace conversion,
+ * preview, and rotation.
+ */
+static bool need_ic(struct mx6cam_dev *dev,
+		    struct v4l2_mbus_framefmt *sf,
+		    struct v4l2_format *uf,
+		    struct v4l2_rect *crop)
+{
+	struct v4l2_pix_format *user_fmt = &uf->fmt.pix;
+	enum ipu_color_space sensor_cs, user_cs;
+	bool ret;
+
+	sensor_cs = ipu_mbus_code_to_colorspace(sf->code);
+	user_cs = ipu_pixelformat_to_colorspace(user_fmt->pixelformat);
+
+	ret = (user_fmt->width != crop->width ||
+	       user_fmt->height != crop->height ||
+	       user_cs != sensor_cs ||
+	       dev->preview_on ||
+	       dev->rot_mode != IPU_ROTATE_NONE);
+
+	return ret;
+}
+
+/*
+ * Return true if user and sensor formats currently meet the IC
+ * restrictions:
+ *     o the parallel CSI bus cannot be 16-bit wide.
+ *     o the endpoint id must be 0 (for MIPI CSI2, the endpoint id is the
+ *       virtual channel number, and only VC0 can pass through the IC).
+ *     o the resizer output size must be at or below 1024x1024.
+ */
+static bool can_use_ic(struct mx6cam_dev *dev,
+		       struct v4l2_mbus_framefmt *sf,
+		       struct v4l2_format *uf)
+{
+	struct mx6cam_endpoint *ep = dev->ep;
+	struct ipu_csi_signal_cfg csicfg;
+
+	ipu_csi_mbus_fmt_to_sig_cfg(&csicfg, sf->code);
+
+	return ((ep->ep.bus_type == V4L2_MBUS_CSI2 ||
+		 csicfg.data_width != IPU_CSI_DATA_WIDTH_16) &&
+		ep->ep.base.id == 0 &&
+		uf->fmt.pix.width <= MAX_W_IC &&
+		uf->fmt.pix.height <= MAX_H_IC);
+}
+
+/*
+ * Adjusts passed width and height to meet IC resizer limits.
+ */
+static void adjust_to_resizer_limits(struct mx6cam_dev *dev,
+				     struct v4l2_format *uf,
+				     struct v4l2_rect *crop)
+{
+	u32 *width, *height;
+
+	if (uf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		width = &uf->fmt.pix.width;
+		height = &uf->fmt.pix.height;
+	} else {
+		width = &uf->fmt.win.w.width;
+		height = &uf->fmt.win.w.height;
+	}
+
+	/* output of resizer can't be above 1024x1024 */
+	*width = min_t(__u32, *width, MAX_W_IC);
+	*height = min_t(__u32, *height, MAX_H_IC);
+
+	/* resizer cannot downsize more than 8:1 */
+	if (dev->rot_mode >= IPU_ROTATE_90_RIGHT) {
+		*height = max_t(__u32, *height, crop->width / 8);
+		*width = max_t(__u32, *width, crop->height / 8);
+	} else {
+		*width = max_t(__u32, *width, crop->width / 8);
+		*height = max_t(__u32, *height, crop->height / 8);
+	}
+}
+
+static void adjust_user_fmt(struct mx6cam_dev *dev,
+			    struct v4l2_mbus_framefmt *sf,
+			    struct v4l2_format *uf,
+			    struct v4l2_rect *crop)
+{
+	/*
+	 * Make sure resolution is within IC resizer limits
+	 * if we need the Image Converter.
+	 */
+	if (need_ic(dev, sf, uf, crop))
+		adjust_to_resizer_limits(dev, uf, crop);
+
+	/*
+	 * Force the resolution to match crop window if
+	 * we can't use the Image Converter.
+	 */
+	if (!can_use_ic(dev, sf, uf)) {
+		uf->fmt.pix.width = crop->width;
+		uf->fmt.pix.height = crop->height;
+	}
+
+	uf->fmt.pix.bytesperline =
+		(uf->fmt.pix.width *
+		 ipu_bits_per_pixel(uf->fmt.pix.pixelformat)) >> 3;
+	uf->fmt.pix.sizeimage = uf->fmt.pix.height * uf->fmt.pix.bytesperline;
+}
+
+/*
+ * Calculate what the default active crop window should be. Ask
+ * the sensor via g_crop. This crop window will be stored to dev->crop.
+ */
+static void calc_default_crop(struct mx6cam_dev *dev,
+			      struct v4l2_rect *rect,
+			      struct v4l2_mbus_framefmt *sf)
+{
+	struct v4l2_crop crop;
+	int ret;
+
+	crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	ret = v4l2_subdev_call(dev->ep->sd, video, g_crop, &crop);
+	if (ret) {
+		/* sensor doesn't support .g_crop(), assume sensor frame */
+		rect->top = rect->left = 0;
+		rect->width = sf->width;
+		rect->height = sf->height;
+	} else
+		*rect = crop.c;
+
+	/* adjust crop window to h/w alignment restrictions */
+	rect->width &= ~0x7;
+	rect->left &= ~0x3;
+}
+
+/*
+ * Use the parsed endpoint info and sensor format to fill
+ * ipu_csi_signal_cfg.
+ */
+static void fill_csi_signal_cfg(struct mx6cam_dev *dev)
+{
+	struct ipu_csi_signal_cfg *csicfg = &dev->ep->csi_sig_cfg;
+	struct v4l2_of_endpoint *ep = &dev->ep->ep;
+
+	memset(csicfg, 0, sizeof(*csicfg));
+
+	ipu_csi_mbus_fmt_to_sig_cfg(csicfg, dev->sensor_fmt.code);
+
+	switch (ep->bus_type) {
+	case V4L2_MBUS_PARALLEL:
+		csicfg->ext_vsync = 0;
+		csicfg->vsync_pol = (ep->bus.parallel.flags &
+				     V4L2_MBUS_VSYNC_ACTIVE_LOW) ? 1 : 0;
+		csicfg->hsync_pol = (ep->bus.parallel.flags &
+				     V4L2_MBUS_HSYNC_ACTIVE_LOW) ? 1 : 0;
+		csicfg->pixclk_pol = (ep->bus.parallel.flags &
+				      V4L2_MBUS_PCLK_SAMPLE_FALLING) ? 1 : 0;
+		csicfg->clk_mode = IPU_CSI_CLK_MODE_GATED_CLK;
+		break;
+	case V4L2_MBUS_BT656:
+		csicfg->ext_vsync = 1;
+		if (dev->sensor_fmt.field == V4L2_FIELD_INTERLACED)
+			csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED;
+		else
+			csicfg->clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE;
+		break;
+	case V4L2_MBUS_CSI2:
+		/*
+		 * MIPI CSI-2 requires non gated clock mode, all other
+		 * parameters are not applicable for MIPI CSI-2 bus.
+		 */
+		csicfg->clk_mode = IPU_CSI_CLK_MODE_NONGATED_CLK;
+		break;
+	default:
+		/* will never get here, keep compiler quiet */
+		break;
+	}
+}
+
+static int update_sensor_std(struct mx6cam_dev *dev)
+{
+	return v4l2_subdev_call(dev->ep->sd, video, querystd,
+				&dev->current_std);
+}
+
+static int update_sensor_fmt(struct mx6cam_dev *dev)
+{
+	int ret;
+
+	ret = v4l2_subdev_call(dev->ep->sd, video, g_mbus_fmt,
+			       &dev->sensor_fmt);
+	if (ret)
+		return ret;
+
+	fill_csi_signal_cfg(dev);
+
+	/* update sensor crop bounds */
+	dev->crop_bounds.top = dev->crop_bounds.left = 0;
+	dev->crop_bounds.width = dev->sensor_fmt.width;
+	dev->crop_bounds.height = dev->sensor_fmt.height;
+	dev->crop_defrect = dev->crop_bounds;
+
+	return 0;
+}
+
+/*
+ * Turn current sensor power on/off according to power_count.
+ */
+static int sensor_set_power(struct mx6cam_dev *dev, int on)
+{
+	struct mx6cam_endpoint *ep = dev->ep;
+	struct v4l2_subdev *sd = ep->sd;
+	int ret;
+
+	if (on && ep->power_count++ > 0)
+		return 0;
+	else if (!on && (ep->power_count == 0 || --ep->power_count > 0))
+		return 0;
+
+	ret = v4l2_subdev_call(sd, core, s_power, on);
+	return ret != -ENOIOCTLCMD ? ret : 0;
+}
+
+/*
+ * Turn current sensor streaming on/off according to stream_count.
+ */
+static int sensor_set_stream(struct mx6cam_dev *dev, int on)
+{
+	struct mx6cam_endpoint *ep = dev->ep;
+	struct v4l2_subdev *sd = ep->sd;
+	int ret;
+
+	if (on && ep->stream_count++ > 0)
+		return 0;
+	else if (!on && (ep->stream_count == 0 || --ep->stream_count > 0))
+		return 0;
+
+	ret = v4l2_subdev_call(sd, video, s_stream, on);
+	return ret != -ENOIOCTLCMD ? ret : 0;
+}
+
+/*
+ * Start the encoder for buffer streaming. There must be at least two
+ * frames in the vb2 queue.
+ */
+static int start_encoder(struct mx6cam_dev *dev)
+{
+	int ret;
+
+	if (dev->encoder_on)
+		return 0;
+
+	/* sensor stream on */
+	ret = sensor_set_stream(dev, 1);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "sensor stream on failed\n");
+		return ret;
+	}
+
+	/* encoder stream on */
+	ret = v4l2_subdev_call(dev->encoder_sd, video, s_stream, 1);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "encoder stream on failed\n");
+		return ret;
+	}
+
+	dev->encoder_on = true;
+	return 0;
+}
+
+/*
+ * Stop the encoder.
+ */
+static int stop_encoder(struct mx6cam_dev *dev)
+{
+	int ret;
+
+	if (!dev->encoder_on)
+		return 0;
+
+	/* encoder off */
+	ret = v4l2_subdev_call(dev->encoder_sd, video, s_stream, 0);
+	if (ret)
+		v4l2_err(&dev->v4l2_dev, "encoder stream off failed\n");
+
+	/* sensor stream off */
+	ret = sensor_set_stream(dev, 0);
+	if (ret)
+		v4l2_err(&dev->v4l2_dev, "sensor stream off failed\n");
+
+	dev->encoder_on = false;
+	return ret;
+}
+
+/*
+ * Start preview.
+ */
+static int start_preview(struct mx6cam_dev *dev)
+{
+	int ret;
+
+	if (atomic_read(&dev->status_change)) {
+		update_signal_lock_status(dev);
+		update_sensor_std(dev);
+		update_sensor_fmt(dev);
+		/* reset active crop window */
+		calc_default_crop(dev, &dev->crop, &dev->sensor_fmt);
+		atomic_set(&dev->status_change, 0);
+		v4l2_info(&dev->v4l2_dev, "at preview on: %s, %s\n",
+			  mx6cam_v4l2_std_to_string(dev->current_std),
+			  dev->signal_locked ? "signal locked" : "no signal");
+	}
+
+	/* sensor stream on */
+	ret = sensor_set_stream(dev, 1);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "sensor stream on failed\n");
+		return ret;
+	}
+
+	/* preview stream on */
+	ret = v4l2_subdev_call(dev->preview_sd, video, s_stream, 1);
+	if (ret)
+		v4l2_err(&dev->v4l2_dev, "preview stream on failed\n");
+
+	return ret;
+}
+
+/*
+ * Stop preview.
+ */
+static int stop_preview(struct mx6cam_dev *dev)
+{
+	int ret;
+
+	/* preview stream off */
+	ret = v4l2_subdev_call(dev->preview_sd, video, s_stream, 0);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "preview stream off failed\n");
+		return ret;
+	}
+
+	/* sensor stream off */
+	ret = sensor_set_stream(dev, 0);
+	if (ret)
+		v4l2_err(&dev->v4l2_dev, "sensor stream off failed\n");
+
+	return ret;
+}
+
+/*
+ * Start/Stop streaming.
+ */
+static int set_stream(struct mx6cam_ctx *ctx, bool on)
+{
+	struct mx6cam_dev *dev = ctx->dev;
+	int ret = 0;
+
+	if (on) {
+		if (atomic_read(&dev->status_change)) {
+			update_signal_lock_status(dev);
+			update_sensor_std(dev);
+			update_sensor_fmt(dev);
+			/* reset active crop window */
+			calc_default_crop(dev, &dev->crop, &dev->sensor_fmt);
+			atomic_set(&dev->status_change, 0);
+			v4l2_info(&dev->v4l2_dev, "at stream on: %s, %s\n",
+				  mx6cam_v4l2_std_to_string(dev->current_std),
+				  dev->signal_locked ?
+				  "signal locked" : "no signal");
+		}
+
+		dev->using_ic =
+			(need_ic(dev, &dev->sensor_fmt, &dev->user_fmt,
+				 &dev->crop) &&
+			 can_use_ic(dev, &dev->sensor_fmt, &dev->user_fmt));
+
+		if (dev->preview_on)
+			stop_preview(dev);
+
+		/*
+		 * If there are two or more frames in the queue, we can start
+		 * the encoder now. Otherwise the encoding will start once
+		 * two frames have been queued.
+		 */
+		if (!list_empty(&ctx->ready_q) &&
+		    !list_is_singular(&ctx->ready_q))
+			ret = start_encoder(dev);
+
+		if (dev->preview_on)
+			start_preview(dev);
+	} else {
+		ret = stop_encoder(dev);
+	}
+
+	return ret;
+}
+
+/*
+ * Restart work handler. This is called in three cases during active
+ * streaming and/or preview:
+ *
+ * o NFB4EOF errors
+ * o A decoder's signal lock status or autodetected video standard changes
+ * o End-of-Frame timeouts
+ */
+static void restart_work_handler(struct work_struct *w)
+{
+	struct mx6cam_ctx *ctx = container_of(w, struct mx6cam_ctx,
+					      restart_work);
+	struct mx6cam_dev *dev = ctx->dev;
+
+	mutex_lock(&dev->mutex);
+
+	if (!vb2_is_streaming(&dev->buffer_queue)) {
+		/* just restart preview if on */
+		if (dev->preview_on) {
+			v4l2_warn(&dev->v4l2_dev, "restarting preview\n");
+			stop_preview(dev);
+			start_preview(dev);
+		}
+		goto out_unlock;
+	}
+
+	v4l2_warn(&dev->v4l2_dev, "restarting\n");
+
+	set_stream(ctx, false);
+	set_stream(ctx, true);
+
+out_unlock:
+	mutex_unlock(&dev->mutex);
+}
+
+/*
+ * Stop work handler. Not currently needed but keep around.
+ */
+static void stop_work_handler(struct work_struct *w)
+{
+	struct mx6cam_ctx *ctx = container_of(w, struct mx6cam_ctx,
+					      stop_work);
+	struct mx6cam_dev *dev = ctx->dev;
+
+	mutex_lock(&dev->mutex);
+
+	if (dev->preview_on) {
+		v4l2_err(&dev->v4l2_dev, "stopping preview\n");
+		stop_preview(dev);
+		dev->preview_on = false;
+	}
+
+	if (vb2_is_streaming(&dev->buffer_queue)) {
+		v4l2_err(&dev->v4l2_dev, "stopping\n");
+		vb2_streamoff(&dev->buffer_queue, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+	}
+
+	mutex_unlock(&dev->mutex);
+}
+
+/*
+ * Restart timer function. Schedules a restart.
+ */
+static void mx6cam_restart_timeout(unsigned long data)
+{
+	struct mx6cam_ctx *ctx = (struct mx6cam_ctx *)data;
+
+	schedule_work(&ctx->restart_work);
+}
+
+/* Controls */
+static int mx6cam_set_rotation(struct mx6cam_dev *dev,
+			       int rotation, bool hflip, bool vflip)
+{
+	enum ipu_rotate_mode rot_mode;
+	int ret;
+
+	ret = ipu_degrees_to_rot_mode(&rot_mode, rotation,
+				      hflip, vflip);
+	if (ret)
+		return ret;
+
+	if (rot_mode != dev->rot_mode) {
+		/* can't change rotation mid-streaming */
+		if (vb2_is_streaming(&dev->buffer_queue)) {
+			v4l2_err(&dev->v4l2_dev,
+				 "%s: not allowed while streaming\n",
+				 __func__);
+			return -EBUSY;
+		}
+
+		if (rot_mode != IPU_ROTATE_NONE &&
+		    !can_use_ic(dev, &dev->sensor_fmt, &dev->user_fmt)) {
+			v4l2_err(&dev->v4l2_dev,
+				"%s: current format does not allow rotation\n",
+				 __func__);
+			return -EINVAL;
+		}
+	}
+
+	dev->rot_mode = rot_mode;
+	dev->rotation = rotation;
+	dev->hflip = hflip;
+	dev->vflip = vflip;
+
+	return 0;
+}
+
+static int mx6cam_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct mx6cam_dev *dev = container_of(ctrl->handler,
+					      struct mx6cam_dev, ctrl_hdlr);
+	bool hflip, vflip;
+	int rotation;
+
+	rotation = dev->rotation;
+	hflip = dev->hflip;
+	vflip = dev->vflip;
+
+	switch (ctrl->id) {
+	case V4L2_CID_HFLIP:
+		hflip = (ctrl->val == 1);
+		break;
+	case V4L2_CID_VFLIP:
+		vflip = (ctrl->val == 1);
+		break;
+	case V4L2_CID_ROTATE:
+		rotation = ctrl->val;
+		break;
+	default:
+		v4l2_err(&dev->v4l2_dev, "Invalid control\n");
+		return -EINVAL;
+	}
+
+	return mx6cam_set_rotation(dev, rotation, hflip, vflip);
+}
+
+static const struct v4l2_ctrl_ops mx6cam_ctrl_ops = {
+	.s_ctrl = mx6cam_s_ctrl,
+};
+
+static int mx6cam_init_controls(struct mx6cam_dev *dev)
+{
+	struct v4l2_ctrl_handler *hdlr = &dev->ctrl_hdlr;
+	int ret;
+
+	v4l2_ctrl_handler_init(hdlr, 3);
+
+	v4l2_ctrl_new_std(hdlr, &mx6cam_ctrl_ops, V4L2_CID_HFLIP,
+			  0, 1, 1, 0);
+	v4l2_ctrl_new_std(hdlr, &mx6cam_ctrl_ops, V4L2_CID_VFLIP,
+			  0, 1, 1, 0);
+	v4l2_ctrl_new_std(hdlr, &mx6cam_ctrl_ops, V4L2_CID_ROTATE,
+			  0, 270, 90, 0);
+
+	if (hdlr->error) {
+		ret = hdlr->error;
+		v4l2_ctrl_handler_free(hdlr);
+		return ret;
+	}
+
+	dev->v4l2_dev.ctrl_handler = hdlr;
+	dev->vfd->ctrl_handler = hdlr;
+
+	v4l2_ctrl_handler_setup(hdlr);
+
+	return 0;
+}
+
+
+/*
+ * Video ioctls follow
+ */
+
+static int vidioc_querycap(struct file *file, void *priv,
+			   struct v4l2_capability *cap)
+{
+	strncpy(cap->driver, DEVICE_NAME, sizeof(cap->driver) - 1);
+	strncpy(cap->card, DEVICE_NAME, sizeof(cap->card) - 1);
+	cap->bus_info[0] = 0;
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+		V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OVERLAY;
+
+	return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+				   struct v4l2_fmtdesc *f)
+{
+	struct mx6cam_pixfmt *fmt;
+
+	if (f->index >= NUM_FORMATS)
+		return -EINVAL;
+
+	fmt = &mx6cam_pixformats[f->index];
+	strncpy(f->description, fmt->name, sizeof(f->description) - 1);
+	f->pixelformat = fmt->fourcc;
+	return 0;
+}
+
+static int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv,
+				       struct v4l2_fmtdesc *f)
+{
+	return vidioc_enum_fmt_vid_cap(file, priv, f);
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct mx6cam_dev *dev = ctx->dev;
+
+	f->fmt.pix = dev->user_fmt.fmt.pix;
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_overlay(struct file *file, void *priv,
+				    struct v4l2_format *f)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct mx6cam_dev *dev = ctx->dev;
+
+	f->fmt.win = dev->win;
+	return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct mx6cam_dev *dev = ctx->dev;
+	struct v4l2_mbus_framefmt mbus_fmt;
+	struct mx6cam_pixfmt *fmt;
+	unsigned int width_align;
+	struct v4l2_rect crop;
+	int ret;
+
+	fmt = mx6cam_get_format(f->fmt.pix.pixelformat);
+	if (!fmt) {
+		v4l2_err(&dev->v4l2_dev,
+			 "Fourcc format (0x%08x) invalid.\n",
+			 f->fmt.pix.pixelformat);
+		return -EINVAL;
+	}
+
+	/*
+	 * We have to adjust the width such that the physaddrs and U and
+	 * U and V plane offsets are multiples of 8 bytes as required by
+	 * the IPU DMA Controller. For the planar formats, this corresponds
+	 * to a pixel alignment of 16. For all the packed formats, 8 is
+	 * good enough.
+	 */
+	width_align = ipu_pixelformat_is_planar(fmt->fourcc) ? 4 : 3;
+
+	v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W,
+			      width_align, &f->fmt.pix.height,
+			      MIN_H, MAX_H, H_ALIGN, S_ALIGN);
+
+	v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, 0);
+	ret = v4l2_subdev_call(dev->ep->sd, video, try_mbus_fmt, &mbus_fmt);
+	if (ret)
+		return ret;
+
+	/*
+	 * calculate what the optimal crop window will be for this
+	 * sensor format and make any user format adjustments.
+	 */
+	calc_default_crop(dev, &crop, &mbus_fmt);
+	adjust_user_fmt(dev, &mbus_fmt, f, &crop);
+
+	return 0;
+}
+
+static int vidioc_try_fmt_vid_overlay(struct file *file, void *priv,
+				      struct v4l2_format *f)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct mx6cam_dev *dev = ctx->dev;
+	struct v4l2_window *win = &f->fmt.win;
+	unsigned int width_align;
+
+	width_align = ipu_pixelformat_is_planar(dev->fbuf.fmt.pixelformat) ?
+		4 : 3;
+
+	v4l_bound_align_image(&win->w.width, MIN_W, MAX_W_IC,
+			      width_align, &win->w.height,
+			      MIN_H, MAX_H_IC, H_ALIGN, S_ALIGN);
+
+	adjust_to_resizer_limits(dev, f, &dev->crop);
+
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct mx6cam_dev *dev = ctx->dev;
+	struct v4l2_mbus_framefmt mbus_fmt;
+	int ret;
+
+	if (vb2_is_busy(&dev->buffer_queue)) {
+		v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__);
+		return -EBUSY;
+	}
+
+	ret = vidioc_try_fmt_vid_cap(file, priv, f);
+	if (ret)
+		return ret;
+
+	v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, 0);
+	ret = v4l2_subdev_call(dev->ep->sd, video, s_mbus_fmt, &mbus_fmt);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "%s s_mbus_fmt failed\n", __func__);
+		return ret;
+	}
+
+	ret = update_sensor_fmt(dev);
+	if (ret)
+		return ret;
+
+	/* reset active crop window */
+	calc_default_crop(dev, &dev->crop, &dev->sensor_fmt);
+
+	dev->user_fmt = *f;
+
+	return 0;
+}
+
+static int vidioc_enum_framesizes(struct file *file, void *priv,
+				  struct v4l2_frmsizeenum *fsize)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct mx6cam_dev *dev = ctx->dev;
+	struct mx6cam_pixfmt *fmt;
+	struct v4l2_format uf;
+	int ret = 0;
+
+	fmt = mx6cam_get_format(fsize->pixel_format);
+	if (!fmt)
+		return -EINVAL;
+
+	if (!v4l2src_compat) {
+		if (fsize->index)
+			return -EINVAL;
+
+		fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+		fsize->stepwise.min_width = MIN_W;
+		fsize->stepwise.step_width =
+			ipu_pixelformat_is_planar(fmt->fourcc) ? 16 : 8;
+		fsize->stepwise.min_height = MIN_H;
+		fsize->stepwise.step_height = 1 << H_ALIGN;
+
+		uf = dev->user_fmt;
+		uf.fmt.pix.pixelformat = fmt->fourcc;
+
+		if (need_ic(dev, &dev->sensor_fmt, &uf, &dev->crop)) {
+			fsize->stepwise.max_width = MAX_W_IC;
+			fsize->stepwise.max_height = MAX_H_IC;
+		} else {
+			fsize->stepwise.max_width = MAX_W;
+			fsize->stepwise.max_height = MAX_H;
+		}
+	} else {
+		ret = v4l2_subdev_call(dev->ep->sd, video,
+				       enum_framesizes, fsize);
+	}
+
+	return ret;
+}
+
+static int vidioc_enum_frameintervals(struct file *file, void *priv,
+				      struct v4l2_frmivalenum *fival)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct mx6cam_dev *dev = ctx->dev;
+	struct mx6cam_pixfmt *fmt;
+
+	fmt = mx6cam_get_format(fival->pixel_format);
+	if (!fmt)
+		return -EINVAL;
+
+	return v4l2_subdev_call(dev->ep->sd, video, enum_frameintervals, fival);
+}
+
+static int vidioc_s_fmt_vid_overlay(struct file *file, void *priv,
+				    struct v4l2_format *f)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct mx6cam_dev *dev = ctx->dev;
+	struct v4l2_window *win = &f->fmt.win;
+	int ret;
+
+	ret = vidioc_try_fmt_vid_overlay(file, priv, f);
+	if (ret)
+		return ret;
+
+	if (dev->preview_on)
+		stop_preview(dev);
+
+	dev->win = *win;
+
+	if (dev->preview_on)
+		start_preview(dev);
+
+	return 0;
+}
+
+static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct mx6cam_dev *dev = ctx->dev;
+	int ret;
+
+	ret = update_sensor_std(dev);
+	if (!ret)
+		*std = dev->current_std;
+	return ret;
+}
+
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct mx6cam_dev *dev = ctx->dev;
+
+	*std = dev->current_std;
+	return 0;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id std)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct mx6cam_dev *dev = ctx->dev;
+	int ret;
+
+	if (vb2_is_busy(&dev->buffer_queue))
+		return -EBUSY;
+
+	ret = v4l2_subdev_call(dev->ep->sd, video, s_std, std);
+	if (ret < 0)
+		return ret;
+
+	dev->current_std = std;
+	return 0;
+}
+
+static int vidioc_enum_input(struct file *file, void *priv,
+			     struct v4l2_input *input)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct mx6cam_dev *dev = ctx->dev;
+	struct mx6cam_sensor_input *epinput;
+	struct mx6cam_endpoint *ep;
+	int sensor_input;
+
+	/* find the endpoint that is handling this input */
+	ep = find_ep_by_input_index(dev, input->index);
+	if (!ep)
+		return -EINVAL;
+
+	epinput = &ep->sensor_input;
+	sensor_input = input->index - epinput->first;
+
+	input->type = V4L2_INPUT_TYPE_CAMERA;
+	input->capabilities = epinput->caps[sensor_input];
+	strncpy(input->name, epinput->name[sensor_input], sizeof(input->name));
+
+	if (input->index == dev->current_input) {
+		v4l2_subdev_call(ep->sd, video, g_input_status, &input->status);
+		update_sensor_std(dev);
+		input->std = dev->current_std;
+	} else {
+		input->status = V4L2_IN_ST_NO_SIGNAL;
+		input->std = V4L2_STD_UNKNOWN;
+	}
+
+	return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *index)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct mx6cam_dev *dev = ctx->dev;
+
+	*index = dev->current_input;
+	return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct mx6cam_dev *dev = ctx->dev;
+	struct mx6cam_sensor_input *epinput;
+	struct mx6cam_endpoint *ep;
+	int ret, sensor_input;
+
+	if (index == dev->current_input)
+		return 0;
+
+	/* find the endpoint that is handling this input */
+	ep = find_ep_by_input_index(dev, index);
+	if (!ep)
+		return -EINVAL;
+
+	if (dev->ep != ep) {
+		/*
+		 * don't allow switching sensors if there are queued buffers,
+		 * preview is on, or there are other users of the current
+		 * sensor besides us.
+		 */
+		if (vb2_is_busy(&dev->buffer_queue) || dev->preview_on ||
+		    dev->ep->power_count > 1)
+			return -EBUSY;
+
+		v4l2_info(&dev->v4l2_dev, "switching to sensor %s\n",
+			  ep->sd->name);
+
+		/* power down current sensor before enabling new one */
+		ret = sensor_set_power(dev, 0);
+		if (ret)
+			v4l2_warn(&dev->v4l2_dev, "sensor power off failed\n");
+
+		/* set new endpoint */
+		dev->ep = ep;
+
+		/* power-on the new sensor */
+		ret = sensor_set_power(dev, 1);
+		if (ret)
+			v4l2_warn(&dev->v4l2_dev, "sensor power on failed\n");
+
+		/* power-on the csi2 receiver */
+		if (dev->ep->ep.bus_type == V4L2_MBUS_CSI2 && dev->csi2_sd) {
+			ret = v4l2_subdev_call(dev->csi2_sd, core, s_power,
+					       true);
+			if (ret)
+				v4l2_err(&dev->v4l2_dev,
+					 "csi2 power on failed\n");
+		}
+	}
+
+	/* finally select the sensor's input */
+	epinput = &ep->sensor_input;
+	sensor_input = index - epinput->first;
+	ret = v4l2_subdev_call(dev->ep->sd, video, s_routing,
+			       epinput->value[sensor_input], 0, 0);
+
+	dev->current_input = index;
+
+	/*
+	 * sometimes on switching video input on video decoder devices
+	 * no lock status change event is generated, but vertical sync
+	 * is messed up nevertheless. So schedule a restart to correct it.
+	 */
+	if (ctx->io_allowed)
+		mod_timer(&ctx->restart_timer,
+			  jiffies + msecs_to_jiffies(MX6CAM_RESTART_DELAY));
+
+	return 0;
+}
+
+static int vidioc_g_parm(struct file *file, void *fh,
+			 struct v4l2_streamparm *a)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct mx6cam_dev *dev = ctx->dev;
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	return v4l2_subdev_call(dev->ep->sd, video, g_parm, a);
+}
+
+static int vidioc_s_parm(struct file *file, void *fh,
+			 struct v4l2_streamparm *a)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct mx6cam_dev *dev = ctx->dev;
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	return v4l2_subdev_call(dev->ep->sd, video, s_parm, a);
+}
+
+static int vidioc_cropcap(struct file *file, void *priv,
+			  struct v4l2_cropcap *cropcap)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct mx6cam_dev *dev = ctx->dev;
+
+	if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+	    cropcap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+		return -EINVAL;
+
+	cropcap->bounds = dev->crop_bounds;
+	cropcap->defrect = dev->crop_defrect;
+	cropcap->pixelaspect.numerator = 1;
+	cropcap->pixelaspect.denominator = 1;
+	return 0;
+}
+
+static int vidioc_g_crop(struct file *file, void *priv,
+			 struct v4l2_crop *crop)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct mx6cam_dev *dev = ctx->dev;
+
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+	    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+		return -EINVAL;
+
+	crop->c = dev->crop;
+	return 0;
+}
+
+static int vidioc_s_crop(struct file *file, void *priv,
+			 const struct v4l2_crop *crop)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct mx6cam_dev *dev = ctx->dev;
+	struct v4l2_rect *bounds = &dev->crop_bounds;
+
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+	    crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+		return -EINVAL;
+
+	if (vb2_is_busy(&dev->buffer_queue))
+		return -EBUSY;
+
+	/* make sure crop window is within bounds */
+	if (crop->c.top < 0 || crop->c.left < 0 ||
+	    crop->c.left + crop->c.width > bounds->width ||
+	    crop->c.top + crop->c.height > bounds->height)
+		return -EINVAL;
+
+	/*
+	 * FIXME: the IPU currently does not setup the CCIR code
+	 * registers properly to handle arbitrary crop windows. So
+	 * ignore this request if the sensor bus is BT.656.
+	 */
+	if (dev->ep->ep.bus_type == V4L2_MBUS_BT656)
+		return 0;
+
+	dev->crop = crop->c;
+
+	/* adjust crop window to h/w alignment restrictions */
+	dev->crop.width &= ~0x7;
+	dev->crop.left &= ~0x3;
+
+	/*
+	 * Crop window has changed, we need to adjust the user
+	 * width/height to meet new IC resizer restrictions or to
+	 * match the new crop window if the IC can't be used.
+	 */
+	adjust_user_fmt(dev, &dev->sensor_fmt, &dev->user_fmt,
+			&dev->crop);
+
+	return 0;
+}
+
+static int vidioc_s_fbuf(struct file *file, void *priv,
+			 const struct v4l2_framebuffer *fbuf)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct mx6cam_dev *dev = ctx->dev;
+	struct mx6cam_pixfmt *fmt;
+
+	if (fbuf->flags != V4L2_FBUF_FLAG_OVERLAY || !fbuf->base)
+		return -EINVAL;
+
+	fmt = mx6cam_get_format(fbuf->fmt.pixelformat);
+	if (!fmt) {
+		v4l2_err(&dev->v4l2_dev,
+			 "Fourcc format (0x%08x) invalid.\n",
+			 fbuf->fmt.pixelformat);
+		return -EINVAL;
+	}
+
+	if (dev->preview_on)
+		stop_preview(dev);
+
+	dev->fbuf = *fbuf;
+
+	if (dev->preview_on)
+		start_preview(dev);
+
+	return 0;
+}
+
+static int vidioc_g_fbuf(struct file *file, void *priv,
+			 struct v4l2_framebuffer *fbuf)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct mx6cam_dev *dev = ctx->dev;
+
+	*fbuf = dev->fbuf;
+
+	return 0;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+			  struct v4l2_requestbuffers *reqbufs)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct mx6cam_dev *dev = ctx->dev;
+	struct vb2_queue *vq = &dev->buffer_queue;
+	int ret;
+
+	if (vb2_is_busy(vq))
+		return -EBUSY;
+
+	ctx->alloc_ctx = vb2_dma_contig_init_ctx(dev->dev);
+	if (IS_ERR(ctx->alloc_ctx)) {
+		v4l2_err(&dev->v4l2_dev, "failed to alloc vb2 context\n");
+		return PTR_ERR(ctx->alloc_ctx);
+	}
+
+	INIT_LIST_HEAD(&ctx->ready_q);
+	INIT_WORK(&ctx->restart_work, restart_work_handler);
+	INIT_WORK(&ctx->stop_work, stop_work_handler);
+	init_timer(&ctx->restart_timer);
+	ctx->restart_timer.data = (unsigned long)ctx;
+	ctx->restart_timer.function = mx6cam_restart_timeout;
+
+	vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+	vq->drv_priv = ctx;
+	vq->buf_struct_size = sizeof(struct mx6cam_buffer);
+	vq->ops = &mx6cam_qops;
+	vq->mem_ops = &vb2_dma_contig_memops;
+	vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+	ret = vb2_queue_init(vq);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "vb2_queue_init failed\n");
+		goto alloc_ctx_free;
+	}
+
+	ctx->io_allowed = true;
+	dev->io_ctx = ctx;
+
+	return vb2_reqbufs(vq, reqbufs);
+
+alloc_ctx_free:
+	vb2_dma_contig_cleanup_ctx(ctx->alloc_ctx);
+	return ret;
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+			   struct v4l2_buffer *buf)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct vb2_queue *vq = &ctx->dev->buffer_queue;
+
+	return vb2_querybuf(vq, buf);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct vb2_queue *vq = &ctx->dev->buffer_queue;
+
+	if (!ctx->io_allowed)
+		return -EBUSY;
+
+	return vb2_qbuf(vq, buf);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct vb2_queue *vq = &ctx->dev->buffer_queue;
+
+	if (!ctx->io_allowed)
+		return -EBUSY;
+
+	return vb2_dqbuf(vq, buf, file->f_flags & O_NONBLOCK);
+}
+
+static int vidioc_expbuf(struct file *file, void *priv,
+			 struct v4l2_exportbuffer *eb)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct vb2_queue *vq = &ctx->dev->buffer_queue;
+
+	if (!ctx->io_allowed)
+		return -EBUSY;
+
+	return vb2_expbuf(vq, eb);
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+			   enum v4l2_buf_type type)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct vb2_queue *vq = &ctx->dev->buffer_queue;
+
+	if (!ctx->io_allowed)
+		return -EBUSY;
+
+	return vb2_streamon(vq, type);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+			    enum v4l2_buf_type type)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct vb2_queue *vq = &ctx->dev->buffer_queue;
+
+	if (!ctx->io_allowed)
+		return -EBUSY;
+
+	return vb2_streamoff(vq, type);
+}
+
+static int vidioc_overlay(struct file *file, void *priv,
+			  unsigned int enable)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct mx6cam_dev *dev = ctx->dev;
+	int ret = 0;
+
+	if (!ctx->io_allowed)
+		return -EBUSY;
+
+	if (enable && !dev->preview_on) {
+		if (vb2_is_streaming(&dev->buffer_queue) && !dev->using_ic) {
+			v4l2_err(&dev->v4l2_dev,
+				 "%s: not allowed while streaming w/o IC\n",
+				 __func__);
+			return -EBUSY;
+		}
+
+		if (!can_use_ic(dev, &dev->sensor_fmt, &dev->user_fmt)) {
+			v4l2_err(&dev->v4l2_dev,
+				 "%s: current format does not allow preview\n",
+				 __func__);
+			return -EINVAL;
+		}
+
+		ret = start_preview(dev);
+		if (!ret)
+			dev->preview_on = true;
+	} else if (!enable && dev->preview_on) {
+		ret = stop_preview(dev);
+		dev->preview_on = false;
+	}
+
+	return ret;
+}
+
+static const struct v4l2_ioctl_ops mx6cam_ioctl_ops = {
+	.vidioc_querycap	= vidioc_querycap,
+
+	.vidioc_enum_fmt_vid_cap        = vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap           = vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap         = vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap           = vidioc_s_fmt_vid_cap,
+
+	.vidioc_enum_framesizes         = vidioc_enum_framesizes,
+	.vidioc_enum_frameintervals     = vidioc_enum_frameintervals,
+
+	.vidioc_enum_fmt_vid_overlay    = vidioc_enum_fmt_vid_overlay,
+	.vidioc_g_fmt_vid_overlay	= vidioc_g_fmt_vid_overlay,
+	.vidioc_try_fmt_vid_overlay	= vidioc_try_fmt_vid_overlay,
+	.vidioc_s_fmt_vid_overlay	= vidioc_s_fmt_vid_overlay,
+
+	.vidioc_querystd        = vidioc_querystd,
+	.vidioc_g_std           = vidioc_g_std,
+	.vidioc_s_std           = vidioc_s_std,
+
+	.vidioc_enum_input      = vidioc_enum_input,
+	.vidioc_g_input         = vidioc_g_input,
+	.vidioc_s_input         = vidioc_s_input,
+
+	.vidioc_g_parm          = vidioc_g_parm,
+	.vidioc_s_parm          = vidioc_s_parm,
+
+	.vidioc_g_fbuf          = vidioc_g_fbuf,
+	.vidioc_s_fbuf          = vidioc_s_fbuf,
+
+	.vidioc_cropcap         = vidioc_cropcap,
+	.vidioc_g_crop          = vidioc_g_crop,
+	.vidioc_s_crop          = vidioc_s_crop,
+
+	.vidioc_reqbufs		= vidioc_reqbufs,
+	.vidioc_querybuf	= vidioc_querybuf,
+	.vidioc_qbuf		= vidioc_qbuf,
+	.vidioc_dqbuf		= vidioc_dqbuf,
+	.vidioc_expbuf		= vidioc_expbuf,
+
+	.vidioc_streamon	= vidioc_streamon,
+	.vidioc_streamoff	= vidioc_streamoff,
+	.vidioc_overlay         = vidioc_overlay,
+};
+
+
+/*
+ * Queue operations
+ */
+
+static int mx6cam_queue_setup(struct vb2_queue *vq,
+			      const struct v4l2_format *fmt,
+			      unsigned int *nbuffers, unsigned int *nplanes,
+			      unsigned int sizes[], void *alloc_ctxs[])
+{
+	struct mx6cam_ctx *ctx = vb2_get_drv_priv(vq);
+	struct mx6cam_dev *dev = ctx->dev;
+	unsigned int count = *nbuffers;
+	u32 sizeimage = dev->user_fmt.fmt.pix.sizeimage;
+
+	if (vq->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	while (sizeimage * count > VID_MEM_LIMIT)
+		count--;
+
+	*nplanes = 1;
+	*nbuffers = count;
+	sizes[0] = sizeimage;
+
+	alloc_ctxs[0] = ctx->alloc_ctx;
+
+	dprintk(dev, "get %d buffer(s) of size %d each.\n", count, sizeimage);
+
+	return 0;
+}
+
+static int mx6cam_buf_init(struct vb2_buffer *vb)
+{
+	struct mx6cam_buffer *buf = to_mx6cam_vb(vb);
+	INIT_LIST_HEAD(&buf->list);
+	return 0;
+}
+
+static int mx6cam_buf_prepare(struct vb2_buffer *vb)
+{
+	struct mx6cam_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct mx6cam_dev *dev = ctx->dev;
+
+	if (vb2_plane_size(vb, 0) < dev->user_fmt.fmt.pix.sizeimage) {
+		v4l2_err(&dev->v4l2_dev,
+			 "data will not fit into plane (%lu < %lu)\n",
+			 vb2_plane_size(vb, 0),
+			 (long)dev->user_fmt.fmt.pix.sizeimage);
+		return -EINVAL;
+	}
+
+	vb2_set_plane_payload(vb, 0, dev->user_fmt.fmt.pix.sizeimage);
+
+	return 0;
+}
+
+static void mx6cam_buf_queue(struct vb2_buffer *vb)
+{
+	struct mx6cam_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct mx6cam_dev *dev = ctx->dev;
+	struct mx6cam_buffer *buf = to_mx6cam_vb(vb);
+	unsigned long flags;
+	bool kickstart;
+
+	spin_lock_irqsave(&dev->irqlock, flags);
+
+	list_add_tail(&buf->list, &ctx->ready_q);
+
+	/* kickstart DMA chain if we have two frames in active q */
+	kickstart = (vb2_is_streaming(vb->vb2_queue) &&
+		     !(list_empty(&ctx->ready_q) ||
+		       list_is_singular(&ctx->ready_q)));
+
+	spin_unlock_irqrestore(&dev->irqlock, flags);
+
+	if (kickstart)
+		start_encoder(dev);
+}
+
+static void mx6cam_lock(struct vb2_queue *vq)
+{
+	struct mx6cam_ctx *ctx = vb2_get_drv_priv(vq);
+	struct mx6cam_dev *dev = ctx->dev;
+
+	mutex_lock(&dev->mutex);
+}
+
+static void mx6cam_unlock(struct vb2_queue *vq)
+{
+	struct mx6cam_ctx *ctx = vb2_get_drv_priv(vq);
+	struct mx6cam_dev *dev = ctx->dev;
+
+	mutex_unlock(&dev->mutex);
+}
+
+static int mx6cam_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+	struct mx6cam_ctx *ctx = vb2_get_drv_priv(vq);
+
+	if (vb2_is_streaming(vq))
+		return 0;
+
+	return set_stream(ctx, true);
+}
+
+static void mx6cam_stop_streaming(struct vb2_queue *vq)
+{
+	struct mx6cam_ctx *ctx = vb2_get_drv_priv(vq);
+	struct mx6cam_dev *dev = ctx->dev;
+	struct mx6cam_buffer *frame;
+	unsigned long flags;
+
+	if (!vb2_is_streaming(vq))
+		return;
+
+	set_stream(ctx, false);
+
+	spin_lock_irqsave(&dev->irqlock, flags);
+
+	/* release all active buffers */
+	while (!list_empty(&ctx->ready_q)) {
+		frame = list_entry(ctx->ready_q.next,
+				   struct mx6cam_buffer, list);
+		list_del(&frame->list);
+		vb2_buffer_done(&frame->vb, VB2_BUF_STATE_ERROR);
+	}
+
+	spin_unlock_irqrestore(&dev->irqlock, flags);
+}
+
+static struct vb2_ops mx6cam_qops = {
+	.queue_setup	 = mx6cam_queue_setup,
+	.buf_init        = mx6cam_buf_init,
+	.buf_prepare	 = mx6cam_buf_prepare,
+	.buf_queue	 = mx6cam_buf_queue,
+	.wait_prepare	 = mx6cam_unlock,
+	.wait_finish	 = mx6cam_lock,
+	.start_streaming = mx6cam_start_streaming,
+	.stop_streaming  = mx6cam_stop_streaming,
+};
+
+/*
+ * File operations
+ */
+static int mx6cam_open(struct file *file)
+{
+	struct mx6cam_dev *dev = video_drvdata(file);
+	struct mx6cam_ctx *ctx;
+	int ret;
+
+	if (mutex_lock_interruptible(&dev->mutex))
+		return -ERESTARTSYS;
+
+	if (!dev->ep || !dev->ep->sd) {
+		v4l2_err(&dev->v4l2_dev, "no subdevice registered\n");
+		ret = -ENODEV;
+		goto unlock;
+	}
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx) {
+		ret = -ENOMEM;
+		goto unlock;
+	}
+
+	v4l2_fh_init(&ctx->fh, video_devdata(file));
+	file->private_data = &ctx->fh;
+	ctx->dev = dev;
+	v4l2_fh_add(&ctx->fh);
+	ctx->io_allowed = false;
+
+	ret = sensor_set_power(dev, 1);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "sensor power on failed\n");
+		goto ctx_free;
+	}
+
+	if (dev->ep->ep.bus_type == V4L2_MBUS_CSI2 && dev->csi2_sd) {
+		ret = v4l2_subdev_call(dev->csi2_sd, core, s_power, true);
+		if (ret) {
+			v4l2_err(&dev->v4l2_dev, "csi2 power on failed\n");
+			goto sensor_off;
+		}
+	}
+
+	/* update the sensor's current format */
+	update_sensor_fmt(dev);
+	/* and init crop window if needed */
+	if (!dev->crop.width || !dev->crop.height)
+		calc_default_crop(dev, &dev->crop, &dev->sensor_fmt);
+
+	mutex_unlock(&dev->mutex);
+	return 0;
+
+sensor_off:
+	sensor_set_power(dev, 0);
+ctx_free:
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	kfree(ctx);
+unlock:
+	mutex_unlock(&dev->mutex);
+	return ret;
+}
+
+static int mx6cam_release(struct file *file)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct mx6cam_dev *dev = ctx->dev;
+	int ret = 0;
+
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+
+	mutex_lock(&dev->mutex);
+
+	if (ctx->io_allowed) {
+		BUG_ON(dev->io_ctx != ctx);
+
+		vb2_queue_release(&dev->buffer_queue);
+		vb2_dma_contig_cleanup_ctx(ctx->alloc_ctx);
+
+		if (dev->preview_on) {
+			stop_preview(dev);
+			dev->preview_on = false;
+		}
+
+		dev->io_ctx = NULL;
+	}
+
+	if (dev->ep == NULL || dev->ep->sd == NULL) {
+		v4l2_warn(&dev->v4l2_dev, "lost the slave?\n");
+		goto unlock;
+	}
+
+	ret = sensor_set_power(dev, 0);
+	if (ret)
+		v4l2_err(&dev->v4l2_dev, "sensor power off failed\n");
+
+unlock:
+	mutex_unlock(&dev->mutex);
+	kfree(ctx);
+	return ret;
+}
+
+static unsigned int mx6cam_poll(struct file *file,
+				 struct poll_table_struct *wait)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct mx6cam_dev *dev = ctx->dev;
+	struct vb2_queue *vq = &dev->buffer_queue;
+	int ret;
+
+	if (mutex_lock_interruptible(&dev->mutex))
+		return -ERESTARTSYS;
+
+	ret = vb2_poll(vq, file, wait);
+
+	mutex_unlock(&dev->mutex);
+	return ret;
+}
+
+static int mx6cam_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct mx6cam_ctx *ctx = file2ctx(file);
+	struct mx6cam_dev *dev = ctx->dev;
+	struct vb2_queue *vq = &dev->buffer_queue;
+	int ret;
+
+	if (mutex_lock_interruptible(&dev->mutex))
+		return -ERESTARTSYS;
+
+	ret = vb2_mmap(vq, vma);
+
+	mutex_unlock(&dev->mutex);
+	return ret;
+}
+
+static const struct v4l2_file_operations mx6cam_fops = {
+	.owner		= THIS_MODULE,
+	.open		= mx6cam_open,
+	.release	= mx6cam_release,
+	.poll		= mx6cam_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= mx6cam_mmap,
+};
+
+static struct video_device mx6cam_videodev = {
+	.name		= DEVICE_NAME,
+	.fops		= &mx6cam_fops,
+	.ioctl_ops	= &mx6cam_ioctl_ops,
+	.minor		= -1,
+	.release	= video_device_release,
+	.vfl_dir	= VFL_DIR_RX,
+	.tvnorms	= V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM,
+};
+
+/*
+ * Handle notifications from the subdevs.
+ */
+static void mx6cam_subdev_notification(struct v4l2_subdev *sd,
+				       unsigned int notification,
+				       void *arg)
+{
+	struct mx6cam_dev *dev;
+	struct mx6cam_ctx *ctx;
+
+	if (sd == NULL)
+		return;
+
+	dev = sd2dev(sd);
+	ctx = dev->io_ctx;
+
+	switch (notification) {
+	case MX6CAM_NFB4EOF_NOTIFY:
+		if (ctx)
+			mod_timer(&ctx->restart_timer, jiffies +
+				  msecs_to_jiffies(MX6CAM_RESTART_DELAY));
+		break;
+	case DECODER_STATUS_CHANGE_NOTIFY:
+		atomic_set(&dev->status_change, 1);
+		if (ctx) {
+			v4l2_warn(&dev->v4l2_dev, "decoder status change\n");
+			mod_timer(&ctx->restart_timer, jiffies +
+				  msecs_to_jiffies(MX6CAM_RESTART_DELAY));
+		}
+		break;
+	case MX6CAM_EOF_TIMEOUT_NOTIFY:
+		if (ctx) {
+			/* cancel a running restart timer since we are
+			   restarting now anyway */
+			del_timer_sync(&ctx->restart_timer);
+			/* and restart now */
+			schedule_work(&ctx->restart_work);
+		}
+		break;
+	}
+}
+
+static int mx6cam_add_sensor(struct mx6cam_dev *dev,
+			     struct device_node *remote,
+			     struct mx6cam_endpoint *ep)
+{
+	struct i2c_client *client;
+	int ret = 0;
+
+	client = of_find_i2c_device_by_node(remote);
+	if (!client)
+		return -EPROBE_DEFER;
+
+	device_lock(&client->dev);
+
+	if (!client->dev.driver ||
+	    !try_module_get(client->dev.driver->owner)) {
+		ret = -EPROBE_DEFER;
+		v4l2_info(&dev->v4l2_dev, "No driver found for %s\n",
+			  remote->full_name);
+		goto unlock;
+	}
+
+	ep->sd = i2c_get_clientdata(client);
+	ret = v4l2_device_register_subdev(&dev->v4l2_dev, ep->sd);
+	if (ret < 0) {
+		v4l2_err(&dev->v4l2_dev, "failed to register subdev %s\n",
+			 ep->sd->name);
+		goto mod_put;
+	}
+
+	v4l2_info(&dev->v4l2_dev, "Registered sensor subdev %s on CSI%d\n",
+		  ep->sd->name, ep->ep.base.port);
+	ret = 0;
+
+mod_put:
+	module_put(client->dev.driver->owner);
+unlock:
+	device_unlock(&client->dev);
+	put_device(&client->dev);
+	return ret;
+}
+
+static int mx6cam_add_csi2_receiver(struct mx6cam_dev *dev)
+{
+	struct platform_device *pdev;
+	struct device_node *node;
+	int ret = -EPROBE_DEFER;
+
+	node = of_find_compatible_node(NULL, NULL, "fsl,imx6-mipi-csi2");
+	if (!node)
+		return 0;
+
+	pdev = of_find_device_by_node(node);
+	of_node_put(node);
+	if (!pdev)
+		return 0;
+
+	/* Lock to ensure dev->driver won't change. */
+	device_lock(&pdev->dev);
+
+	if (!pdev->dev.driver || !try_module_get(pdev->dev.driver->owner))
+		goto dev_unlock;
+
+	dev->csi2_sd = dev_get_drvdata(&pdev->dev);
+
+	ret = v4l2_device_register_subdev(&dev->v4l2_dev, dev->csi2_sd);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "failed to register mipi_csi2!\n");
+		goto mod_put;
+	}
+
+	v4l2_info(&dev->v4l2_dev, "Registered subdev %s\n",
+		  dev->csi2_sd->name);
+mod_put:
+	module_put(pdev->dev.driver->owner);
+dev_unlock:
+	device_unlock(&pdev->dev);
+	if (ret == -EPROBE_DEFER)
+		v4l2_info(&dev->v4l2_dev,
+			  "deferring mipi_csi2 registration\n");
+	else if (ret < 0)
+		v4l2_err(&dev->v4l2_dev,
+			 "mipi_csi2 registration failed (%d)\n", ret);
+	return ret;
+}
+
+/* parse inputs property from v4l2_of_endpoint node */
+static int mx6cam_parse_inputs(struct mx6cam_dev *dev,
+			       struct device_node *node,
+			       int next_input,
+			       struct mx6cam_endpoint *ep)
+{
+	struct mx6cam_sensor_input *epinput = &ep->sensor_input;
+	int ret, i;
+
+	for (i = 0; i < MX6CAM_MAX_INPUTS; i++) {
+		const char *input_name;
+		u32 val;
+
+		ret = of_property_read_u32_index(node, "inputs", i, &val);
+		if (ret)
+			break;
+
+		epinput->value[i] = val;
+
+		ret = of_property_read_string_index(node, "input-names", i,
+						    &input_name);
+		if (!ret)
+			strncpy(epinput->name[i], input_name,
+				sizeof(epinput->name[i]));
+		else
+			snprintf(epinput->name[i], sizeof(epinput->name[i]),
+				 "%s-%d", ep->sd->name, i);
+
+		val = 0;
+		ret = of_property_read_u32_index(node, "input-caps", i, &val);
+		epinput->caps[i] = val;
+	}
+
+	epinput->num = i;
+
+	/* if no inputs provided just assume a single input */
+	if (epinput->num == 0) {
+		epinput->num = 1;
+		epinput->caps[0] = 0;
+		strncpy(epinput->name[0], ep->sd->name,
+			sizeof(epinput->name[0]));
+	}
+
+	epinput->first = next_input;
+	epinput->last = next_input + epinput->num - 1;
+	return epinput->last + 1;
+}
+
+static int mx6cam_parse_endpoints(struct mx6cam_dev *dev,
+				  struct device_node *node)
+{
+	struct device_node *remote, *epnode = NULL;
+	struct v4l2_of_endpoint ep;
+	int ret, next_input = 0;
+
+	while (dev->num_eps < MX6CAM_MAX_ENDPOINTS) {
+		epnode = of_graph_get_next_endpoint(node, epnode);
+		if (!epnode)
+			break;
+
+		v4l2_of_parse_endpoint(epnode, &ep);
+
+		if (ep.base.port > 1) {
+			v4l2_err(&dev->v4l2_dev, "invalid port %d\n",
+				 ep.base.port);
+			of_node_put(epnode);
+			return -EINVAL;
+		}
+
+		remote = of_graph_get_remote_port_parent(epnode);
+		if (!remote) {
+			v4l2_err(&dev->v4l2_dev,
+				 "failed to find remote port parent\n");
+			of_node_put(epnode);
+			return -EINVAL;
+		}
+
+		dev->eplist[dev->num_eps].ep = ep;
+		ret = mx6cam_add_sensor(dev, remote,
+					&dev->eplist[dev->num_eps]);
+		if (ret)
+			goto out;
+
+		next_input = mx6cam_parse_inputs(dev, epnode, next_input,
+						 &dev->eplist[dev->num_eps]);
+
+		dev->num_eps++;
+
+		of_node_put(remote);
+		of_node_put(epnode);
+	}
+
+	if (!dev->num_eps) {
+		v4l2_err(&dev->v4l2_dev, "no endpoints defined!\n");
+		return -EINVAL;
+	}
+
+	dev->ep = &dev->eplist[0];
+	return 0;
+out:
+	of_node_put(remote);
+	of_node_put(epnode);
+	return ret;
+}
+
+static void mx6cam_unregister_subdevs(struct mx6cam_dev *dev)
+{
+	struct i2c_adapter *adapter;
+	struct i2c_client *client;
+	struct mx6cam_endpoint *ep;
+	int i;
+
+	if (!IS_ERR_OR_NULL(dev->encoder_sd))
+		v4l2_device_unregister_subdev(dev->encoder_sd);
+
+	if (!IS_ERR_OR_NULL(dev->preview_sd))
+		v4l2_device_unregister_subdev(dev->preview_sd);
+
+	if (!IS_ERR_OR_NULL(dev->csi2_sd))
+		v4l2_device_unregister_subdev(dev->csi2_sd);
+
+	for (i = 0; i < dev->num_eps; i++) {
+		ep = &dev->eplist[i];
+		if (!ep->sd)
+			continue;
+		client = v4l2_get_subdevdata(ep->sd);
+		if (!client)
+			continue;
+
+		v4l2_device_unregister_subdev(ep->sd);
+
+		if (!client->dev.of_node) {
+			adapter = client->adapter;
+			i2c_unregister_device(client);
+			if (adapter)
+				i2c_put_adapter(adapter);
+		}
+	}
+}
+
+static int mx6cam_probe(struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct mx6cam_dev *dev;
+	struct video_device *vfd;
+	struct pinctrl *pinctrl;
+	int ret;
+
+	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	dev->dev = &pdev->dev;
+	mutex_init(&dev->mutex);
+	spin_lock_init(&dev->irqlock);
+
+	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+	if (ret)
+		return ret;
+
+	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+	/* get our parent IPU */
+	dev->ipu = dev_get_drvdata(pdev->dev.parent);
+	if (IS_ERR(dev->ipu)) {
+		v4l2_err(&dev->v4l2_dev, "could not get parent ipu\n");
+		ret = -ENODEV;
+		goto unreg_dev;
+	}
+
+	vfd = video_device_alloc();
+	if (!vfd) {
+		v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n");
+		ret = -ENOMEM;
+		goto unreg_dev;
+	}
+
+	*vfd = mx6cam_videodev;
+	vfd->lock = &dev->mutex;
+	vfd->v4l2_dev = &dev->v4l2_dev;
+	dev->v4l2_dev.notify = mx6cam_subdev_notification;
+
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+		goto unreg_vdev;
+	}
+
+	video_set_drvdata(vfd, dev);
+	snprintf(vfd->name, sizeof(vfd->name), "%s", mx6cam_videodev.name);
+	dev->vfd = vfd;
+
+	platform_set_drvdata(pdev, dev);
+
+	/* Get any pins needed */
+	pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+
+	/* setup some defaults */
+	dev->user_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	dev->user_fmt.fmt.pix.width = 640;
+	dev->user_fmt.fmt.pix.height = 480;
+	dev->user_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
+	dev->user_fmt.fmt.pix.bytesperline = (640 * 12) >> 3;
+	dev->user_fmt.fmt.pix.sizeimage =
+		(480 * dev->user_fmt.fmt.pix.bytesperline);
+	dev->current_std = V4L2_STD_ALL;
+
+	/* init our controls */
+	ret = mx6cam_init_controls(dev);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "init controls failed\n");
+		goto unreg_vdev;
+	}
+
+	/* find and register mipi csi2 receiver subdev */
+	ret = mx6cam_add_csi2_receiver(dev);
+	if (ret)
+		goto free_ctrls;
+
+	/* parse and register all sensor endpoints */
+	ret = mx6cam_parse_endpoints(dev, node);
+	if (ret)
+		goto unreg_subdevs;
+
+	dev->encoder_sd = mx6cam_encoder_init(dev);
+	if (IS_ERR(dev->encoder_sd)) {
+		ret = PTR_ERR(dev->encoder_sd);
+		goto unreg_subdevs;
+	}
+
+	dev->preview_sd = mx6cam_preview_init(dev);
+	if (IS_ERR(dev->preview_sd)) {
+		ret = PTR_ERR(dev->preview_sd);
+		goto unreg_subdevs;
+	}
+
+	ret = v4l2_device_register_subdev(&dev->v4l2_dev, dev->encoder_sd);
+	if (ret < 0) {
+		v4l2_err(&dev->v4l2_dev,
+			 "failed to register encoder subdev\n");
+		goto unreg_subdevs;
+	}
+	v4l2_info(&dev->v4l2_dev, "Registered subdev %s\n",
+		  dev->encoder_sd->name);
+
+	ret = v4l2_device_register_subdev(&dev->v4l2_dev, dev->preview_sd);
+	if (ret < 0) {
+		v4l2_err(&dev->v4l2_dev,
+			 "failed to register preview subdev\n");
+		goto unreg_subdevs;
+	}
+	v4l2_info(&dev->v4l2_dev, "Registered subdev %s\n",
+		  dev->preview_sd->name);
+
+	ret = v4l2_device_register_subdev_nodes(&dev->v4l2_dev);
+	if (ret)
+		goto unreg_subdevs;
+
+	v4l2_info(&dev->v4l2_dev,
+		  "Device registered as /dev/video%d, parent is ipu%d\n",
+		  vfd->num, ipu_get_num(dev->ipu));
+
+	return 0;
+
+unreg_subdevs:
+	mx6cam_unregister_subdevs(dev);
+free_ctrls:
+	v4l2_ctrl_handler_free(&dev->ctrl_hdlr);
+unreg_vdev:
+	video_unregister_device(dev->vfd);
+unreg_dev:
+	v4l2_device_unregister(&dev->v4l2_dev);
+	return ret;
+}
+
+static int mx6cam_remove(struct platform_device *pdev)
+{
+	struct mx6cam_dev *dev =
+		(struct mx6cam_dev *)platform_get_drvdata(pdev);
+
+	v4l2_info(&dev->v4l2_dev, "Removing " DEVICE_NAME "\n");
+	v4l2_ctrl_handler_free(&dev->ctrl_hdlr);
+	video_unregister_device(dev->vfd);
+	mx6cam_unregister_subdevs(dev);
+	v4l2_device_unregister(&dev->v4l2_dev);
+
+	return 0;
+}
+
+static struct of_device_id mx6cam_dt_ids[] = {
+	{ .compatible = "fsl,imx6-v4l2-capture" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mx6cam_dt_ids);
+
+static struct platform_driver mx6cam_pdrv = {
+	.probe		= mx6cam_probe,
+	.remove		= mx6cam_remove,
+	.driver		= {
+		.name	= DEVICE_NAME,
+		.owner	= THIS_MODULE,
+		.of_match_table	= mx6cam_dt_ids,
+	},
+};
+
+module_platform_driver(mx6cam_pdrv);
+
+MODULE_DESCRIPTION("i.MX6 v4l2 capture driver");
+MODULE_AUTHOR("Mentor Graphics Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/imx6/capture/mx6-camif.h b/drivers/staging/media/imx6/capture/mx6-camif.h
new file mode 100644
index 0000000..6ebcec6
--- /dev/null
+++ b/drivers/staging/media/imx6/capture/mx6-camif.h
@@ -0,0 +1,197 @@
+/*
+ * Video Capture driver for Freescale i.MX6 SOC
+ *
+ * Copyright (c) 2012-2014 Mentor Graphics Inc.
+ * Copyright 2004-2012 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.
+ */
+#ifndef _MX6_CAMIF_H
+#define _MX6_CAMIF_H
+
+#define dprintk(dev, fmt, arg...)					\
+	v4l2_dbg(1, 1, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
+
+/*
+ * There can be a maximum of 5 endpoints (and 5 sensors attached to those
+ * endpoints): 1 parallel endpoints, and 4 MIPI-CSI2 endpoints for each
+ * virtual channel.
+ */
+#define MX6CAM_MAX_ENDPOINTS 5
+
+/*
+ * How long before no EOF interrupts cause a stream/preview
+ * restart, or a buffer dequeue timeout, in msec. The dequeue
+ * timeout should be longer than the EOF timeout.
+ */
+#define MX6CAM_EOF_TIMEOUT       1000
+#define MX6CAM_DQ_TIMEOUT        5000
+
+/*
+ * How long to delay a restart on ADV718x status changes or NFB4EOF,
+ * in msec.
+ */
+#define MX6CAM_RESTART_DELAY      200
+
+/*
+ * Internal subdev notifications
+ */
+#define MX6CAM_NFB4EOF_NOTIFY      _IO('6', 0)
+#define MX6CAM_EOF_TIMEOUT_NOTIFY  _IO('6', 1)
+
+struct mx6cam_buffer {
+	struct vb2_buffer vb; /* v4l buffer must be first */
+	struct list_head  list;
+};
+
+static inline struct mx6cam_buffer *to_mx6cam_vb(struct vb2_buffer *vb)
+{
+	return container_of(vb, struct mx6cam_buffer, vb);
+}
+
+struct mx6cam_pixfmt {
+	char	*name;
+	u32	fourcc;
+	int     depth;   /* total bpp */
+	int     y_depth; /* depth of first Y plane for planar formats */
+};
+
+struct mx6cam_dma_buf {
+	void          *virt;
+	dma_addr_t     phys;
+	unsigned long  len;
+};
+
+/*
+ * A sensor's inputs parsed from v4l2_of_endpoint nodes in devicetree
+ */
+#define MX6CAM_MAX_INPUTS 16
+
+struct mx6cam_sensor_input {
+	/* input values passed to s_routing */
+	u32 value[MX6CAM_MAX_INPUTS];
+	/* input capabilities (V4L2_IN_CAP_*) */
+	u32 caps[MX6CAM_MAX_INPUTS];
+	/* input names */
+	char name[MX6CAM_MAX_INPUTS][32];
+
+	/* number of inputs */
+	int num;
+	/* first and last input indexes from mx6cam perspective */
+	int first;
+	int last;
+};
+
+/*
+ * Everything to describe a V4L2 endpoint. Endpoints are handled by
+ * one of the two CSI's, and connect to exactly one remote sensor.
+ */
+struct mx6cam_endpoint {
+	struct v4l2_of_endpoint ep;      /* the parsed DT endpoint info */
+	struct v4l2_subdev     *sd;      /* the remote sensor when attached
+					    to this endpoint */
+	struct mx6cam_sensor_input sensor_input;
+	struct ipu_csi_signal_cfg csi_sig_cfg;
+	int power_count;                 /* power use counter */
+	int stream_count;                /* stream use counter */
+};
+
+struct mx6cam_ctx;
+
+struct mx6cam_dev {
+	struct v4l2_device	v4l2_dev;
+	struct video_device	*vfd;
+	struct device           *dev;
+
+	struct mutex		mutex;
+	spinlock_t		irqlock;
+
+	/* buffer queue used in videobuf2 */
+	struct vb2_queue        buffer_queue;
+
+	/* v4l2 controls */
+	struct v4l2_ctrl_handler ctrl_hdlr;
+	int                      rotation; /* degrees */
+	bool                     hflip;
+	bool                     vflip;
+	/* derived from rotation, hflip, vflip controls */
+	enum ipu_rotate_mode     rot_mode;
+
+	/* the format from sensor and from userland */
+	struct v4l2_format        user_fmt;
+	struct v4l2_mbus_framefmt sensor_fmt;
+
+	/*
+	 * win (from s_fmt_vid_cap_overlay) holds global alpha, chromakey,
+	 * and interlace info for the preview overlay.
+	 */
+	struct v4l2_window      win;
+
+	/*
+	 * info about the overlay framebuffer for preview (base address,
+	 * width/height, pix format).
+	 */
+	struct v4l2_framebuffer fbuf;
+
+	/*
+	 * the crop rectangle (from s_crop) specifies the crop dimensions
+	 * and position over the raw capture frame boundaries.
+	 */
+	struct v4l2_rect        crop_bounds;
+	struct v4l2_rect        crop_defrect;
+	struct v4l2_rect        crop;
+
+	/* misc status */
+	int                     current_input; /* the current input */
+	v4l2_std_id             current_std;   /* current video standard */
+	atomic_t                status_change; /* sensor status change */
+	bool                    signal_locked; /* sensor signal lock */
+	bool                    encoder_on;    /* encode is on */
+	bool                    preview_on;    /* preview is on */
+	bool                    using_ic;      /* IC is being used for encode */
+
+	/* encoder, preview, and mipi csi2 subdevices */
+	struct v4l2_subdev     *encoder_sd;
+	struct v4l2_subdev     *preview_sd;
+	struct v4l2_subdev     *csi2_sd;
+
+	/* sensor endpoints */
+	struct mx6cam_endpoint  eplist[MX6CAM_MAX_ENDPOINTS];
+	struct mx6cam_endpoint  *ep; /* the current active endpoint */
+	int                     num_eps;
+
+	/*
+	 * the current open context that is doing IO (there can only
+	 * be one allowed IO context at a time).
+	 */
+	struct mx6cam_ctx       *io_ctx;
+
+	/* parent IPU */
+	struct ipu_soc          *ipu;
+};
+
+struct mx6cam_ctx {
+	struct v4l2_fh          fh;
+	struct mx6cam_dev       *dev;
+
+	struct vb2_alloc_ctx    *alloc_ctx;
+
+	/* streaming buffer queue */
+	struct list_head        ready_q;
+
+	/* stream/preview stop and restart handling */
+	struct work_struct      restart_work;
+	struct work_struct      stop_work;
+	struct timer_list       restart_timer;
+
+	/* is this ctx allowed to do IO */
+	bool                    io_allowed;
+};
+
+struct v4l2_subdev *mx6cam_encoder_init(struct mx6cam_dev *dev);
+struct v4l2_subdev *mx6cam_preview_init(struct mx6cam_dev *dev);
+
+#endif /* _MX6_CAMIF_H */
diff --git a/drivers/staging/media/imx6/capture/mx6-encode.c b/drivers/staging/media/imx6/capture/mx6-encode.c
new file mode 100644
index 0000000..fad36aa
--- /dev/null
+++ b/drivers/staging/media/imx6/capture/mx6-encode.c
@@ -0,0 +1,775 @@
+/*
+ * V4L2 Capture Encoder Subdev for Freescale i.MX6 SOC
+ *
+ * Copyright (c) 2012-2014 Mentor Graphics Inc.
+ * Copyright 2004-2012 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.
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-of.h>
+#include <media/v4l2-ctrls.h>
+#include <linux/platform_data/imx-ipu-v3.h>
+#include <media/imx6.h>
+#include "mx6-camif.h"
+
+struct encoder_priv {
+	struct mx6cam_dev    *dev;
+	struct v4l2_subdev    sd;
+
+	struct ipuv3_channel *enc_ch;
+	struct ipuv3_channel *enc_rot_in_ch;
+	struct ipuv3_channel *enc_rot_out_ch;
+	struct ipu_ic *ic_enc;
+	struct ipu_irt *irt;
+	struct ipu_smfc *smfc;
+	struct ipu_csi *csi;
+
+	/* active (undergoing DMA) buffers, one for each IPU buffer */
+	struct mx6cam_buffer *active_frame[2];
+
+	struct mx6cam_dma_buf rot_buf[2];
+	struct mx6cam_dma_buf underrun_buf;
+	int buf_num;
+
+	struct timer_list eof_timeout_timer;
+	int eof_irq;
+	int nfb4eof_irq;
+
+	bool last_eof;  /* waiting for last EOF at encoder off */
+	struct completion last_eof_comp;
+};
+
+/*
+ * Update the CSI whole sensor and active windows, and initialize
+ * the CSI interface and muxes.
+ */
+static void encoder_setup_csi(struct encoder_priv *priv)
+{
+	struct mx6cam_dev *dev = priv->dev;
+
+	ipu_csi_set_window_size(priv->csi, dev->crop.width, dev->crop.height);
+	ipu_csi_set_window_pos(priv->csi, dev->crop.left, dev->crop.top);
+	ipu_csi_init_interface(priv->csi, dev->crop_bounds.width,
+			       dev->crop_bounds.height, &dev->ep->csi_sig_cfg);
+
+	if (dev->ep->ep.bus_type == V4L2_MBUS_CSI2)
+		ipu_csi_set_mipi_datatype(priv->csi, dev->ep->ep.base.id,
+					  &dev->ep->csi_sig_cfg);
+
+	/* select either parallel or MIPI-CSI2 as input to our CSI */
+	ipu_csi_set_src(priv->csi, dev->ep->ep.base.id,
+			dev->ep->ep.bus_type == V4L2_MBUS_CSI2);
+	/* set CSI destination to IC or direct to mem via SMFC */
+	ipu_csi_set_dest(priv->csi, dev->using_ic);
+}
+
+static void encoder_put_ipu_resources(struct encoder_priv *priv)
+{
+	if (!IS_ERR_OR_NULL(priv->irt))
+		ipu_irt_put(priv->irt);
+	priv->irt = NULL;
+
+	if (!IS_ERR_OR_NULL(priv->ic_enc))
+		ipu_ic_put(priv->ic_enc);
+	priv->ic_enc = NULL;
+
+	if (!IS_ERR_OR_NULL(priv->enc_ch))
+		ipu_idmac_put(priv->enc_ch);
+	priv->enc_ch = NULL;
+
+	if (!IS_ERR_OR_NULL(priv->enc_rot_in_ch))
+		ipu_idmac_put(priv->enc_rot_in_ch);
+	priv->enc_rot_in_ch = NULL;
+
+	if (!IS_ERR_OR_NULL(priv->enc_rot_out_ch))
+		ipu_idmac_put(priv->enc_rot_out_ch);
+	priv->enc_rot_out_ch = NULL;
+
+	if (!IS_ERR_OR_NULL(priv->smfc))
+		ipu_smfc_put(priv->smfc);
+	priv->smfc = NULL;
+
+	if (!IS_ERR_OR_NULL(priv->csi))
+		ipu_csi_put(priv->csi);
+	priv->csi = NULL;
+}
+
+static int encoder_get_ipu_resources(struct encoder_priv *priv)
+{
+	struct mx6cam_dev *dev = priv->dev;
+	int csi_id, csi_ch_num, err;
+
+	csi_id = dev->ep->ep.base.port;
+	priv->csi = ipu_csi_get(dev->ipu, csi_id);
+	if (IS_ERR(priv->csi)) {
+		v4l2_err(&priv->sd, "failed to get CSI %d\n", csi_id);
+		return PTR_ERR(priv->csi);
+	}
+
+	if (dev->using_ic) {
+		priv->ic_enc = ipu_ic_get(dev->ipu, IC_TASK_ENCODER);
+		if (IS_ERR(priv->ic_enc)) {
+			v4l2_err(&priv->sd, "failed to get IC ENC\n");
+			err = PTR_ERR(priv->ic_enc);
+			goto out;
+		}
+
+		priv->irt = ipu_irt_get(dev->ipu);
+		if (IS_ERR(priv->irt)) {
+			v4l2_err(&priv->sd, "failed to get IRT\n");
+			err = PTR_ERR(priv->irt);
+			goto out;
+		}
+
+		priv->enc_ch = ipu_idmac_get(dev->ipu,
+					     IPUV3_CHANNEL_IC_PRP_ENC_MEM);
+		if (IS_ERR(priv->enc_ch)) {
+			v4l2_err(&priv->sd, "could not get IDMAC channel %u\n",
+				 IPUV3_CHANNEL_IC_PRP_ENC_MEM);
+			err = PTR_ERR(priv->enc_ch);
+			goto out;
+		}
+
+		priv->enc_rot_in_ch = ipu_idmac_get(dev->ipu,
+						    IPUV3_CHANNEL_MEM_ROT_ENC);
+		if (IS_ERR(priv->enc_rot_in_ch)) {
+			v4l2_err(&priv->sd, "could not get IDMAC channel %u\n",
+				 IPUV3_CHANNEL_MEM_ROT_ENC);
+			err = PTR_ERR(priv->enc_rot_in_ch);
+			goto out;
+		}
+
+		priv->enc_rot_out_ch = ipu_idmac_get(dev->ipu,
+						     IPUV3_CHANNEL_ROT_ENC_MEM);
+		if (IS_ERR(priv->enc_rot_out_ch)) {
+			v4l2_err(&priv->sd, "could not get IDMAC channel %u\n",
+				 IPUV3_CHANNEL_ROT_ENC_MEM);
+			err = PTR_ERR(priv->enc_rot_out_ch);
+			goto out;
+		}
+	} else {
+		priv->smfc = ipu_smfc_get(dev->ipu);
+		if (IS_ERR(priv->smfc)) {
+			v4l2_err(&priv->sd, "failed to get SMFC\n");
+			err = PTR_ERR(priv->smfc);
+			goto out;
+		}
+
+		/*
+		 * Choose the direct CSI-->SMFC-->MEM channel corresponding
+		 * to the IPU and CSI IDs.
+		 */
+		csi_ch_num = IPUV3_CHANNEL_CSI0 +
+			(ipu_get_num(dev->ipu) << 1) + csi_id;
+
+		priv->enc_ch = ipu_idmac_get(dev->ipu, csi_ch_num);
+		if (IS_ERR(priv->enc_ch)) {
+			v4l2_err(&priv->sd, "could not get IDMAC channel %u\n",
+				 csi_ch_num);
+			err = PTR_ERR(priv->enc_ch);
+			goto out;
+		}
+	}
+
+	return 0;
+out:
+	encoder_put_ipu_resources(priv);
+	return err;
+}
+
+static irqreturn_t encoder_eof_interrupt(int irq, void *dev_id)
+{
+	struct encoder_priv *priv = dev_id;
+	struct mx6cam_dev *dev = priv->dev;
+	struct mx6cam_ctx *ctx = dev->io_ctx;
+	struct mx6cam_buffer *frame;
+	struct ipuv3_channel *channel;
+	enum vb2_buffer_state state;
+	struct timeval cur_time;
+	unsigned long flags;
+	dma_addr_t phys;
+
+	spin_lock_irqsave(&dev->irqlock, flags);
+
+	/* timestamp and return the completed frame */
+	frame = priv->active_frame[priv->buf_num];
+	if (frame) {
+		do_gettimeofday(&cur_time);
+		frame->vb.v4l2_buf.timestamp = cur_time;
+		state = dev->signal_locked ?
+			VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
+		vb2_buffer_done(&frame->vb, state);
+	}
+
+	if (priv->last_eof) {
+		complete(&priv->last_eof_comp);
+		priv->active_frame[priv->buf_num] = NULL;
+		priv->last_eof = false;
+		goto unlock;
+	}
+
+	/* bump the EOF timeout timer */
+	mod_timer(&priv->eof_timeout_timer,
+		  jiffies + msecs_to_jiffies(MX6CAM_EOF_TIMEOUT));
+
+	if (!list_empty(&ctx->ready_q)) {
+		frame = list_entry(ctx->ready_q.next,
+				   struct mx6cam_buffer, list);
+		phys = vb2_dma_contig_plane_dma_addr(&frame->vb, 0);
+		list_del(&frame->list);
+		priv->active_frame[priv->buf_num] = frame;
+	} else {
+		phys = priv->underrun_buf.phys;
+		priv->active_frame[priv->buf_num] = NULL;
+	}
+
+	channel = (dev->rot_mode >= IPU_ROTATE_90_RIGHT) ?
+		priv->enc_rot_out_ch : priv->enc_ch;
+
+	if (ipu_idmac_buffer_is_ready(channel, priv->buf_num))
+		ipu_idmac_clear_buffer(channel, priv->buf_num);
+
+	ipu_cpmem_set_buffer(channel, priv->buf_num, phys);
+	ipu_idmac_select_buffer(channel, priv->buf_num);
+
+	priv->buf_num ^= 1;
+
+unlock:
+	spin_unlock_irqrestore(&dev->irqlock, flags);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t encoder_nfb4eof_interrupt(int irq, void *dev_id)
+{
+	struct encoder_priv *priv = dev_id;
+	struct mx6cam_dev *dev = priv->dev;
+
+	v4l2_err(&priv->sd, "NFB4EOF\n");
+
+	/*
+	 * It has been discovered that with rotation, encoder disable
+	 * creates a single NFB4EOF event which is 100% repeatable. So
+	 * scheduling a restart here causes an endless NFB4EOF-->restart
+	 * cycle. The error itself seems innocuous, capture is not adversely
+	 * affected.
+	 *
+	 * So don't schedule a restart on NFB4EOF error. If the source
+	 * of the NFB4EOF event on disable is ever found, it can
+	 * be re-enabled, but is probably not necessary. Detecting the
+	 * interrupt (and clearing the irq status in the IPU) seems to
+	 * be enough.
+	 */
+	if (!dev->using_ic)
+		v4l2_subdev_notify(&priv->sd, MX6CAM_NFB4EOF_NOTIFY, NULL);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * EOF timeout timer function.
+ */
+static void encoder_eof_timeout(unsigned long data)
+{
+	struct encoder_priv *priv = (struct encoder_priv *)data;
+
+	v4l2_err(&priv->sd, "encoder EOF timeout\n");
+
+	v4l2_subdev_notify(&priv->sd, MX6CAM_EOF_TIMEOUT_NOTIFY, NULL);
+}
+
+static void encoder_free_dma_buf(struct encoder_priv *priv,
+				 struct mx6cam_dma_buf *buf)
+{
+	struct mx6cam_dev *dev = priv->dev;
+
+	if (buf->virt)
+		dma_free_coherent(dev->dev, buf->len, buf->virt, buf->phys);
+
+	buf->virt = NULL;
+	buf->phys = 0;
+}
+
+static int encoder_alloc_dma_buf(struct encoder_priv *priv,
+				 struct mx6cam_dma_buf *buf,
+				 int size)
+{
+	struct mx6cam_dev *dev = priv->dev;
+
+	encoder_free_dma_buf(priv, buf);
+
+	buf->len = PAGE_ALIGN(size);
+	buf->virt = dma_alloc_coherent(dev->dev, buf->len, &buf->phys,
+				       GFP_DMA | GFP_KERNEL);
+	if (!buf->virt) {
+		v4l2_err(&priv->sd, "failed to alloc dma buffer\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void encoder_setup_channel(struct encoder_priv *priv,
+				  struct ipuv3_channel *channel,
+				  struct v4l2_pix_format *f,
+				  enum ipu_rotate_mode rot_mode,
+				  dma_addr_t addr0, dma_addr_t addr1,
+				  bool rot_swap_width_height)
+{
+	struct mx6cam_dev *dev = priv->dev;
+	u32 width, height, stride;
+	unsigned int burst_size;
+	struct ipu_image image;
+
+	if (dev->using_ic && rot_swap_width_height) {
+		width = f->height;
+		height = f->width;
+	} else {
+		width = f->width;
+		height = f->height;
+	}
+	stride = ipu_stride_to_bytes(width, f->pixelformat);
+
+	ipu_cpmem_zero(channel);
+
+	memset(&image, 0, sizeof(image));
+	image.pix.width = image.rect.width = width;
+	image.pix.height = image.rect.height = height;
+	image.pix.bytesperline = stride;
+	image.pix.pixelformat = f->pixelformat;
+	image.phys0 = addr0;
+	image.phys1 = addr1;
+	ipu_cpmem_set_image(channel, &image);
+
+	if (channel == priv->enc_rot_in_ch ||
+	    channel == priv->enc_rot_out_ch) {
+		burst_size = 8;
+		ipu_cpmem_set_block_mode(channel);
+	} else
+		burst_size = (width % 16) ? 8 : 16;
+
+	ipu_cpmem_set_burstsize(channel, burst_size);
+
+	if (!dev->using_ic) {
+		int csi_id = ipu_csi_get_num(priv->csi);
+		bool passthrough;
+
+		/*
+		 * If the sensor uses 16-bit parallel CSI bus, we must handle
+		 * the data internally in the IPU as 16-bit generic, aka
+		 * passthrough mode.
+		 */
+		passthrough = (dev->ep->ep.bus_type != V4L2_MBUS_CSI2 &&
+			       dev->ep->csi_sig_cfg.data_width ==
+			       IPU_CSI_DATA_WIDTH_16);
+
+		if (passthrough)
+			ipu_cpmem_set_format_passthrough(channel, 16);
+
+		if (dev->ep->ep.bus_type == V4L2_MBUS_CSI2)
+			ipu_smfc_map(priv->smfc, channel, csi_id,
+				     dev->ep->ep.base.id);
+		else
+			ipu_smfc_map(priv->smfc, channel, csi_id, 0);
+
+		/*
+		 * Set the channel for the direct CSI-->memory via SMFC
+		 * use-case to very high priority, by enabling the watermark
+		 * signal in the SMFC, enabling WM in the channel, and setting
+		 * the channel priority to high.
+		 *
+		 * Refer to the iMx6 rev. D TRM Table 36-8: Calculated priority
+		 * value.
+		 *
+		 * The WM's are set very low by intention here to ensure that
+		 * the SMFC FIFOs do not overflow.
+		 */
+		ipu_smfc_set_wmc(priv->smfc, channel, false, 0x01);
+		ipu_smfc_set_wmc(priv->smfc, channel, true, 0x02);
+		ipu_cpmem_set_high_priority(channel);
+		ipu_idmac_enable_watermark(channel, true);
+		ipu_cpmem_set_axi_id(channel, 0);
+		ipu_idmac_lock_enable(channel, 8);
+
+		ipu_smfc_set_burst_size(priv->smfc, channel,
+					burst_size, passthrough);
+	}
+
+	if (rot_mode)
+		ipu_cpmem_set_rotation(channel, rot_mode);
+
+	if (ipu_csi_is_interlaced(priv->csi) && channel == priv->enc_ch)
+		ipu_cpmem_interlaced_scan(channel, stride);
+
+	if (dev->using_ic) {
+		ipu_ic_task_idma_init(priv->ic_enc, channel, width, height,
+				      burst_size, rot_mode);
+		ipu_cpmem_set_axi_id(channel, 1);
+	}
+
+	ipu_idmac_set_double_buffer(channel, true);
+}
+
+static int encoder_setup_rotation(struct encoder_priv *priv,
+				  dma_addr_t phys0, dma_addr_t phys1,
+				  struct v4l2_mbus_framefmt *inf,
+				  struct v4l2_pix_format *outf)
+{
+	struct mx6cam_dev *dev = priv->dev;
+	enum ipu_color_space in_cs, out_cs;
+	int out_size = (outf->width * outf->height *
+			ipu_bits_per_pixel(outf->pixelformat)) >> 3;
+	int err;
+
+	err = encoder_alloc_dma_buf(priv, &priv->underrun_buf, out_size);
+	if (err) {
+		v4l2_err(&priv->sd, "failed to alloc underrun_buf, %d\n", err);
+		return err;
+	}
+
+	err = encoder_alloc_dma_buf(priv, &priv->rot_buf[0], out_size);
+	if (err) {
+		v4l2_err(&priv->sd, "failed to alloc rot_buf[0], %d\n", err);
+		goto free_underrun;
+	}
+	err = encoder_alloc_dma_buf(priv, &priv->rot_buf[1], out_size);
+	if (err) {
+		v4l2_err(&priv->sd, "failed to alloc rot_buf[1], %d\n", err);
+		goto free_rot0;
+	}
+
+	in_cs = ipu_mbus_code_to_colorspace(inf->code);
+	out_cs = ipu_pixelformat_to_colorspace(outf->pixelformat);
+
+	err = ipu_ic_task_init(priv->ic_enc,
+			       inf->width, inf->height,
+			       outf->height, outf->width,
+			       in_cs, out_cs);
+	if (err) {
+		v4l2_err(&priv->sd, "ipu_ic_task_init failed, %d\n", err);
+		goto free_rot1;
+	}
+
+	/* init the IC ENC-->MEM IDMAC channel */
+	encoder_setup_channel(priv, priv->enc_ch, outf,
+			      IPU_ROTATE_NONE,
+			      priv->rot_buf[0].phys,
+			      priv->rot_buf[1].phys,
+			      true);
+
+	/* init the MEM-->IC ENC ROT IDMAC channel */
+	encoder_setup_channel(priv, priv->enc_rot_in_ch, outf,
+			      dev->rot_mode,
+			      priv->rot_buf[0].phys,
+			      priv->rot_buf[1].phys,
+			      true);
+
+	/* init the destination IC ENC ROT-->MEM IDMAC channel */
+	encoder_setup_channel(priv, priv->enc_rot_out_ch, outf,
+			      IPU_ROTATE_NONE,
+			      phys0, phys1,
+			      false);
+
+	/* now link IC PRP-->MEM to MEM-->IC PRP ROT */
+	ipu_link_prp_enc_rot_enc(dev->ipu);
+
+	/* enable the IC and IRT */
+	ipu_ic_enable(priv->ic_enc);
+	ipu_irt_enable(priv->irt);
+
+	/* set buffers ready */
+	ipu_idmac_select_buffer(priv->enc_ch, 0);
+	ipu_idmac_select_buffer(priv->enc_ch, 1);
+	ipu_idmac_select_buffer(priv->enc_rot_out_ch, 0);
+	ipu_idmac_select_buffer(priv->enc_rot_out_ch, 1);
+
+	/* enable the channels */
+	ipu_idmac_enable_channel(priv->enc_ch);
+	ipu_idmac_enable_channel(priv->enc_rot_in_ch);
+	ipu_idmac_enable_channel(priv->enc_rot_out_ch);
+
+	/* and finally enable the IC PRPENC task */
+	ipu_ic_task_enable(priv->ic_enc);
+
+	return 0;
+
+free_rot1:
+	encoder_free_dma_buf(priv, &priv->rot_buf[1]);
+free_rot0:
+	encoder_free_dma_buf(priv, &priv->rot_buf[0]);
+free_underrun:
+	encoder_free_dma_buf(priv, &priv->underrun_buf);
+	return err;
+}
+
+static int encoder_setup_norotation(struct encoder_priv *priv,
+				    dma_addr_t phys0, dma_addr_t phys1,
+				    struct v4l2_mbus_framefmt *inf,
+				    struct v4l2_pix_format *outf)
+{
+	struct mx6cam_dev *dev = priv->dev;
+	enum ipu_color_space in_cs, out_cs;
+	int out_size = (outf->width * outf->height *
+			ipu_bits_per_pixel(outf->pixelformat)) >> 3;
+	int err;
+
+	err = encoder_alloc_dma_buf(priv, &priv->underrun_buf, out_size);
+	if (err) {
+		v4l2_err(&priv->sd, "failed to alloc underrun_buf, %d\n", err);
+		return err;
+	}
+
+	in_cs = ipu_mbus_code_to_colorspace(inf->code);
+	out_cs = ipu_pixelformat_to_colorspace(outf->pixelformat);
+
+	if (dev->using_ic) {
+		err = ipu_ic_task_init(priv->ic_enc,
+				       inf->width, inf->height,
+				       outf->width, outf->height,
+				       in_cs, out_cs);
+		if (err) {
+			v4l2_err(&priv->sd, "ipu_ic_task_init failed, %d\n",
+				 err);
+			goto free_underrun;
+		}
+	}
+
+	/* init the IC PRP-->MEM IDMAC channel */
+	encoder_setup_channel(priv, priv->enc_ch, outf,
+			      dev->rot_mode, phys0, phys1, false);
+
+	if (dev->using_ic)
+		ipu_ic_enable(priv->ic_enc);
+	else
+		ipu_smfc_enable(priv->smfc);
+
+	/* set buffers ready */
+	ipu_idmac_select_buffer(priv->enc_ch, 0);
+	ipu_idmac_select_buffer(priv->enc_ch, 1);
+
+	/* enable the channels */
+	ipu_idmac_enable_channel(priv->enc_ch);
+
+	if (dev->using_ic) {
+		/* enable the IC ENCODE task */
+		ipu_ic_task_enable(priv->ic_enc);
+	}
+
+	return 0;
+
+free_underrun:
+	encoder_free_dma_buf(priv, &priv->underrun_buf);
+	return err;
+}
+
+static int encoder_start(struct encoder_priv *priv)
+{
+	struct mx6cam_dev *dev = priv->dev;
+	struct mx6cam_ctx *ctx = dev->io_ctx;
+	struct v4l2_mbus_framefmt inf;
+	struct v4l2_pix_format outf;
+	struct mx6cam_buffer *frame, *tmp;
+	dma_addr_t phys[2];
+	int i = 0, err;
+
+	err = encoder_get_ipu_resources(priv);
+	if (err)
+		return err;
+
+	phys[0] = phys[1] = 0;
+	list_for_each_entry_safe(frame, tmp, &ctx->ready_q, list) {
+		phys[i] = vb2_dma_contig_plane_dma_addr(&frame->vb, 0);
+		list_del(&frame->list);
+		priv->active_frame[i++] = frame;
+		if (i >= 2)
+			break;
+	}
+
+	/* if preview is enabled it has already setup the CSI */
+	if (!dev->preview_on)
+		encoder_setup_csi(priv);
+
+	inf = dev->sensor_fmt;
+	inf.width = dev->crop.width;
+	inf.height = dev->crop.height;
+	outf = dev->user_fmt.fmt.pix;
+
+	priv->buf_num = 0;
+
+	if (dev->rot_mode >= IPU_ROTATE_90_RIGHT)
+		err = encoder_setup_rotation(priv, phys[0], phys[1],
+					     &inf, &outf);
+	else
+		err = encoder_setup_norotation(priv, phys[0], phys[1],
+					       &inf, &outf);
+	if (err)
+		goto out_put_ipu;
+
+	priv->nfb4eof_irq = ipu_idmac_channel_irq(dev->ipu,
+						 priv->enc_ch,
+						 IPU_IRQ_NFB4EOF);
+	err = devm_request_irq(dev->dev, priv->nfb4eof_irq,
+			       encoder_nfb4eof_interrupt, 0,
+			       "mx6cam-enc-nfb4eof", priv);
+	if (err) {
+		v4l2_err(&priv->sd,
+			 "Error registering encode NFB4EOF irq: %d\n", err);
+		goto out_put_ipu;
+	}
+
+	if (dev->rot_mode >= IPU_ROTATE_90_RIGHT)
+		priv->eof_irq = ipu_idmac_channel_irq(
+			dev->ipu, priv->enc_rot_out_ch, IPU_IRQ_EOF);
+	else
+		priv->eof_irq = ipu_idmac_channel_irq(
+			dev->ipu, priv->enc_ch, IPU_IRQ_EOF);
+
+	err = devm_request_irq(dev->dev, priv->eof_irq,
+			       encoder_eof_interrupt, 0,
+			       "mx6cam-enc-eof", priv);
+	if (err) {
+		v4l2_err(&priv->sd,
+			 "Error registering encode eof irq: %d\n", err);
+		goto out_free_nfb4eof_irq;
+	}
+
+	err = ipu_csi_enable(priv->csi);
+	if (err) {
+		v4l2_err(&priv->sd, "CSI enable error: %d\n", err);
+		goto out_free_eof_irq;
+	}
+
+	/* start the EOF timeout timer */
+	mod_timer(&priv->eof_timeout_timer,
+		  jiffies + msecs_to_jiffies(MX6CAM_EOF_TIMEOUT));
+
+	return 0;
+
+out_free_eof_irq:
+	devm_free_irq(dev->dev, priv->eof_irq, priv);
+out_free_nfb4eof_irq:
+	devm_free_irq(dev->dev, priv->nfb4eof_irq, priv);
+out_put_ipu:
+	encoder_put_ipu_resources(priv);
+	return err;
+}
+
+static int encoder_stop(struct encoder_priv *priv)
+{
+	struct mx6cam_dev *dev = priv->dev;
+	struct mx6cam_buffer *frame;
+	struct timeval cur_time;
+	int i, ret;
+
+	/* stop the EOF timeout timer */
+	del_timer_sync(&priv->eof_timeout_timer);
+
+	/*
+	 * Mark next EOF interrupt as the last before encoder off,
+	 * and then wait for interrupt handler to mark completion.
+	 */
+	init_completion(&priv->last_eof_comp);
+	priv->last_eof = true;
+	ret = wait_for_completion_timeout(&priv->last_eof_comp,
+					  msecs_to_jiffies(MX6CAM_EOF_TIMEOUT));
+	if (ret == 0)
+		v4l2_warn(&priv->sd, "wait last encode EOF timeout\n");
+
+	ipu_csi_disable(priv->csi);
+
+	devm_free_irq(dev->dev, priv->eof_irq, priv);
+	devm_free_irq(dev->dev, priv->nfb4eof_irq, priv);
+
+	/* disable IC tasks and the channels */
+	if (dev->using_ic)
+		ipu_ic_task_disable(priv->ic_enc);
+
+	ipu_idmac_disable_channel(priv->enc_ch);
+	if (dev->rot_mode >= IPU_ROTATE_90_RIGHT) {
+		ipu_idmac_disable_channel(priv->enc_rot_in_ch);
+		ipu_idmac_disable_channel(priv->enc_rot_out_ch);
+	}
+
+	if (dev->rot_mode >= IPU_ROTATE_90_RIGHT)
+		ipu_unlink_prp_enc_rot_enc(dev->ipu);
+
+	if (dev->using_ic)
+		ipu_ic_disable(priv->ic_enc);
+	else
+		ipu_smfc_disable(priv->smfc);
+
+	if (dev->rot_mode >= IPU_ROTATE_90_RIGHT)
+		ipu_irt_disable(priv->irt);
+
+	encoder_free_dma_buf(priv, &priv->rot_buf[0]);
+	encoder_free_dma_buf(priv, &priv->rot_buf[1]);
+	encoder_free_dma_buf(priv, &priv->underrun_buf);
+
+	encoder_put_ipu_resources(priv);
+
+	/* return any remaining active frames with error */
+	for (i = 0; i < 2; i++) {
+		frame = priv->active_frame[i];
+		if (frame && frame->vb.state == VB2_BUF_STATE_ACTIVE) {
+			do_gettimeofday(&cur_time);
+			frame->vb.v4l2_buf.timestamp = cur_time;
+			vb2_buffer_done(&frame->vb, VB2_BUF_STATE_ERROR);
+		}
+	}
+
+	return 0;
+}
+
+static int encoder_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct encoder_priv *priv = v4l2_get_subdevdata(sd);
+
+	if (enable)
+		return encoder_start(priv);
+	else
+		return encoder_stop(priv);
+}
+
+static struct v4l2_subdev_video_ops encoder_video_ops = {
+	.s_stream = encoder_s_stream,
+};
+
+static struct v4l2_subdev_ops encoder_subdev_ops = {
+	.video = &encoder_video_ops,
+};
+
+struct v4l2_subdev *mx6cam_encoder_init(struct mx6cam_dev *dev)
+{
+	struct encoder_priv *priv;
+
+	priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return ERR_PTR(-ENOMEM);
+
+	init_timer(&priv->eof_timeout_timer);
+	priv->eof_timeout_timer.data = (unsigned long)priv;
+	priv->eof_timeout_timer.function = encoder_eof_timeout;
+
+	v4l2_subdev_init(&priv->sd, &encoder_subdev_ops);
+	strlcpy(priv->sd.name, "mx6-camera-encoder", sizeof(priv->sd.name));
+	v4l2_set_subdevdata(&priv->sd, priv);
+
+	priv->dev = dev;
+	return &priv->sd;
+}
diff --git a/drivers/staging/media/imx6/capture/mx6-preview.c b/drivers/staging/media/imx6/capture/mx6-preview.c
new file mode 100644
index 0000000..01d1e54
--- /dev/null
+++ b/drivers/staging/media/imx6/capture/mx6-preview.c
@@ -0,0 +1,748 @@
+/*
+ * V4L2 Preview Subdev for Freescale i.MX6 SOC
+ *
+ * Copyright (c) 2012-2014 Mentor Graphics Inc.
+ * Copyright 2004-2012 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.
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-of.h>
+#include <media/v4l2-ctrls.h>
+#include <linux/platform_data/imx-ipu-v3.h>
+#include <media/imx6.h>
+#include "mx6-camif.h"
+
+struct preview_priv {
+	struct mx6cam_dev    *dev;
+	struct v4l2_subdev    sd;
+	struct v4l2_ctrl_handler ctrl_hdlr;
+
+	struct ipuv3_channel *preview_ch;
+	struct ipuv3_channel *preview_rot_in_ch;
+	struct ipuv3_channel *preview_rot_out_ch;
+	struct ipu_ic *ic_vf;
+	struct ipu_irt *irt;
+	struct ipu_csi *csi;
+
+	/* v4l2 controls */
+	int                   rotation; /* degrees */
+	bool                  hflip;
+	bool                  vflip;
+	/* derived from rotation, hflip, vflip controls */
+	enum ipu_rotate_mode  rot_mode;
+
+	struct timer_list eof_timeout_timer;
+	int eof_irq;
+	int nfb4eof_irq;
+
+	struct mx6cam_dma_buf rot_buf[2];
+	int buf_num;
+
+	bool preview_active;
+	bool last_eof;  /* waiting for last EOF at preview off */
+	struct completion last_eof_comp;
+};
+
+/*
+ * Update the CSI whole sensor and active windows, and initialize
+ * the CSI interface and muxes.
+ */
+static void preview_setup_csi(struct preview_priv *priv)
+{
+	struct mx6cam_dev *dev = priv->dev;
+
+	ipu_csi_set_window_size(priv->csi, dev->crop.width, dev->crop.height);
+	ipu_csi_set_window_pos(priv->csi, dev->crop.left, dev->crop.top);
+	ipu_csi_init_interface(priv->csi, dev->crop_bounds.width,
+			       dev->crop_bounds.height, &dev->ep->csi_sig_cfg);
+
+	if (dev->ep->ep.bus_type == V4L2_MBUS_CSI2)
+		ipu_csi_set_mipi_datatype(priv->csi, dev->ep->ep.base.id,
+					  &dev->ep->csi_sig_cfg);
+
+	/* select either parallel or MIPI-CSI2 as input to our CSI */
+	ipu_csi_set_src(priv->csi, dev->ep->ep.base.id,
+			dev->ep->ep.bus_type == V4L2_MBUS_CSI2);
+	/* set CSI destination to IC */
+	ipu_csi_set_dest(priv->csi, true);
+}
+
+static void preview_put_ipu_resources(struct preview_priv *priv)
+{
+	if (!IS_ERR_OR_NULL(priv->irt))
+		ipu_irt_put(priv->irt);
+	priv->irt = NULL;
+
+	if (!IS_ERR_OR_NULL(priv->ic_vf))
+		ipu_ic_put(priv->ic_vf);
+	priv->ic_vf = NULL;
+
+	if (!IS_ERR_OR_NULL(priv->preview_ch))
+		ipu_idmac_put(priv->preview_ch);
+	priv->preview_ch = NULL;
+
+	if (!IS_ERR_OR_NULL(priv->preview_rot_in_ch))
+		ipu_idmac_put(priv->preview_rot_in_ch);
+	priv->preview_rot_in_ch = NULL;
+
+	if (!IS_ERR_OR_NULL(priv->preview_rot_out_ch))
+		ipu_idmac_put(priv->preview_rot_out_ch);
+	priv->preview_rot_out_ch = NULL;
+
+	if (!IS_ERR_OR_NULL(priv->csi))
+		ipu_csi_put(priv->csi);
+	priv->csi = NULL;
+}
+
+static int preview_get_ipu_resources(struct preview_priv *priv)
+{
+	struct mx6cam_dev *dev = priv->dev;
+	int csi_id, err;
+
+	csi_id = dev->ep->ep.base.port;
+	priv->csi = ipu_csi_get(dev->ipu, csi_id);
+	if (IS_ERR(priv->csi)) {
+		v4l2_err(&priv->sd, "failed to get CSI %d\n", csi_id);
+		return PTR_ERR(priv->csi);
+	}
+
+	priv->ic_vf = ipu_ic_get(dev->ipu, IC_TASK_VIEWFINDER);
+	if (IS_ERR(priv->ic_vf)) {
+		v4l2_err(&priv->sd, "failed to get IC VF\n");
+		err = PTR_ERR(priv->ic_vf);
+		goto out;
+	}
+
+	priv->irt = ipu_irt_get(dev->ipu);
+	if (IS_ERR(priv->irt)) {
+		v4l2_err(&priv->sd, "failed to get IRT\n");
+		err = PTR_ERR(priv->irt);
+		goto out;
+	}
+
+	priv->preview_ch = ipu_idmac_get(dev->ipu,
+					 IPUV3_CHANNEL_IC_PRP_VF_MEM);
+	if (IS_ERR(priv->preview_ch)) {
+		v4l2_err(&priv->sd, "could not get IDMAC channel %u\n",
+			 IPUV3_CHANNEL_IC_PRP_VF_MEM);
+		err = PTR_ERR(priv->preview_ch);
+		goto out;
+	}
+
+	priv->preview_rot_in_ch = ipu_idmac_get(dev->ipu,
+						IPUV3_CHANNEL_MEM_ROT_VF);
+	if (IS_ERR(priv->preview_rot_in_ch)) {
+		v4l2_err(&priv->sd, "could not get IDMAC channel %u\n",
+			 IPUV3_CHANNEL_MEM_ROT_ENC);
+		err = PTR_ERR(priv->preview_rot_in_ch);
+		goto out;
+	}
+
+	priv->preview_rot_out_ch = ipu_idmac_get(dev->ipu,
+						 IPUV3_CHANNEL_ROT_VF_MEM);
+	if (IS_ERR(priv->preview_rot_out_ch)) {
+		v4l2_err(&priv->sd, "could not get IDMAC channel %u\n",
+			 IPUV3_CHANNEL_ROT_ENC_MEM);
+		err = PTR_ERR(priv->preview_rot_out_ch);
+		goto out;
+	}
+
+	return 0;
+out:
+	preview_put_ipu_resources(priv);
+	return err;
+}
+
+static irqreturn_t preview_eof_interrupt(int irq, void *dev_id)
+{
+	struct preview_priv *priv = dev_id;
+
+	if (priv->last_eof) {
+		complete(&priv->last_eof_comp);
+		priv->last_eof = false;
+		return IRQ_HANDLED;
+	}
+
+	/* bump the EOF timeout timer */
+	mod_timer(&priv->eof_timeout_timer,
+		  jiffies + msecs_to_jiffies(MX6CAM_EOF_TIMEOUT));
+
+	if (priv->rot_mode >= IPU_ROTATE_90_RIGHT)
+		ipu_idmac_select_buffer(priv->preview_rot_out_ch,
+					priv->buf_num);
+	else
+		ipu_idmac_select_buffer(priv->preview_ch, priv->buf_num);
+
+	priv->buf_num ^= 1;
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t preview_nfb4eof_interrupt(int irq, void *dev_id)
+{
+	struct preview_priv *priv = dev_id;
+
+	v4l2_err(&priv->sd, "preview NFB4EOF\n");
+
+	/*
+	 * It has been discovered that with rotation, preview disable
+	 * creates a single NFB4EOF event which is 100% repeatable. So
+	 * scheduling a restart here causes an endless NFB4EOF-->restart
+	 * cycle. The error itself seems innocuous, capture is not adversely
+	 * affected.
+	 *
+	 * So don't schedule a restart on NFB4EOF error. If the source
+	 * of the NFB4EOF event on preview disable is ever found, it can
+	 * be re-enabled, but is probably not necessary. Detecting the
+	 * interrupt (and clearing the irq status in the IPU) seems to
+	 * be enough.
+	 */
+#if 0
+	v4l2_subdev_notify(&priv->sd, MX6CAM_NFB4EOF_NOTIFY, NULL);
+#endif
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * EOF timeout timer function.
+ */
+static void preview_eof_timeout(unsigned long data)
+{
+	struct preview_priv *priv = (struct preview_priv *)data;
+
+	v4l2_err(&priv->sd, "preview EOF timeout\n");
+
+	v4l2_subdev_notify(&priv->sd, MX6CAM_EOF_TIMEOUT_NOTIFY, NULL);
+}
+
+static void preview_free_dma_buf(struct preview_priv *priv,
+				 struct mx6cam_dma_buf *buf)
+{
+	struct mx6cam_dev *dev = priv->dev;
+
+	if (buf->virt)
+		dma_free_coherent(dev->dev, buf->len, buf->virt, buf->phys);
+
+	buf->virt = NULL;
+	buf->phys = 0;
+}
+
+static int preview_alloc_dma_buf(struct preview_priv *priv,
+				 struct mx6cam_dma_buf *buf,
+				 int size)
+{
+	struct mx6cam_dev *dev = priv->dev;
+
+	preview_free_dma_buf(priv, buf);
+
+	buf->len = PAGE_ALIGN(size);
+	buf->virt = dma_alloc_coherent(dev->dev, buf->len, &buf->phys,
+				       GFP_DMA | GFP_KERNEL);
+	if (!buf->virt) {
+		v4l2_err(&priv->sd, "failed to alloc dma buffer\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void preview_setup_channel(struct preview_priv *priv,
+				  struct ipuv3_channel *channel,
+				  struct v4l2_pix_format *f,
+				  enum ipu_rotate_mode rot_mode,
+				  dma_addr_t addr0, dma_addr_t addr1,
+				  bool rot_swap_width_height)
+{
+	unsigned int burst_size;
+	u32 width, height, stride;
+	struct ipu_image image;
+
+	if (rot_swap_width_height) {
+		width = f->height;
+		height = f->width;
+	} else {
+		width = f->width;
+		height = f->height;
+	}
+	stride = ipu_stride_to_bytes(width, f->pixelformat);
+
+	ipu_cpmem_zero(channel);
+
+	memset(&image, 0, sizeof(image));
+	image.pix.width = image.rect.width = width;
+	image.pix.height = image.rect.height = height;
+	image.pix.bytesperline = stride;
+	image.pix.pixelformat = f->pixelformat;
+	image.phys0 = addr0;
+	image.phys1 = addr1;
+	ipu_cpmem_set_image(channel, &image);
+
+	if (rot_mode)
+		ipu_cpmem_set_rotation(channel, rot_mode);
+
+	if (channel == priv->preview_rot_in_ch ||
+	    channel == priv->preview_rot_out_ch) {
+		burst_size = 8;
+		ipu_cpmem_set_block_mode(channel);
+	} else
+		burst_size = (width % 16) ? 8 : 16;
+
+	ipu_cpmem_set_burstsize(channel, burst_size);
+
+	if (ipu_csi_is_interlaced(priv->csi) && channel == priv->preview_ch)
+		ipu_cpmem_interlaced_scan(channel, stride);
+
+	ipu_ic_task_idma_init(priv->ic_vf, channel, width, height,
+			      burst_size, rot_mode);
+
+	ipu_cpmem_set_axi_id(channel, 1);
+
+	ipu_idmac_set_double_buffer(channel, true);
+}
+
+static int preview_setup_rotation(struct preview_priv *priv,
+				  dma_addr_t phys0, dma_addr_t phys1,
+				  struct v4l2_mbus_framefmt *inf,
+				  struct v4l2_pix_format *outf)
+{
+	struct mx6cam_dev *dev = priv->dev;
+	enum ipu_color_space in_cs, out_cs;
+	int out_size = (outf->width * outf->height *
+			ipu_bits_per_pixel(outf->pixelformat)) >> 3;
+	int err;
+
+	err = preview_alloc_dma_buf(priv, &priv->rot_buf[0], out_size);
+	if (err) {
+		v4l2_err(&priv->sd, "failed to alloc rot_buf[0], %d\n", err);
+		return err;
+	}
+	err = preview_alloc_dma_buf(priv, &priv->rot_buf[1], out_size);
+	if (err) {
+		v4l2_err(&priv->sd, "failed to alloc rot_buf[1], %d\n", err);
+		goto free_rot0;
+	}
+
+	in_cs = ipu_mbus_code_to_colorspace(inf->code);
+	out_cs = ipu_pixelformat_to_colorspace(outf->pixelformat);
+
+	err = ipu_ic_task_init(priv->ic_vf,
+			       inf->width, inf->height,
+			       outf->height, outf->width,
+			       in_cs, out_cs);
+	if (err) {
+		v4l2_err(&priv->sd, "ipu_ic_task_init failed, %d\n", err);
+		goto free_rot1;
+	}
+
+	/* init the IC PREVIEW-->MEM IDMAC channel */
+	preview_setup_channel(priv, priv->preview_ch, outf,
+			      IPU_ROTATE_NONE,
+			      priv->rot_buf[0].phys,
+			      priv->rot_buf[1].phys,
+			      true);
+
+	/* init the MEM-->IC PREVIEW ROT IDMAC channel */
+	preview_setup_channel(priv, priv->preview_rot_in_ch, outf,
+			      priv->rot_mode,
+			      priv->rot_buf[0].phys,
+			      priv->rot_buf[1].phys,
+			      true);
+
+	/* init the destination IC PREVIEW ROT-->MEM IDMAC channel */
+	preview_setup_channel(priv, priv->preview_rot_out_ch, outf,
+			      IPU_ROTATE_NONE,
+			      phys0, phys1,
+			      false);
+
+	/* now link IC PREVIEW-->MEM to MEM-->IC PREVIEW ROT */
+	ipu_link_prpvf_rot_prpvf(dev->ipu);
+
+	/* enable the IC and IRT */
+	ipu_ic_enable(priv->ic_vf);
+	ipu_irt_enable(priv->irt);
+
+	/* set buffers ready */
+	ipu_idmac_select_buffer(priv->preview_ch, 0);
+	ipu_idmac_select_buffer(priv->preview_ch, 1);
+	ipu_idmac_select_buffer(priv->preview_rot_out_ch, 0);
+	ipu_idmac_select_buffer(priv->preview_rot_out_ch, 1);
+
+	/* enable the channels */
+	ipu_idmac_enable_channel(priv->preview_ch);
+	ipu_idmac_enable_channel(priv->preview_rot_in_ch);
+	ipu_idmac_enable_channel(priv->preview_rot_out_ch);
+
+	/* and finally enable the IC PREVIEW task */
+	ipu_ic_task_enable(priv->ic_vf);
+
+	return 0;
+
+free_rot1:
+	preview_free_dma_buf(priv, &priv->rot_buf[1]);
+free_rot0:
+	preview_free_dma_buf(priv, &priv->rot_buf[0]);
+	return err;
+}
+
+static int preview_setup_norotation(struct preview_priv *priv,
+				    dma_addr_t phys0, dma_addr_t phys1,
+				    struct v4l2_mbus_framefmt *inf,
+				    struct v4l2_pix_format *outf)
+{
+	enum ipu_color_space in_cs, out_cs;
+	int err;
+
+	in_cs = ipu_mbus_code_to_colorspace(inf->code);
+	out_cs = ipu_pixelformat_to_colorspace(outf->pixelformat);
+
+	err = ipu_ic_task_init(priv->ic_vf,
+			       inf->width, inf->height,
+			       outf->width, outf->height,
+			       in_cs, out_cs);
+	if (err) {
+		v4l2_err(&priv->sd, "ipu_ic_task_init failed, %d\n", err);
+		return err;
+	}
+
+	/* init the IC PREVIEW-->MEM IDMAC channel */
+	preview_setup_channel(priv, priv->preview_ch, outf,
+			      priv->rot_mode, phys0, phys1, false);
+
+	ipu_ic_enable(priv->ic_vf);
+
+	/* set buffers ready */
+	ipu_idmac_select_buffer(priv->preview_ch, 0);
+	ipu_idmac_select_buffer(priv->preview_ch, 1);
+
+	/* enable the channels */
+	ipu_idmac_enable_channel(priv->preview_ch);
+
+	/* and finally enable the IC PREVIEW task */
+	ipu_ic_task_enable(priv->ic_vf);
+
+	return 0;
+}
+
+static int preview_start(struct preview_priv *priv)
+{
+	struct mx6cam_dev *dev = priv->dev;
+	struct v4l2_mbus_framefmt inf;
+	struct v4l2_pix_format outf;
+	dma_addr_t fb_buf;
+	int err = 0;
+
+	if (priv->preview_active) {
+		v4l2_warn(&priv->sd, "preview already started\n");
+		return 0;
+	}
+
+	err = preview_get_ipu_resources(priv);
+	if (err)
+		return err;
+
+	/* if encoder is enabled it has already setup the CSI */
+	if (!dev->encoder_on)
+		preview_setup_csi(priv);
+
+	inf = dev->sensor_fmt;
+	inf.width = dev->crop.width;
+	inf.height = dev->crop.height;
+	outf.width = dev->win.w.width;
+	outf.height = dev->win.w.height;
+	outf.pixelformat = dev->fbuf.fmt.pixelformat;
+
+	fb_buf = (dma_addr_t)dev->fbuf.base;
+
+	priv->buf_num = 0;
+
+	if (priv->rot_mode >= IPU_ROTATE_90_RIGHT)
+		err = preview_setup_rotation(priv, fb_buf, fb_buf,
+					     &inf, &outf);
+	else
+		err = preview_setup_norotation(priv, fb_buf, fb_buf,
+					       &inf, &outf);
+	if (err)
+		goto out_put_ipu;
+
+	priv->nfb4eof_irq = ipu_idmac_channel_irq(dev->ipu,
+						  priv->preview_ch,
+						  IPU_IRQ_NFB4EOF);
+	err = devm_request_irq(dev->dev, priv->nfb4eof_irq,
+			       preview_nfb4eof_interrupt, 0,
+			       "mx6cam-preview-nfb4eof", priv);
+	if (err) {
+		v4l2_err(&priv->sd,
+			 "Error registering preview NFB4EOF irq: %d\n", err);
+		goto out_put_ipu;
+	}
+
+	if (priv->rot_mode >= IPU_ROTATE_90_RIGHT)
+		priv->eof_irq = ipu_idmac_channel_irq(dev->ipu,
+						      priv->preview_rot_out_ch,
+						      IPU_IRQ_EOF);
+	else
+		priv->eof_irq = ipu_idmac_channel_irq(dev->ipu,
+						      priv->preview_ch,
+						      IPU_IRQ_EOF);
+
+	err = devm_request_irq(dev->dev, priv->eof_irq,
+			       preview_eof_interrupt, 0,
+			       "mx6cam-preview-eof", priv);
+	if (err) {
+		v4l2_err(&priv->sd,
+			 "Error registering preview eof irq: %d\n", err);
+		goto out_free_nfb4eof_irq;
+	}
+
+	err = ipu_csi_enable(priv->csi);
+	if (err) {
+		v4l2_err(&priv->sd, "CSI enable error: %d\n", err);
+		goto out_free_eof_irq;
+	}
+
+	priv->preview_active = true;
+
+	/* start the VF EOF timeout timer */
+	mod_timer(&priv->eof_timeout_timer,
+		  jiffies + msecs_to_jiffies(MX6CAM_EOF_TIMEOUT));
+
+	return 0;
+
+out_free_eof_irq:
+	devm_free_irq(dev->dev, priv->eof_irq, priv);
+out_free_nfb4eof_irq:
+	devm_free_irq(dev->dev, priv->nfb4eof_irq, priv);
+out_put_ipu:
+	preview_put_ipu_resources(priv);
+	return err;
+}
+
+static int preview_stop(struct preview_priv *priv)
+{
+	struct mx6cam_dev *dev = priv->dev;
+	int ret;
+
+	if (!priv->preview_active)
+		return 0;
+
+	/* stop the VF EOF timeout timer */
+	del_timer_sync(&priv->eof_timeout_timer);
+
+	/*
+	 * Mark next EOF interrupt as the last before preview off,
+	 * and then wait for interrupt handler to mark completion.
+	 */
+	init_completion(&priv->last_eof_comp);
+	priv->last_eof = true;
+	ret = wait_for_completion_timeout(&priv->last_eof_comp,
+					  msecs_to_jiffies(MX6CAM_EOF_TIMEOUT));
+	if (ret == 0)
+		v4l2_warn(&priv->sd, "wait last preview EOF timeout\n");
+
+	ipu_csi_disable(priv->csi);
+
+	devm_free_irq(dev->dev, priv->eof_irq, priv);
+	devm_free_irq(dev->dev, priv->nfb4eof_irq, priv);
+
+	/* disable IC tasks and the channels */
+	ipu_ic_task_disable(priv->ic_vf);
+
+	ipu_idmac_disable_channel(priv->preview_ch);
+	if (priv->rot_mode >= IPU_ROTATE_90_RIGHT) {
+		ipu_idmac_disable_channel(priv->preview_rot_in_ch);
+		ipu_idmac_disable_channel(priv->preview_rot_out_ch);
+	}
+
+	if (priv->rot_mode >= IPU_ROTATE_90_RIGHT)
+		ipu_unlink_prpvf_rot_prpvf(dev->ipu);
+
+	ipu_ic_disable(priv->ic_vf);
+	if (priv->rot_mode >= IPU_ROTATE_90_RIGHT)
+		ipu_irt_disable(priv->irt);
+
+	preview_free_dma_buf(priv, &priv->rot_buf[0]);
+	preview_free_dma_buf(priv, &priv->rot_buf[1]);
+
+	preview_put_ipu_resources(priv);
+
+	priv->preview_active = false;
+	return 0;
+}
+
+static int preview_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct preview_priv *priv = v4l2_get_subdevdata(sd);
+
+	if (enable)
+		return preview_start(priv);
+	else
+		return preview_stop(priv);
+}
+
+static void preview_unregistered(struct v4l2_subdev *sd)
+{
+	struct preview_priv *priv = v4l2_get_subdevdata(sd);
+
+	v4l2_ctrl_handler_free(&priv->ctrl_hdlr);
+}
+
+/* Controls */
+
+static int preview_set_rotation(struct preview_priv *priv,
+				int rotation, bool hflip, bool vflip)
+{
+	struct mx6cam_dev *dev = priv->dev;
+	enum ipu_rotate_mode rot_mode;
+	int ret;
+
+	ret = ipu_degrees_to_rot_mode(&rot_mode, rotation,
+				      hflip, vflip);
+	if (ret)
+		return ret;
+
+	priv->rotation = rotation;
+	priv->hflip = hflip;
+	priv->vflip = vflip;
+
+	if (rot_mode != priv->rot_mode) {
+		if (dev->preview_on)
+			preview_stop(priv);
+		priv->rot_mode = rot_mode;
+		if (dev->preview_on)
+			preview_start(priv);
+	}
+
+	return 0;
+}
+
+static int preview_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct preview_priv *priv = container_of(ctrl->handler,
+						 struct preview_priv,
+						 ctrl_hdlr);
+	struct mx6cam_dev *dev = priv->dev;
+	bool hflip, vflip;
+	int rotation;
+
+	rotation = priv->rotation;
+	hflip = priv->hflip;
+	vflip = priv->vflip;
+
+	switch (ctrl->id) {
+	case V4L2_CID_HFLIP:
+		hflip = (ctrl->val == 1);
+		break;
+	case V4L2_CID_VFLIP:
+		vflip = (ctrl->val == 1);
+		break;
+	case V4L2_CID_ROTATE:
+		rotation = ctrl->val;
+		break;
+	default:
+
+		v4l2_err(&dev->v4l2_dev, "Invalid control\n");
+		return -EINVAL;
+	}
+
+	return preview_set_rotation(priv, rotation, hflip, vflip);
+}
+
+static const struct v4l2_ctrl_ops preview_ctrl_ops = {
+	.s_ctrl = preview_s_ctrl,
+};
+
+static int preview_setup_controls(struct preview_priv *priv)
+{
+	struct v4l2_ctrl_handler *hdlr = &priv->ctrl_hdlr;
+	int ret;
+
+	v4l2_ctrl_handler_init(hdlr, 3);
+
+	v4l2_ctrl_new_std(hdlr, &preview_ctrl_ops, V4L2_CID_HFLIP,
+			  0, 1, 1, 0);
+	v4l2_ctrl_new_std(hdlr, &preview_ctrl_ops, V4L2_CID_VFLIP,
+			  0, 1, 1, 0);
+	v4l2_ctrl_new_std(hdlr, &preview_ctrl_ops, V4L2_CID_ROTATE,
+			  0, 270, 90, 0);
+
+	priv->sd.ctrl_handler = hdlr;
+
+	if (hdlr->error) {
+		ret = hdlr->error;
+		v4l2_ctrl_handler_free(hdlr);
+		return ret;
+	}
+
+	v4l2_ctrl_handler_setup(hdlr);
+
+	return 0;
+}
+
+static struct v4l2_subdev_core_ops preview_core_ops = {
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
+};
+
+static struct v4l2_subdev_video_ops preview_video_ops = {
+	.s_stream = preview_s_stream,
+};
+
+static struct v4l2_subdev_ops preview_subdev_ops = {
+	.core = &preview_core_ops,
+	.video = &preview_video_ops,
+};
+
+static struct v4l2_subdev_internal_ops preview_internal_ops = {
+	.unregistered = preview_unregistered,
+};
+
+struct v4l2_subdev *mx6cam_preview_init(struct mx6cam_dev *dev)
+{
+	struct preview_priv *priv;
+	int ret;
+
+	priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return ERR_PTR(-ENOMEM);
+
+	init_timer(&priv->eof_timeout_timer);
+	priv->eof_timeout_timer.data = (unsigned long)priv;
+	priv->eof_timeout_timer.function = preview_eof_timeout;
+
+	v4l2_subdev_init(&priv->sd, &preview_subdev_ops);
+	strlcpy(priv->sd.name, "mx6-camera-preview", sizeof(priv->sd.name));
+	v4l2_set_subdevdata(&priv->sd, priv);
+	priv->sd.internal_ops = &preview_internal_ops;
+	priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	ret = preview_setup_controls(priv);
+	if (ret) {
+		kfree(priv);
+		return ERR_PTR(ret);
+	}
+
+	priv->dev = dev;
+	return &priv->sd;
+}
diff --git a/include/media/imx6.h b/include/media/imx6.h
new file mode 100644
index 0000000..232378b
--- /dev/null
+++ b/include/media/imx6.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2014 Mentor Graphics 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
+ */
+
+#ifndef __MEDIA_IMX6_H__
+#define __MEDIA_IMX6_H__
+
+/*
+ * Analog decoder status change notifications
+ */
+#define DECODER_STATUS_CHANGE_NOTIFY  _IO('7', 0)
+
+#endif
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 40/43] media: imx6: Add support for MIPI CSI-2 OV5640
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (38 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 39/43] media: Add new camera interface driver for i.MX6 Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-11 11:39   ` Philipp Zabel
  2014-06-07 21:56 ` [PATCH 41/43] media: imx6: Add support for Parallel OV5642 Steve Longerbeam
                   ` (4 subsequent siblings)
  44 siblings, 1 reply; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

This driver is based on ov5640_mipi.c from Freescale imx_3.10.17_1.0.0_beta
branch, modified heavily for code cleanup and converted from int-device
to subdev.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/media/imx6/capture/Kconfig       |    8 +
 drivers/staging/media/imx6/capture/Makefile      |    1 +
 drivers/staging/media/imx6/capture/ov5640-mipi.c | 2158 ++++++++++++++++++++++
 3 files changed, 2167 insertions(+)
 create mode 100644 drivers/staging/media/imx6/capture/ov5640-mipi.c

diff --git a/drivers/staging/media/imx6/capture/Kconfig b/drivers/staging/media/imx6/capture/Kconfig
index ee4f017..6d81e3f 100644
--- a/drivers/staging/media/imx6/capture/Kconfig
+++ b/drivers/staging/media/imx6/capture/Kconfig
@@ -8,4 +8,12 @@ config IMX6_MIPI_CSI2
          MIPI CSI-2 Receiver driver support. This driver is required
 	 for sensor drivers with a MIPI CSI2 interface.
 
+config IMX6_CAMERA_OV5640_MIPI
+       tristate "OmniVision OV5640 MIPI CSI-2 camera support"
+       depends on VIDEO_IMX6_CAMERA
+       select IMX6_MIPI_CSI2
+       default y
+       ---help---
+         MIPI CSI-2 OV5640 Camera support.
+
 endmenu
diff --git a/drivers/staging/media/imx6/capture/Makefile b/drivers/staging/media/imx6/capture/Makefile
index 832d75d..6aaa4cc 100644
--- a/drivers/staging/media/imx6/capture/Makefile
+++ b/drivers/staging/media/imx6/capture/Makefile
@@ -2,3 +2,4 @@ mx6-camera-objs := mx6-camif.o mx6-encode.o mx6-preview.o
 
 obj-$(CONFIG_VIDEO_IMX6_CAMERA) += mx6-camera.o
 obj-$(CONFIG_IMX6_MIPI_CSI2) += mipi-csi2.o
+obj-$(CONFIG_IMX6_CAMERA_OV5640_MIPI) += ov5640-mipi.o
diff --git a/drivers/staging/media/imx6/capture/ov5640-mipi.c b/drivers/staging/media/imx6/capture/ov5640-mipi.c
new file mode 100644
index 0000000..3910bc7
--- /dev/null
+++ b/drivers/staging/media/imx6/capture/ov5640-mipi.c
@@ -0,0 +1,2158 @@
+/*
+ * Copyright (c) 2014 Mentor Graphics Inc.
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/types.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-of.h>
+#include <media/v4l2-ctrls.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
+
+/* min/typical/max system clock (xclk) frequencies */
+#define OV5640_XCLK_MIN  6000000
+#define OV5640_XCLK_TYP 24000000
+#define OV5640_XCLK_MAX 54000000
+
+/* min/typical/max pixel clock (mclk) frequencies */
+#define OV5640_MCLK_MIN 48000000
+#define OV5640_MCLK_TYP 48000000
+#define OV5640_MCLK_MAX 96000000
+
+#define OV5640_CHIP_ID  0x300A
+
+#define OV5640_MAX_CONTROLS 64
+
+enum ov5640_mode {
+	ov5640_mode_MIN = 0,
+	ov5640_mode_QCIF_176_144 = 0,
+	ov5640_mode_QVGA_320_240,
+	ov5640_mode_VGA_640_480,
+	ov5640_mode_NTSC_720_480,
+	ov5640_mode_PAL_720_576,
+	ov5640_mode_XGA_1024_768,
+	ov5640_mode_720P_1280_720,
+	ov5640_mode_1080P_1920_1080,
+	ov5640_mode_QSXGA_2592_1944,
+	ov5640_num_modes,
+	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,
+};
+#define ov5640_num_framerates ARRAY_SIZE(ov5640_framerates)
+
+/* image size under 1280 * 960 are SUBSAMPLING
+ * image size upper 1280 * 960 are SCALING
+ */
+enum ov5640_downsize_mode {
+	SUBSAMPLING,
+	SCALING,
+};
+
+struct reg_value {
+	u16 reg_addr;
+	u8 val;
+	u8 mask;
+	u32 delay_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_dev {
+	struct i2c_client *i2c_client;
+	struct device *dev;
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler ctrl_hdl;
+	struct v4l2_of_endpoint ep; /* the parsed DT endpoint info */
+	struct v4l2_mbus_framefmt fmt;
+	struct v4l2_captureparm streamcap;
+	struct clk *xclk; /* system clock to OV5640 */
+	int xclk_freq;    /* requested xclk freq from devicetree */
+
+	enum ov5640_mode current_mode;
+	enum ov5640_frame_rate current_fr;
+
+	bool on;
+	bool awb_on;
+	bool agc_on;
+
+	/* cached control settings */
+	int ctrl_cache[OV5640_MAX_CONTROLS];
+
+	int reset_gpio;
+	int pwdn_gpio;
+	int gp_gpio;
+
+	int prev_sysclk, prev_hts;
+	int ae_low, ae_high, ae_target;
+
+	struct regulator *io_regulator;
+	struct regulator *core_regulator;
+	struct regulator *analog_regulator;
+	struct regulator *gpo_regulator;
+};
+
+static inline struct ov5640_dev *to_ov5640_dev(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct ov5640_dev, sd);
+}
+
+static inline struct ov5640_dev *ctrl_to_ov5640_dev(struct v4l2_ctrl *ctrl)
+{
+	return container_of(ctrl->handler, struct ov5640_dev, ctrl_hdl);
+}
+
+struct ov5640_control {
+	struct v4l2_queryctrl ctrl;
+	int (*set)(struct ov5640_dev *sensor, int value);
+};
+
+static void ov5640_power(struct ov5640_dev *sensor, bool enable);
+static void ov5640_reset(struct ov5640_dev *sensor);
+static int ov5640_restore_ctrls(struct ov5640_dev *sensor);
+static int ov5640_set_agc(struct ov5640_dev *sensor, int value);
+static int ov5640_set_exposure(struct ov5640_dev *sensor, int value);
+static int ov5640_get_exposure(struct ov5640_dev *sensor);
+static int ov5640_set_gain(struct ov5640_dev *sensor, int value);
+static int ov5640_get_gain(struct ov5640_dev *sensor);
+
+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[ov5640_num_framerates][ov5640_num_modes] = {
+	{
+		{ov5640_mode_QCIF_176_144, SUBSAMPLING, 176, 144,
+		 ov5640_setting_15fps_QCIF_176_144,
+		 ARRAY_SIZE(ov5640_setting_15fps_QCIF_176_144)},
+		{ov5640_mode_QVGA_320_240, SUBSAMPLING, 320,  240,
+		 ov5640_setting_15fps_QVGA_320_240,
+		 ARRAY_SIZE(ov5640_setting_15fps_QVGA_320_240)},
+		{ov5640_mode_VGA_640_480, SUBSAMPLING, 640,  480,
+		 ov5640_setting_15fps_VGA_640_480,
+		 ARRAY_SIZE(ov5640_setting_15fps_VGA_640_480)},
+		{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_XGA_1024_768, SUBSAMPLING, 1024, 768,
+		 ov5640_setting_15fps_XGA_1024_768,
+		 ARRAY_SIZE(ov5640_setting_15fps_XGA_1024_768)},
+		{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_30fps_QCIF_176_144,
+		 ARRAY_SIZE(ov5640_setting_30fps_QCIF_176_144)},
+		{ov5640_mode_QVGA_320_240, SUBSAMPLING, 320,  240,
+		 ov5640_setting_30fps_QVGA_320_240,
+		 ARRAY_SIZE(ov5640_setting_30fps_QVGA_320_240)},
+		{ov5640_mode_VGA_640_480, SUBSAMPLING, 640,  480,
+		 ov5640_setting_30fps_VGA_640_480,
+		 ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480)},
+		{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_XGA_1024_768, SUBSAMPLING, 1024, 768,
+		 ov5640_setting_30fps_XGA_1024_768,
+		 ARRAY_SIZE(ov5640_setting_30fps_XGA_1024_768)},
+		{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},
+	},
+};
+
+static int ov5640_probe(struct i2c_client *adapter,
+			const struct i2c_device_id *device_id);
+static int ov5640_remove(struct i2c_client *client);
+
+static int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val)
+{
+	u8 buf[3] = {0};
+	int retval;
+
+	buf[0] = reg >> 8;
+	buf[1] = reg & 0xff;
+	buf[2] = val;
+
+	retval = i2c_master_send(sensor->i2c_client, buf, 3);
+	if (retval < 0) {
+		v4l2_err(&sensor->sd, "%s: error: reg=%x, val=%x\n",
+			__func__, reg, val);
+		return retval;
+	}
+
+	return 0;
+}
+
+static int ov5640_read_reg(struct ov5640_dev *sensor, u16 reg, u8 *val)
+{
+	u8 reg_buf[2] = {0};
+	u8 read_val = 0;
+
+	reg_buf[0] = reg >> 8;
+	reg_buf[1] = reg & 0xff;
+
+	if (2 != i2c_master_send(sensor->i2c_client, reg_buf, 2)) {
+		v4l2_err(&sensor->sd, "%s: write reg error: reg=%x\n",
+			__func__, reg);
+		return -EIO;
+	}
+
+	if (1 != i2c_master_recv(sensor->i2c_client, &read_val, 1)) {
+		v4l2_err(&sensor->sd, "%s: read reg error: reg=%x, val=%x\n",
+			__func__, reg, read_val);
+		return -EIO;
+	}
+
+	if (val)
+		*val = read_val;
+
+	return read_val;
+}
+
+static int ov5640_read_reg16(struct ov5640_dev *sensor, u16 reg, u16 *val)
+{
+	u16 read_val = 0;
+	u8 hi, lo;
+	int ret;
+
+	ret = ov5640_read_reg(sensor, reg, &hi);
+	if (ret < 0)
+		return ret;
+	ret = ov5640_read_reg(sensor, reg+1, &lo);
+	if (ret < 0)
+		return ret;
+
+	read_val = ((u16)hi << 8) | (u16)lo;
+
+	if (val)
+		*val = read_val;
+
+	return read_val;
+}
+
+static int ov5640_write_reg16(struct ov5640_dev *sensor, u16 reg, u16 val)
+{
+	int ret;
+
+	ret = ov5640_write_reg(sensor, reg, val >> 8);
+	if (ret < 0)
+		return ret;
+	return ov5640_write_reg(sensor, reg+1, val & 0xff);
+}
+
+static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg,
+			  u8 mask, u8 val)
+{
+	u8 readval;
+	int retval;
+
+	retval = ov5640_read_reg(sensor, reg, &readval);
+	if (retval < 0)
+		return retval;
+
+	readval &= ~mask;
+	val &= mask;
+	val |= readval;
+
+	return ov5640_write_reg(sensor, reg, val);
+}
+
+/* download ov5640 settings to sensor through i2c */
+static int ov5640_load_regs(struct ov5640_dev *sensor,
+			    struct reg_value *regs,
+			    int size)
+{
+	register u32 delay_ms = 0;
+	register u16 reg_addr = 0;
+	register u8 mask = 0;
+	register u8 val = 0;
+	int i, retval = 0;
+
+	for (i = 0; i < size; ++i, ++regs) {
+		delay_ms = regs->delay_ms;
+		reg_addr = regs->reg_addr;
+		val = regs->val;
+		mask = regs->mask;
+
+		if (mask)
+			retval = ov5640_mod_reg(sensor, reg_addr, mask, val);
+		else
+			retval = ov5640_write_reg(sensor, reg_addr, val);
+		if (retval)
+			break;
+		if (delay_ms)
+			usleep_range(1000*delay_ms, 1000*delay_ms+1);
+	}
+
+	return retval;
+}
+
+static void ov5640_set_stream(struct ov5640_dev *sensor, bool on)
+{
+	ov5640_write_reg(sensor, 0x4202, on ? 0x00 : 0x0f);
+}
+
+static int ov5640_get_sysclk(struct ov5640_dev *sensor)
+{
+	 /* calculate sysclk */
+	int xvclk = sensor->xclk_freq / 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(sensor, 0x3034, &temp);
+	temp2 = temp1 & 0x0f;
+	if (temp2 == 8 || temp2 == 10)
+		bit_div2x = temp2 / 2;
+
+	temp1 = ov5640_read_reg(sensor, 0x3035, &temp);
+	sysdiv = temp1>>4;
+	if (sysdiv == 0)
+		sysdiv = 16;
+
+	temp1 = ov5640_read_reg(sensor, 0x3036, &temp);
+	multiplier = temp1;
+
+	temp1 = ov5640_read_reg(sensor, 0x3037, &temp);
+	prediv = temp1 & 0x0f;
+	pll_rdiv = ((temp1 >> 4) & 0x01) + 1;
+
+	temp1 = ov5640_read_reg(sensor, 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(struct ov5640_dev *sensor)
+{
+	 /* read HTS from register settings */
+	u8 mode;
+
+	ov5640_read_reg(sensor, 0x3a00, &mode);
+	mode &= 0xfb;
+	ov5640_write_reg(sensor, 0x3a00, mode);
+}
+
+static int ov5640_get_HTS(struct ov5640_dev *sensor)
+{
+	 /* read HTS from register settings */
+	u16 HTS;
+
+	ov5640_read_reg16(sensor, 0x380c, &HTS);
+
+	return HTS;
+}
+
+static int ov5640_get_VTS(struct ov5640_dev *sensor)
+{
+	u16 VTS;
+
+	ov5640_read_reg16(sensor, 0x380e, &VTS);
+
+	return VTS;
+}
+
+static int ov5640_set_VTS(struct ov5640_dev *sensor, int VTS)
+{
+	return ov5640_write_reg16(sensor, 0x380e, VTS);
+}
+
+static int ov5640_get_light_freq(struct ov5640_dev *sensor)
+{
+	/* get banding filter value */
+	int temp, temp1, light_freq = 0;
+	u8 tmp;
+
+	temp = ov5640_read_reg(sensor, 0x3c01, &tmp);
+
+	if (temp & 0x80) {
+		/* manual */
+		temp1 = ov5640_read_reg(sensor, 0x3c00, &tmp);
+		if (temp1 & 0x04) {
+			/* 50Hz */
+			light_freq = 50;
+		} else {
+			/* 60Hz */
+			light_freq = 60;
+		}
+	} else {
+		/* auto */
+		temp1 = ov5640_read_reg(sensor, 0x3c0c, &tmp);
+		if (temp1 & 0x01) {
+			/* 50Hz */
+			light_freq = 50;
+		} else {
+			/* 60Hz */
+		}
+	}
+	return light_freq;
+}
+
+static void ov5640_set_bandingfilter(struct ov5640_dev *sensor)
+{
+	int prev_vts;
+	int band_step60, max_band60, band_step50, max_band50;
+
+	/* read preview PCLK */
+	sensor->prev_sysclk = ov5640_get_sysclk(sensor);
+	/* read preview HTS */
+	sensor->prev_hts = ov5640_get_HTS(sensor);
+
+	/* read preview VTS */
+	prev_vts = ov5640_get_VTS(sensor);
+
+	/* calculate banding filter */
+	/* 60Hz */
+	band_step60 = sensor->prev_sysclk * 100 / sensor->prev_hts * 100/120;
+	ov5640_write_reg16(sensor, 0x3a0a, band_step60);
+
+	max_band60 = (int)((prev_vts-4)/band_step60);
+	ov5640_write_reg(sensor, 0x3a0d, max_band60);
+
+	/* 50Hz */
+	band_step50 = sensor->prev_sysclk * 100 / sensor->prev_hts;
+	ov5640_write_reg16(sensor, 0x3a08, band_step50);
+
+	max_band50 = (int)((prev_vts-4)/band_step50);
+	ov5640_write_reg(sensor, 0x3a0e, max_band50);
+}
+
+static int ov5640_set_AE_target(struct ov5640_dev *sensor, int target)
+{
+	/* stable in high */
+	int fast_high, fast_low;
+
+	sensor->ae_low = target * 23 / 25;	/* 0.92 */
+	sensor->ae_high = target * 27 / 25;	/* 1.08 */
+
+	fast_high = sensor->ae_high<<1;
+	if (fast_high > 255)
+		fast_high = 255;
+
+	fast_low = sensor->ae_low >> 1;
+
+	ov5640_write_reg(sensor, 0x3a0f, sensor->ae_high);
+	ov5640_write_reg(sensor, 0x3a10, sensor->ae_low);
+	ov5640_write_reg(sensor, 0x3a1b, sensor->ae_high);
+	ov5640_write_reg(sensor, 0x3a1e, sensor->ae_low);
+	ov5640_write_reg(sensor, 0x3a11, fast_high);
+	ov5640_write_reg(sensor, 0x3a1f, fast_low);
+
+	return 0;
+}
+
+static bool ov5640_binning_on(struct ov5640_dev *sensor)
+{
+	u8 temp;
+	ov5640_read_reg(sensor, 0x3821, &temp);
+	temp &= 0xfe;
+	return temp ? true : false;
+}
+
+static void ov5640_set_virtual_channel(struct ov5640_dev *sensor)
+{
+	u8 temp, channel = sensor->ep.base.id;
+
+	ov5640_read_reg(sensor, 0x4814, &temp);
+	temp &= ~(3 << 6);
+	temp |= (channel << 6);
+	ov5640_write_reg(sensor, 0x4814, temp);
+}
+
+static enum ov5640_mode
+ov5640_find_nearest_mode(struct ov5640_dev *sensor,
+			 int width, int height)
+{
+	int i;
+
+	for (i = ov5640_num_modes - 1; i >= 0; i--) {
+		if (ov5640_mode_info_data[0][i].width <= width &&
+		    ov5640_mode_info_data[0][i].height <= height)
+			break;
+	}
+
+	if (i < 0)
+		i = 0;
+
+	return (enum ov5640_mode)i;
+}
+
+/*
+ * sensor changes between scaling and subsampling, go through
+ * exposure calculation
+ */
+static int ov5640_change_mode_exposure_calc(struct ov5640_dev *sensor,
+					    enum ov5640_frame_rate frame_rate,
+					    enum ov5640_mode mode)
+{
+	struct reg_value *mode_data = NULL;
+	int mode_size = 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 */
+	mode_data = ov5640_mode_info_data[frame_rate][mode].init_data_ptr;
+	mode_size = ov5640_mode_info_data[frame_rate][mode].init_data_size;
+
+	sensor->fmt.width = ov5640_mode_info_data[frame_rate][mode].width;
+	sensor->fmt.height = ov5640_mode_info_data[frame_rate][mode].height;
+
+	if (sensor->fmt.width == 0 || sensor->fmt.height == 0 ||
+	    mode_data == NULL || mode_size == 0)
+		return -EINVAL;
+
+	/* auto focus */
+	/* ov5640_auto_focus();//if no af function, just skip it */
+
+	/* turn off AE/AG */
+	ov5640_set_agc(sensor, false);
+
+	/* read preview shutter */
+	prev_shutter = ov5640_get_exposure(sensor);
+	if (ov5640_binning_on(sensor) &&
+	    mode != ov5640_mode_720P_1280_720 &&
+	    mode != ov5640_mode_1080P_1920_1080)
+		prev_shutter *= 2;
+
+	/* read preview gain */
+	prev_gain16 = ov5640_get_gain(sensor);
+
+	/* get average */
+	ov5640_read_reg(sensor, 0x56a1, &average);
+
+	/* turn off night mode for capture */
+	ov5640_set_night_mode(sensor);
+
+	/* turn off overlay */
+	/* ov5640_write_reg(0x3022, 0x06);//if no af function, just skip it */
+
+	ov5640_set_stream(sensor, false);
+
+	/* Write capture setting */
+	retval = ov5640_load_regs(sensor, mode_data, mode_size);
+	if (retval < 0)
+		goto err;
+
+	/* read capture VTS */
+	cap_vts = ov5640_get_VTS(sensor);
+	cap_hts = ov5640_get_HTS(sensor);
+	cap_sysclk = ov5640_get_sysclk(sensor);
+
+	/* calculate capture banding filter */
+	light_freq = ov5640_get_light_freq(sensor);
+	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 > sensor->ae_low && average < sensor->ae_high) {
+		/* in stable range */
+		cap_gain16_shutter =
+			prev_gain16 * prev_shutter *
+			cap_sysclk / sensor->prev_sysclk *
+			sensor->prev_hts / cap_hts *
+			sensor->ae_target / average;
+	} else {
+		cap_gain16_shutter =
+			prev_gain16 * prev_shutter *
+			cap_sysclk / sensor->prev_sysclk *
+			sensor->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_gain(sensor, cap_gain16);
+
+	/* write capture shutter */
+	if (cap_shutter > (cap_vts - 4)) {
+		cap_vts = cap_shutter + 4;
+		ov5640_set_VTS(sensor, cap_vts);
+	}
+
+	ov5640_set_exposure(sensor, cap_shutter);
+
+	ov5640_set_stream(sensor, true);
+
+err:
+	return retval;
+}
+
+/*
+ * if sensor changes inside scaling or subsampling
+ * change mode directly
+ */
+static int ov5640_change_mode_direct(struct ov5640_dev *sensor,
+				     enum ov5640_frame_rate frame_rate,
+				     enum ov5640_mode mode)
+{
+	struct reg_value *mode_data = NULL;
+	int mode_size = 0;
+	int retval = 0;
+
+	/* check if the input mode and frame rate is valid */
+	mode_data = ov5640_mode_info_data[frame_rate][mode].init_data_ptr;
+	mode_size = ov5640_mode_info_data[frame_rate][mode].init_data_size;
+
+	sensor->fmt.width = ov5640_mode_info_data[frame_rate][mode].width;
+	sensor->fmt.height = ov5640_mode_info_data[frame_rate][mode].height;
+
+	if (sensor->fmt.width == 0 || sensor->fmt.height == 0 ||
+	    mode_data == NULL || mode_size == 0)
+		return -EINVAL;
+
+	/* turn off AE/AG */
+	ov5640_set_agc(sensor, false);
+
+	ov5640_set_stream(sensor, false);
+
+	/* Write capture setting */
+	retval = ov5640_load_regs(sensor, mode_data, mode_size);
+	if (retval < 0)
+		goto err;
+
+	ov5640_set_stream(sensor, true);
+
+	ov5640_set_agc(sensor, true);
+
+err:
+	return retval;
+}
+
+static int ov5640_change_mode(struct ov5640_dev *sensor,
+			      enum ov5640_frame_rate frame_rate,
+			      enum ov5640_mode mode,
+			      enum ov5640_mode orig_mode)
+{
+	enum ov5640_downsize_mode dn_mode, orig_dn_mode;
+	struct reg_value *mode_data = NULL;
+	int mode_size = 0;
+	int retval = 0;
+
+	if ((mode >= ov5640_num_modes || mode < ov5640_mode_MIN) &&
+	    mode != ov5640_mode_INIT) {
+		v4l2_err(&sensor->sd, "Wrong ov5640 mode detected!\n");
+		return -EINVAL;
+	}
+
+	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) {
+		mode_data = ov5640_init_setting_30fps_VGA;
+		mode_size = ARRAY_SIZE(ov5640_init_setting_30fps_VGA);
+
+		sensor->fmt.width = 640;
+		sensor->fmt.height = 480;
+		retval = ov5640_load_regs(sensor, mode_data, mode_size);
+		if (retval < 0)
+			goto err;
+
+		mode_data = ov5640_setting_30fps_VGA_640_480;
+		mode_size = ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480);
+		retval = ov5640_load_regs(sensor, mode_data, mode_size);
+	} 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(sensor, frame_rate,
+							  mode);
+	} else {
+		/* change inside subsampling or scaling
+		 * download firmware directly */
+		retval = ov5640_change_mode_direct(sensor, frame_rate, mode);
+	}
+
+	if (retval < 0)
+		goto err;
+
+	ov5640_set_AE_target(sensor, sensor->ae_target);
+	ov5640_get_light_freq(sensor);
+	ov5640_set_bandingfilter(sensor);
+	ov5640_set_virtual_channel(sensor);
+
+	/* restore controls */
+	ov5640_restore_ctrls(sensor);
+
+	if (retval >= 0 && mode != ov5640_mode_INIT) {
+		sensor->current_mode = mode;
+		sensor->current_fr = frame_rate;
+	}
+
+err:
+	return retval;
+}
+
+/* restore the last set video mode after chip power-on */
+static int ov5640_restore_mode(struct ov5640_dev *sensor)
+{
+	int retval = 0;
+
+	/* first we need to set some initial register values */
+	retval = ov5640_change_mode(sensor, sensor->current_fr,
+				    ov5640_mode_INIT, ov5640_mode_INIT);
+	if (retval < 0)
+		return retval;
+
+	/* now restore the last capture mode */
+	return ov5640_change_mode(sensor,
+				  sensor->current_fr,
+				  sensor->current_mode,
+				  ov5640_mode_VGA_640_480);
+}
+
+static int ov5640_regulators_on(struct ov5640_dev *sensor)
+{
+	int ret;
+
+	if (sensor->io_regulator) {
+		ret = regulator_enable(sensor->io_regulator);
+		if (ret) {
+			v4l2_err(&sensor->sd, "io reg enable failed\n");
+			return ret;
+		}
+	}
+	if (sensor->core_regulator) {
+		ret = regulator_enable(sensor->core_regulator);
+		if (ret) {
+			v4l2_err(&sensor->sd, "core reg enable failed\n");
+			return ret;
+		}
+	}
+	if (sensor->gpo_regulator) {
+		ret = regulator_enable(sensor->gpo_regulator);
+		if (ret) {
+			v4l2_err(&sensor->sd, "gpo reg enable failed\n");
+			return ret;
+		}
+	}
+	if (sensor->analog_regulator) {
+		ret = regulator_enable(sensor->analog_regulator);
+		if (ret) {
+			v4l2_err(&sensor->sd, "analog reg enable failed\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void ov5640_regulators_off(struct ov5640_dev *sensor)
+{
+	if (sensor->analog_regulator)
+		regulator_disable(sensor->analog_regulator);
+	if (sensor->core_regulator)
+		regulator_disable(sensor->core_regulator);
+	if (sensor->io_regulator)
+		regulator_disable(sensor->io_regulator);
+	if (sensor->gpo_regulator)
+		regulator_disable(sensor->gpo_regulator);
+}
+
+/* --------------- Subdev Operations --------------- */
+
+static int ov5640_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct ov5640_dev *sensor = to_ov5640_dev(sd);
+	int ret;
+
+	if (on && !sensor->on) {
+		if (sensor->xclk)
+			clk_prepare_enable(sensor->xclk);
+
+		ret = ov5640_regulators_on(sensor);
+		if (ret)
+			return ret;
+
+		ov5640_reset(sensor);
+		ov5640_power(sensor, true);
+		ov5640_restore_mode(sensor);
+	} else if (!on && sensor->on) {
+		ov5640_power(sensor, false);
+
+		ov5640_regulators_off(sensor);
+
+		if (sensor->xclk)
+			clk_disable_unprepare(sensor->xclk);
+	}
+
+	sensor->on = on;
+
+	return 0;
+}
+
+static int ov5640_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+	struct ov5640_dev *sensor = to_ov5640_dev(sd);
+	struct v4l2_captureparm *cparm = &a->parm.capture;
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	/* This is the only case currently handled. */
+	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;
+
+	return 0;
+}
+
+static int ov5640_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+	struct ov5640_dev *sensor = to_ov5640_dev(sd);
+	struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+	enum ov5640_frame_rate frame_rate;
+	u32 tgt_fps;	/* target frames per secound */
+	int ret = 0;
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	/* 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 {
+		v4l2_err(&sensor->sd, "frame rate %u not supported!\n",
+			 tgt_fps);
+		return -EINVAL;
+	}
+
+	ret = ov5640_change_mode(sensor, frame_rate,
+				 sensor->current_mode,
+				 sensor->current_mode);
+	if (ret < 0)
+		return ret;
+
+	sensor->streamcap.timeperframe = *timeperframe;
+
+	return 0;
+}
+
+static int ov5640_g_mbus_fmt(struct v4l2_subdev *sd,
+			     struct v4l2_mbus_framefmt *fmt)
+{
+	struct ov5640_dev *sensor = to_ov5640_dev(sd);
+
+	*fmt = sensor->fmt;
+
+	return 0;
+}
+
+static int ov5640_s_mbus_fmt(struct v4l2_subdev *sd,
+			     struct v4l2_mbus_framefmt *fmt)
+{
+	struct ov5640_dev *sensor = to_ov5640_dev(sd);
+	enum ov5640_mode new_mode;
+	int retval;
+
+	new_mode = ov5640_find_nearest_mode(sensor, fmt->width, fmt->height);
+
+	fmt->width = ov5640_mode_info_data[0][new_mode].width;
+	fmt->height = ov5640_mode_info_data[0][new_mode].height;
+	fmt->code = sensor->fmt.code;
+
+	retval = ov5640_change_mode(sensor, sensor->current_fr,
+				    new_mode, sensor->current_mode);
+	if (retval >= 0)
+		sensor->fmt = *fmt;
+
+	return retval;
+}
+
+
+/*
+ * Sensor Controls.
+ */
+
+static int ov5640_set_hue(struct ov5640_dev *sensor, int value)
+{
+	if (value) {
+		ov5640_mod_reg(sensor, 0x5580, 1 << 0, 1 << 0);
+		ov5640_write_reg16(sensor, 0x5581, value);
+	} else
+		ov5640_mod_reg(sensor, 0x5580, 1 << 0, 0);
+	return 0;
+}
+
+static int ov5640_set_contrast(struct ov5640_dev *sensor, int value)
+{
+	if (value) {
+		ov5640_mod_reg(sensor, 0x5580, 1 << 2, 1 << 2);
+		ov5640_write_reg(sensor, 0x5585, value & 0xff);
+	} else
+		ov5640_mod_reg(sensor, 0x5580, 1 << 2, 0);
+	return 0;
+}
+
+static int ov5640_set_saturation(struct ov5640_dev *sensor, int value)
+{
+	if (value) {
+		ov5640_mod_reg(sensor, 0x5580, 1 << 1, 1 << 1);
+		ov5640_write_reg(sensor, 0x5583, value & 0xff);
+		ov5640_write_reg(sensor, 0x5584, value & 0xff);
+	} else
+		ov5640_mod_reg(sensor, 0x5580, 1 << 1, 0);
+	return 0;
+}
+
+static int ov5640_set_awb(struct ov5640_dev *sensor, int value)
+{
+	sensor->awb_on = value ? true : false;
+	ov5640_mod_reg(sensor, 0x3406, 1 << 0, sensor->awb_on ? 0 : 1);
+	return 0;
+}
+
+static int ov5640_set_red_balance(struct ov5640_dev *sensor, int value)
+{
+	if (sensor->awb_on)
+		return -EINVAL;
+
+	ov5640_write_reg(sensor, 0x3401, value & 0xff);
+	ov5640_write_reg(sensor, 0x3400, (value & 0xf00) >> 8);
+
+	return 0;
+}
+
+#if 0
+static int ov5640_set_green_balance(struct ov5640_dev *sensor, int value)
+{
+	if (sensor->awb_on)
+		return -EINVAL;
+
+	ov5640_write_reg(sensor, 0x3403, value & 0xff);
+	ov5640_write_reg(sensor, 0x3402, (value & 0xf00) >> 8);
+
+	return 0;
+}
+#endif
+
+static int ov5640_set_blue_balance(struct ov5640_dev *sensor, int value)
+{
+	if (sensor->awb_on)
+		return -EINVAL;
+
+	ov5640_write_reg(sensor, 0x3405, value & 0xff);
+	ov5640_write_reg(sensor, 0x3404, (value & 0xf00) >> 8);
+
+	return 0;
+}
+
+static int ov5640_set_exposure(struct ov5640_dev *sensor, int value)
+{
+	u16 max_exp = 0;
+
+	if (sensor->agc_on)
+		return -EINVAL;
+
+	ov5640_read_reg16(sensor, 0x350c, &max_exp);
+	if (value < max_exp) {
+		u32 exp = value << 4;
+		ov5640_write_reg(sensor, 0x3502, exp & 0xff);
+		ov5640_write_reg(sensor, 0x3501, (exp >> 8) & 0xff);
+		ov5640_write_reg(sensor, 0x3500, (exp >> 16) & 0x0f);
+	}
+
+	return 0;
+}
+
+/* read exposure, in number of line periods */
+static int ov5640_get_exposure(struct ov5640_dev *sensor)
+{
+	int exp;
+
+	if (sensor->agc_on)
+		return -EINVAL;
+
+	exp = ((int)ov5640_read_reg(sensor, 0x3500, NULL) & 0x0f) << 16;
+	exp |= ((int)ov5640_read_reg(sensor, 0x3501, NULL) << 8);
+	exp |= (int)ov5640_read_reg(sensor, 0x3502, NULL);
+	return exp >> 4;
+}
+
+static int ov5640_set_agc(struct ov5640_dev *sensor, int value)
+{
+	/* this enables/disables both AEC and AGC */
+	sensor->agc_on = value ? true : false;
+	ov5640_mod_reg(sensor, 0x3503, 0x3, sensor->agc_on ? 0 : 0x3);
+	return 0;
+}
+
+static int ov5640_set_gain(struct ov5640_dev *sensor, int value)
+{
+	if (sensor->agc_on)
+		return -EINVAL;
+
+	return ov5640_write_reg16(sensor, 0x350a, value & 0x3ff);
+}
+
+static int ov5640_get_gain(struct ov5640_dev *sensor)
+{
+	u16 gain;
+	int ret;
+
+	if (sensor->agc_on)
+		return -EINVAL;
+
+	ret = ov5640_read_reg16(sensor, 0x350a, &gain);
+
+	return ret < 0 ? ret : gain & 0x3ff;
+}
+
+#if 0
+static int ov5640_set_test_pattern(struct ov5640_dev *sensor, int value)
+{
+	ov5640_mod_reg(sensor, 0x503d, 0xa4, value ? 0xa4 : 0);
+	return 0;
+}
+#endif
+
+static struct ov5640_control ov5640_ctrls[] = {
+	{
+		.set = ov5640_set_agc,
+		.ctrl = {
+			.id = V4L2_CID_AUTOGAIN,
+			.name = "Auto Gain/Exposure Control",
+			.minimum = 0,
+			.maximum = 1,
+			.step = 1,
+			.default_value = 1,
+			.type = V4L2_CTRL_TYPE_BOOLEAN,
+		},
+	}, {
+		.set = ov5640_set_exposure,
+		.ctrl = {
+			.id = V4L2_CID_EXPOSURE,
+			.name = "Exposure",
+			.minimum = 0,
+			.maximum = 65535,
+			.step = 1,
+			.default_value = 0,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+		},
+	}, {
+		.set = ov5640_set_gain,
+		.ctrl = {
+			.id = V4L2_CID_GAIN,
+			.name = "Gain",
+			.minimum = 0,
+			.maximum = 1023,
+			.step = 1,
+			.default_value = 0,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+		},
+	}, {
+		.set = ov5640_set_hue,
+		.ctrl = {
+			.id = V4L2_CID_HUE,
+			.name = "Hue",
+			.minimum = 0,
+			.maximum = 359,
+			.step = 1,
+			.default_value = 0,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+		},
+	}, {
+		.set = ov5640_set_contrast,
+		.ctrl = {
+			.id = V4L2_CID_CONTRAST,
+			.name = "Contrast",
+			.minimum = 0,
+			.maximum = 255,
+			.step = 1,
+			.default_value = 0,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+		},
+	}, {
+		.set = ov5640_set_saturation,
+		.ctrl = {
+			.id = V4L2_CID_SATURATION,
+			.name = "Saturation",
+			.minimum = 0,
+			.maximum = 255,
+			.step = 1,
+			.default_value = 64,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+		},
+	}, {
+		.set = ov5640_set_awb,
+		.ctrl = {
+			.id = V4L2_CID_AUTO_WHITE_BALANCE,
+			.name = "Auto White Balance",
+			.minimum = 0,
+			.maximum = 1,
+			.step = 1,
+			.default_value = 1,
+			.type = V4L2_CTRL_TYPE_BOOLEAN,
+		},
+	}, {
+		.set = ov5640_set_red_balance,
+		.ctrl = {
+			.id = V4L2_CID_RED_BALANCE,
+			.name = "Red Balance",
+			.minimum = 0,
+			.maximum = 4095,
+			.step = 1,
+			.default_value = 0,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+		},
+	}, {
+		.set = ov5640_set_blue_balance,
+		.ctrl = {
+			.id = V4L2_CID_BLUE_BALANCE,
+			.name = "Blue Balance",
+			.minimum = 0,
+			.maximum = 4095,
+			.step = 1,
+			.default_value = 0,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+		},
+	},
+};
+#define OV5640_NUM_CONTROLS ARRAY_SIZE(ov5640_ctrls)
+
+static struct ov5640_control *ov5640_get_ctrl(int id, int *index)
+{
+	struct ov5640_control *ret = NULL;
+	int i;
+
+	for (i = 0; i < OV5640_NUM_CONTROLS; i++) {
+		if (id == ov5640_ctrls[i].ctrl.id) {
+			ret = &ov5640_ctrls[i];
+			break;
+		}
+	}
+
+	if (ret && index)
+		*index = i;
+	return ret;
+}
+
+static int ov5640_restore_ctrls(struct ov5640_dev *sensor)
+{
+	struct ov5640_control *c;
+	int i;
+
+	for (i = 0; i < OV5640_NUM_CONTROLS; i++) {
+		c = &ov5640_ctrls[i];
+		c->set(sensor, sensor->ctrl_cache[i]);
+	}
+
+	return 0;
+}
+
+static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct ov5640_dev *sensor = ctrl_to_ov5640_dev(ctrl);
+	struct ov5640_control *c;
+	int ret = 0;
+	int i;
+
+	c = ov5640_get_ctrl(ctrl->id, &i);
+	if (!c)
+		return -EINVAL;
+
+	ret = c->set(sensor, ctrl->val);
+	/* update cached value if no error */
+	if (!ret)
+		sensor->ctrl_cache[i] = ctrl->val;
+
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops ov5640_ctrl_ops = {
+	.s_ctrl = ov5640_s_ctrl,
+};
+
+static int ov5640_init_controls(struct ov5640_dev *sensor)
+{
+	struct ov5640_control *c;
+	int i;
+
+	v4l2_ctrl_handler_init(&sensor->ctrl_hdl, OV5640_NUM_CONTROLS);
+
+	for (i = 0; i < OV5640_NUM_CONTROLS; i++) {
+		c = &ov5640_ctrls[i];
+
+		v4l2_ctrl_new_std(&sensor->ctrl_hdl, &ov5640_ctrl_ops,
+				  c->ctrl.id, c->ctrl.minimum, c->ctrl.maximum,
+				  c->ctrl.step, c->ctrl.default_value);
+	}
+
+	sensor->sd.ctrl_handler = &sensor->ctrl_hdl;
+	if (sensor->ctrl_hdl.error) {
+		int err = sensor->ctrl_hdl.error;
+
+		v4l2_ctrl_handler_free(&sensor->ctrl_hdl);
+
+		v4l2_err(&sensor->sd, "%s: error %d\n", __func__, err);
+		return err;
+	}
+	v4l2_ctrl_handler_setup(&sensor->ctrl_hdl);
+
+	return 0;
+}
+
+static int ov5640_enum_framesizes(struct v4l2_subdev *sd,
+				  struct v4l2_frmsizeenum *fsize)
+{
+	if (fsize->index >= ov5640_num_modes)
+		return -EINVAL;
+
+	fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+	fsize->discrete.width = ov5640_mode_info_data[0][fsize->index].width;
+	fsize->discrete.height = ov5640_mode_info_data[0][fsize->index].height;
+
+	return 0;
+}
+
+static int ov5640_enum_frameintervals(struct v4l2_subdev *sd,
+				      struct v4l2_frmivalenum *fi)
+{
+	struct ov5640_dev *sensor = to_ov5640_dev(sd);
+	enum ov5640_mode mode;
+
+	if (fi->index < 0 || fi->index >= ov5640_num_framerates)
+		return -EINVAL;
+
+	if (fi->width == 0 || fi->height == 0)
+		return -EINVAL;
+
+	fi->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+	fi->discrete.numerator = 1;
+
+	mode = ov5640_find_nearest_mode(sensor, fi->width, fi->height);
+
+	if (ov5640_mode_info_data[fi->index][mode].init_data_ptr == NULL)
+		return -EINVAL;
+
+	fi->discrete.denominator = ov5640_framerates[fi->index];
+
+	dev_dbg(sensor->dev, "%dx%d: [%d] = %d fps\n",
+		fi->width, fi->height, fi->index, fi->discrete.denominator);
+	return 0;
+}
+
+static int ov5640_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+	struct ov5640_dev *sensor = to_ov5640_dev(sd);
+
+	*status = !sensor->on ? V4L2_IN_ST_NO_POWER : 0;
+
+	return 0;
+}
+
+static int ov5640_s_routing(struct v4l2_subdev *sd, u32 input,
+			    u32 output, u32 config)
+{
+	return (input != 0) ? -EINVAL : 0;
+}
+
+static int ov5640_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+	*std = V4L2_STD_ALL;
+	return 0;
+}
+
+static int ov5640_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+				enum v4l2_mbus_pixelcode *code)
+{
+	struct ov5640_dev *sensor = to_ov5640_dev(sd);
+
+	if (index != 0)
+		return -EINVAL;
+
+	*code = sensor->fmt.code;
+
+	return 0;
+}
+
+static int ov5640_try_mbus_fmt(struct v4l2_subdev *sd,
+			       struct v4l2_mbus_framefmt *fmt)
+{
+	struct ov5640_dev *sensor = to_ov5640_dev(sd);
+	enum ov5640_mode mode;
+
+	mode = ov5640_find_nearest_mode(sensor, fmt->width, fmt->height);
+
+	fmt->width = ov5640_mode_info_data[0][mode].width;
+	fmt->height = ov5640_mode_info_data[0][mode].height;
+	fmt->code = sensor->fmt.code;
+
+	return 0;
+}
+
+static int ov5640_g_mbus_config(struct v4l2_subdev *sd,
+				struct v4l2_mbus_config *cfg)
+{
+	struct ov5640_dev *sensor = to_ov5640_dev(sd);
+
+	cfg->type = V4L2_MBUS_CSI2;
+	cfg->flags = sensor->ep.bus.mipi_csi2.flags;
+	cfg->flags |= (1 << (sensor->ep.bus.mipi_csi2.num_data_lanes - 1));
+	cfg->flags |= V4L2_MBUS_CSI2_CHANNEL_0;
+
+	return 0;
+}
+
+static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct ov5640_dev *sensor = to_ov5640_dev(sd);
+
+	ov5640_set_stream(sensor, enable);
+
+	return 0;
+}
+
+static struct v4l2_subdev_core_ops ov5640_core_ops = {
+	.s_power = ov5640_s_power,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
+};
+
+static struct v4l2_subdev_video_ops ov5640_video_ops = {
+	.enum_mbus_fmt = ov5640_enum_mbus_fmt,
+	.try_mbus_fmt = ov5640_try_mbus_fmt,
+	.g_mbus_fmt = ov5640_g_mbus_fmt,
+	.s_mbus_fmt = ov5640_s_mbus_fmt,
+	.s_parm = ov5640_s_parm,
+	.g_parm = ov5640_g_parm,
+	.enum_frameintervals = ov5640_enum_frameintervals,
+	.enum_framesizes = ov5640_enum_framesizes,
+	.g_input_status = ov5640_g_input_status,
+	.s_routing = ov5640_s_routing,
+	.querystd = ov5640_querystd,
+	.g_mbus_config  = ov5640_g_mbus_config,
+	.s_stream = ov5640_s_stream,
+};
+
+static struct v4l2_subdev_ops ov5640_subdev_ops = {
+	.core = &ov5640_core_ops,
+	.video = &ov5640_video_ops,
+};
+
+static void ov5640_power(struct ov5640_dev *sensor, bool enable)
+{
+	gpio_set_value(sensor->pwdn_gpio, enable ? 0 : 1);
+}
+
+static void ov5640_reset(struct ov5640_dev *sensor)
+{
+	gpio_set_value(sensor->reset_gpio, 1);
+
+	/* camera power cycle */
+	ov5640_power(sensor, false);
+	usleep_range(5000, 5001);
+	ov5640_power(sensor, true);
+	usleep_range(5000, 5001);
+
+	gpio_set_value(sensor->reset_gpio, 0);
+	usleep_range(1000, 1001);
+
+	gpio_set_value(sensor->reset_gpio, 1);
+	usleep_range(5000, 5001);
+}
+
+static void ov5640_get_regulators(struct ov5640_dev *sensor)
+{
+	sensor->io_regulator = devm_regulator_get(sensor->dev, "DOVDD");
+	if (!IS_ERR(sensor->io_regulator)) {
+		regulator_set_voltage(sensor->io_regulator,
+				      OV5640_VOLTAGE_DIGITAL_IO,
+				      OV5640_VOLTAGE_DIGITAL_IO);
+	} else {
+		dev_dbg(sensor->dev, "%s: no io voltage reg found\n",
+			__func__);
+		sensor->io_regulator = NULL;
+	}
+
+	sensor->core_regulator = devm_regulator_get(sensor->dev, "DVDD");
+	if (!IS_ERR(sensor->core_regulator)) {
+		regulator_set_voltage(sensor->core_regulator,
+				      OV5640_VOLTAGE_DIGITAL_CORE,
+				      OV5640_VOLTAGE_DIGITAL_CORE);
+	} else {
+		sensor->core_regulator = NULL;
+		dev_dbg(sensor->dev, "%s: no core voltage reg found\n",
+			__func__);
+	}
+
+	sensor->analog_regulator = devm_regulator_get(sensor->dev, "AVDD");
+	if (!IS_ERR(sensor->analog_regulator)) {
+		regulator_set_voltage(sensor->analog_regulator,
+				      OV5640_VOLTAGE_ANALOG,
+				      OV5640_VOLTAGE_ANALOG);
+	} else {
+		sensor->analog_regulator = NULL;
+		dev_dbg(sensor->dev, "%s: no analog voltage reg found\n",
+			__func__);
+	}
+}
+
+static int ov5640_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct device_node *endpoint;
+	struct ov5640_dev *sensor;
+	int i, xclk, ret;
+
+	sensor = devm_kzalloc(dev, sizeof(struct ov5640_dev), GFP_KERNEL);
+	if (!sensor)
+		return -ENOMEM;
+
+	sensor->i2c_client = client;
+	sensor->dev = dev;
+	sensor->fmt.code = V4L2_MBUS_FMT_UYVY8_2X8;
+	sensor->fmt.width = 640;
+	sensor->fmt.height = 480;
+	sensor->streamcap.capability = V4L2_MODE_HIGHQUALITY |
+					   V4L2_CAP_TIMEPERFRAME;
+	sensor->streamcap.capturemode = 0;
+	sensor->streamcap.timeperframe.denominator = DEFAULT_FPS;
+	sensor->streamcap.timeperframe.numerator = 1;
+
+	sensor->current_mode = ov5640_mode_VGA_640_480;
+	sensor->current_fr = ov5640_30_fps;
+
+	sensor->ae_target = 52;
+
+	endpoint = of_graph_get_next_endpoint(client->dev.of_node, NULL);
+	if (!endpoint) {
+		dev_err(dev, "endpoint node not found\n");
+		return -EINVAL;
+	}
+
+	v4l2_of_parse_endpoint(endpoint, &sensor->ep);
+	if (sensor->ep.bus_type != V4L2_MBUS_CSI2) {
+		dev_err(dev, "invalid bus type, must be MIPI CSI2\n");
+		return -EINVAL;
+	}
+	of_node_put(endpoint);
+
+	/* get system clock (xclk) frequency */
+	ret = of_property_read_u32(dev->of_node, "xclk", &xclk);
+	if (!ret) {
+		if (xclk < OV5640_XCLK_MIN || xclk > OV5640_XCLK_MAX) {
+			dev_err(dev, "invalid xclk frequency\n");
+			return -EINVAL;
+		}
+		sensor->xclk_freq = xclk;
+	}
+
+	/* get system clock (xclk) */
+	sensor->xclk = devm_clk_get(dev, "xclk");
+	if (!IS_ERR(sensor->xclk)) {
+		if (!sensor->xclk_freq) {
+			dev_err(dev, "xclk requires xclk frequency!\n");
+			return -EINVAL;
+		}
+		clk_set_rate(sensor->xclk, sensor->xclk_freq);
+	} else {
+		/* assume system clock enabled by default */
+		sensor->xclk = NULL;
+	}
+
+	/* request power down pin */
+	ret = of_get_named_gpio(dev->of_node, "pwdn-gpios", 0);
+	if (!gpio_is_valid(ret)) {
+		dev_err(dev, "no sensor pwdn pin available");
+		return -EINVAL;
+	}
+	sensor->pwdn_gpio = ret;
+	ret = devm_gpio_request_one(dev, sensor->pwdn_gpio,
+				    GPIOF_OUT_INIT_HIGH, "ov5640_mipi_pwdn");
+	if (ret < 0) {
+		dev_err(dev, "request for power down gpio failed\n");
+		return ret;
+	}
+
+	/* request reset pin */
+	ret = of_get_named_gpio(dev->of_node, "reset-gpios", 0);
+	if (!gpio_is_valid(ret)) {
+		dev_warn(dev, "no sensor reset pin available");
+		return -EINVAL;
+	}
+	sensor->reset_gpio = ret;
+	ret = devm_gpio_request_one(dev, sensor->reset_gpio,
+				    GPIOF_OUT_INIT_HIGH, "ov5640_mipi_reset");
+	if (ret < 0) {
+		dev_err(dev, "request for reset gpio failed\n");
+		return ret;
+	}
+
+	/* initialize the cached controls to their defaults */
+	for (i = 0; i < OV5640_NUM_CONTROLS; i++) {
+		struct ov5640_control *c = &ov5640_ctrls[i];
+		sensor->ctrl_cache[i] = c->ctrl.default_value;
+	}
+	sensor->awb_on = sensor->agc_on = true;
+
+	v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops);
+
+	ov5640_get_regulators(sensor);
+
+	ov5640_s_power(&sensor->sd, 1);
+
+	ret = ov5640_init_controls(sensor);
+
+	ov5640_s_power(&sensor->sd, 0);
+
+	return ret;
+}
+
+/*!
+ * 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);
+	struct ov5640_dev *sensor = to_ov5640_dev(sd);
+
+	ov5640_regulators_off(sensor);
+
+	v4l2_ctrl_handler_free(&sensor->ctrl_hdl);
+
+	return 0;
+}
+
+static const struct i2c_device_id ov5640_id[] = {
+	{"ov5640_mipi", 0},
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, ov5640_id);
+
+static struct of_device_id ov5640_dt_ids[] = {
+	{ .compatible = "ovti,ov5640_mipi" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ov5640_dt_ids);
+
+static struct i2c_driver ov5640_i2c_driver = {
+	.driver = {
+		.owner = THIS_MODULE,
+		.name  = "ov5640_mipi",
+		.of_match_table	= ov5640_dt_ids,
+	},
+	.id_table = ov5640_id,
+	.probe    = ov5640_probe,
+	.remove   = ov5640_remove,
+};
+
+module_i2c_driver(ov5640_i2c_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("OV5640 MIPI Camera Subdev Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 41/43] media: imx6: Add support for Parallel OV5642
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (39 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 40/43] media: imx6: Add support for MIPI CSI-2 OV5640 Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-07 21:56 ` [PATCH 42/43] media: imx6: Add support for ADV7180 Video Decoder Steve Longerbeam
                   ` (3 subsequent siblings)
  44 siblings, 0 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

This driver is based on ov5642.c from Freescale imx_3.10.17_1.0.0_beta
branch, modified heavily for code cleanup and converted from int-device
to subdev.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/media/imx6/capture/Kconfig  |    7 +
 drivers/staging/media/imx6/capture/Makefile |    1 +
 drivers/staging/media/imx6/capture/ov5642.c | 4258 +++++++++++++++++++++++++++
 3 files changed, 4266 insertions(+)
 create mode 100644 drivers/staging/media/imx6/capture/ov5642.c

diff --git a/drivers/staging/media/imx6/capture/Kconfig b/drivers/staging/media/imx6/capture/Kconfig
index 6d81e3f..5e6a610 100644
--- a/drivers/staging/media/imx6/capture/Kconfig
+++ b/drivers/staging/media/imx6/capture/Kconfig
@@ -8,6 +8,13 @@ config IMX6_MIPI_CSI2
          MIPI CSI-2 Receiver driver support. This driver is required
 	 for sensor drivers with a MIPI CSI2 interface.
 
+config IMX6_CAMERA_OV5642
+       tristate "OmniVision OV5642 Parallel camera support"
+       depends on VIDEO_IMX6_CAMERA
+       default y
+       ---help---
+         Parallel interface OV5642 camera support.
+
 config IMX6_CAMERA_OV5640_MIPI
        tristate "OmniVision OV5640 MIPI CSI-2 camera support"
        depends on VIDEO_IMX6_CAMERA
diff --git a/drivers/staging/media/imx6/capture/Makefile b/drivers/staging/media/imx6/capture/Makefile
index 6aaa4cc..bcb2c16 100644
--- a/drivers/staging/media/imx6/capture/Makefile
+++ b/drivers/staging/media/imx6/capture/Makefile
@@ -3,3 +3,4 @@ mx6-camera-objs := mx6-camif.o mx6-encode.o mx6-preview.o
 obj-$(CONFIG_VIDEO_IMX6_CAMERA) += mx6-camera.o
 obj-$(CONFIG_IMX6_MIPI_CSI2) += mipi-csi2.o
 obj-$(CONFIG_IMX6_CAMERA_OV5640_MIPI) += ov5640-mipi.o
+obj-$(CONFIG_IMX6_CAMERA_OV5642) += ov5642.o
diff --git a/drivers/staging/media/imx6/capture/ov5642.c b/drivers/staging/media/imx6/capture/ov5642.c
new file mode 100644
index 0000000..786da36
--- /dev/null
+++ b/drivers/staging/media/imx6/capture/ov5642.c
@@ -0,0 +1,4258 @@
+/*
+ * Copyright (c) 2012-2014 Mentor Graphics Inc.
+ * Copyright (C) 2012 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/types.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-of.h>
+#include <media/v4l2-ctrls.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
+
+/* min/typical/max system clock (xclk) frequencies */
+#define OV5642_XCLK_MIN  6000000
+#define OV5642_XCLK_TYP 24000000
+#define OV5642_XCLK_MAX 54000000
+
+/* min/typical/max pixel clock (mclk) frequencies */
+#define OV5642_MCLK_MIN 48000000
+#define OV5642_MCLK_TYP 48000000
+#define OV5642_MCLK_MAX 96000000
+
+#define OV5642_CHIP_ID  0x300A
+
+#define OV5642_MAX_CONTROLS 64
+
+enum ov5642_mode {
+	ov5642_mode_MIN = 0,
+	ov5642_mode_QCIF_176_144 = 0,
+	ov5642_mode_QVGA_320_240,
+	ov5642_mode_VGA_640_480,
+	ov5642_mode_NTSC_720_480,
+	ov5642_mode_PAL_720_576,
+	ov5642_mode_XGA_1024_768,
+	ov5642_mode_720P_1280_720,
+	ov5642_mode_1080P_1920_1080,
+	ov5642_mode_QSXGA_2592_1944,
+	ov5642_num_modes,
+};
+
+enum ov5642_frame_rate {
+	ov5642_15_fps,
+	ov5642_30_fps
+};
+
+static int ov5642_framerates[] = {
+	[ov5642_15_fps] = 15,
+	[ov5642_30_fps] = 30,
+};
+#define ov5642_num_framerates ARRAY_SIZE(ov5642_framerates)
+
+struct reg_value {
+	u16 reg_addr;
+	u8 val;
+	u8 mask;
+	u32 delay_ms;
+};
+
+struct ov5642_mode_info {
+	enum ov5642_mode mode;
+	u32 width;
+	u32 height;
+	struct reg_value *init_data_ptr;
+	u32 init_data_size;
+};
+
+struct ov5642_dev {
+	struct i2c_client *i2c_client;
+	struct device *dev;
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler ctrl_hdl;
+	struct v4l2_of_endpoint ep; /* the parsed DT endpoint info */
+	struct v4l2_mbus_framefmt fmt;
+	struct v4l2_captureparm streamcap;
+	struct clk *xclk; /* system clock to OV5642 */
+	int xclk_freq;    /* requested xclk freq from devicetree */
+
+	enum ov5642_mode current_mode;
+	enum ov5642_frame_rate current_fr;
+
+	bool on;
+	bool awb_on;
+	bool agc_on;
+
+	/* cached control settings */
+	int ctrl_cache[OV5642_MAX_CONTROLS];
+
+	int reset_gpio;
+	int pwdn_gpio;
+	int gp_gpio;
+
+	struct regulator *io_regulator;
+	struct regulator *core_regulator;
+	struct regulator *analog_regulator;
+	struct regulator *gpo_regulator;
+};
+
+static inline struct ov5642_dev *to_ov5642_dev(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct ov5642_dev, sd);
+}
+
+static inline struct ov5642_dev *ctrl_to_ov5642_dev(struct v4l2_ctrl *ctrl)
+{
+	return container_of(ctrl->handler, struct ov5642_dev, ctrl_hdl);
+}
+
+struct ov5642_control {
+	struct v4l2_queryctrl ctrl;
+	int (*set)(struct ov5642_dev *sensor, int value);
+};
+
+static void ov5642_power(struct ov5642_dev *sensor, bool enable);
+static int ov5642_restore_ctrls(struct ov5642_dev *sensor);
+static int ov5642_set_agc(struct ov5642_dev *sensor, int value);
+static int ov5642_set_exposure(struct ov5642_dev *sensor, int value);
+static int ov5642_set_gain(struct ov5642_dev *sensor, int value);
+
+#if 0
+/* not used, but keep around */
+static struct reg_value ov5642_rotate_none_VGA[] = {
+	{0x3818, 0xc1, 0x00, 0x00}, {0x3621, 0x87, 0x00, 0x00},
+};
+static struct reg_value ov5642_rotate_vert_flip_VGA[] = {
+	{0x3818, 0x20, 0xbf, 0x00}, {0x3621, 0x20, 0xff, 0x00},
+};
+static struct reg_value ov5642_rotate_horiz_flip_VGA[] = {
+	{0x3818, 0x81, 0x00, 0x01}, {0x3621, 0xa7, 0x00, 0x00},
+};
+static struct reg_value ov5642_rotate_180_VGA[] = {
+	{0x3818, 0x60, 0xff, 0x00}, {0x3621, 0x00, 0xdf, 0x00},
+};
+static struct reg_value ov5642_rotate_none_FULL[] = {
+	{0x3818, 0xc0, 0x00, 0x00}, {0x3621, 0x09, 0x00, 0x00},
+};
+static struct reg_value ov5642_rotate_vert_flip_FULL[] = {
+	{0x3818, 0x20, 0xbf, 0x01}, {0x3621, 0x20, 0xff, 0x00},
+};
+static struct reg_value ov5642_rotate_horiz_flip_FULL[] = {
+	{0x3818, 0x80, 0x00, 0x01}, {0x3621, 0x29, 0x00, 0x00},
+};
+static struct reg_value ov5642_rotate_180_FULL[] = {
+	{0x3818, 0x60, 0xff, 0x00}, {0x3621, 0x00, 0xdf, 0x00},
+};
+#endif
+
+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, 200},
+};
+
+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_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_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_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, 0x10, 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_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 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, 0x10, 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},
+};
+
+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 ov5642_mode_info
+ov5642_mode_info_data[ov5642_num_framerates][ov5642_num_modes] = {
+	{
+		{ov5642_mode_QCIF_176_144, 176, 144,
+		ov5642_setting_15fps_QCIF_176_144,
+		ARRAY_SIZE(ov5642_setting_15fps_QCIF_176_144)},
+		{ov5642_mode_QVGA_320_240,   320,  240,
+		ov5642_setting_15fps_QVGA_320_240,
+		ARRAY_SIZE(ov5642_setting_15fps_QVGA_320_240)},
+		{ov5642_mode_VGA_640_480,    640,  480,
+		ov5642_setting_15fps_VGA_640_480,
+		ARRAY_SIZE(ov5642_setting_15fps_VGA_640_480)},
+		{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_XGA_1024_768, 1024, 768,
+		ov5642_setting_15fps_XGA_1024_768,
+		ARRAY_SIZE(ov5642_setting_15fps_XGA_1024_768)},
+		{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_30fps_QCIF_176_144,
+		ARRAY_SIZE(ov5642_setting_30fps_QCIF_176_144)},
+		{ov5642_mode_QVGA_320_240,   320,  240,
+		ov5642_setting_30fps_QVGA_320_240,
+		ARRAY_SIZE(ov5642_setting_30fps_QVGA_320_240)},
+		{ov5642_mode_VGA_640_480,    640,  480,
+		ov5642_setting_30fps_VGA_640_480,
+		ARRAY_SIZE(ov5642_setting_30fps_VGA_640_480)},
+		{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_XGA_1024_768, 1024, 768,
+		ov5642_setting_30fps_XGA_1024_768,
+		ARRAY_SIZE(ov5642_setting_30fps_XGA_1024_768)},
+		{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},
+	},
+};
+
+static int ov5642_probe(struct i2c_client *adapter,
+				const struct i2c_device_id *device_id);
+static int ov5642_remove(struct i2c_client *client);
+
+static int ov5642_write_reg(struct ov5642_dev *sensor, u16 reg, u8 val)
+{
+	u8 au8Buf[3] = {0};
+	int retval;
+
+	au8Buf[0] = reg >> 8;
+	au8Buf[1] = reg & 0xff;
+	au8Buf[2] = val;
+
+	retval = i2c_master_send(sensor->i2c_client, au8Buf, 3);
+	if (retval < 0) {
+		pr_err("%s:write reg error:reg=%x,val=%x\n",
+			__func__, reg, val);
+		return retval;
+	}
+
+	return 0;
+}
+
+static int ov5642_read_reg(struct ov5642_dev *sensor, u16 reg, u8 *val)
+{
+	u8 au8RegBuf[2] = {0};
+	u8 u8RdVal = 0;
+
+	au8RegBuf[0] = reg >> 8;
+	au8RegBuf[1] = reg & 0xff;
+
+	if (2 != i2c_master_send(sensor->i2c_client, au8RegBuf, 2)) {
+		pr_err("%s:write reg error:reg=%x\n",
+				__func__, reg);
+		return -EIO;
+	}
+
+	if (1 != i2c_master_recv(sensor->i2c_client, &u8RdVal, 1)) {
+		pr_err("%s:read reg error:reg=%x,val=%x\n",
+				__func__, reg, u8RdVal);
+		return -EIO;
+	}
+
+	if (val)
+		*val = u8RdVal;
+
+	return u8RdVal;
+}
+
+static int ov5642_read_reg16(struct ov5642_dev *sensor, u16 reg, u16 *val)
+{
+	u8 hi, lo;
+	int ret;
+
+	ret = ov5642_read_reg(sensor, reg, &hi);
+	if (ret < 0)
+		return ret;
+	ret = ov5642_read_reg(sensor, reg+1, &lo);
+	if (ret < 0)
+		return ret;
+
+	*val = ((u16)hi << 8) | (u16)lo;
+	return 0;
+}
+
+static int ov5642_mod_reg(struct ov5642_dev *sensor, u16 reg,
+			  u8 mask, u8 val)
+{
+	u8 readval;
+	int retval;
+
+	retval = ov5642_read_reg(sensor, reg, &readval);
+	if (retval < 0)
+		return retval;
+
+	readval &= ~mask;
+	val &= mask;
+	val |= readval;
+
+	return ov5642_write_reg(sensor, reg, val);
+}
+
+static int ov5642_load_regs(struct ov5642_dev *sensor,
+			    struct reg_value *regs,
+			    int size)
+{
+	register u32 delay_ms = 0;
+	register u16 reg_addr = 0;
+	register u8 mask = 0;
+	register u8 val = 0;
+	int i, retval = 0;
+
+	for (i = 0; i < size; ++i, ++regs) {
+		delay_ms = regs->delay_ms;
+		reg_addr = regs->reg_addr;
+		val = regs->val;
+		mask = regs->mask;
+
+		if (mask)
+			retval = ov5642_mod_reg(sensor, reg_addr, mask, val);
+		else
+			retval = ov5642_write_reg(sensor, reg_addr, val);
+		if (retval)
+			break;
+		if (delay_ms)
+			usleep_range(1000*delay_ms, 1000*delay_ms+1);
+	}
+
+	return retval;
+}
+
+static void ov5642_dump_format(struct ov5642_dev *sensor)
+{
+	u16 hs, vs, hw, vh;
+	u16 scaling, dvp_w, dvp_h;
+
+	ov5642_read_reg16(sensor, 0x3800, &hs);
+	ov5642_read_reg16(sensor, 0x3802, &vs);
+	ov5642_read_reg16(sensor, 0x3804, &hw);
+	ov5642_read_reg16(sensor, 0x3806, &vh);
+
+	scaling = ov5642_read_reg(sensor, 0x5001, NULL);
+	ov5642_read_reg16(sensor, 0x3808, &dvp_w);
+	ov5642_read_reg16(sensor, 0x380a, &dvp_h);
+
+	pr_debug("Image Window:\n");
+	pr_debug("\thoriz: %u@%u\n", hw, hs);
+	pr_debug("\tvert : %u@%u\n", vh, vs);
+	pr_debug("DVP Scaling:\n");
+	pr_debug("\thoriz %s, vert %s, %ux%u\n",
+		(scaling & (1 << 4)) ? "enabled" : "disabled",
+		(scaling & (1 << 5)) ? "enabled" : "disabled",
+		dvp_w, dvp_h);
+	pr_debug("DVP Padding:\n");
+	pr_debug("\tleft %u pixels, right %u pixels\n",
+		ov5642_read_reg(sensor, 0x4711, NULL),
+		ov5642_read_reg(sensor, 0x4712, NULL));
+	pr_debug("Pixel Format: %02x\n", ov5642_read_reg(sensor, 0x4300, NULL));
+}
+
+static int ov5642_init_mode(struct ov5642_dev *sensor,
+			    enum ov5642_frame_rate frame_rate,
+			    enum ov5642_mode mode);
+static int ov5642_write_snapshot_para(struct ov5642_dev *sensor,
+				      enum ov5642_frame_rate frame_rate,
+				      enum ov5642_mode mode);
+
+static enum ov5642_mode
+ov5642_find_nearest_mode(struct ov5642_dev *sensor,
+			 int width, int height)
+{
+	int i;
+
+	for (i = ov5642_num_modes - 1; i >= 0; i--) {
+		if (ov5642_mode_info_data[0][i].width <= width &&
+		    ov5642_mode_info_data[0][i].height <= height)
+			break;
+	}
+
+	if (i < 0)
+		i = 0;
+
+	return (enum ov5642_mode)i;
+}
+
+static int ov5642_change_mode(struct ov5642_dev *sensor,
+			      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 *mode_data = NULL;
+	int mode_size = 0;
+	int retval = 0;
+
+	if (new_mode >= ov5642_num_modes || new_mode < ov5642_mode_MIN) {
+		pr_err("Wrong ov5642 mode detected!\n");
+		return -EINVAL;
+	}
+
+	if (new_frame_rate == old_frame_rate) {
+		if (new_mode == orig_mode)
+			return 0;
+		else if (new_mode == ov5642_mode_VGA_640_480 &&
+			 orig_mode == ov5642_mode_QSXGA_2592_1944) {
+			mode_data = ov5642_setting_QSXGA_2_VGA;
+			mode_size = ARRAY_SIZE(ov5642_setting_QSXGA_2_VGA);
+			sensor->fmt.width = 640;
+			sensor->fmt.height = 480;
+		} else if (new_mode == ov5642_mode_QVGA_320_240 &&
+			   orig_mode == ov5642_mode_VGA_640_480) {
+			mode_data = ov5642_setting_VGA_2_QVGA;
+			mode_size = ARRAY_SIZE(ov5642_setting_VGA_2_QVGA);
+			sensor->fmt.width = 320;
+			sensor->fmt.height = 240;
+		} else
+			goto load_full;
+
+		retval = ov5642_load_regs(sensor, mode_data, mode_size);
+	} else {
+load_full:
+		retval = ov5642_write_snapshot_para(sensor, new_frame_rate,
+						    new_mode);
+	}
+
+	/* restore controls */
+	ov5642_restore_ctrls(sensor);
+
+	if (retval >= 0) {
+		sensor->current_mode = new_mode;
+		sensor->current_fr = new_frame_rate;
+
+		ov5642_dump_format(sensor);
+	}
+
+	return retval;
+}
+
+static int ov5642_restore_mode(struct ov5642_dev *sensor)
+{
+	int retval = 0;
+
+	/* first we need to set some initial register values */
+	retval = ov5642_load_regs(sensor, ov5642_initial_setting,
+				  ARRAY_SIZE(ov5642_initial_setting));
+	if (retval < 0)
+		return retval;
+
+	/* now restore the last capture mode */
+	return ov5642_change_mode(sensor,
+				  sensor->current_fr,
+				  sensor->current_fr,
+				  sensor->current_mode,
+				  ov5642_mode_VGA_640_480);
+}
+
+static int ov5642_init_mode(struct ov5642_dev *sensor,
+			    enum ov5642_frame_rate frame_rate,
+			    enum ov5642_mode mode)
+{
+	struct reg_value *mode_data = NULL;
+	int mode_size = 0;
+
+	if (mode >= ov5642_num_modes || mode < ov5642_mode_MIN) {
+		pr_err("Wrong ov5642 mode detected!\n");
+		return -EINVAL;
+	}
+
+	mode_data = ov5642_mode_info_data[frame_rate][mode].init_data_ptr;
+	mode_size = ov5642_mode_info_data[frame_rate][mode].init_data_size;
+
+	sensor->fmt.width = ov5642_mode_info_data[frame_rate][mode].width;
+	sensor->fmt.height = ov5642_mode_info_data[frame_rate][mode].height;
+
+	if (sensor->fmt.width == 0 || sensor->fmt.height == 0 ||
+	    mode_data == NULL || mode_size == 0)
+		return -EINVAL;
+
+	return ov5642_load_regs(sensor, mode_data, mode_size);
+}
+
+static int ov5642_write_snapshot_para(struct ov5642_dev *sensor,
+				      enum ov5642_frame_rate frame_rate,
+				      enum ov5642_mode mode)
+{
+	bool m_60Hz = false;
+	u16 capture_frame_rate = 50;
+	u16 g_preview_frame_rate = 225;
+	u8 ret_l, ret_m, ret_h, gain, lines_10ms;
+	u16 ulcapture_exposure, capture_maxlines;
+	u16 icapture_gain, preview_maxlines;
+	u32 ulcapture_exposure_gain, g_preview_exposure;
+	int ret;
+
+	ov5642_set_agc(sensor, 0);
+
+	ret_h = ret_m = ret_l = 0;
+	g_preview_exposure = 0;
+	ov5642_read_reg(sensor, 0x3500, &ret_h);
+	ov5642_read_reg(sensor, 0x3501, &ret_m);
+	ov5642_read_reg(sensor, 0x3502, &ret_l);
+	g_preview_exposure = (ret_h << 12) + (ret_m << 4) + (ret_l >> 4);
+
+	ov5642_read_reg16(sensor, 0x380e, &preview_maxlines);
+	/*Read back AGC Gain for preview*/
+	gain = 0;
+	ov5642_read_reg(sensor, 0x350b, &gain);
+
+	ret = ov5642_init_mode(sensor, frame_rate, mode);
+	if (ret < 0)
+		return ret;
+
+	ov5642_read_reg16(sensor, 0x380e, &capture_maxlines);
+	if (m_60Hz == true)
+		lines_10ms = capture_frame_rate * (u32)capture_maxlines/12000;
+	else
+		lines_10ms = capture_frame_rate * (u32)capture_maxlines/10000;
+
+	if (preview_maxlines == 0)
+		preview_maxlines = 1;
+
+	ulcapture_exposure = (g_preview_exposure * capture_frame_rate *
+			      (u32)capture_maxlines) /
+		(preview_maxlines * g_preview_frame_rate);
+	icapture_gain = (gain & 0x0f) + 16;
+	if (gain & 0x10)
+		icapture_gain = icapture_gain << 1;
+
+	if (gain & 0x20)
+		icapture_gain = icapture_gain << 1;
+
+	if (gain & 0x40)
+		icapture_gain = icapture_gain << 1;
+
+	if (gain & 0x80)
+		icapture_gain = icapture_gain << 1;
+
+	ulcapture_exposure_gain = 2 * ulcapture_exposure * icapture_gain;
+
+	if (ulcapture_exposure_gain < (u32)capture_maxlines*16) {
+		ulcapture_exposure = ulcapture_exposure_gain/16;
+		if (ulcapture_exposure > lines_10ms) {
+			ulcapture_exposure /= lines_10ms;
+			ulcapture_exposure *= lines_10ms;
+		}
+	} else
+		ulcapture_exposure = (u32)capture_maxlines;
+
+	if (ulcapture_exposure == 0)
+		ulcapture_exposure = 1;
+
+	icapture_gain = (ulcapture_exposure_gain*2/ulcapture_exposure + 1)/2;
+	gain = 0;
+	if (icapture_gain > 31) {
+		gain |= 0x10;
+		icapture_gain = icapture_gain >> 1;
+	}
+	if (icapture_gain > 31) {
+		gain |= 0x20;
+		icapture_gain = icapture_gain >> 1;
+	}
+	if (icapture_gain > 31) {
+		gain |= 0x40;
+		icapture_gain = icapture_gain >> 1;
+	}
+	if (icapture_gain > 31) {
+		gain |= 0x80;
+		icapture_gain = icapture_gain >> 1;
+	}
+	if (icapture_gain > 16)
+		gain |= ((icapture_gain - 16) & 0x0f);
+
+	if (gain == 0x10)
+		gain = 0x11;
+
+	ov5642_set_gain(sensor, gain);
+	ov5642_set_exposure(sensor, ulcapture_exposure);
+
+	return 0;
+}
+
+static int ov5642_regulators_on(struct ov5642_dev *sensor)
+{
+	int ret;
+
+	if (sensor->io_regulator) {
+		ret = regulator_enable(sensor->io_regulator);
+		if (ret) {
+			v4l2_err(&sensor->sd, "io reg enable failed\n");
+			return ret;
+		}
+	}
+	if (sensor->core_regulator) {
+		ret = regulator_enable(sensor->core_regulator);
+		if (ret) {
+			v4l2_err(&sensor->sd, "core reg enable failed\n");
+			return ret;
+		}
+	}
+	if (sensor->gpo_regulator) {
+		ret = regulator_enable(sensor->gpo_regulator);
+		if (ret) {
+			v4l2_err(&sensor->sd, "gpo reg enable failed\n");
+			return ret;
+		}
+	}
+	if (sensor->analog_regulator) {
+		ret = regulator_enable(sensor->analog_regulator);
+		if (ret) {
+			v4l2_err(&sensor->sd, "analog reg enable failed\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void ov5642_regulators_off(struct ov5642_dev *sensor)
+{
+	if (sensor->analog_regulator)
+		regulator_disable(sensor->analog_regulator);
+	if (sensor->core_regulator)
+		regulator_disable(sensor->core_regulator);
+	if (sensor->io_regulator)
+		regulator_disable(sensor->io_regulator);
+	if (sensor->gpo_regulator)
+		regulator_disable(sensor->gpo_regulator);
+}
+
+/* --------------- Subdev Operations --------------- */
+
+static int ov5642_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct ov5642_dev *sensor = to_ov5642_dev(sd);
+	int ret;
+
+	if (on && !sensor->on) {
+		if (sensor->xclk)
+			clk_prepare_enable(sensor->xclk);
+
+		ret = ov5642_regulators_on(sensor);
+		if (ret)
+			return ret;
+
+		ov5642_power(sensor, true);
+		ov5642_restore_mode(sensor);
+	} else if (!on && sensor->on) {
+		ov5642_power(sensor, false);
+
+		ov5642_regulators_off(sensor);
+
+		if (sensor->xclk)
+			clk_disable_unprepare(sensor->xclk);
+	}
+
+	sensor->on = on;
+
+	return 0;
+}
+
+static int ov5642_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+	struct ov5642_dev *sensor = to_ov5642_dev(sd);
+	struct v4l2_captureparm *cparm = &a->parm.capture;
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	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;
+
+	return 0;
+}
+
+static int ov5642_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+	struct ov5642_dev *sensor = to_ov5642_dev(sd);
+	struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+	enum ov5642_frame_rate new_frame_rate;
+	u32 tgt_fps;
+	int ret;
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	/* 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;
+	}
+
+	ret = ov5642_change_mode(
+		sensor, new_frame_rate, sensor->current_fr,
+		sensor->current_mode, sensor->current_mode);
+	if (ret < 0)
+		return ret;
+
+	sensor->streamcap.timeperframe = *timeperframe;
+
+	return 0;
+}
+
+static int ov5642_g_mbus_fmt(struct v4l2_subdev *sd,
+			     struct v4l2_mbus_framefmt *fmt)
+{
+	struct ov5642_dev *sensor = to_ov5642_dev(sd);
+
+	*fmt = sensor->fmt;
+
+	return 0;
+}
+
+static int ov5642_s_mbus_fmt(struct v4l2_subdev *sd,
+			     struct v4l2_mbus_framefmt *fmt)
+{
+	struct ov5642_dev *sensor = to_ov5642_dev(sd);
+	enum ov5642_mode new_mode;
+	int retval;
+
+	new_mode = ov5642_find_nearest_mode(sensor, fmt->width, fmt->height);
+
+	fmt->width = ov5642_mode_info_data[0][new_mode].width;
+	fmt->height = ov5642_mode_info_data[0][new_mode].height;
+	fmt->code = sensor->fmt.code;
+
+	retval = ov5642_change_mode(sensor,
+				    sensor->current_fr,
+				    sensor->current_fr,
+				    new_mode, sensor->current_mode);
+	if (retval >= 0)
+		sensor->fmt = *fmt;
+
+	return retval;
+}
+
+
+/*
+ * Sensor Controls.
+ */
+
+static int ov5642_set_hue(struct ov5642_dev *sensor, int value)
+{
+	if (value) {
+		ov5642_mod_reg(sensor, 0x5580, 1 << 0, 1 << 0);
+		ov5642_mod_reg(sensor, 0x558a, 1 << 6, 1 << 6);
+		ov5642_write_reg(sensor, 0x5581, value & 0xff);
+		ov5642_write_reg(sensor, 0x5582, (value & 0x100) >> 8);
+	} else
+		ov5642_mod_reg(sensor, 0x5580, 1 << 0, 0);
+	return 0;
+}
+
+static int ov5642_set_contrast(struct ov5642_dev *sensor, int value)
+{
+	if (value) {
+		ov5642_mod_reg(sensor, 0x5580, 1 << 2, 1 << 2);
+		ov5642_write_reg(sensor, 0x5589, value & 0xff);
+	} else
+		ov5642_mod_reg(sensor, 0x5580, 1 << 2, 0);
+	return 0;
+}
+
+static int ov5642_set_saturation(struct ov5642_dev *sensor, int value)
+{
+	if (value) {
+		ov5642_mod_reg(sensor, 0x5580, 1 << 1, 1 << 1);
+		ov5642_write_reg(sensor, 0x5583, value & 0xff);
+		ov5642_write_reg(sensor, 0x5584, value & 0xff);
+	} else
+		ov5642_mod_reg(sensor, 0x5580, 1 << 1, 0);
+	return 0;
+}
+
+static int ov5642_set_awb(struct ov5642_dev *sensor, int value)
+{
+	sensor->awb_on = value ? true : false;
+	ov5642_mod_reg(sensor, 0x3406, 1 << 0, sensor->awb_on ? 0 : 1);
+	return 0;
+}
+
+static int ov5642_set_red_balance(struct ov5642_dev *sensor, int value)
+{
+	int ret = 0;
+
+	if (!sensor->awb_on) {
+		ov5642_write_reg(sensor, 0x3401, value & 0xff);
+		ov5642_write_reg(sensor, 0x3400, (value & 0xf00) >> 8);
+	} else
+		ret = -EINVAL;
+	return ret;
+}
+
+#if 0
+static int ov5642_set_green_balance(struct ov5642_dev *sensor, int value)
+{
+	int ret = 0;
+
+	if (!sensor->awb_on) {
+		ov5642_write_reg(sensor, 0x3403, value & 0xff);
+		ov5642_write_reg(sensor, 0x3402, (value & 0xf00) >> 8);
+	} else
+		ret = -EINVAL;
+	return ret;
+}
+#endif
+
+static int ov5642_set_blue_balance(struct ov5642_dev *sensor, int value)
+{
+	int ret = 0;
+
+	if (!sensor->awb_on) {
+		ov5642_write_reg(sensor, 0x3405, value & 0xff);
+		ov5642_write_reg(sensor, 0x3404, (value & 0xf00) >> 8);
+	} else
+		ret = -EINVAL;
+	return ret;
+}
+
+static int ov5642_set_exposure(struct ov5642_dev *sensor, int value)
+{
+	u16 max_exp = 0;
+	int ret = 0;
+
+	if (!sensor->agc_on) {
+		ov5642_read_reg16(sensor, 0x350c, &max_exp);
+		if (value < max_exp) {
+			u32 exp = value << 4;
+			ov5642_write_reg(sensor, 0x3502, exp & 0xff);
+			ov5642_write_reg(sensor, 0x3501, (exp >> 8) & 0xff);
+			ov5642_write_reg(sensor, 0x3500, (exp >> 16) & 0x0f);
+		}
+	} else
+		ret = -EINVAL;
+	return ret;
+}
+
+static int ov5642_set_agc(struct ov5642_dev *sensor, int value)
+{
+	/* this enables/disables both AEC and AGC */
+	sensor->agc_on = value ? true : false;
+	ov5642_mod_reg(sensor, 0x3503, 0x7, sensor->agc_on ? 0 : 0x7);
+	return 0;
+}
+
+static int ov5642_set_gain(struct ov5642_dev *sensor, int value)
+{
+	int ret = 0;
+
+	if (!sensor->agc_on) {
+		ov5642_write_reg(sensor, 0x350b, value & 0xff);
+		ov5642_write_reg(sensor, 0x350a, (value & 0x100) >> 8);
+	} else
+		ret = -EINVAL;
+	return ret;
+}
+
+#if 0
+static int ov5642_set_test_pattern(struct ov5642_dev *sensor, int value)
+{
+	ov5642_mod_reg(sensor, 0x503d, 0xa4, value ? 0xa4 : 0);
+	return 0;
+}
+#endif
+
+static struct ov5642_control ov5642_ctrls[] = {
+	{
+		.set = ov5642_set_agc,
+		.ctrl = {
+			.id = V4L2_CID_AUTOGAIN,
+			.name = "Auto Gain/Exposure Control",
+			.minimum = 0,
+			.maximum = 1,
+			.step = 1,
+			.default_value = 1,
+			.type = V4L2_CTRL_TYPE_BOOLEAN,
+		},
+	}, {
+		.set = ov5642_set_exposure,
+		.ctrl = {
+			.id = V4L2_CID_EXPOSURE,
+			.name = "Exposure",
+			.minimum = 0,
+			.maximum = 65535,
+			.step = 1,
+			.default_value = 0,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+		},
+	}, {
+		.set = ov5642_set_gain,
+		.ctrl = {
+			.id = V4L2_CID_GAIN,
+			.name = "Gain",
+			.minimum = 0,
+			.maximum = 511,
+			.step = 1,
+			.default_value = 0,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+		},
+	}, {
+		.set = ov5642_set_hue,
+		.ctrl = {
+			.id = V4L2_CID_HUE,
+			.name = "Hue",
+			.minimum = 0,
+			.maximum = 359,
+			.step = 1,
+			.default_value = 0,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+		},
+	}, {
+		.set = ov5642_set_contrast,
+		.ctrl = {
+			.id = V4L2_CID_CONTRAST,
+			.name = "Contrast",
+			.minimum = 0,
+			.maximum = 255,
+			.step = 1,
+			.default_value = 0,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+		},
+	}, {
+		.set = ov5642_set_saturation,
+		.ctrl = {
+			.id = V4L2_CID_SATURATION,
+			.name = "Saturation",
+			.minimum = 0,
+			.maximum = 255,
+			.step = 1,
+			.default_value = 64,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+		},
+	}, {
+		.set = ov5642_set_awb,
+		.ctrl = {
+			.id = V4L2_CID_AUTO_WHITE_BALANCE,
+			.name = "Auto White Balance",
+			.minimum = 0,
+			.maximum = 1,
+			.step = 1,
+			.default_value = 1,
+			.type = V4L2_CTRL_TYPE_BOOLEAN,
+		},
+	}, {
+		.set = ov5642_set_red_balance,
+		.ctrl = {
+			.id = V4L2_CID_RED_BALANCE,
+			.name = "Red Balance",
+			.minimum = 0,
+			.maximum = 4095,
+			.step = 1,
+			.default_value = 1024,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+		},
+	}, {
+		.set = ov5642_set_blue_balance,
+		.ctrl = {
+			.id = V4L2_CID_BLUE_BALANCE,
+			.name = "Blue Balance",
+			.minimum = 0,
+			.maximum = 4095,
+			.step = 1,
+			.default_value = 1024,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+		},
+	},
+};
+#define OV5642_NUM_CONTROLS ARRAY_SIZE(ov5642_ctrls)
+
+static struct ov5642_control *ov5642_get_ctrl(int id, int *index)
+{
+	struct ov5642_control *ret = NULL;
+	int i;
+
+	for (i = 0; i < OV5642_NUM_CONTROLS; i++) {
+		if (id == ov5642_ctrls[i].ctrl.id) {
+			ret = &ov5642_ctrls[i];
+			break;
+		}
+	}
+
+	if (ret && index)
+		*index = i;
+	return ret;
+}
+
+static int ov5642_restore_ctrls(struct ov5642_dev *sensor)
+{
+	struct ov5642_control *c;
+	int i;
+
+	for (i = 0; i < OV5642_NUM_CONTROLS; i++) {
+		c = &ov5642_ctrls[i];
+		c->set(sensor, sensor->ctrl_cache[i]);
+	}
+
+	return 0;
+}
+
+static int ov5642_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct ov5642_dev *sensor = ctrl_to_ov5642_dev(ctrl);
+	struct ov5642_control *c;
+	int ret = 0;
+	int i;
+
+	c = ov5642_get_ctrl(ctrl->id, &i);
+	if (!c)
+		return -EINVAL;
+
+	ret = c->set(sensor, ctrl->val);
+	/* update cached value if no error */
+	if (!ret)
+		sensor->ctrl_cache[i] = ctrl->val;
+
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops ov5642_ctrl_ops = {
+	.s_ctrl = ov5642_s_ctrl,
+};
+
+static int ov5642_init_controls(struct ov5642_dev *sensor)
+{
+	struct ov5642_control *c;
+	int i;
+
+	v4l2_ctrl_handler_init(&sensor->ctrl_hdl, OV5642_NUM_CONTROLS);
+
+	for (i = 0; i < OV5642_NUM_CONTROLS; i++) {
+		c = &ov5642_ctrls[i];
+
+		v4l2_ctrl_new_std(&sensor->ctrl_hdl, &ov5642_ctrl_ops,
+				  c->ctrl.id, c->ctrl.minimum, c->ctrl.maximum,
+				  c->ctrl.step, c->ctrl.default_value);
+	}
+
+	sensor->sd.ctrl_handler = &sensor->ctrl_hdl;
+	if (sensor->ctrl_hdl.error) {
+		int err = sensor->ctrl_hdl.error;
+
+		v4l2_ctrl_handler_free(&sensor->ctrl_hdl);
+
+		v4l2_err(&sensor->sd, "%s: error %d\n", __func__, err);
+		return err;
+	}
+	v4l2_ctrl_handler_setup(&sensor->ctrl_hdl);
+
+	return 0;
+}
+
+static int ov5642_enum_framesizes(struct v4l2_subdev *sd,
+				  struct v4l2_frmsizeenum *fsize)
+{
+	if (fsize->index >= ov5642_num_modes)
+		return -EINVAL;
+
+	fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+	fsize->discrete.width = ov5642_mode_info_data[0][fsize->index].width;
+	fsize->discrete.height = ov5642_mode_info_data[0][fsize->index].height;
+
+	return 0;
+}
+
+static int ov5642_enum_frameintervals(struct v4l2_subdev *sd,
+				      struct v4l2_frmivalenum *fi)
+{
+	struct ov5642_dev *sensor = to_ov5642_dev(sd);
+	enum ov5642_mode mode;
+
+	if (fi->index < 0 || fi->index >= ov5642_num_framerates)
+		return -EINVAL;
+
+	if (fi->width == 0 || fi->height == 0) {
+		pr_warn("Please assign width and height.\n");
+		return -EINVAL;
+	}
+
+	fi->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+	fi->discrete.numerator = 1;
+
+	mode = ov5642_find_nearest_mode(sensor, fi->width, fi->height);
+
+	if (ov5642_mode_info_data[fi->index][mode].init_data_ptr == NULL)
+		return -EINVAL;
+
+	fi->discrete.denominator = ov5642_framerates[fi->index];
+
+	pr_debug("ov5642: %dx%d: [%d] = %d fps\n",
+		 fi->width, fi->height, fi->index, fi->discrete.denominator);
+	return 0;
+}
+
+static int ov5642_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+	struct ov5642_dev *sensor = to_ov5642_dev(sd);
+
+	*status = !sensor->on ? V4L2_IN_ST_NO_POWER : 0;
+
+	return 0;
+}
+
+static int ov5642_s_routing(struct v4l2_subdev *sd, u32 input,
+			    u32 output, u32 config)
+{
+	return (input != 0) ? -EINVAL : 0;
+}
+
+static int ov5642_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+	*std = V4L2_STD_ALL;
+	return 0;
+}
+
+static int ov5642_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+				enum v4l2_mbus_pixelcode *code)
+{
+	struct ov5642_dev *sensor = to_ov5642_dev(sd);
+
+	if (index != 0)
+		return -EINVAL;
+
+	*code = sensor->fmt.code;
+
+	return 0;
+}
+
+static int ov5642_try_mbus_fmt(struct v4l2_subdev *sd,
+			       struct v4l2_mbus_framefmt *fmt)
+{
+	struct ov5642_dev *sensor = to_ov5642_dev(sd);
+	enum ov5642_mode mode;
+
+	mode = ov5642_find_nearest_mode(sensor, fmt->width, fmt->height);
+
+	fmt->width = ov5642_mode_info_data[0][mode].width;
+	fmt->height = ov5642_mode_info_data[0][mode].height;
+	fmt->code = sensor->fmt.code;
+
+	return 0;
+}
+
+static int ov5642_g_mbus_config(struct v4l2_subdev *sd,
+				struct v4l2_mbus_config *cfg)
+{
+	struct ov5642_dev *sensor = to_ov5642_dev(sd);
+
+	cfg->type = V4L2_MBUS_PARALLEL;
+	cfg->flags = sensor->ep.bus.parallel.flags;
+
+	return 0;
+}
+
+static int ov5642_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	return 0;
+}
+
+static struct v4l2_subdev_core_ops ov5642_core_ops = {
+	.s_power = ov5642_s_power,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
+};
+
+static struct v4l2_subdev_video_ops ov5642_video_ops = {
+	.enum_mbus_fmt = ov5642_enum_mbus_fmt,
+	.try_mbus_fmt = ov5642_try_mbus_fmt,
+	.g_mbus_fmt = ov5642_g_mbus_fmt,
+	.s_mbus_fmt = ov5642_s_mbus_fmt,
+	.s_parm = ov5642_s_parm,
+	.g_parm = ov5642_g_parm,
+	.enum_frameintervals = ov5642_enum_frameintervals,
+	.enum_framesizes = ov5642_enum_framesizes,
+	.g_input_status = ov5642_g_input_status,
+	.s_routing = ov5642_s_routing,
+	.querystd = ov5642_querystd,
+	.g_mbus_config  = ov5642_g_mbus_config,
+	.s_stream = ov5642_s_stream,
+};
+
+static struct v4l2_subdev_ops ov5642_subdev_ops = {
+	.core = &ov5642_core_ops,
+	.video = &ov5642_video_ops,
+};
+
+static void ov5642_power(struct ov5642_dev *sensor, bool enable)
+{
+	gpio_set_value(sensor->pwdn_gpio, enable ? 0 : 1);
+}
+
+#if 0
+/* we never need to reset the chip, but keep around */
+static void ov5642_reset(struct ov5642_dev *sensor)
+{
+	gpio_set_value(sensor->reset_gpio, 0);
+	usleep_range(1000, 1001);
+	gpio_set_value(sensor->reset_gpio, 1);
+}
+#endif
+
+static void ov5642_get_regulators(struct ov5642_dev *sensor)
+{
+	sensor->io_regulator = devm_regulator_get(sensor->dev, "DOVDD");
+	if (!IS_ERR(sensor->io_regulator)) {
+		regulator_set_voltage(sensor->io_regulator,
+				      OV5642_VOLTAGE_DIGITAL_IO,
+				      OV5642_VOLTAGE_DIGITAL_IO);
+	} else {
+		dev_dbg(sensor->dev, "%s: no io voltage reg found\n",
+			__func__);
+		sensor->io_regulator = NULL;
+	}
+
+	sensor->core_regulator = devm_regulator_get(sensor->dev, "DVDD");
+	if (!IS_ERR(sensor->core_regulator)) {
+		regulator_set_voltage(sensor->core_regulator,
+				      OV5642_VOLTAGE_DIGITAL_CORE,
+				      OV5642_VOLTAGE_DIGITAL_CORE);
+	} else {
+		sensor->core_regulator = NULL;
+		dev_dbg(sensor->dev, "%s: no core voltage reg found\n",
+			__func__);
+	}
+
+	sensor->analog_regulator = devm_regulator_get(sensor->dev, "AVDD");
+	if (!IS_ERR(sensor->analog_regulator)) {
+		regulator_set_voltage(sensor->analog_regulator,
+				      OV5642_VOLTAGE_ANALOG,
+				      OV5642_VOLTAGE_ANALOG);
+	} else {
+		sensor->analog_regulator = NULL;
+		dev_dbg(sensor->dev, "%s: no analog voltage reg found\n",
+			__func__);
+	}
+}
+
+/*!
+ * 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 device *dev = &client->dev;
+	struct device_node *endpoint;
+	struct ov5642_dev *sensor;
+	int i, xclk, ret;
+
+	sensor = devm_kzalloc(dev, sizeof(struct ov5642_dev),
+			      GFP_KERNEL);
+	if (!sensor)
+		return -ENOMEM;
+
+	sensor->i2c_client = client;
+	sensor->dev = dev;
+	sensor->fmt.code = V4L2_MBUS_FMT_YUYV8_2X8;
+	sensor->fmt.width = 640;
+	sensor->fmt.height = 480;
+	sensor->fmt.field = V4L2_FIELD_NONE;
+	sensor->streamcap.capability = V4L2_MODE_HIGHQUALITY |
+					   V4L2_CAP_TIMEPERFRAME;
+	sensor->streamcap.capturemode = 0;
+	sensor->streamcap.timeperframe.denominator = DEFAULT_FPS;
+	sensor->streamcap.timeperframe.numerator = 1;
+
+	sensor->current_mode = ov5642_mode_VGA_640_480;
+	sensor->current_fr = ov5642_30_fps;
+
+	endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+	if (!endpoint) {
+		dev_err(dev, "endpoint node not found\n");
+		return -EINVAL;
+	}
+
+	v4l2_of_parse_endpoint(endpoint, &sensor->ep);
+	if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL) {
+		dev_err(dev, "invalid bus type, must be parallel\n");
+		return -EINVAL;
+	}
+	of_node_put(endpoint);
+
+	/* get system clock (xclk) frequency */
+	ret = of_property_read_u32(dev->of_node, "xclk", &xclk);
+	if (!ret) {
+		if (xclk < OV5642_XCLK_MIN || xclk > OV5642_XCLK_MAX) {
+			dev_err(dev, "invalid xclk frequency\n");
+			return -EINVAL;
+		}
+		sensor->xclk_freq = xclk;
+	}
+
+	/* get system clock (xclk) */
+	sensor->xclk = devm_clk_get(dev, "xclk");
+	if (!IS_ERR(sensor->xclk)) {
+		if (!sensor->xclk_freq) {
+			dev_err(dev,
+				"xclk requires xclk frequency!\n");
+			return -EINVAL;
+		}
+		clk_set_rate(sensor->xclk, sensor->xclk_freq);
+	} else
+		sensor->xclk = NULL;
+
+	ret = of_get_named_gpio(dev->of_node, "pwdn-gpios", 0);
+	if (!gpio_is_valid(ret)) {
+		dev_err(dev, "no sensor pwdn pin available");
+		return ret;
+	}
+	sensor->pwdn_gpio = ret;
+	ret = devm_gpio_request_one(dev, sensor->pwdn_gpio,
+				    GPIOF_OUT_INIT_HIGH, "ov5632_pwdn");
+	if (ret < 0) {
+		dev_err(dev, "request for power down gpio failed\n");
+		return ret;
+	}
+
+	ret = of_get_named_gpio(dev->of_node, "reset-gpios", 0);
+	if (!gpio_is_valid(ret)) {
+		dev_err(dev, "no reset pin available");
+		return ret;
+	}
+	sensor->reset_gpio = ret;
+	ret = devm_gpio_request_one(dev, sensor->reset_gpio,
+				    GPIOF_OUT_INIT_HIGH, "ov5632_reset");
+	if (ret < 0) {
+		dev_err(dev, "request for reset gpio failed\n");
+		return ret;
+	}
+
+	/*
+	 * No idea what this "gp" gpio to the sensor is used for,
+	 * but acquire it and set it high.
+	 */
+	ret = of_get_named_gpio(dev->of_node, "gp-gpios", 0);
+	if (gpio_is_valid(ret)) {
+		sensor->gp_gpio = ret;
+		ret = devm_gpio_request_one(dev, sensor->gp_gpio,
+					    GPIOF_OUT_INIT_HIGH, "ov5632_gp");
+		if (ret < 0) {
+			dev_err(dev, "request for gp gpio failed\n");
+			return ret;
+		}
+		gpio_set_value(sensor->gp_gpio, 1);
+	}
+
+	dev_info(dev, "gpios: reset %d, power-down %d, gp %d\n",
+		 sensor->reset_gpio, sensor->pwdn_gpio, sensor->gp_gpio);
+
+	/* initialize the cached controls to their defaults */
+	for (i = 0; i < OV5642_NUM_CONTROLS; i++) {
+		struct ov5642_control *c = &ov5642_ctrls[i];
+		sensor->ctrl_cache[i] = c->ctrl.default_value;
+	}
+	sensor->awb_on = sensor->agc_on = true;
+
+	v4l2_i2c_subdev_init(&sensor->sd, client, &ov5642_subdev_ops);
+
+	ov5642_get_regulators(sensor);
+
+	ov5642_s_power(&sensor->sd, 1);
+
+	ret = ov5642_init_controls(sensor);
+
+	ov5642_s_power(&sensor->sd, 0);
+
+	return ret;
+}
+
+/*!
+ * ov5642 I2C detach function
+ *
+ * @param client            struct i2c_client *
+ * @return  Error code indicating success or failure
+ */
+static int ov5642_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct ov5642_dev *sensor = to_ov5642_dev(sd);
+
+	ov5642_regulators_off(sensor);
+
+	v4l2_ctrl_handler_free(&sensor->ctrl_hdl);
+
+	return 0;
+}
+
+static const struct i2c_device_id ov5642_id[] = {
+	{ "ov5642", 0 },
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, ov5642_id);
+
+static struct of_device_id ov5642_dt_ids[] = {
+	{ .compatible = "ovti,ov5642" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ov5642_dt_ids);
+
+static struct i2c_driver ov5642_driver = {
+	.driver = {
+		.name	= "ov5642",
+		.owner	= THIS_MODULE,
+		.of_match_table	= ov5642_dt_ids,
+	},
+	.id_table	= ov5642_id,
+	.probe		= ov5642_probe,
+	.remove		= ov5642_remove,
+};
+
+module_i2c_driver(ov5642_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("OV5642 Camera Subdev Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 42/43] media: imx6: Add support for ADV7180 Video Decoder
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (40 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 41/43] media: imx6: Add support for Parallel OV5642 Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2015-01-17 19:54   ` Fabio Estevam
  2014-06-07 21:56 ` [PATCH 43/43] ARM: imx_v6_v7_defconfig: Enable video4linux drivers Steve Longerbeam
                   ` (2 subsequent siblings)
  44 siblings, 1 reply; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

This driver is based on adv7180.c from Freescale imx_3.10.17_1.0.0_beta
branch, modified heavily for code cleanup and converted from int-device
to subdev.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 drivers/staging/media/imx6/capture/Kconfig   |    7 +
 drivers/staging/media/imx6/capture/Makefile  |    1 +
 drivers/staging/media/imx6/capture/adv7180.c | 1298 ++++++++++++++++++++++++++
 3 files changed, 1306 insertions(+)
 create mode 100644 drivers/staging/media/imx6/capture/adv7180.c

diff --git a/drivers/staging/media/imx6/capture/Kconfig b/drivers/staging/media/imx6/capture/Kconfig
index 5e6a610..ee4ed8a 100644
--- a/drivers/staging/media/imx6/capture/Kconfig
+++ b/drivers/staging/media/imx6/capture/Kconfig
@@ -23,4 +23,11 @@ config IMX6_CAMERA_OV5640_MIPI
        ---help---
          MIPI CSI-2 OV5640 Camera support.
 
+config IMX6_CAMERA_ADV7180
+       tristate "Analog Devices ADV7180 Video Decoder support"
+       depends on VIDEO_IMX6_CAMERA
+       default y
+       ---help---
+         Analog Devices ADV7180 Video Decoder support.
+
 endmenu
diff --git a/drivers/staging/media/imx6/capture/Makefile b/drivers/staging/media/imx6/capture/Makefile
index bcb2c16..d6b456c 100644
--- a/drivers/staging/media/imx6/capture/Makefile
+++ b/drivers/staging/media/imx6/capture/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_VIDEO_IMX6_CAMERA) += mx6-camera.o
 obj-$(CONFIG_IMX6_MIPI_CSI2) += mipi-csi2.o
 obj-$(CONFIG_IMX6_CAMERA_OV5640_MIPI) += ov5640-mipi.o
 obj-$(CONFIG_IMX6_CAMERA_OV5642) += ov5642.o
+obj-$(CONFIG_IMX6_CAMERA_ADV7180) += adv7180.o
diff --git a/drivers/staging/media/imx6/capture/adv7180.c b/drivers/staging/media/imx6/capture/adv7180.c
new file mode 100644
index 0000000..f924ce7
--- /dev/null
+++ b/drivers/staging/media/imx6/capture/adv7180.c
@@ -0,0 +1,1298 @@
+/*
+ * Analog Device ADV7180 video decoder driver
+ *
+ * Copyright (c) 2012-2014 Mentor Graphics Inc.
+ * Copyright 2005-2012 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/semaphore.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/wait.h>
+#include <linux/videodev2.h>
+#include <linux/workqueue.h>
+#include <linux/regulator/consumer.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-of.h>
+#include <media/v4l2-ctrls.h>
+#include <media/imx6.h>
+
+struct adv7180_dev {
+	struct i2c_client *i2c_client;
+	struct device *dev;
+	struct v4l2_subdev sd;
+	struct v4l2_of_endpoint ep; /* the parsed DT endpoint info */
+	struct v4l2_ctrl_handler ctrl_hdl;
+	struct v4l2_mbus_framefmt fmt;
+	struct v4l2_captureparm streamcap;
+	int rev_id;
+	bool on;
+
+	bool locked;             /* locked to signal */
+
+	/* control settings */
+	int brightness;
+	int hue;
+	int contrast;
+	int saturation;
+	int red;
+	int green;
+	int blue;
+	int ae_mode;
+
+	struct regulator *dvddio;
+	struct regulator *dvdd;
+	struct regulator *avdd;
+	struct regulator *pvdd;
+	int pwdn_gpio;
+
+	v4l2_std_id std_id;
+
+	/* Standard index of ADV7180. */
+	int video_idx;
+
+	/* Current analog input mux */
+	int current_input;
+
+	struct mutex mutex;
+};
+
+static inline struct adv7180_dev *to_adv7180_dev(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct adv7180_dev, sd);
+}
+
+static inline struct adv7180_dev *ctrl_to_adv7180_dev(struct v4l2_ctrl *ctrl)
+{
+	return container_of(ctrl->handler, struct adv7180_dev, ctrl_hdl);
+}
+
+/*! List of input video formats supported. The video formats is corresponding
+ * with v4l2 id in video_fmt_t
+ */
+enum {
+	ADV7180_NTSC = 0,	/*!< Locked on (M) NTSC video signal. */
+	ADV7180_PAL,		/*!< (B, G, H, I, N)PAL video signal. */
+};
+
+/*! Number of video standards supported (including 'not locked' signal). */
+#define ADV7180_STD_MAX		(ADV7180_PAL + 1)
+
+/*! Video format structure. */
+struct video_fmt_t {
+	int v4l2_id;		/*!< Video for linux ID. */
+	char name[16];		/*!< Name (e.g., "NTSC", "PAL", etc.) */
+	struct v4l2_rect raw;
+	struct v4l2_rect crop;
+};
+
+/*! Description of video formats supported.
+ *
+ *  PAL: raw=720x625, crop=720x576.
+ *  NTSC: raw=720x525, crop=720x480.
+ */
+static struct video_fmt_t video_fmts[] = {
+	{       /* NTSC */
+		.v4l2_id = V4L2_STD_NTSC,
+		.name = "NTSC",
+		.raw = {
+			.width = 720,
+			.height = 525,
+		},
+		.crop = {
+			.width = 720,
+			.height = 480,
+			.top = 13,
+			.left = 0,
+		}
+	}, {    /* (B, G, H, I, N) PAL */
+		.v4l2_id = V4L2_STD_PAL,
+		.name = "PAL",
+		.raw = {
+			.width = 720,
+			.height = 625,
+		},
+		.crop = {
+			.width = 720,
+			.height = 576,
+		},
+	},
+};
+
+#define IF_NAME                    "adv7180"
+#define ADV7180_INPUT_CTL              0x00	/* Input Control */
+#define ADV7180_STATUS_1               0x10	/* Status #1 */
+#define   ADV7180_IN_LOCK              (1 << 0)
+#define   ADV7180_LOST_LOCK            (1 << 1)
+#define   ADV7180_FSC_LOCK             (1 << 2)
+#define   ADV7180_AD_RESULT_BIT        4
+#define   ADV7180_AD_RESULT_MASK       (0x7 << ADV7180_AD_RESULT_BIT)
+#define   ADV7180_AD_NTSC              0
+#define   ADV7180_AD_NTSC_4_43         1
+#define   ADV7180_AD_PAL_M             2
+#define   ADV7180_AD_PAL_60            3
+#define   ADV7180_AD_PAL               4
+#define   ADV7180_AD_SECAM             5
+#define   ADV7180_AD_PAL_N             6
+#define   ADV7180_AD_SECAM_525         7
+#define ADV7180_CONTRAST               0x08	/* Contrast */
+#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 */
+#define ADV7180_INT_CONFIG_1           0x40     /* Interrupt Config 1 */
+#define ADV7180_INT_STATUS_1           0x42     /* Interrupt Status 1 (r/o) */
+#define   ADV7180_INT_SD_LOCK          (1 << 0)
+#define   ADV7180_INT_SD_UNLOCK        (1 << 1)
+#define ADV7180_INT_CLEAR_1            0x43     /* Interrupt Clear 1 (w/o) */
+#define ADV7180_INT_MASK_1             0x44     /* Interrupt Mask 1 */
+#define ADV7180_INT_STATUS_2           0x46     /* Interrupt Status 2 (r/o) */
+#define ADV7180_INT_CLEAR_2            0x47     /* Interrupt Clear 2 (w/o) */
+#define ADV7180_INT_MASK_2             0x48     /* Interrupt Mask 2 */
+#define ADV7180_INT_RAW_STATUS_3       0x49   /* Interrupt Raw Status 3 (r/o) */
+#define   ADV7180_INT_SD_V_LOCK        (1 << 1)
+#define ADV7180_INT_STATUS_3           0x4a   /* Interrupt Status 3 (r/o) */
+#define   ADV7180_INT_SD_V_LOCK_CHNG   (1 << 1)
+#define   ADV7180_INT_SD_AD_CHNG       (1 << 3)
+#define ADV7180_INT_CLEAR_3            0x4b     /* Interrupt Clear 3 (w/o) */
+#define ADV7180_INT_MASK_3             0x4c     /* Interrupt Mask 3 */
+
+/* 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 = 0,	/* 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 = 128,	/* check this value */
+		.flags = 0,
+	}, {
+		.id = V4L2_CID_CONTRAST,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+		.name = "Contrast",
+		.minimum = 0,
+		.maximum = 255,
+		.step = 0x1,
+		.default_value = 128,
+		.flags = 0,
+	},
+};
+#define ADV7180_NUM_CONTROLS ARRAY_SIZE(adv7180_qctrl)
+
+struct adv7180_inputs_t {
+	const char *desc;   /* Analog input description */
+	u8 insel;           /* insel bits to select this input */
+};
+
+/* Analog Inputs on 64-Lead and 48-Lead LQFP */
+static const struct adv7180_inputs_t adv7180_inputs_64_48[] = {
+	{ .insel = 0x00, .desc = "ADV7180 Composite on Ain1" },
+	{ .insel = 0x01, .desc = "ADV7180 Composite on Ain2" },
+	{ .insel = 0x02, .desc = "ADV7180 Composite on Ain3" },
+	{ .insel = 0x03, .desc = "ADV7180 Composite on Ain4" },
+	{ .insel = 0x04, .desc = "ADV7180 Composite on Ain5" },
+	{ .insel = 0x05, .desc = "ADV7180 Composite on Ain6" },
+	{ .insel = 0x06, .desc = "ADV7180 Y/C on Ain1/4" },
+	{ .insel = 0x07, .desc = "ADV7180 Y/C on Ain2/5" },
+	{ .insel = 0x08, .desc = "ADV7180 Y/C on Ain3/6" },
+	{ .insel = 0x09, .desc = "ADV7180 YPbPr on Ain1/4/5" },
+	{ .insel = 0x0a, .desc = "ADV7180 YPbPr on Ain2/3/6" },
+};
+#define NUM_INPUTS_64_48 ARRAY_SIZE(adv7180_inputs_64_48)
+
+#if 0
+/*
+ * FIXME: there is no way to distinguish LQFP vs LFCSP chips, so
+ * we will just have to assume LQFP.
+ */
+/* Analog Inputs on 40-Lead and 32-Lead LFCSP */
+static const struct adv7180_inputs_t adv7180_inputs_40_32[] = {
+	{ .insel = 0x00, .desc = "ADV7180 Composite on Ain1" },
+	{ .insel = 0x03, .desc = "ADV7180 Composite on Ain2" },
+	{ .insel = 0x04, .desc = "ADV7180 Composite on Ain3" },
+	{ .insel = 0x06, .desc = "ADV7180 Y/C on Ain1/2" },
+	{ .insel = 0x09, .desc = "ADV7180 YPbPr on Ain1/2/3" },
+};
+#define NUM_INPUTS_40_32 ARRAY_SIZE(adv7180_inputs_40_32)
+#endif
+
+#define ADV7180_VOLTAGE_ANALOG               1800000
+#define ADV7180_VOLTAGE_DIGITAL_CORE         1800000
+#define ADV7180_VOLTAGE_DIGITAL_IO           3300000
+#define ADV7180_VOLTAGE_PLL                  1800000
+
+static int adv7180_regulator_enable(struct adv7180_dev *sensor)
+{
+	struct device *dev = sensor->dev;
+	int ret = 0;
+
+	sensor->dvddio = devm_regulator_get(dev, "DOVDD");
+	if (!IS_ERR(sensor->dvddio)) {
+		regulator_set_voltage(sensor->dvddio,
+				      ADV7180_VOLTAGE_DIGITAL_IO,
+				      ADV7180_VOLTAGE_DIGITAL_IO);
+		ret = regulator_enable(sensor->dvddio);
+		if (ret) {
+			v4l2_err(&sensor->sd, "set io voltage failed\n");
+			return ret;
+		}
+	} else
+		v4l2_warn(&sensor->sd, "cannot get io voltage\n");
+
+	sensor->dvdd = devm_regulator_get(dev, "DVDD");
+	if (!IS_ERR(sensor->dvdd)) {
+		regulator_set_voltage(sensor->dvdd,
+				      ADV7180_VOLTAGE_DIGITAL_CORE,
+				      ADV7180_VOLTAGE_DIGITAL_CORE);
+		ret = regulator_enable(sensor->dvdd);
+		if (ret) {
+			v4l2_err(&sensor->sd, "set core voltage failed\n");
+			return ret;
+		}
+	} else
+		v4l2_warn(&sensor->sd, "cannot get core voltage\n");
+
+	sensor->avdd = devm_regulator_get(dev, "AVDD");
+	if (!IS_ERR(sensor->avdd)) {
+		regulator_set_voltage(sensor->avdd,
+				      ADV7180_VOLTAGE_ANALOG,
+				      ADV7180_VOLTAGE_ANALOG);
+		ret = regulator_enable(sensor->avdd);
+		if (ret) {
+			v4l2_err(&sensor->sd, "set analog voltage failed\n");
+			return ret;
+		}
+	} else
+		v4l2_warn(&sensor->sd, "cannot get analog voltage\n");
+
+	sensor->pvdd = devm_regulator_get(dev, "PVDD");
+	if (!IS_ERR(sensor->pvdd)) {
+		regulator_set_voltage(sensor->pvdd,
+				      ADV7180_VOLTAGE_PLL,
+				      ADV7180_VOLTAGE_PLL);
+		ret = regulator_enable(sensor->pvdd);
+		if (ret) {
+			v4l2_err(&sensor->sd, "set pll voltage failed\n");
+			return ret;
+		}
+	} else
+		v4l2_warn(&sensor->sd, "cannot get pll voltage\n");
+
+	return ret;
+}
+
+static void adv7180_regulator_disable(struct adv7180_dev *sensor)
+{
+	if (sensor->dvddio)
+		regulator_disable(sensor->dvddio);
+
+	if (sensor->dvdd)
+		regulator_disable(sensor->dvdd);
+
+	if (sensor->avdd)
+		regulator_disable(sensor->avdd);
+
+	if (sensor->pvdd)
+		regulator_disable(sensor->pvdd);
+}
+
+/***********************************************************************
+ * I2C transfer.
+ ***********************************************************************/
+
+/*! 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 int adv7180_read(struct adv7180_dev *sensor, u8 reg)
+{
+	int ret = i2c_smbus_read_byte_data(sensor->i2c_client, reg);
+	if (ret < 0)
+		v4l2_err(&sensor->sd, "%s: read reg error: reg=%2x\n",
+			 __func__, reg);
+	return ret;
+}
+
+/*! 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(struct adv7180_dev *sensor, u8 reg, u8 val)
+{
+	int ret = i2c_smbus_write_byte_data(sensor->i2c_client, reg, val);
+	if (ret < 0)
+		v4l2_err(&sensor->sd, "%s: write reg error:reg=%2x,val=%2x\n",
+			 __func__, reg, val);
+	return ret;
+}
+
+/* Read AD_RESULT to get the autodetected video standard */
+static bool adv7180_get_autodetect_std(struct adv7180_dev *sensor)
+{
+	int stat1, ad_result, idx = ADV7180_PAL;
+	v4l2_std_id std = V4L2_STD_PAL;
+	bool ret = false;
+
+	/*
+	 * When the chip loses lock, it continues to send data at whatever
+	 * standard was detected before, so leave the standard at the last
+	 * detected standard.
+	 */
+	if (!sensor->locked)
+		return false; /* no status change */
+
+	stat1 = adv7180_read(sensor, ADV7180_STATUS_1);
+	ad_result = (stat1 & ADV7180_AD_RESULT_MASK) >> ADV7180_AD_RESULT_BIT;
+
+	switch (ad_result) {
+	case ADV7180_AD_PAL:
+		std = V4L2_STD_PAL;
+		idx = ADV7180_PAL;
+		break;
+	case ADV7180_AD_PAL_M:
+		std = V4L2_STD_PAL_M;
+		/* PAL M is very similar to NTSC (same lines/field) */
+		idx = ADV7180_NTSC;
+		break;
+	case ADV7180_AD_PAL_N:
+		std = V4L2_STD_PAL_N;
+		idx = ADV7180_PAL;
+		break;
+	case ADV7180_AD_PAL_60:
+		std = V4L2_STD_PAL_60;
+		/* PAL 60 has same lines as NTSC */
+		idx = ADV7180_NTSC;
+		break;
+	case ADV7180_AD_NTSC:
+		std = V4L2_STD_NTSC;
+		idx = ADV7180_NTSC;
+		break;
+	case ADV7180_AD_NTSC_4_43:
+		std = V4L2_STD_NTSC_443;
+		idx = ADV7180_NTSC;
+		break;
+	case ADV7180_AD_SECAM:
+		std = V4L2_STD_SECAM;
+		idx = ADV7180_PAL;
+		break;
+	case ADV7180_AD_SECAM_525:
+		/*
+		 * FIXME: could not find any info on "SECAM 525", assume
+		 * it is SECAM but with NTSC line standard.
+		 */
+		std = V4L2_STD_SECAM;
+		idx = ADV7180_NTSC;
+		break;
+	}
+
+	if (std != sensor->std_id) {
+		sensor->video_idx = idx;
+		sensor->std_id = std;
+		sensor->fmt.width = video_fmts[sensor->video_idx].raw.width;
+		sensor->fmt.height = video_fmts[sensor->video_idx].raw.height;
+		ret = true;
+	}
+
+	return ret;
+}
+
+/* Update lock status */
+static bool adv7180_update_lock_status(struct adv7180_dev *sensor)
+{
+	int stat1, int_stat1, int_stat3, int_raw_stat3;
+	bool ret;
+
+	stat1 = adv7180_read(sensor, ADV7180_STATUS_1);
+
+	/* Switch to interrupt register map */
+	adv7180_write_reg(sensor, 0x0E, 0x20);
+
+	int_stat1 = adv7180_read(sensor, ADV7180_INT_STATUS_1);
+	int_stat3 = adv7180_read(sensor, ADV7180_INT_STATUS_3);
+	/* clear the interrupts */
+	adv7180_write_reg(sensor, ADV7180_INT_CLEAR_1, int_stat1);
+	adv7180_write_reg(sensor, ADV7180_INT_CLEAR_3, int_stat3);
+
+	int_raw_stat3 = adv7180_read(sensor, ADV7180_INT_RAW_STATUS_3);
+
+	/* Switch back to normal register map */
+	adv7180_write_reg(sensor, 0x0E, 0x00);
+
+	ret = (((int_stat1 & ADV7180_INT_SD_LOCK) ||
+		(int_stat1 & ADV7180_INT_SD_UNLOCK) ||
+		(int_stat3 & ADV7180_INT_SD_V_LOCK_CHNG)) != 0);
+
+	sensor->locked = ((stat1 & ADV7180_IN_LOCK) &&
+			  (stat1 & ADV7180_FSC_LOCK) &&
+			  (int_raw_stat3 & ADV7180_INT_SD_V_LOCK));
+
+	return ret;
+}
+
+static void adv7180_power(struct adv7180_dev *sensor, bool enable)
+{
+	if (enable && !sensor->on) {
+		if (gpio_is_valid(sensor->pwdn_gpio))
+			gpio_set_value_cansleep(sensor->pwdn_gpio, 1);
+
+		usleep_range(5000, 5001);
+		adv7180_write_reg(sensor, ADV7180_PWR_MNG, 0);
+	} else if (!enable && sensor->on) {
+		adv7180_write_reg(sensor, ADV7180_PWR_MNG, 0x24);
+
+		if (gpio_is_valid(sensor->pwdn_gpio))
+			gpio_set_value_cansleep(sensor->pwdn_gpio, 0);
+	}
+
+	sensor->on = enable;
+}
+
+/*
+ * Enable the SD_UNLOCK and SD_AD_CHNG interrupts.
+ */
+static void adv7180_enable_interrupts(struct adv7180_dev *sensor)
+{
+	mutex_lock(&sensor->mutex);
+
+	/* Switch to interrupt register map */
+	adv7180_write_reg(sensor, 0x0E, 0x20);
+	/* INTRQ active low, active until cleared */
+	adv7180_write_reg(sensor, ADV7180_INT_CONFIG_1, 0xd1);
+	/* unmask SD_UNLOCK and SD_LOCK */
+	adv7180_write_reg(sensor, ADV7180_INT_MASK_1,
+			  ADV7180_INT_SD_UNLOCK | ADV7180_INT_SD_LOCK);
+	/* unmask SD_AD_CHNG and SD_V_LOCK_CHNG */
+	adv7180_write_reg(sensor, ADV7180_INT_MASK_3,
+			  ADV7180_INT_SD_AD_CHNG | ADV7180_INT_SD_V_LOCK_CHNG);
+	/* Switch back to normal register map */
+	adv7180_write_reg(sensor, 0x0E, 0x00);
+
+	mutex_unlock(&sensor->mutex);
+}
+
+/* threaded irq handler */
+static irqreturn_t adv7180_interrupt(int irq, void *dev_id)
+{
+	struct adv7180_dev *sensor = dev_id;
+	bool std_change, lock_status_change;
+
+	mutex_lock(&sensor->mutex);
+
+	lock_status_change = adv7180_update_lock_status(sensor);
+	std_change = adv7180_get_autodetect_std(sensor);
+
+	mutex_unlock(&sensor->mutex);
+
+	if (lock_status_change || std_change)
+		v4l2_subdev_notify(&sensor->sd,
+				   DECODER_STATUS_CHANGE_NOTIFY, NULL);
+
+	return IRQ_HANDLED;
+}
+
+static const struct adv7180_inputs_t *
+adv7180_find_input(struct adv7180_dev *sensor, u32 insel)
+{
+	int i;
+
+	for (i = 0; i < NUM_INPUTS_64_48; i++) {
+		if (insel == adv7180_inputs_64_48[i].insel)
+			return &adv7180_inputs_64_48[i];
+	}
+
+	return NULL;
+}
+
+/* --------------- Subdev Operations --------------- */
+
+static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
+{
+	struct adv7180_dev *sensor = to_adv7180_dev(sd);
+
+	mutex_lock(&sensor->mutex);
+
+	/*
+	 * If we have the ADV7180 irq, we can just return the currently
+	 * detected standard. Otherwise we have to poll the AD_RESULT
+	 * bits every time querystd() is called.
+	 */
+	if (!sensor->i2c_client->irq) {
+		adv7180_update_lock_status(sensor);
+		adv7180_get_autodetect_std(sensor);
+	}
+
+	*std = sensor->std_id;
+
+	mutex_unlock(&sensor->mutex);
+
+	return 0;
+}
+
+static int adv7180_s_power(struct v4l2_subdev *sd, int on)
+{
+	return 0;
+}
+
+static int adv7180_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+	struct adv7180_dev *sensor = to_adv7180_dev(sd);
+	struct v4l2_captureparm *cparm = &a->parm.capture;
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	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;
+
+	return 0;
+}
+
+static int adv7180_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
+{
+	return 0;
+}
+
+static int adv7180_g_mbus_fmt(struct v4l2_subdev *sd,
+			      struct v4l2_mbus_framefmt *fmt)
+
+{
+	struct adv7180_dev *sensor = to_adv7180_dev(sd);
+
+	*fmt = sensor->fmt;
+	return 0;
+}
+
+/*
+ * This driver autodetects a standard video mode, so we don't allow
+ * setting a mode, just return the current autodetected mode.
+ *
+ * Return 0.
+ */
+static int adv7180_try_mbus_fmt(struct v4l2_subdev *sd,
+				struct v4l2_mbus_framefmt *fmt)
+{
+	struct adv7180_dev *sensor = to_adv7180_dev(sd);
+
+	*fmt = sensor->fmt;
+	return 0;
+}
+
+/*
+ * This driver autodetects a standard video mode, so we don't allow
+ * setting a mode, just return the current autodetected mode.
+ *
+ * Return 0.
+ */
+static int adv7180_s_mbus_fmt(struct v4l2_subdev *sd,
+			      struct v4l2_mbus_framefmt *fmt)
+{
+	struct adv7180_dev *sensor = to_adv7180_dev(sd);
+
+	*fmt = sensor->fmt;
+	return 0;
+}
+
+
+/* Controls */
+
+static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct adv7180_dev *sensor = ctrl_to_adv7180_dev(ctrl);
+	int retval = 0;
+	u8 tmp;
+
+	switch (ctrl->id) {
+	case V4L2_CID_BRIGHTNESS:
+		tmp = ctrl->val;
+		adv7180_write_reg(sensor, ADV7180_BRIGHTNESS, tmp);
+		sensor->brightness = ctrl->val;
+		break;
+	case V4L2_CID_CONTRAST:
+		tmp = ctrl->val;
+		adv7180_write_reg(sensor, ADV7180_CONTRAST, tmp);
+		sensor->contrast = ctrl->val;
+		break;
+	case V4L2_CID_SATURATION:
+		tmp = ctrl->val;
+		adv7180_write_reg(sensor, ADV7180_SD_SATURATION_CB, tmp);
+		adv7180_write_reg(sensor, ADV7180_SD_SATURATION_CR, tmp);
+		sensor->saturation = ctrl->val;
+		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;
+}
+
+static const struct v4l2_ctrl_ops adv7180_ctrl_ops = {
+	.s_ctrl = adv7180_s_ctrl,
+};
+
+static int adv7180_init_controls(struct adv7180_dev *sensor)
+{
+	struct v4l2_queryctrl *c;
+	int i;
+
+	v4l2_ctrl_handler_init(&sensor->ctrl_hdl, ADV7180_NUM_CONTROLS);
+
+	for (i = 0; i < ADV7180_NUM_CONTROLS; i++) {
+		c = &adv7180_qctrl[i];
+
+		v4l2_ctrl_new_std(&sensor->ctrl_hdl, &adv7180_ctrl_ops,
+				  c->id, c->minimum, c->maximum,
+				  c->step, c->default_value);
+	}
+
+	sensor->sd.ctrl_handler = &sensor->ctrl_hdl;
+	if (sensor->ctrl_hdl.error) {
+		int err = sensor->ctrl_hdl.error;
+
+		v4l2_ctrl_handler_free(&sensor->ctrl_hdl);
+
+		v4l2_err(&sensor->sd, "%s: error %d\n", __func__, err);
+		return err;
+	}
+	v4l2_ctrl_handler_setup(&sensor->ctrl_hdl);
+
+	return 0;
+}
+
+static int adv7180_enum_framesizes(struct v4l2_subdev *sd,
+				   struct v4l2_frmsizeenum *fsize)
+{
+	struct adv7180_dev *sensor = to_adv7180_dev(sd);
+
+	if (fsize->index > 0)
+		return -EINVAL;
+
+	fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+	fsize->discrete.width = video_fmts[sensor->video_idx].crop.width;
+	fsize->discrete.height = video_fmts[sensor->video_idx].crop.height;
+	return 0;
+}
+
+static int adv7180_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+	struct adv7180_dev *sensor = to_adv7180_dev(sd);
+
+	a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	a->c = video_fmts[sensor->video_idx].crop;
+
+	return 0;
+}
+
+static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status)
+{
+	struct adv7180_dev *sensor = to_adv7180_dev(sd);
+
+	mutex_lock(&sensor->mutex);
+
+	*status = 0;
+
+	if (sensor->on) {
+		if (!sensor->locked)
+			*status = V4L2_IN_ST_NO_SIGNAL | V4L2_IN_ST_NO_SYNC;
+	} else
+		*status = V4L2_IN_ST_NO_POWER;
+
+	mutex_unlock(&sensor->mutex);
+
+	return 0;
+}
+
+static int adv7180_s_routing(struct v4l2_subdev *sd, u32 input,
+			     u32 output, u32 config)
+{
+	struct adv7180_dev *sensor = to_adv7180_dev(sd);
+	const struct adv7180_inputs_t *advinput;
+
+	advinput = adv7180_find_input(sensor, input);
+	if (!advinput)
+		return -EINVAL;
+
+	mutex_lock(&sensor->mutex);
+
+	adv7180_write_reg(sensor, ADV7180_INPUT_CTL, advinput->insel);
+
+	sensor->current_input = input;
+
+	mutex_unlock(&sensor->mutex);
+
+	return 0;
+}
+
+static int adv7180_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+				 enum v4l2_mbus_pixelcode *code)
+{
+	struct adv7180_dev *sensor = to_adv7180_dev(sd);
+
+	if (index != 0)
+		return -EINVAL;
+
+	*code = sensor->fmt.code;
+
+	return 0;
+}
+
+static int adv7180_g_mbus_config(struct v4l2_subdev *sd,
+				struct v4l2_mbus_config *cfg)
+{
+	struct adv7180_dev *sensor = to_adv7180_dev(sd);
+
+	cfg->type = V4L2_MBUS_BT656;
+	cfg->flags = sensor->ep.bus.parallel.flags;
+
+	return 0;
+}
+
+static int adv7180_s_stream(struct v4l2_subdev *sd, int enable)
+{
+	return 0;
+}
+
+static struct v4l2_subdev_core_ops adv7180_core_ops = {
+	.s_power = adv7180_s_power,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
+};
+
+static struct v4l2_subdev_video_ops adv7180_video_ops = {
+	.enum_mbus_fmt = adv7180_enum_mbus_fmt,
+	.try_mbus_fmt = adv7180_try_mbus_fmt,
+	.g_mbus_fmt = adv7180_g_mbus_fmt,
+	.s_mbus_fmt = adv7180_s_mbus_fmt,
+	.s_parm = adv7180_s_parm,
+	.g_parm = adv7180_g_parm,
+	.enum_framesizes = adv7180_enum_framesizes,
+	.g_crop = adv7180_g_crop,
+	.g_input_status = adv7180_g_input_status,
+	.s_routing = adv7180_s_routing,
+	.querystd = adv7180_querystd,
+	.g_mbus_config  = adv7180_g_mbus_config,
+	.s_stream = adv7180_s_stream,
+};
+
+static struct v4l2_subdev_ops adv7180_subdev_ops = {
+	.core = &adv7180_core_ops,
+	.video = &adv7180_video_ops,
+};
+
+/***********************************************************************
+ * I2C client and driver.
+ ***********************************************************************/
+
+/*! ADV7180 Reset function.
+ *
+ *  @return		None.
+ */
+static void adv7180_hard_reset(struct adv7180_dev *sensor)
+{
+	/* assert reset bit */
+	adv7180_write_reg(sensor, ADV7180_PWR_MNG, 0x80);
+	usleep_range(5000, 5001);
+
+	/* Set analog mux for Composite Ain1 */
+	adv7180_write_reg(sensor, ADV7180_INPUT_CTL, 0x00);
+
+	/* Datasheet recommends */
+	adv7180_write_reg(sensor, 0x01, 0xc8);
+	adv7180_write_reg(sensor, 0x02, 0x04);
+	adv7180_write_reg(sensor, 0x03, 0x00);
+	adv7180_write_reg(sensor, 0x04, 0x45);
+	adv7180_write_reg(sensor, 0x05, 0x00);
+	adv7180_write_reg(sensor, 0x06, 0x02);
+	adv7180_write_reg(sensor, 0x07, 0x7F);
+	adv7180_write_reg(sensor, 0x08, 0x80);
+	adv7180_write_reg(sensor, 0x0A, 0x00);
+	adv7180_write_reg(sensor, 0x0B, 0x00);
+	adv7180_write_reg(sensor, 0x0C, 0x36);
+	adv7180_write_reg(sensor, 0x0D, 0x7C);
+	adv7180_write_reg(sensor, 0x0E, 0x00);
+	adv7180_write_reg(sensor, 0x0F, 0x00);
+	adv7180_write_reg(sensor, 0x13, 0x00);
+	adv7180_write_reg(sensor, 0x14, 0x12);
+	adv7180_write_reg(sensor, 0x15, 0x00);
+	adv7180_write_reg(sensor, 0x16, 0x00);
+	adv7180_write_reg(sensor, 0x17, 0x01);
+	adv7180_write_reg(sensor, 0x18, 0x93);
+	adv7180_write_reg(sensor, 0xF1, 0x19);
+	adv7180_write_reg(sensor, 0x1A, 0x00);
+	adv7180_write_reg(sensor, 0x1B, 0x00);
+	adv7180_write_reg(sensor, 0x1C, 0x00);
+	adv7180_write_reg(sensor, 0x1D, 0x40);
+	adv7180_write_reg(sensor, 0x1E, 0x00);
+	adv7180_write_reg(sensor, 0x1F, 0x00);
+	adv7180_write_reg(sensor, 0x20, 0x00);
+	adv7180_write_reg(sensor, 0x21, 0x00);
+	adv7180_write_reg(sensor, 0x22, 0x00);
+	adv7180_write_reg(sensor, 0x23, 0xC0);
+	adv7180_write_reg(sensor, 0x24, 0x00);
+	adv7180_write_reg(sensor, 0x25, 0x00);
+	adv7180_write_reg(sensor, 0x26, 0x00);
+	adv7180_write_reg(sensor, 0x27, 0x58);
+	adv7180_write_reg(sensor, 0x28, 0x00);
+	adv7180_write_reg(sensor, 0x29, 0x00);
+	adv7180_write_reg(sensor, 0x2A, 0x00);
+	adv7180_write_reg(sensor, 0x2B, 0xE1);
+	adv7180_write_reg(sensor, 0x2C, 0xAE);
+	adv7180_write_reg(sensor, 0x2D, 0xF4);
+	adv7180_write_reg(sensor, 0x2E, 0x00);
+	adv7180_write_reg(sensor, 0x2F, 0xF0);
+	adv7180_write_reg(sensor, 0x30, 0x00);
+	adv7180_write_reg(sensor, 0x31, 0x12);
+	adv7180_write_reg(sensor, 0x32, 0x41);
+	adv7180_write_reg(sensor, 0x33, 0x84);
+	adv7180_write_reg(sensor, 0x34, 0x00);
+	adv7180_write_reg(sensor, 0x35, 0x02);
+	adv7180_write_reg(sensor, 0x36, 0x00);
+	adv7180_write_reg(sensor, 0x37, 0x01);
+	adv7180_write_reg(sensor, 0x38, 0x80);
+	adv7180_write_reg(sensor, 0x39, 0xC0);
+	adv7180_write_reg(sensor, 0x3A, 0x10);
+	adv7180_write_reg(sensor, 0x3B, 0x05);
+	adv7180_write_reg(sensor, 0x3C, 0x58);
+	adv7180_write_reg(sensor, 0x3D, 0xB2);
+	adv7180_write_reg(sensor, 0x3E, 0x64);
+	adv7180_write_reg(sensor, 0x3F, 0xE4);
+	adv7180_write_reg(sensor, 0x40, 0x90);
+	adv7180_write_reg(sensor, 0x41, 0x01);
+	adv7180_write_reg(sensor, 0x42, 0x7E);
+	adv7180_write_reg(sensor, 0x43, 0xA4);
+	adv7180_write_reg(sensor, 0x44, 0xFF);
+	adv7180_write_reg(sensor, 0x45, 0xB6);
+	adv7180_write_reg(sensor, 0x46, 0x12);
+	adv7180_write_reg(sensor, 0x48, 0x00);
+	adv7180_write_reg(sensor, 0x49, 0x00);
+	adv7180_write_reg(sensor, 0x4A, 0x00);
+	adv7180_write_reg(sensor, 0x4B, 0x00);
+	adv7180_write_reg(sensor, 0x4C, 0x00);
+	adv7180_write_reg(sensor, 0x4D, 0xEF);
+	adv7180_write_reg(sensor, 0x4E, 0x08);
+	adv7180_write_reg(sensor, 0x4F, 0x08);
+	adv7180_write_reg(sensor, 0x50, 0x08);
+	adv7180_write_reg(sensor, 0x51, 0xA4);
+	adv7180_write_reg(sensor, 0x52, 0x0B);
+	adv7180_write_reg(sensor, 0x53, 0x4E);
+	adv7180_write_reg(sensor, 0x54, 0x80);
+	adv7180_write_reg(sensor, 0x55, 0x00);
+	adv7180_write_reg(sensor, 0x56, 0x10);
+	adv7180_write_reg(sensor, 0x57, 0x00);
+	adv7180_write_reg(sensor, 0x58, 0x00);
+	adv7180_write_reg(sensor, 0x59, 0x00);
+	adv7180_write_reg(sensor, 0x5A, 0x00);
+	adv7180_write_reg(sensor, 0x5B, 0x00);
+	adv7180_write_reg(sensor, 0x5C, 0x00);
+	adv7180_write_reg(sensor, 0x5D, 0x00);
+	adv7180_write_reg(sensor, 0x5E, 0x00);
+	adv7180_write_reg(sensor, 0x5F, 0x00);
+	adv7180_write_reg(sensor, 0x60, 0x00);
+	adv7180_write_reg(sensor, 0x61, 0x00);
+	adv7180_write_reg(sensor, 0x62, 0x20);
+	adv7180_write_reg(sensor, 0x63, 0x00);
+	adv7180_write_reg(sensor, 0x64, 0x00);
+	adv7180_write_reg(sensor, 0x65, 0x00);
+	adv7180_write_reg(sensor, 0x66, 0x00);
+	adv7180_write_reg(sensor, 0x67, 0x03);
+	adv7180_write_reg(sensor, 0x68, 0x01);
+	adv7180_write_reg(sensor, 0x69, 0x00);
+	adv7180_write_reg(sensor, 0x6A, 0x00);
+	adv7180_write_reg(sensor, 0x6B, 0xC0);
+	adv7180_write_reg(sensor, 0x6C, 0x00);
+	adv7180_write_reg(sensor, 0x6D, 0x00);
+	adv7180_write_reg(sensor, 0x6E, 0x00);
+	adv7180_write_reg(sensor, 0x6F, 0x00);
+	adv7180_write_reg(sensor, 0x70, 0x00);
+	adv7180_write_reg(sensor, 0x71, 0x00);
+	adv7180_write_reg(sensor, 0x72, 0x00);
+	adv7180_write_reg(sensor, 0x73, 0x10);
+	adv7180_write_reg(sensor, 0x74, 0x04);
+	adv7180_write_reg(sensor, 0x75, 0x01);
+	adv7180_write_reg(sensor, 0x76, 0x00);
+	adv7180_write_reg(sensor, 0x77, 0x3F);
+	adv7180_write_reg(sensor, 0x78, 0xFF);
+	adv7180_write_reg(sensor, 0x79, 0xFF);
+	adv7180_write_reg(sensor, 0x7A, 0xFF);
+	adv7180_write_reg(sensor, 0x7B, 0x1E);
+	adv7180_write_reg(sensor, 0x7C, 0xC0);
+	adv7180_write_reg(sensor, 0x7D, 0x00);
+	adv7180_write_reg(sensor, 0x7E, 0x00);
+	adv7180_write_reg(sensor, 0x7F, 0x00);
+	adv7180_write_reg(sensor, 0x80, 0x00);
+	adv7180_write_reg(sensor, 0x81, 0xC0);
+	adv7180_write_reg(sensor, 0x82, 0x04);
+	adv7180_write_reg(sensor, 0x83, 0x00);
+	adv7180_write_reg(sensor, 0x84, 0x0C);
+	adv7180_write_reg(sensor, 0x85, 0x02);
+	adv7180_write_reg(sensor, 0x86, 0x03);
+	adv7180_write_reg(sensor, 0x87, 0x63);
+	adv7180_write_reg(sensor, 0x88, 0x5A);
+	adv7180_write_reg(sensor, 0x89, 0x08);
+	adv7180_write_reg(sensor, 0x8A, 0x10);
+	adv7180_write_reg(sensor, 0x8B, 0x00);
+	adv7180_write_reg(sensor, 0x8C, 0x40);
+	adv7180_write_reg(sensor, 0x8D, 0x00);
+	adv7180_write_reg(sensor, 0x8E, 0x40);
+	adv7180_write_reg(sensor, 0x8F, 0x00);
+	adv7180_write_reg(sensor, 0x90, 0x00);
+	adv7180_write_reg(sensor, 0x91, 0x50);
+	adv7180_write_reg(sensor, 0x92, 0x00);
+	adv7180_write_reg(sensor, 0x93, 0x00);
+	adv7180_write_reg(sensor, 0x94, 0x00);
+	adv7180_write_reg(sensor, 0x95, 0x00);
+	adv7180_write_reg(sensor, 0x96, 0x00);
+	adv7180_write_reg(sensor, 0x97, 0xF0);
+	adv7180_write_reg(sensor, 0x98, 0x00);
+	adv7180_write_reg(sensor, 0x99, 0x00);
+	adv7180_write_reg(sensor, 0x9A, 0x00);
+	adv7180_write_reg(sensor, 0x9B, 0x00);
+	adv7180_write_reg(sensor, 0x9C, 0x00);
+	adv7180_write_reg(sensor, 0x9D, 0x00);
+	adv7180_write_reg(sensor, 0x9E, 0x00);
+	adv7180_write_reg(sensor, 0x9F, 0x00);
+	adv7180_write_reg(sensor, 0xA0, 0x00);
+	adv7180_write_reg(sensor, 0xA1, 0x00);
+	adv7180_write_reg(sensor, 0xA2, 0x00);
+	adv7180_write_reg(sensor, 0xA3, 0x00);
+	adv7180_write_reg(sensor, 0xA4, 0x00);
+	adv7180_write_reg(sensor, 0xA5, 0x00);
+	adv7180_write_reg(sensor, 0xA6, 0x00);
+	adv7180_write_reg(sensor, 0xA7, 0x00);
+	adv7180_write_reg(sensor, 0xA8, 0x00);
+	adv7180_write_reg(sensor, 0xA9, 0x00);
+	adv7180_write_reg(sensor, 0xAA, 0x00);
+	adv7180_write_reg(sensor, 0xAB, 0x00);
+	adv7180_write_reg(sensor, 0xAC, 0x00);
+	adv7180_write_reg(sensor, 0xAD, 0x00);
+	adv7180_write_reg(sensor, 0xAE, 0x60);
+	adv7180_write_reg(sensor, 0xAF, 0x00);
+	adv7180_write_reg(sensor, 0xB0, 0x00);
+	adv7180_write_reg(sensor, 0xB1, 0x60);
+	adv7180_write_reg(sensor, 0xB2, 0x1C);
+	adv7180_write_reg(sensor, 0xB3, 0x54);
+	adv7180_write_reg(sensor, 0xB4, 0x00);
+	adv7180_write_reg(sensor, 0xB5, 0x00);
+	adv7180_write_reg(sensor, 0xB6, 0x00);
+	adv7180_write_reg(sensor, 0xB7, 0x13);
+	adv7180_write_reg(sensor, 0xB8, 0x03);
+	adv7180_write_reg(sensor, 0xB9, 0x33);
+	adv7180_write_reg(sensor, 0xBF, 0x02);
+	adv7180_write_reg(sensor, 0xC0, 0x00);
+	adv7180_write_reg(sensor, 0xC1, 0x00);
+	adv7180_write_reg(sensor, 0xC2, 0x00);
+	adv7180_write_reg(sensor, 0xC3, 0x00);
+	adv7180_write_reg(sensor, 0xC4, 0x00);
+	adv7180_write_reg(sensor, 0xC5, 0x81);
+	adv7180_write_reg(sensor, 0xC6, 0x00);
+	adv7180_write_reg(sensor, 0xC7, 0x00);
+	adv7180_write_reg(sensor, 0xC8, 0x00);
+	adv7180_write_reg(sensor, 0xC9, 0x04);
+	adv7180_write_reg(sensor, 0xCC, 0x69);
+	adv7180_write_reg(sensor, 0xCD, 0x00);
+	adv7180_write_reg(sensor, 0xCE, 0x01);
+	adv7180_write_reg(sensor, 0xCF, 0xB4);
+	adv7180_write_reg(sensor, 0xD0, 0x00);
+	adv7180_write_reg(sensor, 0xD1, 0x10);
+	adv7180_write_reg(sensor, 0xD2, 0xFF);
+	adv7180_write_reg(sensor, 0xD3, 0xFF);
+	adv7180_write_reg(sensor, 0xD4, 0x7F);
+	adv7180_write_reg(sensor, 0xD5, 0x7F);
+	adv7180_write_reg(sensor, 0xD6, 0x3E);
+	adv7180_write_reg(sensor, 0xD7, 0x08);
+	adv7180_write_reg(sensor, 0xD8, 0x3C);
+	adv7180_write_reg(sensor, 0xD9, 0x08);
+	adv7180_write_reg(sensor, 0xDA, 0x3C);
+	adv7180_write_reg(sensor, 0xDB, 0x9B);
+	adv7180_write_reg(sensor, 0xDC, 0xAC);
+	adv7180_write_reg(sensor, 0xDD, 0x4C);
+	adv7180_write_reg(sensor, 0xDE, 0x00);
+	adv7180_write_reg(sensor, 0xDF, 0x00);
+	adv7180_write_reg(sensor, 0xE0, 0x14);
+	adv7180_write_reg(sensor, 0xE1, 0x80);
+	adv7180_write_reg(sensor, 0xE2, 0x80);
+	adv7180_write_reg(sensor, 0xE3, 0x80);
+	adv7180_write_reg(sensor, 0xE4, 0x80);
+	adv7180_write_reg(sensor, 0xE5, 0x25);
+	adv7180_write_reg(sensor, 0xE6, 0x44);
+	adv7180_write_reg(sensor, 0xE7, 0x63);
+	adv7180_write_reg(sensor, 0xE8, 0x65);
+	adv7180_write_reg(sensor, 0xE9, 0x14);
+	adv7180_write_reg(sensor, 0xEA, 0x63);
+	adv7180_write_reg(sensor, 0xEB, 0x55);
+	adv7180_write_reg(sensor, 0xEC, 0x55);
+	adv7180_write_reg(sensor, 0xEE, 0x00);
+	adv7180_write_reg(sensor, 0xEF, 0x4A);
+	adv7180_write_reg(sensor, 0xF0, 0x44);
+	adv7180_write_reg(sensor, 0xF1, 0x0C);
+	adv7180_write_reg(sensor, 0xF2, 0x32);
+	adv7180_write_reg(sensor, 0xF3, 0x00);
+	adv7180_write_reg(sensor, 0xF4, 0x3F);
+	adv7180_write_reg(sensor, 0xF5, 0xE0);
+	adv7180_write_reg(sensor, 0xF6, 0x69);
+	adv7180_write_reg(sensor, 0xF7, 0x10);
+	adv7180_write_reg(sensor, 0xF8, 0x00);
+	adv7180_write_reg(sensor, 0xF9, 0x03);
+	adv7180_write_reg(sensor, 0xFA, 0xFA);
+	adv7180_write_reg(sensor, 0xFB, 0x40);
+}
+
+/*!
+ * 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)
+{
+	struct device_node *endpoint;
+	struct adv7180_dev *sensor;
+	struct device_node *np;
+	const char *norm = "pal";
+	int ret = 0;
+
+	sensor = devm_kzalloc(&client->dev, sizeof(struct adv7180_dev),
+			      GFP_KERNEL);
+	if (!sensor)
+		return -ENOMEM;
+
+	sensor->dev = &client->dev;
+	np = sensor->dev->of_node;
+
+	ret = of_property_read_string(np, "default-std", &norm);
+	if (ret < 0 && ret != -EINVAL) {
+		dev_err(sensor->dev, "error reading default-std property!\n");
+		return ret;
+	}
+	if (!strcasecmp(norm, "pal")) {
+		sensor->std_id = V4L2_STD_PAL;
+		sensor->video_idx = ADV7180_PAL;
+		dev_info(sensor->dev, "defaulting to PAL!\n");
+	} else if (!strcasecmp(norm, "ntsc")) {
+		sensor->std_id = V4L2_STD_NTSC;
+		sensor->video_idx = ADV7180_NTSC;
+		dev_info(sensor->dev, "defaulting to NTSC!\n");
+	} else {
+		dev_err(sensor->dev, "invalid default-std value: '%s'!\n",
+			norm);
+		return -EINVAL;
+	}
+
+	/* Set initial values for the sensor struct. */
+	sensor->i2c_client = client;
+	sensor->streamcap.timeperframe.denominator = 30;
+	sensor->streamcap.timeperframe.numerator = 1;
+	sensor->fmt.width = video_fmts[sensor->video_idx].raw.width;
+	sensor->fmt.height = video_fmts[sensor->video_idx].raw.height;
+	sensor->fmt.code = V4L2_MBUS_FMT_UYVY8_2X8;
+	sensor->fmt.field = V4L2_FIELD_INTERLACED;
+
+	mutex_init(&sensor->mutex);
+
+	endpoint = of_graph_get_next_endpoint(np, NULL);
+	if (!endpoint) {
+		dev_err(sensor->dev, "endpoint node not found\n");
+		return -EINVAL;
+	}
+
+	v4l2_of_parse_endpoint(endpoint, &sensor->ep);
+	if (sensor->ep.bus_type != V4L2_MBUS_BT656) {
+		dev_err(sensor->dev, "invalid bus type, must be bt.656\n");
+		return -EINVAL;
+	}
+	of_node_put(endpoint);
+
+	ret = of_get_named_gpio(np, "pwdn-gpio", 0);
+	if (gpio_is_valid(ret)) {
+		sensor->pwdn_gpio = ret;
+		ret = devm_gpio_request_one(sensor->dev,
+					    sensor->pwdn_gpio,
+					    GPIOF_OUT_INIT_HIGH,
+					    "adv7180_pwdn");
+		if (ret < 0) {
+			dev_err(sensor->dev,
+				"request for power down gpio failed\n");
+			return ret;
+		}
+	} else {
+		if (ret == -EPROBE_DEFER)
+			return ret;
+		/* assume a power-down gpio is not required */
+		sensor->pwdn_gpio = -1;
+	}
+
+	adv7180_regulator_enable(sensor);
+
+	/* Power on the chip */
+	adv7180_power(sensor, true);
+
+	/*! ADV7180 initialization. */
+	adv7180_hard_reset(sensor);
+
+	/*! Read the revision ID of the chip */
+	sensor->rev_id = adv7180_read(sensor, ADV7180_IDENT);
+	if (sensor->rev_id < 0) {
+		dev_err(sensor->dev,
+			"failed to read ADV7180 IDENT register!\n");
+		ret = -ENODEV;
+		goto cleanup;
+	}
+
+	dev_info(sensor->dev, "Analog Devices ADV7180 Rev 0x%02X detected!\n",
+		 sensor->rev_id);
+
+	v4l2_i2c_subdev_init(&sensor->sd, client, &adv7180_subdev_ops);
+
+	/* see if there is a signal lock already */
+	adv7180_update_lock_status(sensor);
+	adv7180_get_autodetect_std(sensor);
+
+	if (sensor->i2c_client->irq) {
+		ret = request_threaded_irq(sensor->i2c_client->irq,
+					   NULL, adv7180_interrupt,
+					   IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+					   IF_NAME, sensor);
+		if (ret < 0) {
+			dev_err(sensor->dev, "Failed to register irq %d\n",
+				sensor->i2c_client->irq);
+			goto cleanup;
+		}
+
+		adv7180_enable_interrupts(sensor);
+
+		dev_info(sensor->dev, "Registered irq %d\n",
+			 sensor->i2c_client->irq);
+	}
+
+	return adv7180_init_controls(sensor);
+
+cleanup:
+	adv7180_regulator_disable(sensor);
+	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)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct adv7180_dev *sensor = to_adv7180_dev(sd);
+
+	if (sensor->i2c_client->irq)
+		free_irq(sensor->i2c_client->irq, sensor);
+
+	v4l2_ctrl_handler_free(&sensor->ctrl_hdl);
+
+	/* Power off the chip */
+	adv7180_power(sensor, false);
+
+	adv7180_regulator_disable(sensor);
+
+	return 0;
+}
+
+static const struct i2c_device_id adv7180_id[] = {
+	{ "adv7180", 0 },
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, adv7180_id);
+
+static struct of_device_id adv7180_dt_ids[] = {
+	{ .compatible = "adi,adv7180" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, adv7180_dt_ids);
+
+static struct i2c_driver adv7180_driver = {
+	.driver = {
+		.name	= "adv7180",
+		.owner	= THIS_MODULE,
+		.of_match_table	= adv7180_dt_ids,
+	},
+	.id_table	= adv7180_id,
+	.probe		= adv7180_probe,
+	.remove		= adv7180_detach,
+};
+
+module_i2c_driver(adv7180_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Analog Devices ADV7180 Subdev driver");
+MODULE_LICENSE("GPL");
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH 43/43] ARM: imx_v6_v7_defconfig: Enable video4linux drivers
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (41 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 42/43] media: imx6: Add support for ADV7180 Video Decoder Steve Longerbeam
@ 2014-06-07 21:56 ` Steve Longerbeam
  2014-06-08  8:36 ` [PATCH 00/43] i.MX6 Video capture Hans Verkuil
  2014-06-11 11:21 ` Philipp Zabel
  44 siblings, 0 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-07 21:56 UTC (permalink / raw)
  To: linux-media; +Cc: Steve Longerbeam

Enable imx6 staging v4l2 drivers as modules. For video capture on
the SabreAuto, the ADV7180 video decoder also requires the
i2c-mux-gpio and the max7310 port expander.

Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
---
 arch/arm/configs/imx_v6_v7_defconfig |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 09e9743..cd1099d 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -148,6 +148,7 @@ CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_MXC_RNGA=y
 # CONFIG_I2C_COMPAT is not set
 CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MUX_GPIO=m
 # CONFIG_I2C_HELPER_AUTO is not set
 CONFIG_I2C_ALGOPCF=m
 CONFIG_I2C_ALGOPCA=m
@@ -156,6 +157,7 @@ CONFIG_SPI=y
 CONFIG_SPI_IMX=y
 CONFIG_GPIO_SYSFS=y
 CONFIG_GPIO_MC9S08DZ60=y
+CONFIG_GPIO_PCA953X=m
 # CONFIG_HWMON is not set
 CONFIG_WATCHDOG=y
 CONFIG_IMX2_WDT=y
@@ -238,6 +240,8 @@ CONFIG_DMADEVICES=y
 CONFIG_IMX_SDMA=y
 CONFIG_MXS_DMA=y
 CONFIG_STAGING=y
+CONFIG_STAGING_MEDIA=y
+CONFIG_VIDEO_IMX6=m
 CONFIG_DRM_IMX=y
 CONFIG_DRM_IMX_FB_HELPER=y
 CONFIG_DRM_IMX_PARALLEL_DISPLAY=y
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* Re: [PATCH 00/43] i.MX6 Video capture
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (42 preceding siblings ...)
  2014-06-07 21:56 ` [PATCH 43/43] ARM: imx_v6_v7_defconfig: Enable video4linux drivers Steve Longerbeam
@ 2014-06-08  8:36 ` Hans Verkuil
  2014-06-08  8:39   ` Hans Verkuil
  2014-06-09 16:42   ` Steve Longerbeam
  2014-06-11 11:21 ` Philipp Zabel
  44 siblings, 2 replies; 79+ messages in thread
From: Hans Verkuil @ 2014-06-08  8:36 UTC (permalink / raw)
  To: Steve Longerbeam, linux-media; +Cc: Steve Longerbeam, David Peverley

Hi Steve!

On 06/07/2014 11:56 PM, Steve Longerbeam wrote:
> Hi all,
> 
> This patch set adds video capture support for the Freescale i.MX6 SOC.
> 
> It is a from-scratch standardized driver that works with community
> v4l2 utilities, such as v4l2-ctl, v4l2-cap, and the v4l2src gstreamer
> plugin. It uses the latest v4l2 interfaces (subdev, videobuf2).
> Please see Documentation/video4linux/mx6_camera.txt for it's full list
> of features!
> 
> The first 38 patches:
> 
> - prepare the ipu-v3 driver for video capture support. The current driver
>   contains only video display functionality to support the imx DRM drivers.
>   At some point ipu-v3 should be moved out from under staging/imx-drm since
>   it will no longer only support DRM.
> 
> - Adds the device tree nodes and OF graph bindings for video capture support
>   on sabrelite, sabresd, and sabreauto reference platforms.
> 
> The new i.MX6 capture host interface driver is at patch 39.
> 
> To support the sensors found on the sabrelite, sabresd, and sabreauto,
> three patches add sensor subdev's for parallel OV5642, MIPI CSI-2 OV5640,
> and the ADV7180 decoder chip, beginning at patch 40.
> 
> There is an existing adv7180 subdev driver under drivers/media/i2c, but
> it needs some extra functionality to work on the sabreauto. It will need
> OF graph bindings support and gpio for a power-on pin on the sabreauto.
> It would also need to send a new subdev notification to take advantage
> of decoder status change handling provided by the host driver. This
> feature makes it possible to correctly handle "hot" (while streaming)
> signal lock/unlock and autodetected video standard changes.

A new V4L2_EVENT_SOURCE_CHANGE event has just been added for that.

> Usage notes are found in Documentation/video4linux/mx6_camera.txt for the
> above three reference platforms.
> 
> The driver source is under drivers/staging/media/imx6/capture/.

Thank you for this patch series! Much appreciated that this hardware is
finally going to supported with a proper driver.

I did a quick scan of the driver and I noticed a few things that need
to be fixed: instead of implementing g/s_crop, implement g/s_selection:
new drivers should implement the selection API and they will get the crop
API for free.

You should use the vb2 helper functions (vb2_fop_*, vb2_ioctl_*) unless
there is a good reason not to do it. Those functions should simplify the
code and they give you proper 'streaming ownership'. See also the example
code Documentation/video4linux/v4l2-pci-skeleton.c.

Finally you should run the v4l2-compliance test tool and fix any failures.

That tool is part of git://linuxtv.org/v4l-utils.git. Always compile from
that repository to be sure you use the latest code.

Test first with 'v4l2-compliance'. When all issues are fixed, then test
with 'v4l2-compliance -s' to test actual streaming behavior as well.

When you post v2 of this patch series I want to see the output of
'v4l2-compliance -s'! New drivers should pass v4l2-compliance. However,
this is a staging driver so I won't be that strict, but it seems to be
the intention that this driver will become a mainline driver, so I would
recommend to fix any issues now rather than later.

If you have questions about v4l2-compliance it it might be easiest to
set up an irc session where we go through them. In that case mail me
so we can set up a time and date to do that. I'm in timezone UTC+2.

Regards,

	Hans

> 
> 
> Steve Longerbeam (43):
>   imx-drm: ipu-v3: Move imx-ipu-v3.h to include/linux/platform_data/
>   ARM: dts: imx6qdl: Add ipu aliases
>   imx-drm: ipu-v3: Add ipu_get_num()
>   imx-drm: ipu-v3: Add solo/dual-lite IPU device type
>   imx-drm: ipu-v3: Map IOMUXC registers
>   imx-drm: ipu-v3: Add functions to set CSI/IC source muxes
>   imx-drm: ipu-v3: Rename and add IDMAC channels
>   imx-drm: ipu-v3: Add units required for video capture
>   imx-drm: ipu-v3: Add ipu_mbus_code_to_colorspace()
>   imx-drm: ipu-v3: Add rotation mode conversion utilities
>   imx-drm: ipu-v3: Add helper function checking if pixfmt is planar
>   imx-drm: ipu-v3: Move IDMAC channel names to imx-ipu-v3.h
>   imx-drm: ipu-v3: Add ipu_idmac_buffer_is_ready()
>   imx-drm: ipu-v3: Add ipu_idmac_clear_buffer()
>   imx-drm: ipu-v3: Add ipu_idmac_current_buffer()
>   imx-drm: ipu-v3: Add __ipu_idmac_reset_current_buffer()
>   imx-drm: ipu-v3: Add ipu_stride_to_bytes()
>   imx-drm: ipu-v3: Add ipu_idmac_enable_watermark()
>   imx-drm: ipu-v3: Add ipu_idmac_lock_enable()
>   imx-drm: ipu-v3: Add idmac channel linking support
>   imx-drm: ipu-v3: Add ipu_bits_per_pixel()
>   imx-drm: ipu-v3: Add ipu-cpmem unit
>   imx-drm: ipu-cpmem: Add ipu_cpmem_set_block_mode()
>   imx-drm: ipu-cpmem: Add ipu_cpmem_set_axi_id()
>   imx-drm: ipu-cpmem: Add ipu_cpmem_set_rotation()
>   imx-drm: ipu-cpmem: Add second buffer support to ipu_cpmem_set_image()
>   imx-drm: ipu-v3: Add more planar formats support
>   imx-drm: ipu-cpmem: Add ipu_cpmem_dump()
>   imx-drm: ipu-v3: Add ipu_dump()
>   ARM: dts: imx6: add pin groups for imx6q/dl for IPU1 CSI0
>   ARM: dts: imx6qdl: Flesh out MIPI CSI2 receiver node
>   ARM: dts: imx: sabrelite: add video capture ports and endpoints
>   ARM: dts: imx6-sabresd: add video capture ports and endpoints
>   ARM: dts: imx6-sabreauto: add video capture ports and endpoints
>   ARM: dts: imx6qdl: Add simple-bus to ipu compatibility
>   gpio: pca953x: Add reset-gpios property
>   ARM: imx6q: clk: Add video 27m clock
>   media: imx6: Add device tree binding documentation
>   media: Add new camera interface driver for i.MX6
>   media: imx6: Add support for MIPI CSI-2 OV5640
>   media: imx6: Add support for Parallel OV5642
>   media: imx6: Add support for ADV7180 Video Decoder
>   ARM: imx_v6_v7_defconfig: Enable video4linux drivers
> 
>  .../devicetree/bindings/clock/imx6q-clock.txt      |    1 +
>  Documentation/devicetree/bindings/media/imx6.txt   |  433 ++
>  .../bindings/staging/imx-drm/fsl-imx-drm.txt       |    6 +-
>  .../devicetree/bindings/vendor-prefixes.txt        |    1 +
>  Documentation/video4linux/mx6_camera.txt           |  188 +
>  arch/arm/boot/dts/imx6q.dtsi                       |    3 +-
>  arch/arm/boot/dts/imx6qdl-sabreauto.dtsi           |  149 +
>  arch/arm/boot/dts/imx6qdl-sabrelite.dtsi           |   91 +
>  arch/arm/boot/dts/imx6qdl-sabresd.dtsi             |  116 +
>  arch/arm/boot/dts/imx6qdl.dtsi                     |   62 +-
>  arch/arm/configs/imx_v6_v7_defconfig               |    4 +
>  arch/arm/mach-imx/clk-imx6q.c                      |    3 +-
>  drivers/gpio/gpio-pca953x.c                        |   26 +
>  drivers/staging/imx-drm/imx-hdmi.c                 |    2 +-
>  drivers/staging/imx-drm/imx-tve.c                  |    2 +-
>  drivers/staging/imx-drm/ipu-v3/Makefile            |    3 +-
>  drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h        |  326 --
>  drivers/staging/imx-drm/ipu-v3/ipu-common.c        | 1151 ++++--
>  drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c         |  814 ++++
>  drivers/staging/imx-drm/ipu-v3/ipu-csi.c           |  821 ++++
>  drivers/staging/imx-drm/ipu-v3/ipu-dc.c            |    2 +-
>  drivers/staging/imx-drm/ipu-v3/ipu-di.c            |    2 +-
>  drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c          |    2 +-
>  drivers/staging/imx-drm/ipu-v3/ipu-dp.c            |    2 +-
>  drivers/staging/imx-drm/ipu-v3/ipu-ic.c            |  835 ++++
>  drivers/staging/imx-drm/ipu-v3/ipu-irt.c           |  103 +
>  drivers/staging/imx-drm/ipu-v3/ipu-prv.h           |  126 +-
>  drivers/staging/imx-drm/ipu-v3/ipu-smfc.c          |  348 ++
>  drivers/staging/imx-drm/ipuv3-crtc.c               |    2 +-
>  drivers/staging/imx-drm/ipuv3-plane.c              |   18 +-
>  drivers/staging/media/Kconfig                      |    2 +
>  drivers/staging/media/Makefile                     |    1 +
>  drivers/staging/media/imx6/Kconfig                 |   25 +
>  drivers/staging/media/imx6/Makefile                |    1 +
>  drivers/staging/media/imx6/capture/Kconfig         |   33 +
>  drivers/staging/media/imx6/capture/Makefile        |    7 +
>  drivers/staging/media/imx6/capture/adv7180.c       | 1298 ++++++
>  drivers/staging/media/imx6/capture/mipi-csi2.c     |  322 ++
>  drivers/staging/media/imx6/capture/mx6-camif.c     | 2235 ++++++++++
>  drivers/staging/media/imx6/capture/mx6-camif.h     |  197 +
>  drivers/staging/media/imx6/capture/mx6-encode.c    |  775 ++++
>  drivers/staging/media/imx6/capture/mx6-preview.c   |  748 ++++
>  drivers/staging/media/imx6/capture/ov5640-mipi.c   | 2158 ++++++++++
>  drivers/staging/media/imx6/capture/ov5642.c        | 4258 ++++++++++++++++++++
>  include/linux/platform_data/imx-ipu-v3.h           |  425 ++
>  include/media/imx6.h                               |   18 +
>  46 files changed, 17340 insertions(+), 805 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/media/imx6.txt
>  create mode 100644 Documentation/video4linux/mx6_camera.txt
>  delete mode 100644 drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
>  create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c
>  create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-csi.c
>  create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-ic.c
>  create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-irt.c
>  create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-smfc.c
>  create mode 100644 drivers/staging/media/imx6/Kconfig
>  create mode 100644 drivers/staging/media/imx6/Makefile
>  create mode 100644 drivers/staging/media/imx6/capture/Kconfig
>  create mode 100644 drivers/staging/media/imx6/capture/Makefile
>  create mode 100644 drivers/staging/media/imx6/capture/adv7180.c
>  create mode 100644 drivers/staging/media/imx6/capture/mipi-csi2.c
>  create mode 100644 drivers/staging/media/imx6/capture/mx6-camif.c
>  create mode 100644 drivers/staging/media/imx6/capture/mx6-camif.h
>  create mode 100644 drivers/staging/media/imx6/capture/mx6-encode.c
>  create mode 100644 drivers/staging/media/imx6/capture/mx6-preview.c
>  create mode 100644 drivers/staging/media/imx6/capture/ov5640-mipi.c
>  create mode 100644 drivers/staging/media/imx6/capture/ov5642.c
>  create mode 100644 include/linux/platform_data/imx-ipu-v3.h
>  create mode 100644 include/media/imx6.h
> 


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 00/43] i.MX6 Video capture
  2014-06-08  8:36 ` [PATCH 00/43] i.MX6 Video capture Hans Verkuil
@ 2014-06-08  8:39   ` Hans Verkuil
  2014-06-09 16:42   ` Steve Longerbeam
  1 sibling, 0 replies; 79+ messages in thread
From: Hans Verkuil @ 2014-06-08  8:39 UTC (permalink / raw)
  To: Steve Longerbeam, linux-media; +Cc: Steve Longerbeam, David Peverley

I forgot to mention that I CC-ed David Peverley who was/is also working on a
proper i.MX6 v4l2 driver. I'm sure he'll be interested in this as well.

Regards,

	Hans

On 06/08/2014 10:36 AM, Hans Verkuil wrote:
> Hi Steve!
> 
> On 06/07/2014 11:56 PM, Steve Longerbeam wrote:
>> Hi all,
>>
>> This patch set adds video capture support for the Freescale i.MX6 SOC.
>>
>> It is a from-scratch standardized driver that works with community
>> v4l2 utilities, such as v4l2-ctl, v4l2-cap, and the v4l2src gstreamer
>> plugin. It uses the latest v4l2 interfaces (subdev, videobuf2).
>> Please see Documentation/video4linux/mx6_camera.txt for it's full list
>> of features!
>>
>> The first 38 patches:
>>
>> - prepare the ipu-v3 driver for video capture support. The current driver
>>   contains only video display functionality to support the imx DRM drivers.
>>   At some point ipu-v3 should be moved out from under staging/imx-drm since
>>   it will no longer only support DRM.
>>
>> - Adds the device tree nodes and OF graph bindings for video capture support
>>   on sabrelite, sabresd, and sabreauto reference platforms.
>>
>> The new i.MX6 capture host interface driver is at patch 39.
>>
>> To support the sensors found on the sabrelite, sabresd, and sabreauto,
>> three patches add sensor subdev's for parallel OV5642, MIPI CSI-2 OV5640,
>> and the ADV7180 decoder chip, beginning at patch 40.
>>
>> There is an existing adv7180 subdev driver under drivers/media/i2c, but
>> it needs some extra functionality to work on the sabreauto. It will need
>> OF graph bindings support and gpio for a power-on pin on the sabreauto.
>> It would also need to send a new subdev notification to take advantage
>> of decoder status change handling provided by the host driver. This
>> feature makes it possible to correctly handle "hot" (while streaming)
>> signal lock/unlock and autodetected video standard changes.
> 
> A new V4L2_EVENT_SOURCE_CHANGE event has just been added for that.
> 
>> Usage notes are found in Documentation/video4linux/mx6_camera.txt for the
>> above three reference platforms.
>>
>> The driver source is under drivers/staging/media/imx6/capture/.
> 
> Thank you for this patch series! Much appreciated that this hardware is
> finally going to supported with a proper driver.
> 
> I did a quick scan of the driver and I noticed a few things that need
> to be fixed: instead of implementing g/s_crop, implement g/s_selection:
> new drivers should implement the selection API and they will get the crop
> API for free.
> 
> You should use the vb2 helper functions (vb2_fop_*, vb2_ioctl_*) unless
> there is a good reason not to do it. Those functions should simplify the
> code and they give you proper 'streaming ownership'. See also the example
> code Documentation/video4linux/v4l2-pci-skeleton.c.
> 
> Finally you should run the v4l2-compliance test tool and fix any failures.
> 
> That tool is part of git://linuxtv.org/v4l-utils.git. Always compile from
> that repository to be sure you use the latest code.
> 
> Test first with 'v4l2-compliance'. When all issues are fixed, then test
> with 'v4l2-compliance -s' to test actual streaming behavior as well.
> 
> When you post v2 of this patch series I want to see the output of
> 'v4l2-compliance -s'! New drivers should pass v4l2-compliance. However,
> this is a staging driver so I won't be that strict, but it seems to be
> the intention that this driver will become a mainline driver, so I would
> recommend to fix any issues now rather than later.
> 
> If you have questions about v4l2-compliance it it might be easiest to
> set up an irc session where we go through them. In that case mail me
> so we can set up a time and date to do that. I'm in timezone UTC+2.
> 
> Regards,
> 
> 	Hans
> 
>>
>>
>> Steve Longerbeam (43):
>>   imx-drm: ipu-v3: Move imx-ipu-v3.h to include/linux/platform_data/
>>   ARM: dts: imx6qdl: Add ipu aliases
>>   imx-drm: ipu-v3: Add ipu_get_num()
>>   imx-drm: ipu-v3: Add solo/dual-lite IPU device type
>>   imx-drm: ipu-v3: Map IOMUXC registers
>>   imx-drm: ipu-v3: Add functions to set CSI/IC source muxes
>>   imx-drm: ipu-v3: Rename and add IDMAC channels
>>   imx-drm: ipu-v3: Add units required for video capture
>>   imx-drm: ipu-v3: Add ipu_mbus_code_to_colorspace()
>>   imx-drm: ipu-v3: Add rotation mode conversion utilities
>>   imx-drm: ipu-v3: Add helper function checking if pixfmt is planar
>>   imx-drm: ipu-v3: Move IDMAC channel names to imx-ipu-v3.h
>>   imx-drm: ipu-v3: Add ipu_idmac_buffer_is_ready()
>>   imx-drm: ipu-v3: Add ipu_idmac_clear_buffer()
>>   imx-drm: ipu-v3: Add ipu_idmac_current_buffer()
>>   imx-drm: ipu-v3: Add __ipu_idmac_reset_current_buffer()
>>   imx-drm: ipu-v3: Add ipu_stride_to_bytes()
>>   imx-drm: ipu-v3: Add ipu_idmac_enable_watermark()
>>   imx-drm: ipu-v3: Add ipu_idmac_lock_enable()
>>   imx-drm: ipu-v3: Add idmac channel linking support
>>   imx-drm: ipu-v3: Add ipu_bits_per_pixel()
>>   imx-drm: ipu-v3: Add ipu-cpmem unit
>>   imx-drm: ipu-cpmem: Add ipu_cpmem_set_block_mode()
>>   imx-drm: ipu-cpmem: Add ipu_cpmem_set_axi_id()
>>   imx-drm: ipu-cpmem: Add ipu_cpmem_set_rotation()
>>   imx-drm: ipu-cpmem: Add second buffer support to ipu_cpmem_set_image()
>>   imx-drm: ipu-v3: Add more planar formats support
>>   imx-drm: ipu-cpmem: Add ipu_cpmem_dump()
>>   imx-drm: ipu-v3: Add ipu_dump()
>>   ARM: dts: imx6: add pin groups for imx6q/dl for IPU1 CSI0
>>   ARM: dts: imx6qdl: Flesh out MIPI CSI2 receiver node
>>   ARM: dts: imx: sabrelite: add video capture ports and endpoints
>>   ARM: dts: imx6-sabresd: add video capture ports and endpoints
>>   ARM: dts: imx6-sabreauto: add video capture ports and endpoints
>>   ARM: dts: imx6qdl: Add simple-bus to ipu compatibility
>>   gpio: pca953x: Add reset-gpios property
>>   ARM: imx6q: clk: Add video 27m clock
>>   media: imx6: Add device tree binding documentation
>>   media: Add new camera interface driver for i.MX6
>>   media: imx6: Add support for MIPI CSI-2 OV5640
>>   media: imx6: Add support for Parallel OV5642
>>   media: imx6: Add support for ADV7180 Video Decoder
>>   ARM: imx_v6_v7_defconfig: Enable video4linux drivers
>>
>>  .../devicetree/bindings/clock/imx6q-clock.txt      |    1 +
>>  Documentation/devicetree/bindings/media/imx6.txt   |  433 ++
>>  .../bindings/staging/imx-drm/fsl-imx-drm.txt       |    6 +-
>>  .../devicetree/bindings/vendor-prefixes.txt        |    1 +
>>  Documentation/video4linux/mx6_camera.txt           |  188 +
>>  arch/arm/boot/dts/imx6q.dtsi                       |    3 +-
>>  arch/arm/boot/dts/imx6qdl-sabreauto.dtsi           |  149 +
>>  arch/arm/boot/dts/imx6qdl-sabrelite.dtsi           |   91 +
>>  arch/arm/boot/dts/imx6qdl-sabresd.dtsi             |  116 +
>>  arch/arm/boot/dts/imx6qdl.dtsi                     |   62 +-
>>  arch/arm/configs/imx_v6_v7_defconfig               |    4 +
>>  arch/arm/mach-imx/clk-imx6q.c                      |    3 +-
>>  drivers/gpio/gpio-pca953x.c                        |   26 +
>>  drivers/staging/imx-drm/imx-hdmi.c                 |    2 +-
>>  drivers/staging/imx-drm/imx-tve.c                  |    2 +-
>>  drivers/staging/imx-drm/ipu-v3/Makefile            |    3 +-
>>  drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h        |  326 --
>>  drivers/staging/imx-drm/ipu-v3/ipu-common.c        | 1151 ++++--
>>  drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c         |  814 ++++
>>  drivers/staging/imx-drm/ipu-v3/ipu-csi.c           |  821 ++++
>>  drivers/staging/imx-drm/ipu-v3/ipu-dc.c            |    2 +-
>>  drivers/staging/imx-drm/ipu-v3/ipu-di.c            |    2 +-
>>  drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c          |    2 +-
>>  drivers/staging/imx-drm/ipu-v3/ipu-dp.c            |    2 +-
>>  drivers/staging/imx-drm/ipu-v3/ipu-ic.c            |  835 ++++
>>  drivers/staging/imx-drm/ipu-v3/ipu-irt.c           |  103 +
>>  drivers/staging/imx-drm/ipu-v3/ipu-prv.h           |  126 +-
>>  drivers/staging/imx-drm/ipu-v3/ipu-smfc.c          |  348 ++
>>  drivers/staging/imx-drm/ipuv3-crtc.c               |    2 +-
>>  drivers/staging/imx-drm/ipuv3-plane.c              |   18 +-
>>  drivers/staging/media/Kconfig                      |    2 +
>>  drivers/staging/media/Makefile                     |    1 +
>>  drivers/staging/media/imx6/Kconfig                 |   25 +
>>  drivers/staging/media/imx6/Makefile                |    1 +
>>  drivers/staging/media/imx6/capture/Kconfig         |   33 +
>>  drivers/staging/media/imx6/capture/Makefile        |    7 +
>>  drivers/staging/media/imx6/capture/adv7180.c       | 1298 ++++++
>>  drivers/staging/media/imx6/capture/mipi-csi2.c     |  322 ++
>>  drivers/staging/media/imx6/capture/mx6-camif.c     | 2235 ++++++++++
>>  drivers/staging/media/imx6/capture/mx6-camif.h     |  197 +
>>  drivers/staging/media/imx6/capture/mx6-encode.c    |  775 ++++
>>  drivers/staging/media/imx6/capture/mx6-preview.c   |  748 ++++
>>  drivers/staging/media/imx6/capture/ov5640-mipi.c   | 2158 ++++++++++
>>  drivers/staging/media/imx6/capture/ov5642.c        | 4258 ++++++++++++++++++++
>>  include/linux/platform_data/imx-ipu-v3.h           |  425 ++
>>  include/media/imx6.h                               |   18 +
>>  46 files changed, 17340 insertions(+), 805 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/media/imx6.txt
>>  create mode 100644 Documentation/video4linux/mx6_camera.txt
>>  delete mode 100644 drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
>>  create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-cpmem.c
>>  create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-csi.c
>>  create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-ic.c
>>  create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-irt.c
>>  create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-smfc.c
>>  create mode 100644 drivers/staging/media/imx6/Kconfig
>>  create mode 100644 drivers/staging/media/imx6/Makefile
>>  create mode 100644 drivers/staging/media/imx6/capture/Kconfig
>>  create mode 100644 drivers/staging/media/imx6/capture/Makefile
>>  create mode 100644 drivers/staging/media/imx6/capture/adv7180.c
>>  create mode 100644 drivers/staging/media/imx6/capture/mipi-csi2.c
>>  create mode 100644 drivers/staging/media/imx6/capture/mx6-camif.c
>>  create mode 100644 drivers/staging/media/imx6/capture/mx6-camif.h
>>  create mode 100644 drivers/staging/media/imx6/capture/mx6-encode.c
>>  create mode 100644 drivers/staging/media/imx6/capture/mx6-preview.c
>>  create mode 100644 drivers/staging/media/imx6/capture/ov5640-mipi.c
>>  create mode 100644 drivers/staging/media/imx6/capture/ov5642.c
>>  create mode 100644 include/linux/platform_data/imx-ipu-v3.h
>>  create mode 100644 include/media/imx6.h
>>
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 00/43] i.MX6 Video capture
  2014-06-08  8:36 ` [PATCH 00/43] i.MX6 Video capture Hans Verkuil
  2014-06-08  8:39   ` Hans Verkuil
@ 2014-06-09 16:42   ` Steve Longerbeam
  2014-06-10 15:11     ` Hans Verkuil
  1 sibling, 1 reply; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-09 16:42 UTC (permalink / raw)
  To: Hans Verkuil, linux-media; +Cc: David Peverley

On 06/08/2014 01:36 AM, Hans Verkuil wrote:
> Hi Steve!
>
> On 06/07/2014 11:56 PM, Steve Longerbeam wrote:
>> Hi all,
>>
>> This patch set adds video capture support for the Freescale i.MX6 SOC.
>>
>> It is a from-scratch standardized driver that works with community
>> v4l2 utilities, such as v4l2-ctl, v4l2-cap, and the v4l2src gstreamer
>> plugin. It uses the latest v4l2 interfaces (subdev, videobuf2).
>> Please see Documentation/video4linux/mx6_camera.txt for it's full list
>> of features!
>>
>> The first 38 patches:
>>
>> - prepare the ipu-v3 driver for video capture support. The current driver
>>   contains only video display functionality to support the imx DRM drivers.
>>   At some point ipu-v3 should be moved out from under staging/imx-drm since
>>   it will no longer only support DRM.
>>
>> - Adds the device tree nodes and OF graph bindings for video capture support
>>   on sabrelite, sabresd, and sabreauto reference platforms.
>>
>> The new i.MX6 capture host interface driver is at patch 39.
>>
>> To support the sensors found on the sabrelite, sabresd, and sabreauto,
>> three patches add sensor subdev's for parallel OV5642, MIPI CSI-2 OV5640,
>> and the ADV7180 decoder chip, beginning at patch 40.
>>
>> There is an existing adv7180 subdev driver under drivers/media/i2c, but
>> it needs some extra functionality to work on the sabreauto. It will need
>> OF graph bindings support and gpio for a power-on pin on the sabreauto.
>> It would also need to send a new subdev notification to take advantage
>> of decoder status change handling provided by the host driver. This
>> feature makes it possible to correctly handle "hot" (while streaming)
>> signal lock/unlock and autodetected video standard changes.
> A new V4L2_EVENT_SOURCE_CHANGE event has just been added for that.

Hello Hans!

Ok, V4L2_EVENT_SOURCE_CHANGE looks promising.

But v4l2-framework.txt states that v4l2 events are passed to userland. So I want to make sure this framework will also work internally; that is, the decoder subdev (adv7180) can generate this event
and it can be subscribed by the capture host driver. That it can be passed to userland is fine and would be useful, it's not necessary in this case.

>
>> Usage notes are found in Documentation/video4linux/mx6_camera.txt for the
>> above three reference platforms.
>>
>> The driver source is under drivers/staging/media/imx6/capture/.
> Thank you for this patch series! Much appreciated that this hardware is
> finally going to supported with a proper driver.
>
> I did a quick scan of the driver and I noticed a few things that need
> to be fixed: instead of implementing g/s_crop, implement g/s_selection:
> new drivers should implement the selection API and they will get the crop
> API for free.

Ok, I'll look into g/s_selection for v2 patches.

>
> You should use the vb2 helper functions (vb2_fop_*, vb2_ioctl_*) unless
> there is a good reason not to do it. Those functions should simplify the
> code and they give you proper 'streaming ownership'. See also the example
> code Documentation/video4linux/v4l2-pci-skeleton.c.

Ok, ditto.

>
> Finally you should run the v4l2-compliance test tool and fix any failures.
>
> That tool is part of git://linuxtv.org/v4l-utils.git. Always compile from
> that repository to be sure you use the latest code.
>
> Test first with 'v4l2-compliance'. When all issues are fixed, then test
> with 'v4l2-compliance -s' to test actual streaming behavior as well.
>
> When you post v2 of this patch series I want to see the output of
> 'v4l2-compliance -s'! New drivers should pass v4l2-compliance. However,
> this is a staging driver so I won't be that strict, but it seems to be
> the intention that this driver will become a mainline driver, so I would
> recommend to fix any issues now rather than later.

Very cool, I'll make sure all v4l2-compliance issues are resolved. I can start that before issuing the v2 patches.


>
> If you have questions about v4l2-compliance it it might be easiest to
> set up an irc session where we go through them. In that case mail me
> so we can set up a time and date to do that. I'm in timezone UTC+2.

Thanks for the offer. Give me a few days to compose v2 patches and I'll start looking at v4l2-compliance.

Steve


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 00/43] i.MX6 Video capture
  2014-06-09 16:42   ` Steve Longerbeam
@ 2014-06-10 15:11     ` Hans Verkuil
  2014-06-11  0:54       ` Steve Longerbeam
  0 siblings, 1 reply; 79+ messages in thread
From: Hans Verkuil @ 2014-06-10 15:11 UTC (permalink / raw)
  To: Steve Longerbeam, linux-media; +Cc: David Peverley

On 06/09/2014 06:42 PM, Steve Longerbeam wrote:
> On 06/08/2014 01:36 AM, Hans Verkuil wrote:
>> Hi Steve!
>>
>> On 06/07/2014 11:56 PM, Steve Longerbeam wrote:
>>> Hi all,
>>>
>>> This patch set adds video capture support for the Freescale i.MX6 SOC.
>>>
>>> It is a from-scratch standardized driver that works with community
>>> v4l2 utilities, such as v4l2-ctl, v4l2-cap, and the v4l2src gstreamer
>>> plugin. It uses the latest v4l2 interfaces (subdev, videobuf2).
>>> Please see Documentation/video4linux/mx6_camera.txt for it's full list
>>> of features!
>>>
>>> The first 38 patches:
>>>
>>> - prepare the ipu-v3 driver for video capture support. The current driver
>>>   contains only video display functionality to support the imx DRM drivers.
>>>   At some point ipu-v3 should be moved out from under staging/imx-drm since
>>>   it will no longer only support DRM.
>>>
>>> - Adds the device tree nodes and OF graph bindings for video capture support
>>>   on sabrelite, sabresd, and sabreauto reference platforms.
>>>
>>> The new i.MX6 capture host interface driver is at patch 39.
>>>
>>> To support the sensors found on the sabrelite, sabresd, and sabreauto,
>>> three patches add sensor subdev's for parallel OV5642, MIPI CSI-2 OV5640,
>>> and the ADV7180 decoder chip, beginning at patch 40.
>>>
>>> There is an existing adv7180 subdev driver under drivers/media/i2c, but
>>> it needs some extra functionality to work on the sabreauto. It will need
>>> OF graph bindings support and gpio for a power-on pin on the sabreauto.
>>> It would also need to send a new subdev notification to take advantage
>>> of decoder status change handling provided by the host driver. This
>>> feature makes it possible to correctly handle "hot" (while streaming)
>>> signal lock/unlock and autodetected video standard changes.
>> A new V4L2_EVENT_SOURCE_CHANGE event has just been added for that.
> 
> Hello Hans!
> 
> Ok, V4L2_EVENT_SOURCE_CHANGE looks promising.
> 
> But v4l2-framework.txt states that v4l2 events are passed to userland. So I want to make sure this framework will also work internally; that is, the decoder subdev (adv7180) can generate this event
> and it can be subscribed by the capture host driver. That it can be passed to userland is fine and would be useful, it's not necessary in this case.

A subdevice can notify its parent device through v4l2_subdev_notify (see
v4l2-device.h). It would be nice if the event API and this notify mechanism
were unified or at least be more similar.

It's on my TODO list, but it is fairly far down that list.

Let me know if you are interested to improve this situation. I should be able
to give some pointers.

Regards,

	Hans

> 
>>
>>> Usage notes are found in Documentation/video4linux/mx6_camera.txt for the
>>> above three reference platforms.
>>>
>>> The driver source is under drivers/staging/media/imx6/capture/.
>> Thank you for this patch series! Much appreciated that this hardware is
>> finally going to supported with a proper driver.
>>
>> I did a quick scan of the driver and I noticed a few things that need
>> to be fixed: instead of implementing g/s_crop, implement g/s_selection:
>> new drivers should implement the selection API and they will get the crop
>> API for free.
> 
> Ok, I'll look into g/s_selection for v2 patches.
> 
>>
>> You should use the vb2 helper functions (vb2_fop_*, vb2_ioctl_*) unless
>> there is a good reason not to do it. Those functions should simplify the
>> code and they give you proper 'streaming ownership'. See also the example
>> code Documentation/video4linux/v4l2-pci-skeleton.c.
> 
> Ok, ditto.
> 
>>
>> Finally you should run the v4l2-compliance test tool and fix any failures.
>>
>> That tool is part of git://linuxtv.org/v4l-utils.git. Always compile from
>> that repository to be sure you use the latest code.
>>
>> Test first with 'v4l2-compliance'. When all issues are fixed, then test
>> with 'v4l2-compliance -s' to test actual streaming behavior as well.
>>
>> When you post v2 of this patch series I want to see the output of
>> 'v4l2-compliance -s'! New drivers should pass v4l2-compliance. However,
>> this is a staging driver so I won't be that strict, but it seems to be
>> the intention that this driver will become a mainline driver, so I would
>> recommend to fix any issues now rather than later.
> 
> Very cool, I'll make sure all v4l2-compliance issues are resolved. I can start that before issuing the v2 patches.
> 
> 
>>
>> If you have questions about v4l2-compliance it it might be easiest to
>> set up an irc session where we go through them. In that case mail me
>> so we can set up a time and date to do that. I'm in timezone UTC+2.
> 
> Thanks for the offer. Give me a few days to compose v2 patches and I'll start looking at v4l2-compliance.
> 
> Steve
> 


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 00/43] i.MX6 Video capture
  2014-06-10 15:11     ` Hans Verkuil
@ 2014-06-11  0:54       ` Steve Longerbeam
  2014-06-11  7:01         ` Hans Verkuil
  0 siblings, 1 reply; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-11  0:54 UTC (permalink / raw)
  To: Hans Verkuil, linux-media; +Cc: David Peverley

On 06/10/2014 08:11 AM, Hans Verkuil wrote:
> On 06/09/2014 06:42 PM, Steve Longerbeam wrote:
>> On 06/08/2014 01:36 AM, Hans Verkuil wrote:
>>> Hi Steve!
>>>
>>> On 06/07/2014 11:56 PM, Steve Longerbeam wrote:
>>>> Hi all,
>>>>
>>>> This patch set adds video capture support for the Freescale i.MX6 SOC.
>>>>
>>>> It is a from-scratch standardized driver that works with community
>>>> v4l2 utilities, such as v4l2-ctl, v4l2-cap, and the v4l2src gstreamer
>>>> plugin. It uses the latest v4l2 interfaces (subdev, videobuf2).
>>>> Please see Documentation/video4linux/mx6_camera.txt for it's full list
>>>> of features!
>>>>
>>>> The first 38 patches:
>>>>
>>>> - prepare the ipu-v3 driver for video capture support. The current driver
>>>>   contains only video display functionality to support the imx DRM drivers.
>>>>   At some point ipu-v3 should be moved out from under staging/imx-drm since
>>>>   it will no longer only support DRM.
>>>>
>>>> - Adds the device tree nodes and OF graph bindings for video capture support
>>>>   on sabrelite, sabresd, and sabreauto reference platforms.
>>>>
>>>> The new i.MX6 capture host interface driver is at patch 39.
>>>>
>>>> To support the sensors found on the sabrelite, sabresd, and sabreauto,
>>>> three patches add sensor subdev's for parallel OV5642, MIPI CSI-2 OV5640,
>>>> and the ADV7180 decoder chip, beginning at patch 40.
>>>>
>>>> There is an existing adv7180 subdev driver under drivers/media/i2c, but
>>>> it needs some extra functionality to work on the sabreauto. It will need
>>>> OF graph bindings support and gpio for a power-on pin on the sabreauto.
>>>> It would also need to send a new subdev notification to take advantage
>>>> of decoder status change handling provided by the host driver. This
>>>> feature makes it possible to correctly handle "hot" (while streaming)
>>>> signal lock/unlock and autodetected video standard changes.
>>> A new V4L2_EVENT_SOURCE_CHANGE event has just been added for that.
>>
>> Hello Hans!
>>
>> Ok, V4L2_EVENT_SOURCE_CHANGE looks promising.
>>
>> But v4l2-framework.txt states that v4l2 events are passed to userland. So
>> I want to make sure this framework will also work internally; that is,
>> the decoder subdev (adv7180) can generate this event and it can be
>> subscribed by the capture host driver. That it can be passed to userland
>> is fine and would be useful, it's not necessary in this case.
> 
> A subdevice can notify its parent device through v4l2_subdev_notify (see
> v4l2-device.h). It would be nice if the event API and this notify mechanism
> were unified or at least be more similar.
> 
> It's on my TODO list, but it is fairly far down that list.
> 
> Let me know if you are interested to improve this situation. I should be able
> to give some pointers.
> 
>

Hi Hans,

It doesn't look possible for subdev's to queue events, since events require
a v4l2 fh context, so it looks like subdev notifications should stick
around.

But perhaps subdev notification can be modified to send a struct v4l2_event,
rather than a u32 notification value. Then at least notify and events can
share event types instead of duplicating them (such as what I caused by
introducing this similar decoder status change notification).

Something like:

/* Send an event to v4l2_device. */
static inline void v4l2_subdev_notify(struct v4l2_subdev *sd,
       	      	   		      struct v4l2_event *ev,
				      void *arg)
{
        if (sd && sd->v4l2_dev && sd->v4l2_dev->notify)
                sd->v4l2_dev->notify(sd, ev, arg);
}


Then the parent is free to consume this event internally, and/or queue it
off to userland via v4l2_event_queue().

Notification values could then completely disappear, replaced with new (or
existing) event types.

Is that what you had in mind, or something completely different?

Steve

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 04/43] imx-drm: ipu-v3: Add solo/dual-lite IPU device type
  2014-06-07 21:56 ` [PATCH 04/43] imx-drm: ipu-v3: Add solo/dual-lite IPU device type Steve Longerbeam
@ 2014-06-11  5:37   ` Sascha Hauer
  2014-06-11 11:38   ` Philipp Zabel
  1 sibling, 0 replies; 79+ messages in thread
From: Sascha Hauer @ 2014-06-11  5:37 UTC (permalink / raw)
  To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam, Jiada Wang

Hi Steve,

On Sat, Jun 07, 2014 at 02:56:06PM -0700, Steve Longerbeam wrote:
> Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
> ---
>  drivers/staging/imx-drm/ipu-v3/ipu-common.c |   18 ++++++++++++++++++
>  include/linux/platform_data/imx-ipu-v3.h    |    1 +
>  2 files changed, 19 insertions(+)
> 
> diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
> index f8e8c56..2d95a7c 100644
> --- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
> +++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
> @@ -829,10 +829,28 @@ static struct ipu_devtype ipu_type_imx6q = {
>  	.type = IPUV3H,
>  };
>  
> +static struct ipu_devtype ipu_type_imx6dl = {
> +	.name = "IPUv3HDL",
> +	.cm_ofs = 0x00200000,
> +	.cpmem_ofs = 0x00300000,
> +	.srm_ofs = 0x00340000,
> +	.tpm_ofs = 0x00360000,
> +	.csi0_ofs = 0x00230000,
> +	.csi1_ofs = 0x00238000,
> +	.disp0_ofs = 0x00240000,
> +	.disp1_ofs = 0x00248000,
> +	.smfc_ofs =  0x00250000,
> +	.ic_ofs = 0x00220000,
> +	.vdi_ofs = 0x00268000,
> +	.dc_tmpl_ofs = 0x00380000,
> +	.type = IPUV3HDL,
> +};

This breaks bisectibility. This patch must come after

[PATCH 08/43] imx-drm: ipu-v3: Add units required for video capture

Besides, is there any difference between IPUv3HDL and IPUv3H? Can't you
reuse it?

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 30/43] ARM: dts: imx6: add pin groups for imx6q/dl for IPU1 CSI0
  2014-06-07 21:56 ` [PATCH 30/43] ARM: dts: imx6: add pin groups for imx6q/dl for IPU1 CSI0 Steve Longerbeam
@ 2014-06-11  5:56   ` Sascha Hauer
  0 siblings, 0 replies; 79+ messages in thread
From: Sascha Hauer @ 2014-06-11  5:56 UTC (permalink / raw)
  To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam, Jiada Wang

On Sat, Jun 07, 2014 at 02:56:32PM -0700, Steve Longerbeam wrote:
> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
> Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
> ---
>  arch/arm/boot/dts/imx6qdl.dtsi |   52 ++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 52 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
> index 04c978c..d793cd6 100644
> --- a/arch/arm/boot/dts/imx6qdl.dtsi
> +++ b/arch/arm/boot/dts/imx6qdl.dtsi
> @@ -664,6 +664,58 @@
>  			iomuxc: iomuxc@020e0000 {
>  				compatible = "fsl,imx6dl-iomuxc", "fsl,imx6q-iomuxc";
>  				reg = <0x020e0000 0x4000>;
> +
> +				ipu1 {
> +					pinctrl_ipu1_csi0_d4_d7: ipu1-csi0-d4-d7 {
> +						fsl,pins = <
> +							MX6QDL_PAD_CSI0_DAT4__IPU1_CSI0_DATA04 0x80000000
> +							MX6QDL_PAD_CSI0_DAT5__IPU1_CSI0_DATA05 0x80000000
> +							MX6QDL_PAD_CSI0_DAT6__IPU1_CSI0_DATA06 0x80000000
> +							MX6QDL_PAD_CSI0_DAT7__IPU1_CSI0_DATA07 0x80000000
> +						>;
> +					};

We no longer have the pinctrl groups in the SoC dts files. Please put
them into the boards instead.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 08/43] imx-drm: ipu-v3: Add units required for video capture
  2014-06-07 21:56 ` [PATCH 08/43] imx-drm: ipu-v3: Add units required for video capture Steve Longerbeam
@ 2014-06-11  6:18   ` Sascha Hauer
  2014-06-11 14:09   ` Philipp Zabel
  1 sibling, 0 replies; 79+ messages in thread
From: Sascha Hauer @ 2014-06-11  6:18 UTC (permalink / raw)
  To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam

On Sat, Jun 07, 2014 at 02:56:10PM -0700, Steve Longerbeam wrote:
> Adds the following new IPU units:
> 
> - Camera Sensor Interface (csi)
> - Sensor Multi FIFO Controller (smfc)
> - Image Converter (ic)
> - Image Rotator (irt)
> 
> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
> ---
>  drivers/staging/imx-drm/ipu-v3/Makefile     |    3 +-
>  drivers/staging/imx-drm/ipu-v3/ipu-common.c |   67 ++-
>  drivers/staging/imx-drm/ipu-v3/ipu-csi.c    |  821 ++++++++++++++++++++++++++
>  drivers/staging/imx-drm/ipu-v3/ipu-ic.c     |  835 +++++++++++++++++++++++++++
>  drivers/staging/imx-drm/ipu-v3/ipu-irt.c    |  103 ++++
>  drivers/staging/imx-drm/ipu-v3/ipu-prv.h    |   24 +
>  drivers/staging/imx-drm/ipu-v3/ipu-smfc.c   |  348 +++++++++++
>  include/linux/platform_data/imx-ipu-v3.h    |  151 +++++
>  8 files changed, 2350 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-csi.c
>  create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-ic.c
>  create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-irt.c
>  create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-smfc.c
> 
> diff --git a/drivers/staging/imx-drm/ipu-v3/Makefile b/drivers/staging/imx-drm/ipu-v3/Makefile
> index 28ed72e..79c0c88 100644
> --- a/drivers/staging/imx-drm/ipu-v3/Makefile
> +++ b/drivers/staging/imx-drm/ipu-v3/Makefile
> @@ -1,3 +1,4 @@
>  obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += imx-ipu-v3.o
>  
> -imx-ipu-v3-objs := ipu-common.o ipu-dc.o ipu-di.o ipu-dp.o ipu-dmfc.o
> +imx-ipu-v3-objs := ipu-common.o ipu-csi.o ipu-dc.o ipu-di.o \
> +	ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-irt.o ipu-smfc.o
> diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
> index 1c606b5..3d7e28d 100644
> --- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
> +++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
> @@ -834,6 +834,10 @@ struct ipu_devtype {
>  	unsigned long cpmem_ofs;
>  	unsigned long srm_ofs;
>  	unsigned long tpm_ofs;
> +	unsigned long csi0_ofs;
> +	unsigned long csi1_ofs;
> +	unsigned long smfc_ofs;
> +	unsigned long ic_ofs;
>  	unsigned long disp0_ofs;
>  	unsigned long disp1_ofs;
>  	unsigned long dc_tmpl_ofs;
> @@ -873,8 +877,12 @@ static struct ipu_devtype ipu_type_imx6q = {
>  	.cpmem_ofs = 0x00300000,
>  	.srm_ofs = 0x00340000,
>  	.tpm_ofs = 0x00360000,
> +	.csi0_ofs = 0x00230000,
> +	.csi1_ofs = 0x00238000,
>  	.disp0_ofs = 0x00240000,
>  	.disp1_ofs = 0x00248000,
> +	.smfc_ofs =  0x00250000,
> +	.ic_ofs = 0x00220000,
>  	.dc_tmpl_ofs = 0x00380000,
>  	.vdi_ofs = 0x00268000,
>  	.type = IPUV3H,
> @@ -915,8 +923,44 @@ static int ipu_submodules_init(struct ipu_soc *ipu,
>  	struct device *dev = &pdev->dev;
>  	const struct ipu_devtype *devtype = ipu->devtype;
>  
> +	ret = ipu_csi_init(ipu, dev, 0, ipu_base + devtype->csi0_ofs,
> +			   IPU_CONF_CSI0_EN, ipu_clk);
> +	if (ret) {
> +		unit = "csi0";
> +		goto err_csi_0;
> +	}

Please be nice to other SoCs. You set csi0_ofs for i.MX6, but not for
i.MX5. For i.MX5 you silently initialize the CSI with bogus register
offsets. Either test for _ofs == 0 before initializing it or add the
correct values for i.MX51/53 (preferred).

> +int ipu_csi_set_src(struct ipu_csi *csi, u32 vc, bool select_mipi_csi2)
> +{
> +	struct ipu_soc *ipu = csi->ipu;
> +	int ipu_id = ipu_get_num(ipu);
> +	u32 val, bit;
> +
> +	/*
> +	 * Set the muxes that choose between mipi-csi2 and parallel inputs
> +	 * to the CSI's.
> +	 */
> +	if (csi->ipu->ipu_type == IPUV3HDL) {
> +		/*
> +		 * On D/L, the mux is in GPR13. The TRM is unclear,
> +		 * but it appears the mux allows selecting the MIPI
> +		 * CSI-2 virtual channel number to route to the CSIs.
> +		 */
> +		bit = GPR13_IPUV3HDL_CSI_MUX_CTL_SHIFT + csi->id * 3;
> +		val = select_mipi_csi2 ? vc << bit : 4 << bit;
> +		regmap_update_bits(ipu->gp_reg, IOMUXC_GPR13,
> +				   0x7 << bit, val);
> +	} else if (csi->ipu->ipu_type == IPUV3H) {
> +		/*
> +		 * For Q/D, the mux only exists on IPU0-CSI0 and IPU1-CSI1,
> +		 * and the routed virtual channel numbers are fixed at 0 and
> +		 * 3 respectively.
> +		 */
> +		if ((ipu_id == 0 && csi->id == 0) ||
> +		    (ipu_id == 1 && csi->id == 1)) {
> +			bit = GPR1_IPU_CSI_MUX_CTL_SHIFT + csi->ipu->id;
> +			val = select_mipi_csi2 ? 0 : 1 << bit;
> +			regmap_update_bits(ipu->gp_reg, IOMUXC_GPR1,
> +					   0x1 << bit, val);
> +		}
> +	} else {
> +		dev_err(csi->ipu->dev,
> +			"ERROR: %s: unsupported CPU version!\n",
> +			__func__);
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * there is another mux in the IPU config register that
> +	 * must be set as well
> +	 */
> +	ipu_set_csi_src_mux(ipu, csi->id, select_mipi_csi2);

This is not a property of the IPU but how the IPU is integrated into the
SoC. I'm unsure this should be integrated like this, it sounds more like
a job for mediactrl.

> +#include <linux/types.h>
> +#include <linux/init.h>
> +#include <linux/errno.h>
> +#include <linux/spinlock.h>
> +#include <linux/videodev2.h>
> +#include <linux/bitrev.h>
> +#include <linux/io.h>
> +#include <linux/err.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>

Please clean up the include list. There is nothing used from
clk-provider.h for example.

> +static int init_csc(struct ipu_ic *ic,
> +		    enum ipu_color_space in_format,
> +		    enum ipu_color_space out_format,
> +		    int csc_index);
> +static int calc_resize_coeffs(struct ipu_ic *ic,
> +			      u32 in_size, u32 out_size,
> +			      u32 *resize_coeff,
> +			      u32 *downsize_coeff);

Please reorder functions to get rid of static function declarations.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 00/43] i.MX6 Video capture
  2014-06-11  0:54       ` Steve Longerbeam
@ 2014-06-11  7:01         ` Hans Verkuil
  0 siblings, 0 replies; 79+ messages in thread
From: Hans Verkuil @ 2014-06-11  7:01 UTC (permalink / raw)
  To: Steve Longerbeam, linux-media; +Cc: David Peverley

On 06/11/2014 02:54 AM, Steve Longerbeam wrote:
> On 06/10/2014 08:11 AM, Hans Verkuil wrote:
>> On 06/09/2014 06:42 PM, Steve Longerbeam wrote:
>>> On 06/08/2014 01:36 AM, Hans Verkuil wrote:
>>>> Hi Steve!
>>>>
>>>> On 06/07/2014 11:56 PM, Steve Longerbeam wrote:
>>>>> Hi all,
>>>>>
>>>>> This patch set adds video capture support for the Freescale i.MX6 SOC.
>>>>>
>>>>> It is a from-scratch standardized driver that works with community
>>>>> v4l2 utilities, such as v4l2-ctl, v4l2-cap, and the v4l2src gstreamer
>>>>> plugin. It uses the latest v4l2 interfaces (subdev, videobuf2).
>>>>> Please see Documentation/video4linux/mx6_camera.txt for it's full list
>>>>> of features!
>>>>>
>>>>> The first 38 patches:
>>>>>
>>>>> - prepare the ipu-v3 driver for video capture support. The current driver
>>>>>   contains only video display functionality to support the imx DRM drivers.
>>>>>   At some point ipu-v3 should be moved out from under staging/imx-drm since
>>>>>   it will no longer only support DRM.
>>>>>
>>>>> - Adds the device tree nodes and OF graph bindings for video capture support
>>>>>   on sabrelite, sabresd, and sabreauto reference platforms.
>>>>>
>>>>> The new i.MX6 capture host interface driver is at patch 39.
>>>>>
>>>>> To support the sensors found on the sabrelite, sabresd, and sabreauto,
>>>>> three patches add sensor subdev's for parallel OV5642, MIPI CSI-2 OV5640,
>>>>> and the ADV7180 decoder chip, beginning at patch 40.
>>>>>
>>>>> There is an existing adv7180 subdev driver under drivers/media/i2c, but
>>>>> it needs some extra functionality to work on the sabreauto. It will need
>>>>> OF graph bindings support and gpio for a power-on pin on the sabreauto.
>>>>> It would also need to send a new subdev notification to take advantage
>>>>> of decoder status change handling provided by the host driver. This
>>>>> feature makes it possible to correctly handle "hot" (while streaming)
>>>>> signal lock/unlock and autodetected video standard changes.
>>>> A new V4L2_EVENT_SOURCE_CHANGE event has just been added for that.
>>>
>>> Hello Hans!
>>>
>>> Ok, V4L2_EVENT_SOURCE_CHANGE looks promising.
>>>
>>> But v4l2-framework.txt states that v4l2 events are passed to userland. So
>>> I want to make sure this framework will also work internally; that is,
>>> the decoder subdev (adv7180) can generate this event and it can be
>>> subscribed by the capture host driver. That it can be passed to userland
>>> is fine and would be useful, it's not necessary in this case.
>>
>> A subdevice can notify its parent device through v4l2_subdev_notify (see
>> v4l2-device.h). It would be nice if the event API and this notify mechanism
>> were unified or at least be more similar.
>>
>> It's on my TODO list, but it is fairly far down that list.
>>
>> Let me know if you are interested to improve this situation. I should be able
>> to give some pointers.
>>
>>
> 
> Hi Hans,
> 
> It doesn't look possible for subdev's to queue events, since events require
> a v4l2 fh context, so it looks like subdev notifications should stick
> around.
> 
> But perhaps subdev notification can be modified to send a struct v4l2_event,
> rather than a u32 notification value. Then at least notify and events can
> share event types instead of duplicating them (such as what I caused by
> introducing this similar decoder status change notification).
> 
> Something like:
> 
> /* Send an event to v4l2_device. */
> static inline void v4l2_subdev_notify(struct v4l2_subdev *sd,
>        	      	   		      struct v4l2_event *ev,
> 				      void *arg)
> {
>         if (sd && sd->v4l2_dev && sd->v4l2_dev->notify)
>                 sd->v4l2_dev->notify(sd, ev, arg);
> }
> 
> 
> Then the parent is free to consume this event internally, and/or queue it
> off to userland via v4l2_event_queue().
> 
> Notification values could then completely disappear, replaced with new (or
> existing) event types.
> 
> Is that what you had in mind, or something completely different?

That is what I had in mind, although the 'arg' argument can be dropped, since
that will be part of the event payload.

There is another notifier function as well in v4l2-ctrls.h: v4l2_ctrl_notify().
This should also switch to using v4l2_subdev_notify(). Instead of setting a
notify callback it should set a v4l2_subdev pointer: that will allow it to
call v4l2_subdev_notify().

Where things get tricky is with the event payload: there is no problem if it
is one of the standard events, but for kernel-internal events it is not quite
clear how those should be defined. Ideally you would like to be able to add
new structs inside the v4l2_event union, but you don't want those to be part
of the public API either.

I'm thinking something like this:

// Range for events that are internal to the kernel
#define V4L2_EVENT_INTERNAL_START 0x04000000

And internal events and associated payload structs are defined in v4l2-event.h.

Add this macro to v4l2-event.h:

#define V4L2_EVENT_CAST(ev, type) ((type *)(&(ev)->u))

Now you should be able to do something like this:

In v4l2-event.h:

#define V4L2_EVENT_INT_FOO (V4L2_EVENT_INTERNAL_START + 0)

struct v4l2_event_int_foo {
	u32 val;
};

In the driver:

	struct v4l2_event ev;
	struct v4l2_event_int_foo *f = V4L2_EVENT_CAST(&ev, struct v4l2_event_int_foo);

	f->val = 10;

	// Or alternatively:
	*V4L2_EVENT_CAST(&ev, u32) = 10;

It's the best I can come up with.

It would be nice to use the same v4l2_event struct for all notifications, it's much more
unified and elegant.

Regards,

	Hans

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 00/43] i.MX6 Video capture
  2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
                   ` (43 preceding siblings ...)
  2014-06-08  8:36 ` [PATCH 00/43] i.MX6 Video capture Hans Verkuil
@ 2014-06-11 11:21 ` Philipp Zabel
  2014-06-12  1:04   ` Steve Longerbeam
  44 siblings, 1 reply; 79+ messages in thread
From: Philipp Zabel @ 2014-06-11 11:21 UTC (permalink / raw)
  To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam

Hi Steve,

Am Samstag, den 07.06.2014, 14:56 -0700 schrieb Steve Longerbeam:
> Hi all,
> 
> This patch set adds video capture support for the Freescale i.MX6 SOC.
>
> It is a from-scratch standardized driver that works with community
> v4l2 utilities, such as v4l2-ctl, v4l2-cap, and the v4l2src gstreamer
> plugin. It uses the latest v4l2 interfaces (subdev, videobuf2).
> Please see Documentation/video4linux/mx6_camera.txt for it's full list
> of features!

That's quite a series to digest! I'll quickly go over the points that
jumped at me and then look at the core code (especially 08/43 and 39/43)
in detail.

> The first 38 patches:
> 
> - prepare the ipu-v3 driver for video capture support. The current driver
>   contains only video display functionality to support the imx DRM drivers.
>   At some point ipu-v3 should be moved out from under staging/imx-drm since
>   it will no longer only support DRM.

The move out of staging is now merged into drm-next with
c1a6e9fe82b46159af8cc4cf34fb51ee47862f05.
After this is merged into mainline, there should be no need to push i.MX
capture support through staging. It would be helpful if you could rebase
on top of that.

> - Adds the device tree nodes and OF graph bindings for video capture support
>   on sabrelite, sabresd, and sabreauto reference platforms.

I disagree with the way you organized the device tree, I'll comment in
the relevant patches.

> The new i.MX6 capture host interface driver is at patch 39.
> 
> To support the sensors found on the sabrelite, sabresd, and sabreauto,
> three patches add sensor subdev's for parallel OV5642, MIPI CSI-2 OV5640,
> and the ADV7180 decoder chip, beginning at patch 40.

Please don't introduce i.MX6-only sensor drivers. Those should live
under drivers/media/i2c and not be i.MX specific.

regards
Philipp


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 02/43] ARM: dts: imx6qdl: Add ipu aliases
  2014-06-07 21:56 ` [PATCH 02/43] ARM: dts: imx6qdl: Add ipu aliases Steve Longerbeam
@ 2014-06-11 11:21   ` Philipp Zabel
  0 siblings, 0 replies; 79+ messages in thread
From: Philipp Zabel @ 2014-06-11 11:21 UTC (permalink / raw)
  To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam

Am Samstag, den 07.06.2014, 14:56 -0700 schrieb Steve Longerbeam:
> Add ipu0 (and ipu1 for quad) aliases to ipu1/ipu2 nodes respectively.
> 
> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
> ---
>  arch/arm/boot/dts/imx6q.dtsi   |    1 +
>  arch/arm/boot/dts/imx6qdl.dtsi |    1 +
>  2 files changed, 2 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
> index addd3f8..c7544f0 100644
> --- a/arch/arm/boot/dts/imx6q.dtsi
> +++ b/arch/arm/boot/dts/imx6q.dtsi
> @@ -15,6 +15,7 @@
>  / {
>  	aliases {
>  		spi4 = &ecspi5;
> +		ipu1 = &ipu2;
>  	};
>  
>  	cpus {
> diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
> index eca0971..04c978c 100644
> --- a/arch/arm/boot/dts/imx6qdl.dtsi
> +++ b/arch/arm/boot/dts/imx6qdl.dtsi
> @@ -43,6 +43,7 @@
>  		spi3 = &ecspi4;
>  		usbphy0 = &usbphy1;
>  		usbphy1 = &usbphy2;
> +		ipu0 = &ipu1;
>  	};
>  
>  	intc: interrupt-controller@00a01000 {

That could be useful, although I think those aliases are supposed to be
in alphabetic order.

regards
Philipp


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 01/43] imx-drm: ipu-v3: Move imx-ipu-v3.h to include/linux/platform_data/
  2014-06-07 21:56 ` [PATCH 01/43] imx-drm: ipu-v3: Move imx-ipu-v3.h to include/linux/platform_data/ Steve Longerbeam
@ 2014-06-11 11:22   ` Philipp Zabel
  0 siblings, 0 replies; 79+ messages in thread
From: Philipp Zabel @ 2014-06-11 11:22 UTC (permalink / raw)
  To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam

Am Samstag, den 07.06.2014, 14:56 -0700 schrieb Steve Longerbeam:
> In subsequent patches, the video capture units will be added (csi, smfc,
> ic, irt). So the IPU prototypes are no longer needed only by imx-drm,
> so we need to export them to a common include path.
> 
> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>

I have already moved the header into include/video/imx-ipu-v3.h in
39b9004d1f626b88b775c7655d3f286e135dfec6.

regards
Philipp


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 03/43] imx-drm: ipu-v3: Add ipu_get_num()
  2014-06-07 21:56 ` [PATCH 03/43] imx-drm: ipu-v3: Add ipu_get_num() Steve Longerbeam
@ 2014-06-11 11:22   ` Philipp Zabel
  0 siblings, 0 replies; 79+ messages in thread
From: Philipp Zabel @ 2014-06-11 11:22 UTC (permalink / raw)
  To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam

Am Samstag, den 07.06.2014, 14:56 -0700 schrieb Steve Longerbeam:
> Adds of-alias id to ipu_soc and retrieve with ipu_get_num().

It would be nice to have a comment here what this will be needed for.

I see that later ipu-csi uses this to find the correct input mux and
mx6-encode selects the DMA channel depending on this.
I feel like the mux should be handled as a separate v4l2_subdev since it
is not part of the IPU, it is different between i.MX6Q and i.MX6DL, and
it doesn't even exist on i.MX5.

regards
Philipp


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 06/43] imx-drm: ipu-v3: Add functions to set CSI/IC source muxes
  2014-06-07 21:56 ` [PATCH 06/43] imx-drm: ipu-v3: Add functions to set CSI/IC source muxes Steve Longerbeam
@ 2014-06-11 11:22   ` Philipp Zabel
  0 siblings, 0 replies; 79+ messages in thread
From: Philipp Zabel @ 2014-06-11 11:22 UTC (permalink / raw)
  To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam

Am Samstag, den 07.06.2014, 14:56 -0700 schrieb Steve Longerbeam:
> Adds two new functions, ipu_set_csi_src_mux() and ipu_set_ic_src_mux(),
> that select the inputs to the CSI and IC respectively. Both muxes are
> programmed in the IPU_CONF register.
> 
> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>

Acked-by: Philipp Zabel <p.zabel@pengutronix.de>

regards
Philipp


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 07/43] imx-drm: ipu-v3: Rename and add IDMAC channels
  2014-06-07 21:56 ` [PATCH 07/43] imx-drm: ipu-v3: Rename and add IDMAC channels Steve Longerbeam
@ 2014-06-11 11:22   ` Philipp Zabel
  0 siblings, 0 replies; 79+ messages in thread
From: Philipp Zabel @ 2014-06-11 11:22 UTC (permalink / raw)
  To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam

Am Samstag, den 07.06.2014, 14:56 -0700 schrieb Steve Longerbeam:
> Rename the ENC/VF/PP rotation channel names, to be more consistent
> with the convention that *_MEM is write-to-memory channels and
> MEM_* is read-from-memory channels. Also add the channels who's
> source and destination is the IC.
> 
> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>

Looks good to me,
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>

regards
Philipp


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 15/43] imx-drm: ipu-v3: Add ipu_idmac_current_buffer()
  2014-06-07 21:56 ` [PATCH 15/43] imx-drm: ipu-v3: Add ipu_idmac_current_buffer() Steve Longerbeam
@ 2014-06-11 11:22   ` Philipp Zabel
  0 siblings, 0 replies; 79+ messages in thread
From: Philipp Zabel @ 2014-06-11 11:22 UTC (permalink / raw)
  To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam

Am Samstag, den 07.06.2014, 14:56 -0700 schrieb Steve Longerbeam:
> Add ipu_idmac_current_buffer(), returns the currently active
> buffer number in the given channel.

This is already implemented in drm-next ...

> Checks for third buffer ready in case triple-buffer support is
> added later.

... but this is not.

regards
Philipp


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 21/43] imx-drm: ipu-v3: Add ipu_bits_per_pixel()
  2014-06-07 21:56 ` [PATCH 21/43] imx-drm: ipu-v3: Add ipu_bits_per_pixel() Steve Longerbeam
@ 2014-06-11 11:23   ` Philipp Zabel
  0 siblings, 0 replies; 79+ messages in thread
From: Philipp Zabel @ 2014-06-11 11:23 UTC (permalink / raw)
  To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam

Am Samstag, den 07.06.2014, 14:56 -0700 schrieb Steve Longerbeam:
> Add simple conversion from pixelformat to total bits-per-pixel.
[...]
> +/*
> + * Standard bpp from pixel format.
> + */
> +int ipu_bits_per_pixel(u32 pixelformat)
> +{
> +	switch (pixelformat) {
> +	case V4L2_PIX_FMT_YUV420:
> +	case V4L2_PIX_FMT_YVU420:
> +		return 12;
> +	case V4L2_PIX_FMT_RGB565:
> +	case V4L2_PIX_FMT_YUYV:
> +	case V4L2_PIX_FMT_UYVY:
> +		return 16;
> +	case V4L2_PIX_FMT_BGR24:
> +	case V4L2_PIX_FMT_RGB24:
> +		return 24;
> +	case V4L2_PIX_FMT_BGR32:
> +	case V4L2_PIX_FMT_RGB32:
> +		return 32;
> +	default:
> +		break;
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(ipu_bits_per_pixel);

This isn't really IPU specific. Should we have a v4l2-wide helper for
this? Also, it seems that this is only ever used to calculate the
bytesperline, so why not return bytes per pixel directly?

regards
Philipp


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 22/43] imx-drm: ipu-v3: Add ipu-cpmem unit
  2014-06-07 21:56 ` [PATCH 22/43] imx-drm: ipu-v3: Add ipu-cpmem unit Steve Longerbeam
@ 2014-06-11 11:23   ` Philipp Zabel
  0 siblings, 0 replies; 79+ messages in thread
From: Philipp Zabel @ 2014-06-11 11:23 UTC (permalink / raw)
  To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam, Drew Moseley

Am Samstag, den 07.06.2014, 14:56 -0700 schrieb Steve Longerbeam:
> Move channel parameter memory setup functions and macros into a new
> submodule ipu-cpmem. In the process, cleanup arguments to the functions
> to take a channel pointer instead of a pointer into cpmem for that
> channel. That allows the structure of the parameter memory to be
> private to ipu-cpmem.c.
> 
> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
> Signed-off-by: Drew Moseley <drew_moseley@mentor.com>

I like the move of cpmem handling code into its own submodule.
Acked-by: Philipp Zabel <p.zabel@pengutronix.de>

regards
Philipp


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 31/43] ARM: dts: imx6qdl: Flesh out MIPI CSI2 receiver node
  2014-06-07 21:56 ` [PATCH 31/43] ARM: dts: imx6qdl: Flesh out MIPI CSI2 receiver node Steve Longerbeam
@ 2014-06-11 11:38   ` Philipp Zabel
  0 siblings, 0 replies; 79+ messages in thread
From: Philipp Zabel @ 2014-06-11 11:38 UTC (permalink / raw)
  To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam

Am Samstag, den 07.06.2014, 14:56 -0700 schrieb Steve Longerbeam:
> Add mode device info to the MIPI CSI2 receiver node: compatible string,
> interrupt sources, clocks.
> 
> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
> ---
>  arch/arm/boot/dts/imx6qdl.dtsi |    7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
> index d793cd6..00130a8 100644
> --- a/arch/arm/boot/dts/imx6qdl.dtsi
> +++ b/arch/arm/boot/dts/imx6qdl.dtsi
> @@ -1011,8 +1011,13 @@
>  				status = "disabled";
>  			};
>  
> -			mipi_csi: mipi@021dc000 {
> +			mipi_csi2: mipi@021dc000 {
> +				compatible = "fsl,imx6-mipi-csi2";
>  				reg = <0x021dc000 0x4000>;
> +				interrupts = <0 100 0x04>, <0 101 0x04>;
> +				clocks = <&clks 138>, <&clks 208>;

clk 138 is hsi_tx_clk_root, gated by the mipi_core_cfg gate bit.
All MIPI CSI input clocks are also gated by mipi_core_cfg, so this
will work just as well. But maybe add a comment?

> +				clock-names = "dphy_clk", "cfg_clk";

It is a bit confusing, though.

The i.MX6DL and i.MX6Q TRMs lists the following gateable input clocks,
all gated by the mipi_core_cfg bit:
- ac_clk_125m from ahb_clk_root,
- ips_clk and ips_clk_s from ipg_clk_root
- cfg_clk and pll_refclk from video_27m_clk_root

Which one is "dphy_clk"?

regards
Philipp


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 32/43] ARM: dts: imx: sabrelite: add video capture ports and endpoints
  2014-06-07 21:56 ` [PATCH 32/43] ARM: dts: imx: sabrelite: add video capture ports and endpoints Steve Longerbeam
@ 2014-06-11 11:38   ` Philipp Zabel
  2014-06-12 17:13     ` Philipp Zabel
  0 siblings, 1 reply; 79+ messages in thread
From: Philipp Zabel @ 2014-06-11 11:38 UTC (permalink / raw)
  To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam

Am Samstag, den 07.06.2014, 14:56 -0700 schrieb Steve Longerbeam:
[...]
> +&ipu1 {
> +	status = "okay";
> +
> +	v4l2-capture {
> +		compatible = "fsl,imx6-v4l2-capture";

I'm not happy with adding the simple-bus compatible to the ipu
device tree node just to instantiate a virtual subdevice. See
my comment in the following mail. I think it would be better to
create this platform device from code, not from the device tree
if something is connected to ipu port@0 or port@1, see below.

> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		status = "okay";
> +		pinctrl-names = "default";
> +		pinctrl-0 = <
> +			&pinctrl_ipu1_csi0_1
> +			&pinctrl_ipu1_csi0_data_en
> +		>;
> +
> +		/* CSI0 */
> +		port@0 {

That port really is a property of the IPU itself. I have left
space for ports 0 and 1 when specifying the IPU output interfaces
as port 2 (DI0) and 3 (DI1).

regards
Philipp


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 04/43] imx-drm: ipu-v3: Add solo/dual-lite IPU device type
  2014-06-07 21:56 ` [PATCH 04/43] imx-drm: ipu-v3: Add solo/dual-lite IPU device type Steve Longerbeam
  2014-06-11  5:37   ` Sascha Hauer
@ 2014-06-11 11:38   ` Philipp Zabel
  1 sibling, 0 replies; 79+ messages in thread
From: Philipp Zabel @ 2014-06-11 11:38 UTC (permalink / raw)
  To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam, Jiada Wang

Am Samstag, den 07.06.2014, 14:56 -0700 schrieb Steve Longerbeam:
> Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
> ---
>  drivers/staging/imx-drm/ipu-v3/ipu-common.c |   18 ++++++++++++++++++
>  include/linux/platform_data/imx-ipu-v3.h    |    1 +
>  2 files changed, 19 insertions(+)
> 
> diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
> index f8e8c56..2d95a7c 100644
> --- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
> +++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
> @@ -829,10 +829,28 @@ static struct ipu_devtype ipu_type_imx6q = {
>  	.type = IPUV3H,
>  };
>  
> +static struct ipu_devtype ipu_type_imx6dl = {
> +	.name = "IPUv3HDL",
> +	.cm_ofs = 0x00200000,
> +	.cpmem_ofs = 0x00300000,
> +	.srm_ofs = 0x00340000,
> +	.tpm_ofs = 0x00360000,
> +	.csi0_ofs = 0x00230000,
> +	.csi1_ofs = 0x00238000,
> +	.disp0_ofs = 0x00240000,
> +	.disp1_ofs = 0x00248000,
> +	.smfc_ofs =  0x00250000,
> +	.ic_ofs = 0x00220000,
> +	.vdi_ofs = 0x00268000,
> +	.dc_tmpl_ofs = 0x00380000,
> +	.type = IPUV3HDL,
> +};

This just duplicates ipu_type_imx6. Do I understand correctly that this
new type was added just to account for the different input multiplexer
setup between i.MX6Q and i.MX6DL outside of the IPU?

This would not be necessary if we describe the multiplexers as separate
v4l2_subdev entities. The same applies to the following patch 05/43.

regards
Philipp


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 35/43] ARM: dts: imx6qdl: Add simple-bus to ipu compatibility
  2014-06-07 21:56 ` [PATCH 35/43] ARM: dts: imx6qdl: Add simple-bus to ipu compatibility Steve Longerbeam
@ 2014-06-11 11:39   ` Philipp Zabel
  0 siblings, 0 replies; 79+ messages in thread
From: Philipp Zabel @ 2014-06-11 11:39 UTC (permalink / raw)
  To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam

Am Samstag, den 07.06.2014, 14:56 -0700 schrieb Steve Longerbeam:
> The IPU can have child devices now, so add "simple-bus" to
> compatible list to ensure creation of the children.
> 
> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
> ---
>  .../bindings/staging/imx-drm/fsl-imx-drm.txt       |    6 ++++--
>  arch/arm/boot/dts/imx6q.dtsi                       |    2 +-
>  arch/arm/boot/dts/imx6qdl.dtsi                     |    2 +-
>  3 files changed, 6 insertions(+), 4 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
> index 3be5ce7..dc759e4 100644
> --- a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
> +++ b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
> @@ -21,7 +21,9 @@ Freescale i.MX IPUv3
>  ====================
>  
>  Required properties:
> -- compatible: Should be "fsl,<chip>-ipu"
> +- compatible: Should be "fsl,<chip>-ipu". The IPU can also have child
> +  devices, so also must include "simple-bus" to ensure creation of the
> +  children.

This would be ok if the submodules (CSI, SMFC, IC, DC, DP, etc.) were
listed as subnodes (which I don't think is a good idea). As it stands,
this is a misuse of simple-bus, as the IPU does not provide access to
the subdevices you are going to add through a simple MMIO mapping.

regards
Philipp


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 36/43] gpio: pca953x: Add reset-gpios property
  2014-06-07 21:56 ` [PATCH 36/43] gpio: pca953x: Add reset-gpios property Steve Longerbeam
@ 2014-06-11 11:39   ` Philipp Zabel
  0 siblings, 0 replies; 79+ messages in thread
From: Philipp Zabel @ 2014-06-11 11:39 UTC (permalink / raw)
  To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam

Am Samstag, den 07.06.2014, 14:56 -0700 schrieb Steve Longerbeam:
[...]
>  static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val,
> @@ -735,6 +741,26 @@ static int pca953x_probe(struct i2c_client *client,
>  		/* If I2C node has no interrupts property, disable GPIO interrupts */
>  		if (of_find_property(client->dev.of_node, "interrupts", NULL) == NULL)
>  			irq_base = -1;
> +
> +		/* see if we need to de-assert a reset pin */
> +		ret = of_get_named_gpio_flags(client->dev.of_node,
> +					      "reset-gpios", 0,
> +					      &chip->reset_gpio_flags);
> +		if (gpio_is_valid(ret)) {
> +			chip->reset_gpio = ret;
> +			ret = devm_gpio_request_one(&client->dev,
> +						    chip->reset_gpio,
> +						    GPIOF_DIR_OUT,
> +						    "pca953x_reset");
> +			if (ret == 0) {
> +				/* bring chip out of reset */
> +				dev_info(&client->dev, "releasing reset\n");

I think dev_dbg would be more appropriate.

> +				gpio_set_value(chip->reset_gpio,
> +					       (chip->reset_gpio_flags ==
> +						OF_GPIO_ACTIVE_LOW) ? 1 : 0);
> +			}

You could use the gpiod API (include/gpio/consumer.h) here and have it
do the polarity handling automatically.

regards
Philipp


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 40/43] media: imx6: Add support for MIPI CSI-2 OV5640
  2014-06-07 21:56 ` [PATCH 40/43] media: imx6: Add support for MIPI CSI-2 OV5640 Steve Longerbeam
@ 2014-06-11 11:39   ` Philipp Zabel
  0 siblings, 0 replies; 79+ messages in thread
From: Philipp Zabel @ 2014-06-11 11:39 UTC (permalink / raw)
  To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam

Am Samstag, den 07.06.2014, 14:56 -0700 schrieb Steve Longerbeam:
> +static const struct i2c_device_id ov5640_id[] = {
> +	{"ov5640_mipi", 0},

Is there really a different ov5640_mipi chip as opposed to ov5640?
I suspect this could be well configured in the OF graph endpoint.

regards
Philipp


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 05/43] imx-drm: ipu-v3: Map IOMUXC registers
  2014-06-07 21:56 ` [PATCH 05/43] imx-drm: ipu-v3: Map IOMUXC registers Steve Longerbeam
@ 2014-06-11 13:11   ` Philipp Zabel
  0 siblings, 0 replies; 79+ messages in thread
From: Philipp Zabel @ 2014-06-11 13:11 UTC (permalink / raw)
  To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam

Am Samstag, den 07.06.2014, 14:56 -0700 schrieb Steve Longerbeam:
> Map the IOMUXC registers, which will be needed by ipu-csi for mux
> control.
> 
> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
> ---
>  drivers/staging/imx-drm/ipu-v3/ipu-common.c |    8 ++++++++
>  drivers/staging/imx-drm/ipu-v3/ipu-prv.h    |    4 ++++
>  2 files changed, 12 insertions(+)
> 
> diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
> index 2d95a7c..635dafe 100644
> --- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
> +++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
> @@ -1196,6 +1196,14 @@ static int ipu_probe(struct platform_device *pdev)
>  	if (!ipu->cm_reg || !ipu->idmac_reg || !ipu->cpmem_base)
>  		return -ENOMEM;
>  
> +	ipu->gp_reg = syscon_regmap_lookup_by_compatible(
> +		"fsl,imx6q-iomuxc-gpr");
> +	if (IS_ERR(ipu->gp_reg)) {
> +		ret = PTR_ERR(ipu->gp_reg);
> +		dev_err(&pdev->dev, "failed to map iomuxc regs with %d\n", ret);
> +		return ret;
> +	}
> +

This will break i.MX5. The IPU core driver shouldn't touch those
registers anyway.

regards
Philipp


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 08/43] imx-drm: ipu-v3: Add units required for video capture
  2014-06-07 21:56 ` [PATCH 08/43] imx-drm: ipu-v3: Add units required for video capture Steve Longerbeam
  2014-06-11  6:18   ` Sascha Hauer
@ 2014-06-11 14:09   ` Philipp Zabel
  1 sibling, 0 replies; 79+ messages in thread
From: Philipp Zabel @ 2014-06-11 14:09 UTC (permalink / raw)
  To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam

Am Samstag, den 07.06.2014, 14:56 -0700 schrieb Steve Longerbeam:
> Adds the following new IPU units:
> 
> - Camera Sensor Interface (csi)
> - Sensor Multi FIFO Controller (smfc)
> - Image Converter (ic)
> - Image Rotator (irt)
> 
> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
> ---
>  drivers/staging/imx-drm/ipu-v3/Makefile     |    3 +-
>  drivers/staging/imx-drm/ipu-v3/ipu-common.c |   67 ++-
>  drivers/staging/imx-drm/ipu-v3/ipu-csi.c    |  821 ++++++++++++++++++++++++++
>  drivers/staging/imx-drm/ipu-v3/ipu-ic.c     |  835 +++++++++++++++++++++++++++
>  drivers/staging/imx-drm/ipu-v3/ipu-irt.c    |  103 ++++
>  drivers/staging/imx-drm/ipu-v3/ipu-prv.h    |   24 +
>  drivers/staging/imx-drm/ipu-v3/ipu-smfc.c   |  348 +++++++++++
>  include/linux/platform_data/imx-ipu-v3.h    |  151 +++++

You are broadening the internal API quite a bit. For the IC and IRT that
certainly can't be helped, but the CSI could very well be completely
encapsulated in a v4l2_subdev. I wonder if it wouldn't be better to move
the CSI code into the drivers/media part.

>  8 files changed, 2350 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-csi.c
>  create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-ic.c
>  create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-irt.c
>  create mode 100644 drivers/staging/imx-drm/ipu-v3/ipu-smfc.c
> 
> diff --git a/drivers/staging/imx-drm/ipu-v3/Makefile b/drivers/staging/imx-drm/ipu-v3/Makefile
> index 28ed72e..79c0c88 100644
> --- a/drivers/staging/imx-drm/ipu-v3/Makefile
> +++ b/drivers/staging/imx-drm/ipu-v3/Makefile
> @@ -1,3 +1,4 @@
>  obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += imx-ipu-v3.o
>  
> -imx-ipu-v3-objs := ipu-common.o ipu-dc.o ipu-di.o ipu-dp.o ipu-dmfc.o
> +imx-ipu-v3-objs := ipu-common.o ipu-csi.o ipu-dc.o ipu-di.o \
> +	ipu-dp.o ipu-dmfc.o ipu-ic.o ipu-irt.o ipu-smfc.o
> diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
> index 1c606b5..3d7e28d 100644
> --- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
> +++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
> @@ -834,6 +834,10 @@ struct ipu_devtype {
>  	unsigned long cpmem_ofs;
>  	unsigned long srm_ofs;
>  	unsigned long tpm_ofs;
> +	unsigned long csi0_ofs;
> +	unsigned long csi1_ofs;
> +	unsigned long smfc_ofs;
> +	unsigned long ic_ofs;
>  	unsigned long disp0_ofs;
>  	unsigned long disp1_ofs;
>  	unsigned long dc_tmpl_ofs;
> @@ -873,8 +877,12 @@ static struct ipu_devtype ipu_type_imx6q = {
>  	.cpmem_ofs = 0x00300000,
>  	.srm_ofs = 0x00340000,
>  	.tpm_ofs = 0x00360000,
> +	.csi0_ofs = 0x00230000,
> +	.csi1_ofs = 0x00238000,
>  	.disp0_ofs = 0x00240000,
>  	.disp1_ofs = 0x00248000,
> +	.smfc_ofs =  0x00250000,
> +	.ic_ofs = 0x00220000,
>  	.dc_tmpl_ofs = 0x00380000,
>  	.vdi_ofs = 0x00268000,
>  	.type = IPUV3H,

This is missing the initalization for i.MX5.

[...]
> +#define GPR1_IPU_CSI_MUX_CTL_SHIFT 19
> +#define GPR13_IPUV3HDL_CSI_MUX_CTL_SHIFT 0
> +
> +int ipu_csi_set_src(struct ipu_csi *csi, u32 vc, bool select_mipi_csi2)
> +{
> +	struct ipu_soc *ipu = csi->ipu;
> +	int ipu_id = ipu_get_num(ipu);
> +	u32 val, bit;
> +
> +	/*
> +	 * Set the muxes that choose between mipi-csi2 and parallel inputs
> +	 * to the CSI's.
> +	 */
> +	if (csi->ipu->ipu_type == IPUV3HDL) {
> +		/*
> +		 * On D/L, the mux is in GPR13. The TRM is unclear,
> +		 * but it appears the mux allows selecting the MIPI
> +		 * CSI-2 virtual channel number to route to the CSIs.
> +		 */
> +		bit = GPR13_IPUV3HDL_CSI_MUX_CTL_SHIFT + csi->id * 3;
> +		val = select_mipi_csi2 ? vc << bit : 4 << bit;
> +		regmap_update_bits(ipu->gp_reg, IOMUXC_GPR13,
> +				   0x7 << bit, val);
> +	} else if (csi->ipu->ipu_type == IPUV3H) {
> +		/*
> +		 * For Q/D, the mux only exists on IPU0-CSI0 and IPU1-CSI1,
> +		 * and the routed virtual channel numbers are fixed at 0 and
> +		 * 3 respectively.
> +		 */
> +		if ((ipu_id == 0 && csi->id == 0) ||
> +		    (ipu_id == 1 && csi->id == 1)) {
> +			bit = GPR1_IPU_CSI_MUX_CTL_SHIFT + csi->ipu->id;
> +			val = select_mipi_csi2 ? 0 : 1 << bit;
> +			regmap_update_bits(ipu->gp_reg, IOMUXC_GPR1,
> +					   0x1 << bit, val);
> +		}
> +	} else {
> +		dev_err(csi->ipu->dev,
> +			"ERROR: %s: unsupported CPU version!\n",
> +			__func__);
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * there is another mux in the IPU config register that
> +	 * must be set as well
> +	 */
> +	ipu_set_csi_src_mux(ipu, csi->id, select_mipi_csi2);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(ipu_csi_set_src);

In my opinion, this doesn't belong here. These multiplexers should be
separate subdevices described in the device tree.

[...]
> +int ipu_csi_get_sensor_protocol(struct ipu_csi *csi)
> +bool ipu_csi_is_interlaced(struct ipu_csi *csi)
> +void ipu_csi_get_window_size(struct ipu_csi *csi, u32 *width, u32 *height)
> +void ipu_csi_set_window_size(struct ipu_csi *csi, u32 width, u32 height)
> +void ipu_csi_set_window_pos(struct ipu_csi *csi, u32 left, u32 top)
> +void ipu_csi_horizontal_downsize_enable(struct ipu_csi *csi)
> +void ipu_csi_horizontal_downsize_disable(struct ipu_csi *csi)
> +void ipu_csi_vertical_downsize_enable(struct ipu_csi *csi)
> +void ipu_csi_vertical_downsize_disable(struct ipu_csi *csi)
> +void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active,
> +				u32 r_value, u32 g_value, u32 b_value,
> +				u32 pix_clk)
> +int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc,
> +			      struct ipu_csi_signal_cfg *cfg)
> +int ipu_csi_set_skip_isp(struct ipu_csi *csi, u32 skip, u32 max_ratio)
> +int ipu_csi_set_skip_smfc(struct ipu_csi *csi, u32 skip,
> +			  u32 max_ratio, u32 id)
> +int ipu_csi_set_dest(struct ipu_csi *csi, bool ic)

All of these are small wrappers around register access, making them
ideal candidates for being inlined if included in the driver using
them ...

> +int ipu_csi_get_num(struct ipu_csi *csi)
> +{
> +	return csi->id;
> +}
> +EXPORT_SYMBOL_GPL(ipu_csi_get_num);

... and this could be dropped completely.

[...]
> +static int init_csc(struct ipu_ic *ic,
> +		    enum ipu_color_space in_format,
> +		    enum ipu_color_space out_format,
> +		    int csc_index)
> +{
> +	struct ipu_ic_priv *priv = ic->priv;
> +	u32 __iomem *base;
> +	u32 param;
> +
> +	base = (u32 __iomem *)
> +		(priv->tpmem_base + ic->reg->tpmem_csc[csc_index]);
> +
> +	if (in_format == IPUV3_COLORSPACE_YUV &&
> +	    out_format == IPUV3_COLORSPACE_RGB) {
> +		/* Init CSC (YCbCr->RGB) */
> +		param = (ycbcr2rgb_coeff[3][0] << 27) |
> +			(ycbcr2rgb_coeff[0][0] << 18) |
> +			(ycbcr2rgb_coeff[1][1] << 9) |
> +			ycbcr2rgb_coeff[2][2];
> +		writel(param, base++);
> +
> +		/* scale = 2, sat = 0 */
> +		param = (ycbcr2rgb_coeff[3][0] >> 5) |
> +			(2L << (40 - 32));
> +		writel(param, base++);
> +
> +		param = (ycbcr2rgb_coeff[3][1] << 27) |
> +			(ycbcr2rgb_coeff[0][1] << 18) |
> +			(ycbcr2rgb_coeff[1][0] << 9) |
> +			ycbcr2rgb_coeff[2][0];
> +		writel(param, base++);
> +
> +		param = (ycbcr2rgb_coeff[3][1] >> 5);
> +		writel(param, base++);
> +
> +		param = (ycbcr2rgb_coeff[3][2] << 27) |
> +			(ycbcr2rgb_coeff[0][2] << 18) |
> +			(ycbcr2rgb_coeff[1][2] << 9) |
> +			ycbcr2rgb_coeff[2][1];
> +		writel(param, base++);
> +
> +		param = (ycbcr2rgb_coeff[3][2] >> 5);
> +		writel(param, base++);

This should be split out into a helper function ...

> +	} else if (in_format == IPUV3_COLORSPACE_RGB &&
> +		   out_format == IPUV3_COLORSPACE_YUV) {
> +		/* Init CSC (RGB->YCbCr) */
> +		param = (rgb2ycbcr_coeff[3][0] << 27) |
> +			(rgb2ycbcr_coeff[0][0] << 18) |
> +			(rgb2ycbcr_coeff[1][1] << 9) |
> +			rgb2ycbcr_coeff[2][2];
> +		writel(param, base++);
> +
> +		/* scale = 1, sat = 0 */
> +		param = (rgb2ycbcr_coeff[3][0] >> 5) | (1UL << 8);
> +		writel(param, base++);
> +
> +		param = (rgb2ycbcr_coeff[3][1] << 27) |
> +			(rgb2ycbcr_coeff[0][1] << 18) |
> +			(rgb2ycbcr_coeff[1][0] << 9) |
> +			rgb2ycbcr_coeff[2][0];
> +		writel(param, base++);
> +
> +		param = (rgb2ycbcr_coeff[3][1] >> 5);
> +		writel(param, base++);
> +
> +		param = (rgb2ycbcr_coeff[3][2] << 27) |
> +			(rgb2ycbcr_coeff[0][2] << 18) |
> +			(rgb2ycbcr_coeff[1][2] << 9) |
> +			rgb2ycbcr_coeff[2][1];
> +		writel(param, base++);
> +
> +		param = (rgb2ycbcr_coeff[3][2] >> 5);
> +		writel(param, base++);

... and be reused here ...

> +	} else if (in_format == IPUV3_COLORSPACE_RGB &&
> +		   out_format == IPUV3_COLORSPACE_RGB) {
> +		/* Init CSC */
> +		param = (rgb2rgb_coeff[3][0] << 27) |
> +			(rgb2rgb_coeff[0][0] << 18) |
> +			(rgb2rgb_coeff[1][1] << 9) |
> +			rgb2rgb_coeff[2][2];
> +		writel(param, base++);
> +
> +		/* scale = 2, sat = 0 */
> +		param = (rgb2rgb_coeff[3][0] >> 5) | (2UL << 8);
> +		writel(param, base++);
> +
> +		param = (rgb2rgb_coeff[3][1] << 27) |
> +			(rgb2rgb_coeff[0][1] << 18) |
> +			(rgb2rgb_coeff[1][0] << 9) |
> +			rgb2rgb_coeff[2][0];
> +		writel(param, base++);
> +
> +		param = (rgb2rgb_coeff[3][1] >> 5);
> +		writel(param, base++);
> +
> +		param = (rgb2rgb_coeff[3][2] << 27) |
> +			(rgb2rgb_coeff[0][2] << 18) |
> +			(rgb2rgb_coeff[1][2] << 9) |
> +			rgb2rgb_coeff[2][1];
> +		writel(param, base++);
> +
> +		param = (rgb2rgb_coeff[3][2] >> 5);
> +		writel(param, base++);

... and here.

> +	} else {
> +		dev_err(priv->ipu->dev, "Unsupported color space conversion\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
[...]
> diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-irt.c b/drivers/staging/imx-drm/ipu-v3/ipu-irt.c

This whole file just contains a use count and and module enable/disable
wrappers. I believe this is simple enough to be included in ipu-common.

[...]
> diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-smfc.c b/drivers/staging/imx-drm/ipu-v3/ipu-smfc.c

This is mostly included in drm-next already. It would be great if you
could rebase on that.

regards
Philipp


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 39/43] media: Add new camera interface driver for i.MX6
  2014-06-07 21:56 ` [PATCH 39/43] media: Add new camera interface driver for i.MX6 Steve Longerbeam
@ 2014-06-11 15:27   ` Philipp Zabel
  0 siblings, 0 replies; 79+ messages in thread
From: Philipp Zabel @ 2014-06-11 15:27 UTC (permalink / raw)
  To: Steve Longerbeam
  Cc: linux-media, Steve Longerbeam, Dmitry Eremin-Solenikov,
	Jiada Wang, Vladimir Zapolskiy

Am Samstag, den 07.06.2014, 14:56 -0700 schrieb Steve Longerbeam:
> This is a V4L2 camera interface driver for i.MX6. See
> Documentation/video4linux/mx6_camera.txt.

The CSI and ICs part are not i.MX6 specific. The only difference between
i.MX5 and i.MX6DL (besides register offsets and some minor changes) are
external to the IPU: the input multiplexers and the MIPI CSI-2 support.

Can you split the mipi-csi2 driver into a separate patch?

> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
> Signed-off-by: Dmitry Eremin-Solenikov <dmitry_eremin@mentor.com>
> Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
> Signed-off-by: Vladimir Zapolskiy <vladimir_zapolskiy@mentor.com>
> ---
>  Documentation/video4linux/mx6_camera.txt         |  188 ++
>  drivers/staging/media/Kconfig                    |    2 +
>  drivers/staging/media/Makefile                   |    1 +
>  drivers/staging/media/imx6/Kconfig               |   25 +
>  drivers/staging/media/imx6/Makefile              |    1 +
>  drivers/staging/media/imx6/capture/Kconfig       |   11 +
>  drivers/staging/media/imx6/capture/Makefile      |    4 +
>  drivers/staging/media/imx6/capture/mipi-csi2.c   |  322 ++++
>  drivers/staging/media/imx6/capture/mx6-camif.c   | 2235 ++++++++++++++++++++++
>  drivers/staging/media/imx6/capture/mx6-camif.h   |  197 ++

>  drivers/staging/media/imx6/capture/mx6-encode.c  |  775 ++++++++
>  drivers/staging/media/imx6/capture/mx6-preview.c |  748 ++++++++

Except for the v4l2_controls, these two drivers are nearly the same. The
same is true for the encoder/preview helper functions in mx6-camif.c.

To me it seems that it would be better to handle the IC as its own
v4l2_subdev supporting the encoder and preview roles, use the media
controller API to handle the connections between CSI/SMFC/IC, and have a
single CSI v4l2_subdev for each CSI instead of duplicating the same code
with minor differences.

[...]
> +static void __mx6csi2_enable(struct mx6csi2_dev *csi2, bool enable)
> +{
> +	if (enable) {
> +		mx6csi2_write(csi2, 0xffffffff, CSI2_PHY_SHUTDOWNZ);
> +		mx6csi2_write(csi2, 0xffffffff, CSI2_DPHY_RSTZ);
> +		mx6csi2_write(csi2, 0xffffffff, CSI2_RESETN);

I know the Freescale does this, but according to the documentation only
the LSB is the reset/shutdown bit. Doesn't writing 0x1 work here?

> +	} else {
> +		mx6csi2_write(csi2, 0x0, CSI2_PHY_SHUTDOWNZ);
> +		mx6csi2_write(csi2, 0x0, CSI2_DPHY_RSTZ);
> +		mx6csi2_write(csi2, 0x0, CSI2_RESETN);
> +	}
> +}
> +
> +static void mx6csi2_reset(struct mx6csi2_dev *csi2)
> +{
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&csi2->lock, flags);
> +
> +	__mx6csi2_enable(csi2, false);
> +
> +	mx6csi2_write(csi2, 0x00000001, CSI2_PHY_TST_CTRL0);
> +	mx6csi2_write(csi2, 0x00000000, CSI2_PHY_TST_CTRL1);
> +	mx6csi2_write(csi2, 0x00000000, CSI2_PHY_TST_CTRL0);
> +	mx6csi2_write(csi2, 0x00000002, CSI2_PHY_TST_CTRL0);
> +	mx6csi2_write(csi2, 0x00010044, CSI2_PHY_TST_CTRL1);
> +	mx6csi2_write(csi2, 0x00000000, CSI2_PHY_TST_CTRL0);
> +	mx6csi2_write(csi2, 0x00000014, CSI2_PHY_TST_CTRL1);
> +	mx6csi2_write(csi2, 0x00000002, CSI2_PHY_TST_CTRL0);
> +	mx6csi2_write(csi2, 0x00000000, CSI2_PHY_TST_CTRL0);

A comment documenting that this writes 0x14 to D-PHY register 0x44 using
the 8-bit test interface would be nice. Even nicer would be to know what
this actually does, but I don't have the D-PHY documentation.

Or how about
#define PHY_CTRL0_TESTCLR            BIT(0)
#define PHY_CTRL0_TESTCLK            BIT(1)
#define PHY_CTRL1_TESTEN             BIT(16)

> +	__mx6csi2_enable(csi2, true);
> +
> +	spin_unlock_irqrestore(&csi2->lock, flags);
> +}
> +
> +static int mx6csi2_dphy_wait(struct mx6csi2_dev *csi2)
> +{
> +	u32 reg;
> +	int i;
> +
> +	/* wait for mipi sensor ready */
> +	for (i = 0; i < 50; i++) {
> +		reg = mx6csi2_read(csi2, CSI2_PHY_STATE);
> +		if (reg != 0x200)
> +			break;
> +		usleep_range(10000, 10001);

This is very specific. I'd use a broader range here.

[...]
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +
> +	if (!res || csi2->intr1 < 0 || csi2->intr2 < 0) {
> +		v4l2_err(&csi2->sd, "failed to get platform resources\n");
> +		return -ENODEV;
> +	}
> +
> +	csi2->base = devm_ioremap(&pdev->dev, res->start, PAGE_SIZE);
> +	if (!csi2->base) {
> +		v4l2_err(&csi2->sd, "failed to map CSI-2 registers\n");
> +		return -ENOMEM;
> +	}

This can be shortened with devm_ioremap_resource, which also already
handles the error message.

[...]
> +/*
> + * Turn current sensor power on/off according to power_count.
> + */
> +static int sensor_set_power(struct mx6cam_dev *dev, int on)
> +{
> +	struct mx6cam_endpoint *ep = dev->ep;
> +	struct v4l2_subdev *sd = ep->sd;
> +	int ret;
> +
> +	if (on && ep->power_count++ > 0)
> +		return 0;
> +	else if (!on && (ep->power_count == 0 || --ep->power_count > 0))
> +		return 0;
> +
> +	ret = v4l2_subdev_call(sd, core, s_power, on);
> +	return ret != -ENOIOCTLCMD ? ret : 0;
> +}

All of this assumes a single sensor device connected to the CSI
endpoint. If there are further multiplexers, FPGA devices, or other
encoders in the chain, this will only power up the last element.

[...]
> +static int vidioc_g_input(struct file *file, void *priv, unsigned int *index)
> +static int vidioc_s_input(struct file *file, void *priv, unsigned int index)

These also limit the input path to a very simple linear list of options.
Any use case a bit more complicated than single sensors each connected
directly to parallel CSI or MIPI CSI-2 ports can't be described by this.

Granted, the most complicated cases I've seen in the wild so far are
either two cameras and an external multiplexer on the same parallel bus
and a single FPGA with two outputs connected to both CSIs. Still, using
the media controller API here would be much more future proof. Imagine,
for example, eight MIPI CSI-2 cameras connected to a CSI-2 multiplexer
and that connected to the i.MX6 CSI2 input.

> +static int vidioc_querybuf(struct file *file, void *priv,
[...]
> +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
> +{
> +	struct mx6cam_ctx *ctx = file2ctx(file);
> +	struct vb2_queue *vq = &ctx->dev->buffer_queue;
> +
> +	if (!ctx->io_allowed)
> +		return -EBUSY;
> +
> +	return vb2_qbuf(vq, buf);
> +}

What is up the the io_allowed handling here? If not for that, you could
just use the vb2_ioctl_* helpers for a lot of these.

[...]

> +static unsigned int mx6cam_poll(struct file *file,
> +				 struct poll_table_struct *wait)

vb2_fop_poll

> +static int mx6cam_mmap(struct file *file, struct vm_area_struct *vma)

vb2_fop_mmap

[...]
> +static int mx6cam_add_csi2_receiver(struct mx6cam_dev *dev)
> +{
> +	struct platform_device *pdev;
> +	struct device_node *node;
> +	int ret = -EPROBE_DEFER;
> +
> +	node = of_find_compatible_node(NULL, NULL, "fsl,imx6-mipi-csi2");
> +	if (!node)
> +		return 0;

Why not connect the mipi-csi2 node to the ipu csi input port via OF
graph bindings?

> +/* parse inputs property from v4l2_of_endpoint node */
> +static int mx6cam_parse_inputs(struct mx6cam_dev *dev,
> +			       struct device_node *node,
> +			       int next_input,
> +			       struct mx6cam_endpoint *ep)
> +{
> +	struct mx6cam_sensor_input *epinput = &ep->sensor_input;
> +	int ret, i;
> +
> +	for (i = 0; i < MX6CAM_MAX_INPUTS; i++) {
> +		const char *input_name;
> +		u32 val;
> +
> +		ret = of_property_read_u32_index(node, "inputs", i, &val);
> +		if (ret)
> +			break;
> +
> +		epinput->value[i] = val;
> +
> +		ret = of_property_read_string_index(node, "input-names", i,
> +						    &input_name);
> +		if (!ret)
> +			strncpy(epinput->name[i], input_name,
> +				sizeof(epinput->name[i]));
> +		else
> +			snprintf(epinput->name[i], sizeof(epinput->name[i]),
> +				 "%s-%d", ep->sd->name, i);
> +
> +		val = 0;
> +		ret = of_property_read_u32_index(node, "input-caps", i, &val);
> +		epinput->caps[i] = val;
> +	}
> +
> +	epinput->num = i;
> +
> +	/* if no inputs provided just assume a single input */
> +	if (epinput->num == 0) {
> +		epinput->num = 1;
> +		epinput->caps[0] = 0;
> +		strncpy(epinput->name[0], ep->sd->name,
> +			sizeof(epinput->name[0]));
> +	}
> +
> +	epinput->first = next_input;
> +	epinput->last = next_input + epinput->num - 1;
> +	return epinput->last + 1;
> +}

I don't see why this is necessary when all possible input paths
are already described via the OF graph bindings.

regards
Philipp


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 00/43] i.MX6 Video capture
  2014-06-11 11:21 ` Philipp Zabel
@ 2014-06-12  1:04   ` Steve Longerbeam
  2014-06-12 16:50     ` Philipp Zabel
  0 siblings, 1 reply; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-12  1:04 UTC (permalink / raw)
  To: Philipp Zabel, Steve Longerbeam; +Cc: linux-media

On 06/11/2014 04:21 AM, Philipp Zabel wrote:
> Hi Steve,
> 
> Am Samstag, den 07.06.2014, 14:56 -0700 schrieb Steve Longerbeam:
>> Hi all,
>>
>> This patch set adds video capture support for the Freescale i.MX6 SOC.
>>
>> It is a from-scratch standardized driver that works with community
>> v4l2 utilities, such as v4l2-ctl, v4l2-cap, and the v4l2src gstreamer
>> plugin. It uses the latest v4l2 interfaces (subdev, videobuf2).
>> Please see Documentation/video4linux/mx6_camera.txt for it's full list
>> of features!
> 
> That's quite a series to digest! I'll quickly go over the points that
> jumped at me and then look at the core code (especially 08/43 and 39/43)
> in detail.
> 
>> The first 38 patches:
>>
>> - prepare the ipu-v3 driver for video capture support. The current driver
>>   contains only video display functionality to support the imx DRM drivers.
>>   At some point ipu-v3 should be moved out from under staging/imx-drm since
>>   it will no longer only support DRM.
> 
> The move out of staging is now merged into drm-next with
> c1a6e9fe82b46159af8cc4cf34fb51ee47862f05.
> After this is merged into mainline, there should be no need to push i.MX
> capture support through staging. It would be helpful if you could rebase
> on top of that.
> 


Hi Philipp and Sascha,

First of all, thanks for the detailed review.

I think it's obvious that this patch set should be split into two: first,
the changes to IPU core driver submitted to drm-next, and the capture driver
to media-tree.

Or, do you prefer I submit the IPU core patches to your own pengutronix git
tree, and we can correspond on one of your internal mailing lists? I can
then leave it to you to push those changes to drm-next.

I agree with most of your feedback, and most is specific to the IPU core
changes. We can discuss those in detail elsewhere, but just in summary here,
some of your comments seem to conflict:

1. Regarding the input muxes to the CSI and IC, Philipp you acked those
functions but would like to see these muxes as v4l2 subdevs and configured
in the DT, but Sascha, you had a comment that this should be a job for
mediactrl.

2. Philipp, you would like to see CSI, IC, and SMFC units moved out of IPU
core and become v4l2 subdevs. I agree with that, but drm-next has ipu-smfc
as part of IPU core, and SMFC is most definitely v4l2 capture specific.


Steve

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 00/43] i.MX6 Video capture
  2014-06-12  1:04   ` Steve Longerbeam
@ 2014-06-12 16:50     ` Philipp Zabel
  2014-06-12 21:05       ` Steve Longerbeam
  0 siblings, 1 reply; 79+ messages in thread
From: Philipp Zabel @ 2014-06-12 16:50 UTC (permalink / raw)
  To: Steve Longerbeam; +Cc: Steve Longerbeam, linux-media, Russell King

Hi Steve,

[Added Russell to Cc: because of the question how to send IPU core 
 patches to drm-next]

Am Mittwoch, den 11.06.2014, 18:04 -0700 schrieb Steve Longerbeam:
> Hi Philipp and Sascha,
> 
> First of all, thanks for the detailed review.

You are welcome. I am tasked to prepare our own capture drivers for
mainline submission, but they are not quite there yet. I'd be very
interested in getting this worked out together, especially since we
seem to be interested in orthogonal features (we had no use for the
preview and and encoder IC tasks or MIPI CSI-2 so far, but we need
media controller support and mem2mem scaling via the post-processor IC
task).
I'm going to post our current series as is, if only to illustrate my
point of view.

> I think it's obvious that this patch set should be split into two: first,
> the changes to IPU core driver submitted to drm-next, and the capture driver
> to media-tree.

I agree.

> Or, do you prefer I submit the IPU core patches to your own pengutronix git
> tree, and we can correspond on one of your internal mailing lists?

Why would we move discussion to an internal mailing list? Since we are
sitting right inbetween dri-devel and linux-media with the IPU core
code, I think either mailing list is an appropriate place for discussing
these patches, depending on the context.

> I can then leave it to you to push those changes to drm-next.

I think a central place to collect IPU core patches before sending them
off to drm-next is a good idea. I offer to do the collecting in my tree.
I also know Russell volunteered to collect and send off imx-drm patches
towards staging. Russell, I'm not sure if this offer extends to non-DRM
IPU core patches to be submitted to drm-next? (And if yes, whether you'd
rather keep at it or have this taken off your hands.)

> I agree with most of your feedback, and most is specific to the IPU core
> changes.

Excellent. For the core changes, rebasing them onto next and then
integrating some remaining changes from our patchset shouldn't be a
problem.
The big issue I have with the media parts is the missing media
controller support and the code organization around the IC tasks
instead of around hardware submodules.

>  We can discuss those in detail elsewhere, but just in summary here,
> some of your comments seem to conflict:
> 
> 1. Regarding the input muxes to the CSI and IC, Philipp you acked those
> functions but would like to see these muxes as v4l2 subdevs and configured
> in the DT, but Sascha, you had a comment that this should be a job for
> mediactrl.

No conflict here, there are different multiplexers to talk about.

First, there are two external multiplexers controlled by IOMUXC (on
i.MX6, these don't exist on i.MX5): MIPI_IPU1/2_MUX on i.MX6Q and
IPU_CSI0/1_MUX. They are not part of the IPU.
They each sit between a set of parallel input pads and the CSI2IPU
gasket on one side and one CSI on the other side.
In my opinion, these should be handled by separate v4l2_subdev drivers
and their connections described in the device tree. The links between
subdevices can then be controlled via the media controller framework.
This is what my comments on patches 05/43 and 08/43 are about.

Second, there are the CSI0/1_DATA_SOURCE muxes and the CSI_SEL/IC_INPUT
muxes controlled by the IPU_CONF register. These should not be described
in the device tree. Just as CSI and IC, they are an IPU internal detail.

The CSI0/1_DATA_SOURCE, if I understand correctly, muxes not the data
bus, but the 8-bit mct_di bus which carries the MIPI channel id and data
type. This should be controlled by the CSI subdevice driver directly
when choosing its input format.

The CSI_SEL/IC_INPUT multiplexer selects the input to the IC to come
from either CSI0, CSI1, or the VDI. Each of those subunits would fit
the media entity abstraction well. This multiplexer should be controlled
by the media controller framework.

I acked the CSI/IC source mux functions in patch 06/43 because I think
those functions are in the right place and useful in the above scenario.

> 2. Philipp, you would like to see CSI, IC, and SMFC units moved out of IPU
> core and become v4l2 subdevs. I agree with that, but drm-next has ipu-smfc
> as part of IPU core, and SMFC is most definitely v4l2 capture specific.

About the CSI I'm just a tiny bit conflicted myself, that seems to show.

>From an organizational standpoint, with all the other register access
code in gpu/ipu-v3, having the ipu-csi code in there too looks nice and
as expected. On the other hand, this should really be only used by one
v4l2_subdev driver. When I look at it this way, I see a driver that is
split in two parts, wasting exported symbol space for no very good
reason.

The IC I'd like to describe as a v4l2_subdev. But I'd also like to use
the IC from the DRM driver. So the IC core code has to stay in
gpu/ipu-v3. I'd just like to pool all V4L2 code that uses this into a IC
v4l2_subdev driver if possible. The only use we have for the IC
currently is 

The SMFC code is small and, more importantly, its functionality is
limited enough that it doesn't warrant its own v4l2_subdev. I see not
enough reason to move this away from the other IPU core code, since the
v4l2_device capture driver that uses it certainly is not the right place
to map SMFC registers directly.

So the CSI only is a special case because the code in ipu-csi.c aligns
so well with a single v4l2_subdev driver.

regards
Philipp


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 32/43] ARM: dts: imx: sabrelite: add video capture ports and endpoints
  2014-06-11 11:38   ` Philipp Zabel
@ 2014-06-12 17:13     ` Philipp Zabel
  0 siblings, 0 replies; 79+ messages in thread
From: Philipp Zabel @ 2014-06-12 17:13 UTC (permalink / raw)
  To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam

Am Mittwoch, den 11.06.2014, 13:38 +0200 schrieb Philipp Zabel:
> Am Samstag, den 07.06.2014, 14:56 -0700 schrieb Steve Longerbeam:
> [...]
> > +&ipu1 {
> > +	status = "okay";
> > +
> > +	v4l2-capture {
> > +		compatible = "fsl,imx6-v4l2-capture";
> 
> I'm not happy with adding the simple-bus compatible to the ipu
> device tree node just to instantiate a virtual subdevice. See
> my comment in the following mail. I think it would be better to
> create this platform device from code, not from the device tree
> if something is connected to ipu port@0 or port@1, see below.
> 
> > +		#address-cells = <1>;
> > +		#size-cells = <0>;
> > +		status = "okay";
> > +		pinctrl-names = "default";
> > +		pinctrl-0 = <
> > +			&pinctrl_ipu1_csi0_1
> > +			&pinctrl_ipu1_csi0_data_en
> > +		>;
> > +
> > +		/* CSI0 */
> > +		port@0 {
> 
> That port really is a property of the IPU itself. I have left
> space for ports 0 and 1 when specifying the IPU output interfaces
> as port 2 (DI0) and 3 (DI1).

Shawn Guo's for-next tree contains the CSI ports in
1fbf4ad8e1983732aa6a1de10da0bfcc7384f626

regards
Philipp


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 00/43] i.MX6 Video capture
  2014-06-12 16:50     ` Philipp Zabel
@ 2014-06-12 21:05       ` Steve Longerbeam
  2014-06-12 21:35         ` Troy Kisky
  2014-06-13 15:37         ` Philipp Zabel
  0 siblings, 2 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-12 21:05 UTC (permalink / raw)
  To: Philipp Zabel; +Cc: Steve Longerbeam, linux-media, Russell King

On 06/12/2014 09:50 AM, Philipp Zabel wrote:
> Hi Steve,
> 
> [Added Russell to Cc: because of the question how to send IPU core 
>  patches to drm-next]
> 
> Am Mittwoch, den 11.06.2014, 18:04 -0700 schrieb Steve Longerbeam:
>> Hi Philipp and Sascha,
>>
>> First of all, thanks for the detailed review.
> 
> You are welcome. I am tasked to prepare our own capture drivers for
> mainline submission, but they are not quite there yet. I'd be very
> interested in getting this worked out together, especially since we
> seem to be interested in orthogonal features (we had no use for the
> preview and and encoder IC tasks or MIPI CSI-2 so far, but we need
> media controller support

Ok. Yes, we definitely need preview and MIPI CSI-2, and adding IC to the
capture path is nice too, since it allows userland to select arbitrary user
resolutions, pixel format color space, and also rotation controls. The
capture driver decides whether to include the IC in the capture pipeline
based on user format and rotation control. I.e. if user colorspace is
different from what the sensor can output, IC CSC is required. If user
resolution is different from the selected capture cropping rectangle,
IC resizer is required, and finally if user requests rotation, the IC
rotation unit is required. If none of those are true, the capture driver
decides to exclude the IC from the pipeline and send raw sensor frames
(well, after cropping anyway) directly to memory via the SMFC.

So in our driver, the decision to link the IC in a pipeline is made
internally by the driver and is not a decision exported to userland.

My plan was to add media device framework support, but only after basic
video capture is in place. Our driver is full featured in terms of basic
capture support, and it works on all three reference platforms. But I
agree it needs to convert subdev's to media entities and allow some of
them to be linked via the media controller API.

But only some linkages make sense to me. As I explain above, if the IC were
to be made a media entity, I think it's linkage should be made internally
by the capture driver, and this should not be controllable by userspace.

>and mem2mem scaling via the post-processor IC task).


Heh, we have a mem2mem driver as well, and it also uses IC post-processor
task. It uses banding and striping to support resized output frames larger
than 1024x1024. It also makes use of IC rotation and CSC.

But again this is not converted to a media entity. And again, if IC were to
be made a standalone media entity, then the mem2mem device would _always_
require the IC post-processor be linked to it, since the essential feature
of mem2mem is to make use of IC post-processor task for CSC, resize, and
rotation operations.

So as you can see I'm confused about where allowing control of media entity
linking would make sense.


> I'm going to post our current series as is, if only to illustrate my
> point of view.

I see them thanks. I'll study them.

> 
>> I think it's obvious that this patch set should be split into two: first,
>> the changes to IPU core driver submitted to drm-next, and the capture driver
>> to media-tree.
> 
> I agree.
> 
>> Or, do you prefer I submit the IPU core patches to your own pengutronix git
>> tree, and we can correspond on one of your internal mailing lists?
> 
> Why would we move discussion to an internal mailing list? Since we are
> sitting right inbetween dri-devel and linux-media with the IPU core
> code, I think either mailing list is an appropriate place for discussing
> these patches, depending on the context.
> 
>> I can then leave it to you to push those changes to drm-next.
> 
> I think a central place to collect IPU core patches before sending them
> off to drm-next is a good idea. I offer to do the collecting in my tree.
> I also know Russell volunteered to collect and send off imx-drm patches
> towards staging. Russell, I'm not sure if this offer extends to non-DRM
> IPU core patches to be submitted to drm-next? (And if yes, whether you'd
> rather keep at it or have this taken off your hands.)
> 
>> I agree with most of your feedback, and most is specific to the IPU core
>> changes.
> 
> Excellent. For the core changes, rebasing them onto next and then
> integrating some remaining changes from our patchset shouldn't be a
> problem.
> The big issue I have with the media parts is the missing media
> controller support and the code organization around the IC tasks
> instead of around hardware submodules.
> 
>>  We can discuss those in detail elsewhere, but just in summary here,
>> some of your comments seem to conflict:
>>
>> 1. Regarding the input muxes to the CSI and IC, Philipp you acked those
>> functions but would like to see these muxes as v4l2 subdevs and configured
>> in the DT, but Sascha, you had a comment that this should be a job for
>> mediactrl.
> 
> No conflict here, there are different multiplexers to talk about.
> 
> First, there are two external multiplexers controlled by IOMUXC (on
> i.MX6, these don't exist on i.MX5): MIPI_IPU1/2_MUX on i.MX6Q and
> IPU_CSI0/1_MUX. They are not part of the IPU.
> They each sit between a set of parallel input pads and the CSI2IPU
> gasket on one side and one CSI on the other side.
> In my opinion, these should be handled by separate v4l2_subdev drivers
> and their connections described in the device tree. The links between
> subdevices can then be controlled via the media controller framework.

right, this is one place where subdev linking makes sense to me. I.e.
linking sensors to CSI ports.

But you don't mean to allow userspace to make this link arbitrarily,
correct? You mean the driver uses the mediactrl framework to implement
the links defined in the device tree. Maybe that's where I was confused.

> This is what my comments on patches 05/43 and 08/43 are about.
> 
> Second, there are the CSI0/1_DATA_SOURCE muxes and the CSI_SEL/IC_INPUT
> muxes controlled by the IPU_CONF register. These should not be described
> in the device tree. Just as CSI and IC, they are an IPU internal detail.
>

agreed.

> The CSI0/1_DATA_SOURCE, if I understand correctly, muxes not the data
> bus, but the 8-bit mct_di bus which carries the MIPI channel id and data
> type. This should be controlled by the CSI subdevice driver directly
> when choosing its input format.

it's input/sink pad media bus format, agreed.

> 
> The CSI_SEL/IC_INPUT multiplexer selects the input to the IC to come
> from either CSI0, CSI1, or the VDI. Each of those subunits would fit
> the media entity abstraction well. This multiplexer should be controlled
> by the media controller framework.

agreed.

> 
> I acked the CSI/IC source mux functions in patch 06/43 because I think
> those functions are in the right place and useful in the above scenario.
> 
>> 2. Philipp, you would like to see CSI, IC, and SMFC units moved out of IPU
>> core and become v4l2 subdevs. I agree with that, but drm-next has ipu-smfc
>> as part of IPU core, and SMFC is most definitely v4l2 capture specific.
> 
> About the CSI I'm just a tiny bit conflicted myself, that seems to show.
> 
> From an organizational standpoint, with all the other register access
> code in gpu/ipu-v3, having the ipu-csi code in there too looks nice and
> as expected.
> On the other hand, this should really be only used by one
> v4l2_subdev driver. When I look at it this way, I see a driver that is
> split in two parts, wasting exported symbol space for no very good
> reason.

I agree about making CSI a subdev, but I also think we can keep all of the
register access in IPU core as well. The CSI subdev would be a wrapper
around the ipu-csi APIs. I agree it's more use of symbol space, but we
might be able to simplify the ipu-csi API.

> 
> The IC I'd like to describe as a v4l2_subdev. But I'd also like to use
> the IC from the DRM driver. So the IC core code has to stay in
> gpu/ipu-v3. I'd just like to pool all V4L2 code that uses this into a IC
> v4l2_subdev driver if possible. The only use we have for the IC
> currently is

is mem2mem? And you would like to see an IC pads linked with mem2mem
pads. Well, something like this:

input frame from userspace ---> m2m ---> IC-PP ---> m2m ---> to userspace

> 
> The SMFC code is small and, more importantly, its functionality is
> limited enough that it doesn't warrant its own v4l2_subdev. I see not
> enough reason to move this away from the other IPU core code, since the
> v4l2_device capture driver that uses it certainly is not the right place
> to map SMFC registers directly.
> 
> So the CSI only is a special case because the code in ipu-csi.c aligns
> so well with a single v4l2_subdev driver.


Ok, in summary I'm aligned with everything you said. Only that I am still
pondering about which media entity links make sense, and who should be
allowed to make those links.

So how should we proceed? I would argue to use our capture driver as a base,
since it is fully functional and fairly full-featured. It's just missing the
media framework.

Steve

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 00/43] i.MX6 Video capture
  2014-06-12 21:05       ` Steve Longerbeam
@ 2014-06-12 21:35         ` Troy Kisky
  2014-06-13 15:37         ` Philipp Zabel
  1 sibling, 0 replies; 79+ messages in thread
From: Troy Kisky @ 2014-06-12 21:35 UTC (permalink / raw)
  To: Steve Longerbeam, Philipp Zabel
  Cc: Steve Longerbeam, linux-media, Russell King

On 6/12/2014 2:05 PM, Steve Longerbeam wrote:
> On 06/12/2014 09:50 AM, Philipp Zabel wrote:
>> Hi Steve,
>>
>> [Added Russell to Cc: because of the question how to send IPU core 
>>  patches to drm-next]
>>
>> Am Mittwoch, den 11.06.2014, 18:04 -0700 schrieb Steve Longerbeam:
>>> Hi Philipp and Sascha,
>>>
>>> First of all, thanks for the detailed review.
>>
>> You are welcome. I am tasked to prepare our own capture drivers for
>> mainline submission, but they are not quite there yet. I'd be very
>> interested in getting this worked out together, especially since we
>> seem to be interested in orthogonal features (we had no use for the
>> preview and and encoder IC tasks or MIPI CSI-2 so far, but we need
>> media controller support
> 
> Ok. Yes, we definitely need preview and MIPI CSI-2, and adding IC to the
> capture path is nice too, since it allows userland to select arbitrary user
> resolutions, pixel format color space, and also rotation controls. The
> capture driver decides whether to include the IC in the capture pipeline
> based on user format and rotation control. I.e. if user colorspace is
> different from what the sensor can output, IC CSC is required. If user
> resolution is different from the selected capture cropping rectangle,
> IC resizer is required, and finally if user requests rotation, the IC
> rotation unit is required. If none of those are true, the capture driver
> decides to exclude the IC from the pipeline and send raw sensor frames
> (well, after cropping anyway) directly to memory via the SMFC.
> 
> So in our driver, the decision to link the IC in a pipeline is made
> internally by the driver and is not a decision exported to userland.
> 
> My plan was to add media device framework support, but only after basic
> video capture is in place. Our driver is full featured in terms of basic
> capture support, and it works on all three reference platforms. But I
> agree it needs to convert subdev's to media entities and allow some of
> them to be linked via the media controller API.
> 
> But only some linkages make sense to me. As I explain above, if the IC were
> to be made a media entity, I think it's linkage should be made internally
> by the capture driver, and this should not be controllable by userspace.
> 

What if 2 cameras on different CSIs on the same IPU want to use the IC.
Is it 1st come 1st server? Or, both routed to memory, and a separate
memory convert? Is the 1st pipeline shut down and restarted in this mode?





^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 00/43] i.MX6 Video capture
  2014-06-12 21:05       ` Steve Longerbeam
  2014-06-12 21:35         ` Troy Kisky
@ 2014-06-13 15:37         ` Philipp Zabel
  2014-06-15 22:34           ` Steve Longerbeam
  1 sibling, 1 reply; 79+ messages in thread
From: Philipp Zabel @ 2014-06-13 15:37 UTC (permalink / raw)
  To: Steve Longerbeam; +Cc: Steve Longerbeam, linux-media, Russell King

Am Donnerstag, den 12.06.2014, 14:05 -0700 schrieb Steve Longerbeam:
> Ok. Yes, we definitely need preview and MIPI CSI-2, and adding IC to the
> capture path is nice too, since it allows userland to select arbitrary user
> resolutions, pixel format color space, and also rotation controls.

No question about that. It's just that mostly everyone around here seems
to want to capture at least 1080p, or 10-bit grayscale. I hope Freescale
drops the 1024-pixel output limitation in their next SoC ...

>The
> capture driver decides whether to include the IC in the capture pipeline
> based on user format and rotation control. I.e. if user colorspace is
> different from what the sensor can output, IC CSC is required. If user
> resolution is different from the selected capture cropping rectangle,
> IC resizer is required, and finally if user requests rotation, the IC
> rotation unit is required. If none of those are true, the capture driver
> decides to exclude the IC from the pipeline and send raw sensor frames
> (well, after cropping anyway) directly to memory via the SMFC.

That is too much magic for my taste. Especially since whether or not you
can use the IC not only depends on the current video format, but also on
whether the other CSI or the MEM_VDIC_MEM path are using the IC at the
moment.
Since this can change dynamically, it throws a wrench into GStreamer's
static capability negotiation, for example. I'd rather have userspace
select which CSI should be routed through the IC with media-ctl and then
reflect the possible conversions in the respective video_dev's
capabilities.

> So in our driver, the decision to link the IC in a pipeline is made
> internally by the driver and is not a decision exported to userland.

This is exactly the point I am worried about. You lose flexibility and
need all sorts of clever conditional code in the driver. It'd be much
cleaner to just let userspace control the mux.

> My plan was to add media device framework support, but only after basic
> video capture is in place. Our driver is full featured in terms of basic
> capture support, and it works on all three reference platforms. But I
> agree it needs to convert subdev's to media entities and allow some of
> them to be linked via the media controller API.

Alright, so we agree that using the media controller API internally is a
good idea ...

> But only some linkages make sense to me. As I explain above, if the IC were
> to be made a media entity, I think it's linkage should be made internally
> by the capture driver, and this should not be controllable by userspace.

... but we disagree on whether to export the control to userspace. For
more complicated pipelines in front of the CSIs we'll need media-ctl
anyway, so using that same API for the internal components, makes sense.
It also allows userspace to get a clear and stable picture of the
available features for any given multiplexer setting.

> Heh, we have a mem2mem driver as well, and it also uses IC post-processor
> task. It uses banding and striping to support resized output frames larger
> than 1024x1024. It also makes use of IC rotation and CSC.

Of course :)

> But again this is not converted to a media entity. And again, if IC were to
> be made a standalone media entity, then the mem2mem device would _always_
> require the IC post-processor be linked to it, since the essential feature
> of mem2mem is to make use of IC post-processor task for CSC, resize, and
> rotation operations.

Since the three IC tasks are transparently time-multiplexed, the IC
media entity representation could have input and output pads for each of
them.
The preprocessing (encoding, viewfinder) tasks share an input pad that
would be connected to either CSI0, CSI1, or VDI output pad. These links
should control the IC mux. The encoding task output pad would represent
IDMAC channel 20/CB0 or channel 48/CB8, depending on whether the rotator
is active. Since rotation requires tight integration between IC and
IDMAC, I don't think the IRT should be represented as a separate media
entity.
The viewfinder task output pad would correspond to channel 21/CB1 or
channel 49/CB9, and maybe in the future control whether to send that
data off to the DMFC or to memory.
The postprocessing input and output pads would go straight to memory and
are not configurable, so I see no need to describe IC-PP as media
entity.

I'm not quite sure about the VDIC, but I guess that also should be
configurable from userspace as one input to IC. For the deinterlacer to
work, IC_INPUT needs to be set, so while this is active there is no way
to route CSI0/1 through the IC directly.

[...]
> > No conflict here, there are different multiplexers to talk about.
> > 
> > First, there are two external multiplexers controlled by IOMUXC (on
> > i.MX6, these don't exist on i.MX5): MIPI_IPU1/2_MUX on i.MX6Q and
> > IPU_CSI0/1_MUX. They are not part of the IPU.
[...]
> right, this is one place where subdev linking makes sense to me. I.e.
> linking sensors to CSI ports.
> 
> But you don't mean to allow userspace to make this link arbitrarily,
> correct? You mean the driver uses the mediactrl framework to implement
> the links defined in the device tree. Maybe that's where I was confused.

No, this is exactly what I mean. In my opinion, using media-ctl to throw
the switches is much better than letting the driver decide depending on
the old S_INPUT API. Especially since this gives userspace a unified API
when there are input multiplexers (or any other subdevices configurable
on the pad level) external to the SoC.
Also, pad format configuration of the CSI subdev exported to userspace
may be useful to control the compander in the CSI.

[...]
> > From an organizational standpoint, with all the other register access
> > code in gpu/ipu-v3, having the ipu-csi code in there too looks nice and
> > as expected.
> > On the other hand, this should really be only used by one
> > v4l2_subdev driver. When I look at it this way, I see a driver that is
> > split in two parts, wasting exported symbol space for no very good
> > reason.
> 
> I agree about making CSI a subdev, but I also think we can keep all of the
> register access in IPU core as well. The CSI subdev would be a wrapper
> around the ipu-csi APIs. I agree it's more use of symbol space, but we
> might be able to simplify the ipu-csi API.

So be it. In any case, this decision could be changed later with little
effort and without any externally visible changes, if deemed necessary,
as long as the CSI v4l2_subdev driver is the only consumer of this API.

> > The IC I'd like to describe as a v4l2_subdev. But I'd also like to use
> > the IC from the DRM driver. So the IC core code has to stay in
> > gpu/ipu-v3. I'd just like to pool all V4L2 code that uses this into a IC
> > v4l2_subdev driver if possible. The only use we have for the IC
> > currently is
> 
> is mem2mem? And you would like to see an IC pads linked with mem2mem
> pads. Well, something like this:
> 
> input frame from userspace ---> m2m ---> IC-PP ---> m2m ---> to userspace

As long as there is no internal video bus switch somewhere, the
usefulness of this is debatable. You see we also implemented this by
directly calling the IPU IC API, and I'm fine with this.

[...]
> Ok, in summary I'm aligned with everything you said. Only that I am still
> pondering about which media entity links make sense, and who should be
> allowed to make those links.

At least the decision whether to route the CSI0/1 into the IC
preprocessing input should be handled by userspace, as this changes the
capabilities of the corresponding video_dev.

> So how should we proceed? I would argue to use our capture driver as a base,
> since it is fully functional and fairly full-featured. It's just missing the
> media framework.

Initially, I don't care as much about a full featureset as I do about
getting the userspace API and device tree bindings right, since those
won't be easy to change later.
Pending rework into CSI/IC subdevices and agreement on the userspace
facing API, I think your patchset can be a good base.

regards
Philipp


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 00/43] i.MX6 Video capture
  2014-06-13 15:37         ` Philipp Zabel
@ 2014-06-15 22:34           ` Steve Longerbeam
  0 siblings, 0 replies; 79+ messages in thread
From: Steve Longerbeam @ 2014-06-15 22:34 UTC (permalink / raw)
  To: Philipp Zabel; +Cc: Steve Longerbeam, linux-media, Russell King

On 06/13/2014 08:37 AM, Philipp Zabel wrote:
> Am Donnerstag, den 12.06.2014, 14:05 -0700 schrieb Steve Longerbeam:
>> Ok. Yes, we definitely need preview and MIPI CSI-2, and adding IC to the
>> capture path is nice too, since it allows userland to select arbitrary user
>> resolutions, pixel format color space, and also rotation controls.
> 
> No question about that. It's just that mostly everyone around here seems
> to want to capture at least 1080p, or 10-bit grayscale. I hope Freescale
> drops the 1024-pixel output limitation in their next SoC ...

yeah that would be nice.

> 
>> The
>> capture driver decides whether to include the IC in the capture pipeline
>> based on user format and rotation control. I.e. if user colorspace is
>> different from what the sensor can output, IC CSC is required. If user
>> resolution is different from the selected capture cropping rectangle,
>> IC resizer is required, and finally if user requests rotation, the IC
>> rotation unit is required. If none of those are true, the capture driver
>> decides to exclude the IC from the pipeline and send raw sensor frames
>> (well, after cropping anyway) directly to memory via the SMFC.
> 
> That is too much magic for my taste. Especially since whether or not you
> can use the IC not only depends on the current video format, but also on
> whether the other CSI or the MEM_VDIC_MEM path are using the IC at the
> moment.

Right. Our current capture driver just returns -EBUSY if the IC PRPENC task
is currently in use by the other CSI.

But I have come around, I agree with you now that, if we are to make the
capture driver a media device that is controlling an IC entity, that the
links to/from the IC need to be controlled by media controller API. I guess
I've been thinking too much in terms of "classical" V4L2.


> Since this can change dynamically, it throws a wrench into GStreamer's
> static capability negotiation, for example. I'd rather have userspace
> select which CSI should be routed through the IC with media-ctl and then
> reflect the possible conversions in the respective video_dev's
> capabilities.

yes, the capabilities will change dynamically depending on the current video
pipeline that has been setup.

> 
>> So in our driver, the decision to link the IC in a pipeline is made
>> internally by the driver and is not a decision exported to userland.
> 
> This is exactly the point I am worried about. You lose flexibility and
> need all sorts of clever conditional code in the driver. It'd be much
> cleaner to just let userspace control the mux.

the conditionals weren't actually that clever. But like I said, I was
thinking in terms of classic V4L2 where internal video blocks are used or
not depending on user requested format. I agree now that IC usage should
be part of media control.

> 
>> My plan was to add media device framework support, but only after basic
>> video capture is in place. Our driver is full featured in terms of basic
>> capture support, and it works on all three reference platforms. But I
>> agree it needs to convert subdev's to media entities and allow some of
>> them to be linked via the media controller API.
> 
> Alright, so we agree that using the media controller API internally is a
> good idea ...
> 
>> But only some linkages make sense to me. As I explain above, if the IC were
>> to be made a media entity, I think it's linkage should be made internally
>> by the capture driver, and this should not be controllable by userspace.
> 
> ... but we disagree on whether to export the control to userspace. For
> more complicated pipelines in front of the CSIs we'll need media-ctl
> anyway, so using that same API for the internal components, makes sense.
> It also allows userspace to get a clear and stable picture of the
> available features for any given multiplexer setting.
> 
>> Heh, we have a mem2mem driver as well, and it also uses IC post-processor
>> task. It uses banding and striping to support resized output frames larger
>> than 1024x1024. It also makes use of IC rotation and CSC.
> 
> Of course :)
> 
>> But again this is not converted to a media entity. And again, if IC were to
>> be made a standalone media entity, then the mem2mem device would _always_
>> require the IC post-processor be linked to it, since the essential feature
>> of mem2mem is to make use of IC post-processor task for CSC, resize, and
>> rotation operations.
> 
> Since the three IC tasks are transparently time-multiplexed, the IC
> media entity representation could have input and output pads for each of
> them.
> The preprocessing (encoding, viewfinder) tasks share an input pad that
> would be connected to either CSI0, CSI1, or VDI output pad. These links
> should control the IC mux. The encoding task output pad would represent
> IDMAC channel 20/CB0 or channel 48/CB8, depending on whether the rotator
> is active. Since rotation requires tight integration between IC and
> IDMAC, I don't think the IRT should be represented as a separate media
> entity.
> The viewfinder task output pad would correspond to channel 21/CB1 or
> channel 49/CB9, and maybe in the future control whether to send that
> data off to the DMFC or to memory.

right. Currently we don't attempt to use the direct IC-PRPVF --> DMFC
path. Viewfinder code looks much like PRPENC (like you or Sascha pointed out
earlier), it just transfers scaled/CSC/rotated frames to a framebuffer addr
in memory provided by s_fbuf.

> The postprocessing input and output pads would go straight to memory and
> are not configurable, so I see no need to describe IC-PP as media
> entity.

er, now I'm being your own best advocate! :) If IC-PP I/O is going to be
described by pads, then I think IC-PP would have to be described as a media
entity.

For mem2mem device, the sink and source links to IC-PP would have to marked
as immutable (always enabled).


> 
> I'm not quite sure about the VDIC, but I guess that also should be
> configurable from userspace as one input to IC. For the deinterlacer to
> work, IC_INPUT needs to be set, so while this is active there is no way
> to route CSI0/1 through the IC directly.
>

sounds right. But there's too much to think about already.

Btw we have tried to implement direct CSI --> VDIC --> IC path without
success. Freescale's BSP does not use the VDIC in this way, but rather as
mem --> VDIC --> mem, i.e. a kind of post-processing after capture. I'm a
bit vague about this since I haven't looked at VDIC yet in much detail.


> [...]
>>> No conflict here, there are different multiplexers to talk about.
>>>
>>> First, there are two external multiplexers controlled by IOMUXC (on
>>> i.MX6, these don't exist on i.MX5): MIPI_IPU1/2_MUX on i.MX6Q and
>>> IPU_CSI0/1_MUX. They are not part of the IPU.
> [...]
>> right, this is one place where subdev linking makes sense to me. I.e.
>> linking sensors to CSI ports.
>>
>> But you don't mean to allow userspace to make this link arbitrarily,
>> correct? You mean the driver uses the mediactrl framework to implement
>> the links defined in the device tree. Maybe that's where I was confused.
> 
> No, this is exactly what I mean. In my opinion, using media-ctl to throw
> the switches is much better than letting the driver decide depending on
> the old S_INPUT API. Especially since this gives userspace a unified API
> when there are input multiplexers (or any other subdevices configurable
> on the pad level) external to the SoC.
> Also, pad format configuration of the CSI subdev exported to userspace
> may be useful to control the compander in the CSI.
> 
> [...]
>>> From an organizational standpoint, with all the other register access
>>> code in gpu/ipu-v3, having the ipu-csi code in there too looks nice and
>>> as expected.
>>> On the other hand, this should really be only used by one
>>> v4l2_subdev driver. When I look at it this way, I see a driver that is
>>> split in two parts, wasting exported symbol space for no very good
>>> reason.
>>
>> I agree about making CSI a subdev, but I also think we can keep all of the
>> register access in IPU core as well. The CSI subdev would be a wrapper
>> around the ipu-csi APIs. I agree it's more use of symbol space, but we
>> might be able to simplify the ipu-csi API.
> 
> So be it. In any case, this decision could be changed later with little
> effort and without any externally visible changes, if deemed necessary,
> as long as the CSI v4l2_subdev driver is the only consumer of this API.
> 
>>> The IC I'd like to describe as a v4l2_subdev. But I'd also like to use
>>> the IC from the DRM driver. So the IC core code has to stay in
>>> gpu/ipu-v3. I'd just like to pool all V4L2 code that uses this into a IC
>>> v4l2_subdev driver if possible. The only use we have for the IC
>>> currently is
>>
>> is mem2mem? And you would like to see an IC pads linked with mem2mem
>> pads. Well, something like this:
>>
>> input frame from userspace ---> m2m ---> IC-PP ---> m2m ---> to userspace
> 
> As long as there is no internal video bus switch somewhere, the
> usefulness of this is debatable. You see we also implemented this by
> directly calling the IPU IC API, and I'm fine with this.

well, as I said above I think if we are going to make the IC a media entity
we might as well make mem2mem a media device and include IC-PP as an entity
with immutable links to it.

Steve

> 
> [...]
>> Ok, in summary I'm aligned with everything you said. Only that I am still
>> pondering about which media entity links make sense, and who should be
>> allowed to make those links.
> 
> At least the decision whether to route the CSI0/1 into the IC
> preprocessing input should be handled by userspace, as this changes the
> capabilities of the corresponding video_dev.
> 
>> So how should we proceed? I would argue to use our capture driver as a base,
>> since it is fully functional and fairly full-featured. It's just missing the
>> media framework.
> 
> Initially, I don't care as much about a full featureset as I do about
> getting the userspace API and device tree bindings right, since those
> won't be easy to change later.
> Pending rework into CSI/IC subdevices and agreement on the userspace
> facing API, I think your patchset can be a good base.
> 
> regards
> Philipp
> 



^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH 42/43] media: imx6: Add support for ADV7180 Video Decoder
  2014-06-07 21:56 ` [PATCH 42/43] media: imx6: Add support for ADV7180 Video Decoder Steve Longerbeam
@ 2015-01-17 19:54   ` Fabio Estevam
  0 siblings, 0 replies; 79+ messages in thread
From: Fabio Estevam @ 2015-01-17 19:54 UTC (permalink / raw)
  To: Steve Longerbeam; +Cc: linux-media, Steve Longerbeam

Hi Steve,

On Sat, Jun 7, 2014 at 6:56 PM, Steve Longerbeam <slongerbeam@gmail.com> wrote:
> This driver is based on adv7180.c from Freescale imx_3.10.17_1.0.0_beta
> branch, modified heavily for code cleanup and converted from int-device
> to subdev.
>
> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
> ---
>  drivers/staging/media/imx6/capture/Kconfig   |    7 +
>  drivers/staging/media/imx6/capture/Makefile  |    1 +
>  drivers/staging/media/imx6/capture/adv7180.c | 1298 ++++++++++++++++++++++++++

We should use drivers/media/i2c/adv7180.c instead, right?

^ permalink raw reply	[flat|nested] 79+ messages in thread

end of thread, other threads:[~2015-01-17 19:54 UTC | newest]

Thread overview: 79+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-07 21:56 [PATCH 00/43] i.MX6 Video capture Steve Longerbeam
2014-06-07 21:56 ` [PATCH 01/43] imx-drm: ipu-v3: Move imx-ipu-v3.h to include/linux/platform_data/ Steve Longerbeam
2014-06-11 11:22   ` Philipp Zabel
2014-06-07 21:56 ` [PATCH 02/43] ARM: dts: imx6qdl: Add ipu aliases Steve Longerbeam
2014-06-11 11:21   ` Philipp Zabel
2014-06-07 21:56 ` [PATCH 03/43] imx-drm: ipu-v3: Add ipu_get_num() Steve Longerbeam
2014-06-11 11:22   ` Philipp Zabel
2014-06-07 21:56 ` [PATCH 04/43] imx-drm: ipu-v3: Add solo/dual-lite IPU device type Steve Longerbeam
2014-06-11  5:37   ` Sascha Hauer
2014-06-11 11:38   ` Philipp Zabel
2014-06-07 21:56 ` [PATCH 05/43] imx-drm: ipu-v3: Map IOMUXC registers Steve Longerbeam
2014-06-11 13:11   ` Philipp Zabel
2014-06-07 21:56 ` [PATCH 06/43] imx-drm: ipu-v3: Add functions to set CSI/IC source muxes Steve Longerbeam
2014-06-11 11:22   ` Philipp Zabel
2014-06-07 21:56 ` [PATCH 07/43] imx-drm: ipu-v3: Rename and add IDMAC channels Steve Longerbeam
2014-06-11 11:22   ` Philipp Zabel
2014-06-07 21:56 ` [PATCH 08/43] imx-drm: ipu-v3: Add units required for video capture Steve Longerbeam
2014-06-11  6:18   ` Sascha Hauer
2014-06-11 14:09   ` Philipp Zabel
2014-06-07 21:56 ` [PATCH 09/43] imx-drm: ipu-v3: Add ipu_mbus_code_to_colorspace() Steve Longerbeam
2014-06-07 21:56 ` [PATCH 10/43] imx-drm: ipu-v3: Add rotation mode conversion utilities Steve Longerbeam
2014-06-07 21:56 ` [PATCH 11/43] imx-drm: ipu-v3: Add helper function checking if pixfmt is planar Steve Longerbeam
2014-06-07 21:56 ` [PATCH 12/43] imx-drm: ipu-v3: Move IDMAC channel names to imx-ipu-v3.h Steve Longerbeam
2014-06-07 21:56 ` [PATCH 13/43] imx-drm: ipu-v3: Add ipu_idmac_buffer_is_ready() Steve Longerbeam
2014-06-07 21:56 ` [PATCH 14/43] imx-drm: ipu-v3: Add ipu_idmac_clear_buffer() Steve Longerbeam
2014-06-07 21:56 ` [PATCH 15/43] imx-drm: ipu-v3: Add ipu_idmac_current_buffer() Steve Longerbeam
2014-06-11 11:22   ` Philipp Zabel
2014-06-07 21:56 ` [PATCH 16/43] imx-drm: ipu-v3: Add __ipu_idmac_reset_current_buffer() Steve Longerbeam
2014-06-07 21:56 ` [PATCH 17/43] imx-drm: ipu-v3: Add ipu_stride_to_bytes() Steve Longerbeam
2014-06-07 21:56 ` [PATCH 18/43] imx-drm: ipu-v3: Add ipu_idmac_enable_watermark() Steve Longerbeam
2014-06-07 21:56 ` [PATCH 19/43] imx-drm: ipu-v3: Add ipu_idmac_lock_enable() Steve Longerbeam
2014-06-07 21:56 ` [PATCH 20/43] imx-drm: ipu-v3: Add idmac channel linking support Steve Longerbeam
2014-06-07 21:56 ` [PATCH 21/43] imx-drm: ipu-v3: Add ipu_bits_per_pixel() Steve Longerbeam
2014-06-11 11:23   ` Philipp Zabel
2014-06-07 21:56 ` [PATCH 22/43] imx-drm: ipu-v3: Add ipu-cpmem unit Steve Longerbeam
2014-06-11 11:23   ` Philipp Zabel
2014-06-07 21:56 ` [PATCH 23/43] imx-drm: ipu-cpmem: Add ipu_cpmem_set_block_mode() Steve Longerbeam
2014-06-07 21:56 ` [PATCH 24/43] imx-drm: ipu-cpmem: Add ipu_cpmem_set_axi_id() Steve Longerbeam
2014-06-07 21:56 ` [PATCH 25/43] imx-drm: ipu-cpmem: Add ipu_cpmem_set_rotation() Steve Longerbeam
2014-06-07 21:56 ` [PATCH 26/43] imx-drm: ipu-cpmem: Add second buffer support to ipu_cpmem_set_image() Steve Longerbeam
2014-06-07 21:56 ` [PATCH 27/43] imx-drm: ipu-v3: Add more planar formats support Steve Longerbeam
2014-06-07 21:56 ` [PATCH 28/43] imx-drm: ipu-cpmem: Add ipu_cpmem_dump() Steve Longerbeam
2014-06-07 21:56 ` [PATCH 29/43] imx-drm: ipu-v3: Add ipu_dump() Steve Longerbeam
2014-06-07 21:56 ` [PATCH 30/43] ARM: dts: imx6: add pin groups for imx6q/dl for IPU1 CSI0 Steve Longerbeam
2014-06-11  5:56   ` Sascha Hauer
2014-06-07 21:56 ` [PATCH 31/43] ARM: dts: imx6qdl: Flesh out MIPI CSI2 receiver node Steve Longerbeam
2014-06-11 11:38   ` Philipp Zabel
2014-06-07 21:56 ` [PATCH 32/43] ARM: dts: imx: sabrelite: add video capture ports and endpoints Steve Longerbeam
2014-06-11 11:38   ` Philipp Zabel
2014-06-12 17:13     ` Philipp Zabel
2014-06-07 21:56 ` [PATCH 33/43] ARM: dts: imx6-sabresd: " Steve Longerbeam
2014-06-07 21:56 ` [PATCH 34/43] ARM: dts: imx6-sabreauto: " Steve Longerbeam
2014-06-07 21:56 ` [PATCH 35/43] ARM: dts: imx6qdl: Add simple-bus to ipu compatibility Steve Longerbeam
2014-06-11 11:39   ` Philipp Zabel
2014-06-07 21:56 ` [PATCH 36/43] gpio: pca953x: Add reset-gpios property Steve Longerbeam
2014-06-11 11:39   ` Philipp Zabel
2014-06-07 21:56 ` [PATCH 37/43] ARM: imx6q: clk: Add video 27m clock Steve Longerbeam
2014-06-07 21:56 ` [PATCH 38/43] media: imx6: Add device tree binding documentation Steve Longerbeam
2014-06-07 21:56 ` [PATCH 39/43] media: Add new camera interface driver for i.MX6 Steve Longerbeam
2014-06-11 15:27   ` Philipp Zabel
2014-06-07 21:56 ` [PATCH 40/43] media: imx6: Add support for MIPI CSI-2 OV5640 Steve Longerbeam
2014-06-11 11:39   ` Philipp Zabel
2014-06-07 21:56 ` [PATCH 41/43] media: imx6: Add support for Parallel OV5642 Steve Longerbeam
2014-06-07 21:56 ` [PATCH 42/43] media: imx6: Add support for ADV7180 Video Decoder Steve Longerbeam
2015-01-17 19:54   ` Fabio Estevam
2014-06-07 21:56 ` [PATCH 43/43] ARM: imx_v6_v7_defconfig: Enable video4linux drivers Steve Longerbeam
2014-06-08  8:36 ` [PATCH 00/43] i.MX6 Video capture Hans Verkuil
2014-06-08  8:39   ` Hans Verkuil
2014-06-09 16:42   ` Steve Longerbeam
2014-06-10 15:11     ` Hans Verkuil
2014-06-11  0:54       ` Steve Longerbeam
2014-06-11  7:01         ` Hans Verkuil
2014-06-11 11:21 ` Philipp Zabel
2014-06-12  1:04   ` Steve Longerbeam
2014-06-12 16:50     ` Philipp Zabel
2014-06-12 21:05       ` Steve Longerbeam
2014-06-12 21:35         ` Troy Kisky
2014-06-13 15:37         ` Philipp Zabel
2014-06-15 22:34           ` Steve Longerbeam

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).