linux-samsung-soc.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 0/8] A V4L2 driver for Exynos4x12 Imaging Subsystem
@ 2013-03-11 19:44 Sylwester Nawrocki
  2013-03-11 19:44 ` [RFC PATCH 1/8] s5p-fimc: Add Exynos4x12 FIMC-IS driver Sylwester Nawrocki
                   ` (7 more replies)
  0 siblings, 8 replies; 14+ messages in thread
From: Sylwester Nawrocki @ 2013-03-11 19:44 UTC (permalink / raw)
  To: linux-media
  Cc: kyungmin.park, myungjoo.ham, dh09.lee, shaik.samsung, arun.kk,
	a.hajda, linux-samsung-soc, devicetree-discuss, linux-arm-kernel,
	Sylwester Nawrocki

This patch series is an initial version of a driver for the camera ISP
subsystem (FIMC-IS) embedded in Samsung Exynos4x12 SoCs.

The FIMC-IS subsystem is build around a ARM Cortex-A5 CPU that controls
its dedicated peripherals, like I2C, SPI, UART, PWM, ADC,...  and the
ISP chain. There are 3 hardware image processing blocks: ISP, DRC
(dynamic range compression) and FD (face detection) that are normally
controlled by the Cortex-A5 firmware.

The driver currently exposes two additional sub-device to user space:
the image sensor and FIMC-IS-ISP sub-device. Another one might be
added in future for the FD features.

The FIMC-IS has various data inputs, it can capture data from memory
or from other SoC IP blocks (FIMC-LITE). It is currently plugged
between FIMC-LITE and FIMC IP blocks, so there is a media pipeline
like:

sensor -> MIPI-CSIS -> FIMC-LITE -> FIMC-IS-ISP -> FIMC -> memory

A raw Bayer image data can be captured from the ISP block which has
it's own DMA engines. Support for this is not really included in
this series though, only a video capture node driver stubs are added.

This is a bit complicated code, nevertheless I would really appreciate
any review comments you might have.

And this is just a basic set of futures this patch series addresses.
Others include input/output DMA support for the DRC and FD blocks,
support for more ISP controls, etc.

But it all is not immediately needed to make use of this really
great ISP!

A full git tree with all dependencies can be found at:
git://linuxtv.org/snawrocki/samsung.git
http://git.linuxtv.org/snawrocki/samsung.git/exynos4-fimc-is

Sylwester Nawrocki (8):
  s5p-fimc: Add Exynos4x12 FIMC-IS driver
  s5p-fimc: Add FIMC-IS ISP I2C bus driver
  s5p-fimc: Add FIMC-IS parameter region definitions
  s5p-fimc: Add common FIMC-IS image sensor driver
  s5p-fimc: Add ISP video capture driver stubs
  fimc-is: Add Exynos4x12 FIMC-IS device tree bindings documentation
  s5p-fimc: Add fimc-is subdevs registration
  s5p-fimc: Create media links for the FIMC-IS entities

 .../devicetree/bindings/media/exynos4-fimc-is.txt  |   41 +
 drivers/media/platform/s5p-fimc/Kconfig            |   13 +
 drivers/media/platform/s5p-fimc/Makefile           |    4 +
 drivers/media/platform/s5p-fimc/fimc-is-command.h  |  147 +++
 drivers/media/platform/s5p-fimc/fimc-is-errno.c    |  272 ++++++
 drivers/media/platform/s5p-fimc/fimc-is-errno.h    |  248 +++++
 drivers/media/platform/s5p-fimc/fimc-is-i2c.c      |   81 ++
 drivers/media/platform/s5p-fimc/fimc-is-i2c.h      |   15 +
 drivers/media/platform/s5p-fimc/fimc-is-param.c    |  971 +++++++++++++++++++
 drivers/media/platform/s5p-fimc/fimc-is-param.h    | 1018 ++++++++++++++++++++
 drivers/media/platform/s5p-fimc/fimc-is-regs.c     |  242 +++++
 drivers/media/platform/s5p-fimc/fimc-is-regs.h     |  164 ++++
 drivers/media/platform/s5p-fimc/fimc-is-sensor.c   |  308 ++++++
 drivers/media/platform/s5p-fimc/fimc-is-sensor.h   |   80 ++
 drivers/media/platform/s5p-fimc/fimc-is.c          |  970 +++++++++++++++++++
 drivers/media/platform/s5p-fimc/fimc-is.h          |  344 +++++++
 drivers/media/platform/s5p-fimc/fimc-isp-video.c   |  414 ++++++++
 drivers/media/platform/s5p-fimc/fimc-isp-video.h   |   50 +
 drivers/media/platform/s5p-fimc/fimc-isp.c         |  791 +++++++++++++++
 drivers/media/platform/s5p-fimc/fimc-isp.h         |  205 ++++
 drivers/media/platform/s5p-fimc/fimc-mdevice.c     |  129 ++-
 drivers/media/platform/s5p-fimc/fimc-mdevice.h     |   15 +
 22 files changed, 6502 insertions(+), 20 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/media/exynos4-fimc-is.txt
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-is-command.h
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-is-errno.c
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-is-errno.h
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-is-i2c.c
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-is-i2c.h
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-is-param.c
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-is-param.h
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-is-regs.c
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-is-regs.h
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-is-sensor.c
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-is-sensor.h
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-is.c
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-is.h
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-isp-video.c
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-isp-video.h
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-isp.c
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-isp.h

--
1.7.9.5

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

* [RFC PATCH 1/8] s5p-fimc: Add Exynos4x12 FIMC-IS driver
  2013-03-11 19:44 [RFC PATCH 0/8] A V4L2 driver for Exynos4x12 Imaging Subsystem Sylwester Nawrocki
@ 2013-03-11 19:44 ` Sylwester Nawrocki
  2013-03-12 14:27   ` Hans Verkuil
  2013-03-11 19:44 ` [RFC PATCH 2/8] s5p-fimc: Add FIMC-IS ISP I2C bus driver Sylwester Nawrocki
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 14+ messages in thread
From: Sylwester Nawrocki @ 2013-03-11 19:44 UTC (permalink / raw)
  To: linux-media
  Cc: kyungmin.park, myungjoo.ham, dh09.lee, shaik.samsung, arun.kk,
	a.hajda, linux-samsung-soc, devicetree-discuss, linux-arm-kernel,
	Sylwester Nawrocki

This patch adds a set of core files of the Exynos4x12 FIMC-IS
V4L2 driver. This includes main functionality like allocating
memory, loading the firmware, FIMC-IS register interface and
host CPU <-> IS command and error code definitions.

The driver currently exposes a single subdev named FIMC-IS-ISP,
which corresponds to the FIMC-IS ISP and DRC IP blocks.

The FIMC-IS-ISP subdev currently supports only a subset of user
controls. For other controls we need several extensions at the
V4L2 API. The supported standard controls are:
brightness, contrast, saturation, hue, sharpness, 3a_lock,
exposure_time_absolute, white_balance_auto_preset,
iso_sensitivity, iso_sensitivity_auto, exposure_metering_mode.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/platform/s5p-fimc/fimc-is-command.h |  147 ++++
 drivers/media/platform/s5p-fimc/fimc-is-errno.c   |  272 ++++++
 drivers/media/platform/s5p-fimc/fimc-is-errno.h   |  248 ++++++
 drivers/media/platform/s5p-fimc/fimc-is-regs.c    |  242 +++++
 drivers/media/platform/s5p-fimc/fimc-is-regs.h    |  164 ++++
 drivers/media/platform/s5p-fimc/fimc-is.c         |  970 +++++++++++++++++++++
 drivers/media/platform/s5p-fimc/fimc-is.h         |  344 ++++++++
 drivers/media/platform/s5p-fimc/fimc-isp.c        |  791 +++++++++++++++++
 drivers/media/platform/s5p-fimc/fimc-isp.h        |  205 +++++
 9 files changed, 3383 insertions(+)
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-is-command.h
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-is-errno.c
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-is-errno.h
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-is-regs.c
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-is-regs.h
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-is.c
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-is.h
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-isp.c
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-isp.h

diff --git a/drivers/media/platform/s5p-fimc/fimc-is-command.h b/drivers/media/platform/s5p-fimc/fimc-is-command.h
new file mode 100644
index 0000000..b3f48d4
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-is-command.h
@@ -0,0 +1,147 @@
+/*
+ * Samsung Exynos4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * FIMC-IS command set definitions
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *
+ * Authors: Younghwan Joo <yhwan.joo@samsung.com>
+ *          Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef FIMC_IS_CMD_H_
+#define FIMC_IS_CMD_H_
+
+#define FIMC_IS_COMMAND_VER 110	/* FIMC-IS command set version 1.10 */
+
+/* Enumeration of commands beetween the FIMC-IS and the host processor. */
+
+/* HOST to FIMC-IS */
+#define FIMC_IS_HIC_PREVIEW_STILL	0x0001
+#define FIMC_IS_HIC_PREVIEW_VIDEO	0x0002
+#define FIMC_IS_HIC_CAPTURE_STILL	0x0003
+#define FIMC_IS_HIC_CAPTURE_VIDEO	0x0004
+#define FIMC_IS_HIC_STREAM_ON		0x0005
+#define FIMC_IS_HIC_STREAM_OFF		0x0006
+#define FIMC_IS_HIC_SET_PARAMETER	0x0007
+#define FIMC_IS_HIC_GET_PARAMETER	0x0008
+#define FIMC_IS_HIC_SET_TUNE		0x0009
+#define FIMC_IS_HIC_GET_STATUS		0x000b
+/* Sensor part */
+#define FIMC_IS_HIC_OPEN_SENSOR		0x000c
+#define FIMC_IS_HIC_CLOSE_SENSOR	0x000d
+#define FIMC_IS_HIC_SIMMIAN_INIT	0x000e
+#define FIMC_IS_HIC_SIMMIAN_WRITE	0x000f
+#define FIMC_IS_HIC_SIMMIAN_READ	0x0010
+#define FIMC_IS_HIC_POWER_DOWN		0x0011
+#define FIMC_IS_HIC_GET_SET_FILE_ADDR	0x0012
+#define FIMC_IS_HIC_LOAD_SET_FILE	0x0013
+#define FIMC_IS_HIC_MSG_CONFIG		0x0014
+#define FIMC_IS_HIC_MSG_TEST		0x0015
+/* FIMC-IS to HOST */
+#define FIMC_IS_IHC_GET_SENSOR_NUM	0x1000
+#define FIMC_IS_IHC_SET_SHOT_MARK	0x1001
+/* parameter1: frame number */
+/* parameter2: confidence level (smile 0~100) */
+/* parameter3: confidence level (blink 0~100) */
+#define FIMC_IS_IHC_SET_FACE_MARK	0x1002
+/* parameter1: coordinate count */
+/* parameter2: coordinate buffer address */
+#define FIMC_IS_IHC_FRAME_DONE		0x1003
+/* parameter1: frame start number */
+/* parameter2: frame count */
+#define FIMC_IS_IHC_AA_DONE		0x1004
+#define FIMC_IS_IHC_NOT_READY		0x1005
+
+#define FIMC_IS_REPLY_DONE		0x2000
+#define	FIMC_IS_REPLY_NOT_DONE		0x2001
+
+enum fimc_is_scenario {
+	IS_SC_PREVIEW_STILL,
+	IS_SC_PREVIEW_VIDEO,
+	IS_SC_CAPTURE_STILL,
+	IS_SC_CAPTURE_VIDEO,
+	IS_SC_MAX
+};
+
+enum fimc_is_sub_scenario {
+	IS_SC_SUB_DEFAULT,
+	IS_SC_SUB_PS_VTCALL,
+	IS_SC_SUB_CS_VTCALL,
+	IS_SC_SUB_PV_VTCALL,
+	IS_SC_SUB_CV_VTCALL,
+};
+
+struct fimc_is_capability {
+	u32 support_af;
+	u32 iso_gain;
+	u32 aperture;
+	u32 min_exposure;
+	u32 max_exposure;
+	u32 min_gain;
+	u32 max_gain;
+} __packed;
+
+struct is_common_reg {
+	u32 hicmd;
+	u32 hic_sensorid;
+	u32 hic_param[4];
+	u32 reserved1[4];
+
+	u32 ihcmd;
+	u32 ihc_sensorid;
+	u32 ihc_param[4];
+	u32 reserved2[4];
+
+	u32 isp_sensor_id;
+	u32 isp_param[2];
+	u32 reserved3[1];
+
+	u32 scc_sensor_id;
+	u32 scc_param[2];
+	u32 reserved4[1];
+
+	u32 dnr_sensor_id;
+	u32 dnr_param[2];
+	u32 reserved5[1];
+
+	u32 scp_sensor_id;
+	u32 scp_param[2];
+	u32 reserved6[29];
+} __packed;
+
+struct is_mcuctl_reg {
+	u32 mcuctl;
+	u32 bboar;
+
+	u32 intgr0;
+	u32 intcr0;
+	u32 intmr0;
+	u32 intsr0;
+	u32 intmsr0;
+
+	u32 intgr1;
+	u32 intcr1;
+	u32 intmr1;
+	u32 intsr1;
+	u32 intmsr1;
+
+	u32 intcr2;
+	u32 intmr2;
+	u32 intsr2;
+	u32 intmsr2;
+
+	u32 gpoctrl;
+	u32 cpoenctlr;
+	u32 gpictlr;
+
+	u32 pad[0xd];
+
+	struct is_common_reg common;
+} __packed;
+
+#endif /* FIMC_IS_CMD_H_ */
diff --git a/drivers/media/platform/s5p-fimc/fimc-is-errno.c b/drivers/media/platform/s5p-fimc/fimc-is-errno.c
new file mode 100644
index 0000000..e8519e1
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-is-errno.c
@@ -0,0 +1,272 @@
+/*
+ * Samsung Exynos4 SoC series FIMC-IS slave interface driver
+ *
+ * Error log interface functions
+ *
+ * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd.
+ *
+ * Authors: Younghwan Joo <yhwan.joo@samsung.com>
+ *          Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "fimc-is-errno.h"
+
+const char * const fimc_is_param_strerr(unsigned int error)
+{
+	switch (error) {
+	case ERROR_COMMON_CMD:
+		return "ERROR_COMMON_CMD: Invalid Command";
+	case ERROR_COMMON_PARAMETER:
+		return "ERROR_COMMON_PARAMETER: Invalid Parameter";
+	case ERROR_COMMON_SETFILE_LOAD:
+		return "ERROR_COMMON_SETFILE_LOAD: Illegal Setfile Loading";
+	case ERROR_COMMON_SETFILE_ADJUST:
+		return "ERROR_COMMON_SETFILE_ADJUST: Setfile isn't adjusted";
+	case ERROR_COMMON_SETFILE_INDEX:
+		return "ERROR_COMMON_SETFILE_INDEX: Invalid setfile index";
+	case ERROR_COMMON_INPUT_PATH:
+		return "ERROR_COMMON_INPUT_PATH: Input path can be changed in ready state";
+	case ERROR_COMMON_INPUT_INIT:
+		return "ERROR_COMMON_INPUT_INIT: IP can not start if input path is not set";
+	case ERROR_COMMON_OUTPUT_PATH:
+		return "ERROR_COMMON_OUTPUT_PATH: Output path can be changed in ready state (stop)";
+	case ERROR_COMMON_OUTPUT_INIT:
+		return "ERROR_COMMON_OUTPUT_INIT: IP can not start if output path is not set";
+	case ERROR_CONTROL_BYPASS:
+		return "ERROR_CONTROL_BYPASS";
+	case ERROR_OTF_INPUT_FORMAT:
+		return "ERROR_OTF_INPUT_FORMAT: Invalid format  (DRC: YUV444, FD: YUV444, 422, 420)";
+	case ERROR_OTF_INPUT_WIDTH:
+		return "ERROR_OTF_INPUT_WIDTH: Invalid width (DRC: 128~8192, FD: 32~8190)";
+	case ERROR_OTF_INPUT_HEIGHT:
+		return "ERROR_OTF_INPUT_HEIGHT: Invalid bit-width (DRC: 8~12bits, FD: 8bit)";
+	case ERROR_OTF_INPUT_BIT_WIDTH:
+		return "ERROR_OTF_INPUT_BIT_WIDTH: Invalid bit-width (DRC: 8~12bits, FD: 8bit)";
+	case ERROR_DMA_INPUT_WIDTH:
+		return "ERROR_DMA_INPUT_WIDTH: Invalid width (DRC: 128~8192, FD: 32~8190)";
+	case ERROR_DMA_INPUT_HEIGHT:
+		return "ERROR_DMA_INPUT_HEIGHT: Invalid height (DRC: 64~8192, FD: 16~8190)";
+	case ERROR_DMA_INPUT_FORMAT:
+		return "ERROR_DMA_INPUT_FORMAT: Invalid format (DRC: YUV444 or YUV422, FD: YUV444,422,420)";
+	case ERROR_DMA_INPUT_BIT_WIDTH:
+		return "ERROR_DMA_INPUT_BIT_WIDTH: Invalid bit-width (DRC: 8~12bits, FD: 8bit)";
+	case ERROR_DMA_INPUT_ORDER:
+		return "ERROR_DMA_INPUT_ORDER: Invalid order(DRC: YYCbCr,YCbYCr,FD:NO,YYCbCr,YCbYCr,CbCr,CrCb)";
+	case ERROR_DMA_INPUT_PLANE:
+		return "ERROR_DMA_INPUT_PLANE: Invalid palne (DRC: 3, FD: 1, 2, 3)";
+	case ERROR_OTF_OUTPUT_WIDTH:
+		return "ERROR_OTF_OUTPUT_WIDTH: Invalid width (DRC: 128~8192)";
+	case ERROR_OTF_OUTPUT_HEIGHT:
+		return "ERROR_OTF_OUTPUT_HEIGHT: Invalid height (DRC: 64~8192)";
+	case ERROR_OTF_OUTPUT_FORMAT:
+		return "ERROR_OTF_OUTPUT_FORMAT: Invalid format (DRC: YUV444)";
+	case ERROR_OTF_OUTPUT_BIT_WIDTH:
+		return "ERROR_OTF_OUTPUT_BIT_WIDTH: Invalid bit-width (DRC: 8~12bits, FD: 8bit)";
+	case ERROR_DMA_OUTPUT_WIDTH:
+		return "ERROR_DMA_OUTPUT_WIDTH";
+	case ERROR_DMA_OUTPUT_HEIGHT:
+		return "ERROR_DMA_OUTPUT_HEIGHT";
+	case ERROR_DMA_OUTPUT_FORMAT:
+		return "ERROR_DMA_OUTPUT_FORMAT";
+	case ERROR_DMA_OUTPUT_BIT_WIDTH:
+		return "ERROR_DMA_OUTPUT_BIT_WIDTH";
+	case ERROR_DMA_OUTPUT_PLANE:
+		return "ERROR_DMA_OUTPUT_PLANE";
+	case ERROR_DMA_OUTPUT_ORDER:
+		return "ERROR_DMA_OUTPUT_ORDER";
+
+	/* Sensor Error(100~199) */
+	case ERROR_SENSOR_I2C_FAIL:
+		return "ERROR_SENSOR_I2C_FAIL";
+	case ERROR_SENSOR_INVALID_FRAMERATE:
+		return "ERROR_SENSOR_INVALID_FRAMERATE";
+	case ERROR_SENSOR_INVALID_EXPOSURETIME:
+		return "ERROR_SENSOR_INVALID_EXPOSURETIME";
+	case ERROR_SENSOR_INVALID_SIZE:
+		return "ERROR_SENSOR_INVALID_SIZE";
+	case ERROR_SENSOR_INVALID_SETTING:
+		return "ERROR_SENSOR_INVALID_SETTING";
+	case ERROR_SENSOR_ACTURATOR_INIT_FAIL:
+		return "ERROR_SENSOR_ACTURATOR_INIT_FAIL";
+	case ERROR_SENSOR_INVALID_AF_POS:
+		return "ERROR_SENSOR_INVALID_AF_POS";
+	case ERROR_SENSOR_UNSUPPORT_FUNC:
+		return "ERROR_SENSOR_UNSUPPORT_FUNC";
+	case ERROR_SENSOR_UNSUPPORT_PERI:
+		return "ERROR_SENSOR_UNSUPPORT_PERI";
+	case ERROR_SENSOR_UNSUPPORT_AF:
+		return "ERROR_SENSOR_UNSUPPORT_AF";
+
+	/* ISP Error (200~299) */
+	case ERROR_ISP_AF_BUSY:
+		return "ERROR_ISP_AF_BUSY";
+	case ERROR_ISP_AF_INVALID_COMMAND:
+		return "ERROR_ISP_AF_INVALID_COMMAND";
+	case ERROR_ISP_AF_INVALID_MODE:
+		return "ERROR_ISP_AF_INVALID_MODE";
+
+	/* DRC Error (300~399) */
+	/* FD Error  (400~499) */
+	case ERROR_FD_CONFIG_MAX_NUMBER_STATE:
+		return "ERROR_FD_CONFIG_MAX_NUMBER_STATE";
+	case ERROR_FD_CONFIG_MAX_NUMBER_INVALID:
+		return "ERROR_FD_CONFIG_MAX_NUMBER_INVALID";
+	case ERROR_FD_CONFIG_YAW_ANGLE_STATE:
+		return "ERROR_FD_CONFIG_YAW_ANGLE_STATE";
+	case ERROR_FD_CONFIG_YAW_ANGLE_INVALID:
+		return "ERROR_FD_CONFIG_YAW_ANGLE_INVALID\n";
+	case ERROR_FD_CONFIG_ROLL_ANGLE_STATE:
+		return "ERROR_FD_CONFIG_ROLL_ANGLE_STATE";
+	case ERROR_FD_CONFIG_ROLL_ANGLE_INVALID:
+		return "ERROR_FD_CONFIG_ROLL_ANGLE_INVALID";
+	case ERROR_FD_CONFIG_SMILE_MODE_INVALID:
+		return "ERROR_FD_CONFIG_SMILE_MODE_INVALID";
+	case ERROR_FD_CONFIG_BLINK_MODE_INVALID:
+		return "ERROR_FD_CONFIG_BLINK_MODE_INVALID";
+	case ERROR_FD_CONFIG_EYES_DETECT_INVALID:
+		return "ERROR_FD_CONFIG_EYES_DETECT_INVALID";
+	case ERROR_FD_CONFIG_MOUTH_DETECT_INVALID:
+		return "ERROR_FD_CONFIG_MOUTH_DETECT_INVALID";
+	case ERROR_FD_CONFIG_ORIENTATION_STATE:
+		return "ERROR_FD_CONFIG_ORIENTATION_STATE";
+	case ERROR_FD_CONFIG_ORIENTATION_INVALID:
+		return "ERROR_FD_CONFIG_ORIENTATION_INVALID";
+	case ERROR_FD_CONFIG_ORIENTATION_VALUE_INVALID:
+		return "ERROR_FD_CONFIG_ORIENTATION_VALUE_INVALID";
+	case ERROR_FD_RESULT:
+		return "ERROR_FD_RESULT";
+	case ERROR_FD_MODE:
+		return "ERROR_FD_MODE";
+	default:
+		return "Unknown";
+	}
+}
+
+const char * const fimc_is_strerr(unsigned int error)
+{
+	error &= ~IS_ERROR_TIME_OUT_FLAG;
+
+	switch (error) {
+	/* General */
+	case IS_ERROR_INVALID_COMMAND:
+		return "IS_ERROR_INVALID_COMMAND";
+	case IS_ERROR_REQUEST_FAIL:
+		return "IS_ERROR_REQUEST_FAIL";
+	case IS_ERROR_INVALID_SCENARIO:
+		return "IS_ERROR_INVALID_SCENARIO";
+	case IS_ERROR_INVALID_SENSORID:
+		return "IS_ERROR_INVALID_SENSORID";
+	case IS_ERROR_INVALID_MODE_CHANGE:
+		return "IS_ERROR_INVALID_MODE_CHANGE";
+	case IS_ERROR_INVALID_MAGIC_NUMBER:
+		return "IS_ERROR_INVALID_MAGIC_NUMBER";
+	case IS_ERROR_INVALID_SETFILE_HDR:
+		return "IS_ERROR_INVALID_SETFILE_HDR";
+	case IS_ERROR_BUSY:
+		return "IS_ERROR_BUSY";
+	case IS_ERROR_SET_PARAMETER:
+		return "IS_ERROR_SET_PARAMETER";
+	case IS_ERROR_INVALID_PATH:
+		return "IS_ERROR_INVALID_PATH";
+	case IS_ERROR_OPEN_SENSOR_FAIL:
+		return "IS_ERROR_OPEN_SENSOR_FAIL";
+	case IS_ERROR_ENTRY_MSG_THREAD_DOWN:
+		return "IS_ERROR_ENTRY_MSG_THREAD_DOWN";
+	case IS_ERROR_ISP_FRAME_END_NOT_DONE:
+		return "IS_ERROR_ISP_FRAME_END_NOT_DONE";
+	case IS_ERROR_DRC_FRAME_END_NOT_DONE:
+		return "IS_ERROR_DRC_FRAME_END_NOT_DONE";
+	case IS_ERROR_SCALERC_FRAME_END_NOT_DONE:
+		return "IS_ERROR_SCALERC_FRAME_END_NOT_DONE";
+	case IS_ERROR_ODC_FRAME_END_NOT_DONE:
+		return "IS_ERROR_ODC_FRAME_END_NOT_DONE";
+	case IS_ERROR_DIS_FRAME_END_NOT_DONE:
+		return "IS_ERROR_DIS_FRAME_END_NOT_DONE";
+	case IS_ERROR_TDNR_FRAME_END_NOT_DONE:
+		return "IS_ERROR_TDNR_FRAME_END_NOT_DONE";
+	case IS_ERROR_SCALERP_FRAME_END_NOT_DONE:
+		return "IS_ERROR_SCALERP_FRAME_END_NOT_DONE";
+	case IS_ERROR_WAIT_STREAM_OFF_NOT_DONE:
+		return "IS_ERROR_WAIT_STREAM_OFF_NOT_DONE";
+	case IS_ERROR_NO_MSG_IS_RECEIVED:
+		return "IS_ERROR_NO_MSG_IS_RECEIVED";
+	case IS_ERROR_SENSOR_MSG_FAIL:
+		return "IS_ERROR_SENSOR_MSG_FAIL";
+	case IS_ERROR_ISP_MSG_FAIL:
+		return "IS_ERROR_ISP_MSG_FAIL";
+	case IS_ERROR_DRC_MSG_FAIL:
+		return "IS_ERROR_DRC_MSG_FAIL";
+	case IS_ERROR_LHFD_MSG_FAIL:
+		return "IS_ERROR_LHFD_MSG_FAIL";
+	case IS_ERROR_UNKNOWN:
+		return "IS_ERROR_UNKNOWN";
+
+	/* Sensor */
+	case IS_ERROR_SENSOR_PWRDN_FAIL:
+		return "IS_ERROR_SENSOR_PWRDN_FAIL";
+
+	/* ISP */
+	case IS_ERROR_ISP_PWRDN_FAIL:
+		return "IS_ERROR_ISP_PWRDN_FAIL";
+	case IS_ERROR_ISP_MULTIPLE_INPUT:
+		return "IS_ERROR_ISP_MULTIPLE_INPUT";
+	case IS_ERROR_ISP_ABSENT_INPUT:
+		return "IS_ERROR_ISP_ABSENT_INPUT";
+	case IS_ERROR_ISP_ABSENT_OUTPUT:
+		return "IS_ERROR_ISP_ABSENT_OUTPUT";
+	case IS_ERROR_ISP_NONADJACENT_OUTPUT:
+		return "IS_ERROR_ISP_NONADJACENT_OUTPUT";
+	case IS_ERROR_ISP_FORMAT_MISMATCH:
+		return "IS_ERROR_ISP_FORMAT_MISMATCH";
+	case IS_ERROR_ISP_WIDTH_MISMATCH:
+		return "IS_ERROR_ISP_WIDTH_MISMATCH";
+	case IS_ERROR_ISP_HEIGHT_MISMATCH:
+		return "IS_ERROR_ISP_HEIGHT_MISMATCH";
+	case IS_ERROR_ISP_BITWIDTH_MISMATCH:
+		return "IS_ERROR_ISP_BITWIDTH_MISMATCH";
+	case IS_ERROR_ISP_FRAME_END_TIME_OUT:
+		return "IS_ERROR_ISP_FRAME_END_TIME_OUT";
+
+	/* DRC */
+	case IS_ERROR_DRC_PWRDN_FAIL:
+		return "IS_ERROR_DRC_PWRDN_FAIL";
+	case IS_ERROR_DRC_MULTIPLE_INPUT:
+		return "IS_ERROR_DRC_MULTIPLE_INPUT";
+	case IS_ERROR_DRC_ABSENT_INPUT:
+		return "IS_ERROR_DRC_ABSENT_INPUT";
+	case IS_ERROR_DRC_NONADJACENT_INPUT:
+		return "IS_ERROR_DRC_NONADJACENT_INPUT";
+	case IS_ERROR_DRC_ABSENT_OUTPUT:
+		return "IS_ERROR_DRC_ABSENT_OUTPUT";
+	case IS_ERROR_DRC_NONADJACENT_OUTPUT:
+		return "IS_ERROR_DRC_NONADJACENT_OUTPUT";
+	case IS_ERROR_DRC_FORMAT_MISMATCH:
+		return "IS_ERROR_DRC_FORMAT_MISMATCH";
+	case IS_ERROR_DRC_WIDTH_MISMATCH:
+		return "IS_ERROR_DRC_WIDTH_MISMATCH";
+	case IS_ERROR_DRC_HEIGHT_MISMATCH:
+		return "IS_ERROR_DRC_HEIGHT_MISMATCH";
+	case IS_ERROR_DRC_BITWIDTH_MISMATCH:
+		return "IS_ERROR_DRC_BITWIDTH_MISMATCH";
+	case IS_ERROR_DRC_FRAME_END_TIME_OUT:
+		return "IS_ERROR_DRC_FRAME_END_TIME_OUT";
+
+	/* FD */
+	case IS_ERROR_FD_PWRDN_FAIL:
+		return "IS_ERROR_FD_PWRDN_FAIL";
+	case IS_ERROR_FD_MULTIPLE_INPUT:
+		return "IS_ERROR_FD_MULTIPLE_INPUT";
+	case IS_ERROR_FD_ABSENT_INPUT:
+		return "IS_ERROR_FD_ABSENT_INPUT";
+	case IS_ERROR_FD_NONADJACENT_INPUT:
+		return "IS_ERROR_FD_NONADJACENT_INPUT";
+	case IS_ERROR_LHFD_FRAME_END_TIME_OUT:
+		return "IS_ERROR_LHFD_FRAME_END_TIME_OUT";
+	default:
+		return "Unknown";
+	}
+}
diff --git a/drivers/media/platform/s5p-fimc/fimc-is-errno.h b/drivers/media/platform/s5p-fimc/fimc-is-errno.h
new file mode 100644
index 0000000..3de6f6d
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-is-errno.h
@@ -0,0 +1,248 @@
+/*
+ * Samsung Exynos4 SoC series FIMC-IS slave interface driver
+ *
+ * FIMC-IS error code definition
+ *
+ * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd.
+ *
+ * Authors: Younghwan Joo <yhwan.joo@samsung.com>
+ *          Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef FIMC_IS_ERR_H_
+#define FIMC_IS_ERR_H_
+
+#define IS_ERROR_VER			011 /* IS ERROR VERSION 0.11 */
+
+enum {
+	IS_ERROR_NONE,
+
+	/* General 1 ~ 99 */
+	IS_ERROR_INVALID_COMMAND,
+	IS_ERROR_REQUEST_FAIL,
+	IS_ERROR_INVALID_SCENARIO,
+	IS_ERROR_INVALID_SENSORID,
+	IS_ERROR_INVALID_MODE_CHANGE,
+	IS_ERROR_INVALID_MAGIC_NUMBER,
+	IS_ERROR_INVALID_SETFILE_HDR,
+	IS_ERROR_BUSY,
+	IS_ERROR_SET_PARAMETER,
+	IS_ERROR_INVALID_PATH,
+	IS_ERROR_OPEN_SENSOR_FAIL,
+	IS_ERROR_ENTRY_MSG_THREAD_DOWN,
+	IS_ERROR_ISP_FRAME_END_NOT_DONE,
+	IS_ERROR_DRC_FRAME_END_NOT_DONE,
+	IS_ERROR_SCALERC_FRAME_END_NOT_DONE,
+	IS_ERROR_ODC_FRAME_END_NOT_DONE,
+	IS_ERROR_DIS_FRAME_END_NOT_DONE,
+	IS_ERROR_TDNR_FRAME_END_NOT_DONE,
+	IS_ERROR_SCALERP_FRAME_END_NOT_DONE,
+	IS_ERROR_WAIT_STREAM_OFF_NOT_DONE,
+	IS_ERROR_NO_MSG_IS_RECEIVED,
+	IS_ERROR_SENSOR_MSG_FAIL,
+	IS_ERROR_ISP_MSG_FAIL,
+	IS_ERROR_DRC_MSG_FAIL,
+	IS_ERROR_SCALERC_MSG_FAIL,
+	IS_ERROR_ODC_MSG_FAIL,
+	IS_ERROR_DIS_MSG_FAIL,
+	IS_ERROR_TDNR_MSG_FAIL,
+	IS_ERROR_SCALERP_MSG_FAIL,
+	IS_ERROR_LHFD_MSG_FAIL,
+	IS_ERROR_LHFD_INTERNAL_STOP,
+
+	/* Sensor 100 ~ 199 */
+	IS_ERROR_SENSOR_PWRDN_FAIL	= 100,
+	IS_ERROR_SENSOR_STREAM_ON_FAIL,
+	IS_ERROR_SENSOR_STREAM_OFF_FAIL,
+
+	/* ISP 200 ~ 299 */
+	IS_ERROR_ISP_PWRDN_FAIL		= 200,
+	IS_ERROR_ISP_MULTIPLE_INPUT,
+	IS_ERROR_ISP_ABSENT_INPUT,
+	IS_ERROR_ISP_ABSENT_OUTPUT,
+	IS_ERROR_ISP_NONADJACENT_OUTPUT,
+	IS_ERROR_ISP_FORMAT_MISMATCH,
+	IS_ERROR_ISP_WIDTH_MISMATCH,
+	IS_ERROR_ISP_HEIGHT_MISMATCH,
+	IS_ERROR_ISP_BITWIDTH_MISMATCH,
+	IS_ERROR_ISP_FRAME_END_TIME_OUT,
+
+	/* DRC 300 ~ 399 */
+	IS_ERROR_DRC_PWRDN_FAIL		= 300,
+	IS_ERROR_DRC_MULTIPLE_INPUT,
+	IS_ERROR_DRC_ABSENT_INPUT,
+	IS_ERROR_DRC_NONADJACENT_INPUT,
+	IS_ERROR_DRC_ABSENT_OUTPUT,
+	IS_ERROR_DRC_NONADJACENT_OUTPUT,
+	IS_ERROR_DRC_FORMAT_MISMATCH,
+	IS_ERROR_DRC_WIDTH_MISMATCH,
+	IS_ERROR_DRC_HEIGHT_MISMATCH,
+	IS_ERROR_DRC_BITWIDTH_MISMATCH,
+	IS_ERROR_DRC_FRAME_END_TIME_OUT,
+
+	/* SCALERC 400 ~ 499 */
+	IS_ERROR_SCALERC_PWRDN_FAIL	= 400,
+
+	/* ODC 500 ~ 599 */
+	IS_ERROR_ODC_PWRDN_FAIL		= 500,
+
+	/* DIS 600 ~ 699 */
+	IS_ERROR_DIS_PWRDN_FAIL		= 600,
+
+	/* TDNR 700 ~ 799 */
+	IS_ERROR_TDNR_PWRDN_FAIL	= 700,
+
+	/* SCALERC 800 ~ 899 */
+	IS_ERROR_SCALERP_PWRDN_FAIL	= 800,
+
+	/* FD 900 ~ 999 */
+	IS_ERROR_FD_PWRDN_FAIL		= 900,
+	IS_ERROR_FD_MULTIPLE_INPUT,
+	IS_ERROR_FD_ABSENT_INPUT,
+	IS_ERROR_FD_NONADJACENT_INPUT,
+	IS_ERROR_LHFD_FRAME_END_TIME_OUT,
+
+	IS_ERROR_UNKNOWN		= 1000,
+};
+
+#define IS_ERROR_TIME_OUT_FLAG	0x80000000
+
+/* Set parameter error enum */
+enum fimc_is_error {
+	/* Common error (0~99) */
+	ERROR_COMMON_NONE		= 0,
+	ERROR_COMMON_CMD		= 1,	/* Invalid command */
+	ERROR_COMMON_PARAMETER		= 2,	/* Invalid parameter */
+	/* setfile is not loaded before adjusting */
+	ERROR_COMMON_SETFILE_LOAD	= 3,
+	/* setfile is not Adjusted before runnng. */
+	ERROR_COMMON_SETFILE_ADJUST	= 4,
+	/* Index of setfile is not valid (0~MAX_SETFILE_NUM-1) */
+	ERROR_COMMON_SETFILE_INDEX	= 5,
+	/* Input path can be changed in ready state(stop) */
+	ERROR_COMMON_INPUT_PATH		= 6,
+	/* IP can not start if input path is not set */
+	ERROR_COMMON_INPUT_INIT		= 7,
+	/* Output path can be changed in ready state (stop) */
+	ERROR_COMMON_OUTPUT_PATH	= 8,
+	/* IP can not start if output path is not set */
+	ERROR_COMMON_OUTPUT_INIT	= 9,
+
+	ERROR_CONTROL_NONE		= ERROR_COMMON_NONE,
+	ERROR_CONTROL_BYPASS		= 11,	/* Enable or Disable */
+
+	ERROR_OTF_INPUT_NONE		= ERROR_COMMON_NONE,
+	ERROR_OTF_INPUT_CMD		= 21,
+	/* invalid format  (DRC: YUV444, FD: YUV444, 422, 420) */
+	ERROR_OTF_INPUT_FORMAT		= 22,
+	/* invalid width (DRC: 128~8192, FD: 32~8190) */
+	ERROR_OTF_INPUT_WIDTH		= 23,
+	/* invalid height (DRC: 64~8192, FD: 16~8190) */
+	ERROR_OTF_INPUT_HEIGHT		= 24,
+	/* invalid bit-width (DRC: 8~12bits, FD: 8bit) */
+	ERROR_OTF_INPUT_BIT_WIDTH	= 25,
+	/* invalid FrameTime for ISP */
+	ERROR_OTF_INPUT_USER_FRAMETIIME	= 26,
+
+	ERROR_DMA_INPUT_NONE		= ERROR_COMMON_NONE,
+	/* invalid width (DRC: 128~8192, FD: 32~8190) */
+	ERROR_DMA_INPUT_WIDTH		= 31,
+	/* invalid height (DRC: 64~8192, FD: 16~8190) */
+	ERROR_DMA_INPUT_HEIGHT		= 32,
+	/* invalid format (DRC: YUV444 or YUV422, FD: YUV444, 422, 420) */
+	ERROR_DMA_INPUT_FORMAT		= 33,
+	/* invalid bit-width (DRC: 8~12bit, FD: 8bit) */
+	ERROR_DMA_INPUT_BIT_WIDTH	= 34,
+	/* invalid order(DRC: YYCbCrorYCbYCr, FD:NO,YYCbCr,YCbYCr,CbCr,CrCb) */
+	ERROR_DMA_INPUT_ORDER		= 35,
+	/* invalid palne (DRC: 3, FD: 1, 2, 3) */
+	ERROR_DMA_INPUT_PLANE		= 36,
+
+	ERROR_OTF_OUTPUT_NONE		= ERROR_COMMON_NONE,
+	/* invalid width (DRC: 128~8192) */
+	ERROR_OTF_OUTPUT_WIDTH		= 41,
+	/* invalid height (DRC: 64~8192) */
+	ERROR_OTF_OUTPUT_HEIGHT		= 42,
+	/* invalid format (DRC: YUV444) */
+	ERROR_OTF_OUTPUT_FORMAT		= 43,
+	/* invalid bit-width (DRC: 8~12bits) */
+	ERROR_OTF_OUTPUT_BIT_WIDTH	= 44,
+
+	ERROR_DMA_OUTPUT_NONE		= ERROR_COMMON_NONE,
+	ERROR_DMA_OUTPUT_WIDTH		= 51,	/* invalid width */
+	ERROR_DMA_OUTPUT_HEIGHT		= 52,	/* invalid height */
+	ERROR_DMA_OUTPUT_FORMAT		= 53,	/* invalid format */
+	ERROR_DMA_OUTPUT_BIT_WIDTH	= 54,	/* invalid bit-width */
+	ERROR_DMA_OUTPUT_PLANE		= 55,	/* invalid plane */
+	ERROR_DMA_OUTPUT_ORDER		= 56,	/* invalid order */
+
+	ERROR_GLOBAL_SHOTMODE_NONE	= ERROR_COMMON_NONE,
+
+	/* SENSOR Error(100~199) */
+	ERROR_SENSOR_NONE		= ERROR_COMMON_NONE,
+	ERROR_SENSOR_I2C_FAIL		= 101,
+	ERROR_SENSOR_INVALID_FRAMERATE,
+	ERROR_SENSOR_INVALID_EXPOSURETIME,
+	ERROR_SENSOR_INVALID_SIZE,
+	ERROR_SENSOR_INVALID_SETTING,
+	ERROR_SENSOR_ACTURATOR_INIT_FAIL,
+	ERROR_SENSOR_INVALID_AF_POS,
+	ERROR_SENSOR_UNSUPPORT_FUNC,
+	ERROR_SENSOR_UNSUPPORT_PERI,
+	ERROR_SENSOR_UNSUPPORT_AF,
+
+	/* ISP Error (200~299) */
+	ERROR_ISP_AF_NONE		= ERROR_COMMON_NONE,
+	ERROR_ISP_AF_BUSY		= 201,
+	ERROR_ISP_AF_INVALID_COMMAND	= 202,
+	ERROR_ISP_AF_INVALID_MODE	= 203,
+	ERROR_ISP_FLASH_NONE		= ERROR_COMMON_NONE,
+	ERROR_ISP_AWB_NONE		= ERROR_COMMON_NONE,
+	ERROR_ISP_IMAGE_EFFECT_NONE	= ERROR_COMMON_NONE,
+	ERROR_ISP_ISO_NONE		= ERROR_COMMON_NONE,
+	ERROR_ISP_ADJUST_NONE		= ERROR_COMMON_NONE,
+	ERROR_ISP_METERING_NONE		= ERROR_COMMON_NONE,
+	ERROR_ISP_AFC_NONE		= ERROR_COMMON_NONE,
+
+	/* DRC Error (300~399) */
+
+	/* FD Error  (400~499) */
+	ERROR_FD_NONE					= ERROR_COMMON_NONE,
+	/* Invalid max number (1~16) */
+	ERROR_FD_CONFIG_MAX_NUMBER_STATE		= 401,
+	ERROR_FD_CONFIG_MAX_NUMBER_INVALID		= 402,
+	ERROR_FD_CONFIG_YAW_ANGLE_STATE			= 403,
+	ERROR_FD_CONFIG_YAW_ANGLE_INVALID		= 404,
+	ERROR_FD_CONFIG_ROLL_ANGLE_STATE		= 405,
+	ERROR_FD_CONFIG_ROLL_ANGLE_INVALID		= 406,
+	ERROR_FD_CONFIG_SMILE_MODE_INVALID		= 407,
+	ERROR_FD_CONFIG_BLINK_MODE_INVALID		= 408,
+	ERROR_FD_CONFIG_EYES_DETECT_INVALID		= 409,
+	ERROR_FD_CONFIG_MOUTH_DETECT_INVALID		= 410,
+	ERROR_FD_CONFIG_ORIENTATION_STATE		= 411,
+	ERROR_FD_CONFIG_ORIENTATION_INVALID		= 412,
+	ERROR_FD_CONFIG_ORIENTATION_VALUE_INVALID	= 413,
+	/* PARAM_FdResultStr can be only applied in ready-state or stream off */
+	ERROR_FD_RESULT					= 414,
+	/* PARAM_FdModeStr can be only applied in ready-state or stream off */
+	ERROR_FD_MODE					= 415,
+	/* Scaler Error  (500 ~ 599) */
+	ERROR_SCALER_NO_NONE				= ERROR_COMMON_NONE,
+	ERROR_SCALER_DMA_OUTSEL				= 501,
+	ERROR_SCALER_H_RATIO				= 502,
+	ERROR_SCALER_V_RATIO				= 503,
+
+	ERROR_SCALER_IMAGE_EFFECT			= 510,
+
+	ERROR_SCALER_ROTATE				= 520,
+	ERROR_SCALER_FLIP				= 521,
+};
+
+const char * const fimc_is_strerr(unsigned int error);
+const char * const fimc_is_param_strerr(unsigned int error);
+
+#endif /* FIMC_IS_ERR_H_ */
diff --git a/drivers/media/platform/s5p-fimc/fimc-is-regs.c b/drivers/media/platform/s5p-fimc/fimc-is-regs.c
new file mode 100644
index 0000000..53f0250
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-is-regs.c
@@ -0,0 +1,242 @@
+/*
+ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
+ *
+ * Authors: Younghwan Joo <yhwan.joo@samsung.com>
+ *          Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/delay.h>
+
+#include "fimc-is.h"
+#include "fimc-is-command.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-sensor.h"
+
+void fimc_is_fw_clear_irq1(struct fimc_is *is, unsigned int nr)
+{
+	mcuctl_write(1UL << nr, is, MCUCTL_REG_INTCR1);
+}
+
+void fimc_is_fw_clear_irq2(struct fimc_is *is)
+{
+	u32 cfg = mcuctl_read(is, MCUCTL_REG_INTSR2);
+	mcuctl_write(cfg, is, MCUCTL_REG_INTCR2);
+}
+
+void fimc_is_hw_set_intgr0_gd0(struct fimc_is *is)
+{
+	mcuctl_write(INTGR0_INTGD(0), is, MCUCTL_REG_INTGR0);
+}
+
+int fimc_is_hw_wait_intsr0_intsd0(struct fimc_is *is)
+{
+	unsigned int timeout = 2000;
+	u32 cfg, status;
+
+	cfg = mcuctl_read(is, MCUCTL_REG_INTSR0);
+	status = INTSR0_GET_INTSD(0, cfg);
+
+	while (status) {
+		cfg = mcuctl_read(is, MCUCTL_REG_INTSR0);
+		status = INTSR0_GET_INTSD(0, cfg);
+		if (timeout == 0) {
+			dev_warn(&is->pdev->dev, "%s timeout\n",
+				 __func__);
+			return -ETIME;
+		}
+		timeout--;
+		udelay(1);
+	}
+	return 0;
+}
+
+int fimc_is_hw_wait_intmsr0_intmsd0(struct fimc_is *is)
+{
+	unsigned int timeout = 2000;
+	u32 cfg, status;
+
+	cfg = mcuctl_read(is, MCUCTL_REG_INTMSR0);
+	status = INTMSR0_GET_INTMSD(0, cfg);
+
+	while (status) {
+		cfg = mcuctl_read(is, MCUCTL_REG_INTMSR0);
+		status = INTMSR0_GET_INTMSD(0, cfg);
+		if (timeout == 0) {
+			dev_warn(&is->pdev->dev, "%s timeout\n",
+				 __func__);
+			return -ETIME;
+		}
+		timeout--;
+		udelay(1);
+	}
+	return 0;
+}
+
+int fimc_is_hw_set_param(struct fimc_is *is)
+{
+	struct is_config_param *cfg = &is->cfg_param[is->scenario_id];
+
+	fimc_is_hw_wait_intmsr0_intmsd0(is);
+
+	mcuctl_write(FIMC_IS_HIC_SET_PARAMETER, is, MCUCTL_REG_ISSR(0));
+	mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1));
+	mcuctl_write(is->scenario_id, is, MCUCTL_REG_ISSR(2));
+
+	mcuctl_write(atomic_read(&cfg->p_region_num), is, MCUCTL_REG_ISSR(3));
+	mcuctl_write(cfg->p_region_index1, is, MCUCTL_REG_ISSR(4));
+	mcuctl_write(cfg->p_region_index2, is, MCUCTL_REG_ISSR(5));
+
+	fimc_is_hw_set_intgr0_gd0(is);
+	return 0;
+}
+
+int fimc_is_hw_set_tune(struct fimc_is *is)
+{
+	fimc_is_hw_wait_intmsr0_intmsd0(is);
+
+	mcuctl_write(FIMC_IS_HIC_SET_TUNE, is, MCUCTL_REG_ISSR(0));
+	mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1));
+	mcuctl_write(is->h2i_cmd.entry_id, is, MCUCTL_REG_ISSR(2));
+
+	fimc_is_hw_set_intgr0_gd0(is);
+	return 0;
+}
+
+#define FIMC_IS_MAX_PARAMS	4
+
+int fimc_is_hw_get_params(struct fimc_is *is, unsigned int num_args)
+{
+	int i;
+
+	if (num_args > FIMC_IS_MAX_PARAMS)
+		return -EINVAL;
+
+	is->i2h_cmd.num_args = num_args;
+
+	for (i = 0; i < FIMC_IS_MAX_PARAMS; i++) {
+		if (i < num_args)
+			is->i2h_cmd.args[i] = mcuctl_read(is,
+					MCUCTL_REG_ISSR(12 + i));
+		else
+			is->i2h_cmd.args[i] = 0;
+	}
+	return 0;
+}
+
+void fimc_is_hw_set_sensor_num(struct fimc_is *is)
+{
+	pr_debug("setting sensor index to: %d\n", is->sensor_index);
+
+	mcuctl_write(FIMC_IS_REPLY_DONE, is, MCUCTL_REG_ISSR(0));
+	mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1));
+	mcuctl_write(FIMC_IS_IHC_GET_SENSOR_NUM, is, MCUCTL_REG_ISSR(2));
+	mcuctl_write(FIMC_IS_SENSOR_NUM, is, MCUCTL_REG_ISSR(3));
+}
+
+void fimc_is_hw_close_sensor(struct fimc_is *is, unsigned int index)
+{
+	if (is->sensor_index != index)
+		return;
+
+	fimc_is_hw_wait_intmsr0_intmsd0(is);
+	mcuctl_write(FIMC_IS_HIC_CLOSE_SENSOR, is, MCUCTL_REG_ISSR(0));
+	mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1));
+	mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(2));
+	fimc_is_hw_set_intgr0_gd0(is);
+}
+
+void fimc_is_hw_get_setfile_addr(struct fimc_is *is)
+{
+	fimc_is_hw_wait_intmsr0_intmsd0(is);
+	mcuctl_write(FIMC_IS_HIC_GET_SET_FILE_ADDR, is, MCUCTL_REG_ISSR(0));
+	mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1));
+	fimc_is_hw_set_intgr0_gd0(is);
+}
+
+void fimc_is_hw_load_setfile(struct fimc_is *is)
+{
+	fimc_is_hw_wait_intmsr0_intmsd0(is);
+	mcuctl_write(FIMC_IS_HIC_LOAD_SET_FILE, is, MCUCTL_REG_ISSR(0));
+	mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1));
+	fimc_is_hw_set_intgr0_gd0(is);
+}
+
+int fimc_is_hw_change_mode(struct fimc_is *is)
+{
+	const u8 cmd[] = {
+		FIMC_IS_HIC_PREVIEW_STILL, FIMC_IS_HIC_PREVIEW_VIDEO,
+		FIMC_IS_HIC_CAPTURE_STILL, FIMC_IS_HIC_CAPTURE_VIDEO,
+	};
+
+	if (WARN_ON(is->scenario_id > ARRAY_SIZE(cmd)))
+		return -EINVAL;
+
+	mcuctl_write(cmd[is->scenario_id], is, MCUCTL_REG_ISSR(0));
+	mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1));
+	mcuctl_write(is->setfile.sub_index, is, MCUCTL_REG_ISSR(2));
+	fimc_is_hw_set_intgr0_gd0(is);
+	return 0;
+}
+
+void fimc_is_hw_stream_on(struct fimc_is *is)
+{
+	fimc_is_hw_wait_intmsr0_intmsd0(is);
+	mcuctl_write(FIMC_IS_HIC_STREAM_ON, is, MCUCTL_REG_ISSR(0));
+	mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1));
+	mcuctl_write(0, is, MCUCTL_REG_ISSR(2));
+	fimc_is_hw_set_intgr0_gd0(is);
+}
+
+void fimc_is_hw_stream_off(struct fimc_is *is)
+{
+	fimc_is_hw_wait_intmsr0_intmsd0(is);
+	mcuctl_write(FIMC_IS_HIC_STREAM_OFF, is, MCUCTL_REG_ISSR(0));
+	mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1));
+	fimc_is_hw_set_intgr0_gd0(is);
+}
+
+void fimc_is_hw_subip_power_off(struct fimc_is *is)
+{
+	fimc_is_hw_wait_intmsr0_intmsd0(is);
+	mcuctl_write(FIMC_IS_HIC_POWER_DOWN, is, MCUCTL_REG_ISSR(0));
+	mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1));
+	fimc_is_hw_set_intgr0_gd0(is);
+}
+
+int fimc_is_itf_s_param(struct fimc_is *is, bool update)
+{
+	int ret;
+
+	if (update)
+		__is_hw_update_params(is);
+
+	fimc_is_mem_barrier();
+
+	clear_bit(IS_ST_BLOCK_CMD_CLEARED, &is->state);
+	fimc_is_hw_set_param(is);
+	ret = fimc_is_wait_event(is, IS_ST_BLOCK_CMD_CLEARED, 1,
+				FIMC_IS_CONFIG_TIMEOUT);
+	if (ret < 0)
+		dev_err(&is->pdev->dev, "%s() timeout\n", __func__);
+
+	return ret;
+}
+
+int fimc_is_itf_mode_change(struct fimc_is *is)
+{
+	int ret;
+
+	clear_bit(IS_ST_CHANGE_MODE, &is->state);
+	fimc_is_hw_change_mode(is);
+	ret = fimc_is_wait_event(is, IS_ST_CHANGE_MODE, 1,
+				FIMC_IS_CONFIG_TIMEOUT);
+	if (!ret < 0)
+		dev_err(&is->pdev->dev, "%s(): mode change (%d) timeout\n",
+			__func__, is->scenario_id);
+	return ret;
+}
diff --git a/drivers/media/platform/s5p-fimc/fimc-is-regs.h b/drivers/media/platform/s5p-fimc/fimc-is-regs.h
new file mode 100644
index 0000000..5fa249d
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-is-regs.h
@@ -0,0 +1,164 @@
+/*
+ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *
+ * Authors: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *          Younghwan Joo <yhwan.joo@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef FIMC_IS_REG_H_
+#define FIMC_IS_REG_H_
+
+/* WDT_ISP register */
+#define REG_WDT_ISP			0x00170000
+
+/* MCUCTL registers base offset */
+#define MCUCTL_BASE			0x00180000
+
+/* MCU Controller Register */
+#define MCUCTL_REG_MCUCTRL		(MCUCTL_BASE + 0x00)
+#define MCUCTRL_MSWRST			(1 << 0)
+
+/* Boot Base Offset Address Register */
+#define MCUCTL_REG_BBOAR		(MCUCTL_BASE + 0x04)
+
+/* Interrupt Generation Register 0 from Host CPU to VIC */
+#define MCUCTL_REG_INTGR0		(MCUCTL_BASE + 0x08)
+/* __n = 0...9 */
+#define INTGR0_INTGC(__n)		(1 << ((__n) + 16))
+/* __n = 0...5 */
+#define INTGR0_INTGD(__n)		(1 << (__n))
+
+/* Interrupt Clear Register 0 from Host CPU to VIC */
+#define MCUCTL_REG_INTCR0		(MCUCTL_BASE + 0x0c)
+/* __n = 0...9 */
+#define INTCR0_INTGC(__n)		(1 << ((__n) + 16))
+/* __n = 0...5 */
+#define INTCR0_INTCD(__n)		(1 << ((__n) + 16))
+
+/* Interrupt Mask Register 0 from Host CPU to VIC */
+#define MCUCTL_REG_INTMR0		(MCUCTL_BASE + 0x10)
+/* __n = 0...9 */
+#define INTMR0_INTMC(__n)		(1 << ((__n) + 16))
+/* __n = 0...5 */
+#define INTMR0_INTMD(__n)		(1 << (__n))
+
+/* Interrupt Status Register 0 from Host CPU to VIC */
+#define MCUCTL_REG_INTSR0		(MCUCTL_BASE + 0x14)
+/* __n (bit number) = 0...4 */
+#define INTSR0_GET_INTSD(x, __n)	(((x) >> (__n)) & 0x1)
+/* __n (bit number) = 0...9 */
+#define INTSR0_GET_INTSC(x, __n)	(((x) >> ((__n) + 16)) & 0x1)
+
+/* Interrupt Mask Status Register 0 from Host CPU to VIC */
+#define MCUCTL_REG_INTMSR0		(MCUCTL_BASE + 0x18)
+/* __n (bit number) = 0...4 */
+#define INTMSR0_GET_INTMSD(x, __n)	(((x) >> (__n)) & 0x1)
+/* __n (bit number) = 0...9 */
+#define INTMSR0_GET_INTMSC(x, __n)	(((x) >> ((__n) + 16)) & 0x1)
+
+/* Interrupt Generation Register 1 from ISP CPU to Host IC */
+#define MCUCTL_REG_INTGR1		(MCUCTL_BASE + 0x1c)
+/* __n = 0...9 */
+#define INTGR1_INTGC(__n)		(1 << (__n))
+
+/* Interrupt Clear Register 1 from ISP CPU to Host IC */
+#define MCUCTL_REG_INTCR1		(MCUCTL_BASE + 0x20)
+/* __n = 0...9 */
+#define INTCR1_INTCC(__n)		(1 << (__n))
+
+/* Interrupt Mask Register 1 from ISP CPU to Host IC */
+#define MCUCTL_REG_INTMR1		(MCUCTL_BASE + 0x24)
+/* __n = 0...9 */
+#define INTMR1_INTMC(__n)		(1 << (__n))
+
+/* Interrupt Status Register 1 from ISP CPU to Host IC */
+#define MCUCTL_REG_INTSR1		(MCUCTL_BASE + 0x28)
+/* Interrupt Mask Status Register 1 from ISP CPU to Host IC */
+#define MCUCTL_REG_INTMSR1		(MCUCTL_BASE + 0x2c)
+
+/* Interrupt Clear Register 2 from ISP BLK's interrupts to Host IC */
+#define MCUCTL_REG_INTCR2		(MCUCTL_BASE + 0x30)
+/* __n = 0...5 */
+#define INTCR2_INTCC(__n)		(1 << ((__n) + 16))
+
+/* Interrupt Mask Register 2 from ISP BLK's interrupts to Host IC */
+#define MCUCTL_REG_INTMR2		(MCUCTL_BASE + 0x34)
+/* __n = 0...25 */
+#define INTMR2_INTMCIS(__n)		(1 << (__n))
+
+/* Interrupt Status Register 2 from ISP BLK's interrupts to Host IC */
+#define MCUCTL_REG_INTSR2		(MCUCTL_BASE + 0x38)
+/* Interrupt Mask Status Register 2 from ISP BLK's interrupts to Host IC */
+#define MCUCTL_REG_INTMSR2		(MCUCTL_BASE + 0x3c)
+
+/* General Purpose Output Control Register (0~17) */
+#define MCUCTL_REG_GPOCTLR		(MCUCTL_BASE + 0x40)
+/* __n = 0...17 */
+#define GPOCTLR_GPOG(__n)		(1 << (__n))
+
+/* General Purpose Pad Output Enable Register (0~17) */
+#define MCUCTL_REG_GPOENCTLR		(MCUCTL_BASE + 0x44)
+/* __n = 0...17 */
+#define GPOENCTLR_GPOEN(__n)		(1 << (__n))
+
+/* General Purpose Input Control Register (0~17) */
+#define MCUCTL_REG_GPICTLR		(MCUCTL_BASE + 0x48)
+
+/* Shared registers between ISP CPU and the host CPU - ISSRxx */
+
+/* ISSR(1): Command Host -> IS */
+/* ISSR(1): Sensor ID for Command, ISSR2...5 = Parameter 1...4 */
+
+/* ISSR(10): Reply IS -> Host */
+/* ISSR(11): Sensor ID for Reply, ISSR12...15 = Parameter 1...4 */
+
+/* ISSR(20): ISP_FRAME_DONE : SENSOR ID */
+/* ISSR(21): ISP_FRAME_DONE : PARAMETER 1 */
+
+/* ISSR(24): SCALERC_FRAME_DONE : SENSOR ID */
+/* ISSR(25): SCALERC_FRAME_DONE : PARAMETER 1 */
+
+/* ISSR(28): 3DNR_FRAME_DONE : SENSOR ID */
+/* ISSR(29): 3DNR_FRAME_DONE : PARAMETER 1 */
+
+/* ISSR(32): SCALERP_FRAME_DONE : SENSOR ID */
+/* ISSR(33): SCALERP_FRAME_DONE : PARAMETER 1 */
+
+/* __n = 0...63 */
+#define MCUCTL_REG_ISSR(__n)		(MCUCTL_BASE + 0x80 + ((__n) * 4))
+
+/* PMU ISP register offsets definitions */
+#define REG_CMU_RESET_ISP_SYS_PWR_REG	0x1174
+#define REG_CMU_SYSCLK_ISP_SYS_PWR_REG	0x13b8
+#define REG_PMU_ISP_ARM_SYS		0x1050
+#define REG_PMU_ISP_ARM_CONFIGURATION	0x2280
+#define REG_PMU_ISP_ARM_STATUS		0x2284
+#define REG_PMU_ISP_ARM_OPTION		0x2288
+
+void fimc_is_fw_clear_irq1(struct fimc_is *is, unsigned int bit);
+void fimc_is_fw_clear_irq2(struct fimc_is *is);
+int fimc_is_hw_get_params(struct fimc_is *is, unsigned int num);
+
+void fimc_is_hw_set_intgr0_gd0(struct fimc_is *is);
+int fimc_is_hw_wait_intsr0_intsd0(struct fimc_is *is);
+int fimc_is_hw_wait_intmsr0_intmsd0(struct fimc_is *is);
+void fimc_is_hw_set_sensor_num(struct fimc_is *is);
+void fimc_is_hw_stream_on(struct fimc_is *is);
+void fimc_is_hw_stream_off(struct fimc_is *is);
+int fimc_is_hw_set_param(struct fimc_is *is);
+int fimc_is_hw_change_mode(struct fimc_is *is);
+
+void fimc_is_hw_close_sensor(struct fimc_is *is, unsigned int index);
+void fimc_is_hw_get_setfile_addr(struct fimc_is *is);
+void fimc_is_hw_load_setfile(struct fimc_is *is);
+void fimc_is_hw_subip_power_off(struct fimc_is *is);
+
+int fimc_is_itf_s_param(struct fimc_is *is, bool update);
+int fimc_is_itf_mode_change(struct fimc_is *is);
+
+#endif /* FIMC_IS_REG_H_ */
diff --git a/drivers/media/platform/s5p-fimc/fimc-is.c b/drivers/media/platform/s5p-fimc/fimc-is.c
new file mode 100644
index 0000000..670b0f4
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-is.c
@@ -0,0 +1,970 @@
+/*
+ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *
+ * Authors: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *          Younghwan Joo <yhwan.joo@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <linux/bug.h>
+#include <linux/ctype.h>
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/dma-contiguous.h>
+#include <linux/errno.h>
+#include <linux/firmware.h>
+#include <linux/fs.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_i2c.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-of.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "fimc-mdevice.h"
+#include "fimc-is.h"
+#include "fimc-is-command.h"
+#include "fimc-is-errno.h"
+#include "fimc-is-i2c.h"
+#include "fimc-is-param.h"
+#include "fimc-is-regs.h"
+
+static char *fimc_is_clocks[FIMC_IS_MAX_CLOCKS] = {
+	"mpll",
+	"sysreg",
+	"ppmuispx",
+	"ppmuispmx",
+	/* "uart", */
+	"flite0",
+	"flite1",
+};
+
+static void fimc_is_clk_put(struct fimc_is *is)
+{
+	int i;
+	for (i = 0; i < FIMC_IS_MAX_CLOCKS; i++) {
+		if (IS_ERR(is->clocks[i]))
+			continue;
+		clk_unprepare(is->clocks[i]);
+		clk_put(is->clocks[i]);
+		is->clocks[i] = ERR_PTR(-EINVAL);
+	}
+}
+
+static int fimc_is_clk_get(struct fimc_is *is)
+{
+	int i, ret;
+
+	for (i = 0; i < FIMC_IS_MAX_CLOCKS; i++)
+		is->clocks[i] = ERR_PTR(-EINVAL);
+
+	for (i = 0; i < FIMC_IS_MAX_CLOCKS; i++) {
+		is->clocks[i] = clk_get(&is->pdev->dev, fimc_is_clocks[i]);
+		if (IS_ERR(is->clocks[i])) {
+			ret = PTR_ERR(is->clocks[i]);
+			goto err;
+		}
+		ret = clk_prepare(is->clocks[i]);
+		if (ret < 0) {
+			clk_put(is->clocks[i]);
+			is->clocks[i] = ERR_PTR(-EINVAL);
+			goto err;
+		}
+	}
+
+	/* FIXME: ISP UART parent clocks setup */
+	/* clk_set_parent(is->clocks[2], is->clocks[0]); */
+	/* clk_set_rate(is->clocks[2], 50 * 1000000); */
+
+	return 0;
+err:
+	fimc_is_clk_put(is);
+	dev_err(&is->pdev->dev, "failed to get clock: %s\n",
+		fimc_is_clocks[i]);
+	return -ENXIO;
+}
+
+int fimc_is_clk_enable(struct fimc_is *is)
+{
+	int i, ret;
+
+	for (i = 0; i < FIMC_IS_MAX_CLOCKS; i++) {
+		if (IS_ERR(is->clocks[i]))
+			continue;
+		ret = clk_enable(is->clocks[i]);
+		if (ret < 0) {
+			dev_err(&is->pdev->dev, "Clock %s enable failed\n",
+				fimc_is_clocks[i]);
+			for (--i; i >= 0; i--)
+				clk_disable(is->clocks[i]);
+			return ret;
+		}
+		pr_debug("Enabled clock: %s\n", fimc_is_clocks[i]);
+	}
+	return 0;
+}
+
+void fimc_is_clk_disable(struct fimc_is *is)
+{
+	int i;
+
+	for (i = 0; i < FIMC_IS_MAX_CLOCKS; i++) {
+		if (!IS_ERR(is->clocks[i])) {
+			clk_disable(is->clocks[i]);
+			pr_debug("Disabled clock: %s\n", fimc_is_clocks[i]);
+		}
+	}
+}
+
+static int fimc_is_parse_sensor_config(struct fimc_is_sensor *sensor,
+				       struct device_node *np)
+{
+	u32 tmp = 0;
+	int ret;
+
+	np = v4l2_of_get_next_endpoint(np, NULL);
+	if (!np)
+		return -ENXIO;
+	np = v4l2_of_get_remote_port(np);
+	if (!np)
+		return -ENXIO;
+
+	/* Use MIPI-CSIS channel id to determine the ISP I2C bus index. */
+	ret = of_property_read_u32(np, "reg", &tmp);
+	sensor->i2c_bus = tmp - FIMC_INPUT_MIPI_CSI2_0;
+
+	return ret;
+}
+
+static int fimc_is_attach_subdevs(struct fimc_is *is)
+{
+	struct device_node *adapter, *child;
+	int ret = 0;
+
+	ret = fimc_isp_subdev_create(&is->isp);
+	if (ret < 0)
+		return ret;
+
+	for_each_compatible_node(adapter, NULL, FIMC_IS_I2C_COMPATIBLE) {
+		if (!of_find_device_by_node(adapter)) {
+			of_node_put(adapter);
+			return -EPROBE_DEFER;
+		}
+
+		for_each_available_child_of_node(adapter, child) {
+			struct i2c_client *client;
+			struct v4l2_subdev *sd;
+
+			client = of_find_i2c_device_by_node(child);
+			if (!client)
+				goto e_retry;
+
+			sd = i2c_get_clientdata(client);
+			if (!sd)
+				goto e_retry;
+
+			/* FIXME: Add support for multiple sensors */
+			if (WARN_ON(is->sensor))
+				continue;
+
+			is->sensor = v4l2_get_subdevdata(sd);
+
+			if (fimc_is_parse_sensor_config(is->sensor, child)) {
+				dev_warn(&is->pdev->dev, "DT parse error: %s\n",
+							 child->full_name);
+			}
+			pr_debug("%s(): Registered subdev: %p\n",
+				 __func__, sd->name);
+		}
+	}
+	return 0;
+
+e_retry:
+	of_node_put(child);
+	return -EPROBE_DEFER;
+}
+
+static int fimc_is_unregister_subdevs(struct fimc_is *is)
+{
+	fimc_isp_subdev_destroy(&is->isp);
+	is->sensor = NULL;
+	return 0;
+}
+
+static int fimc_is_load_setfile(struct fimc_is *is, char *file_name)
+{
+	const struct firmware *fw;
+	void *buf;
+	int ret;
+
+	ret = request_firmware(&fw, file_name, &is->pdev->dev);
+	if (ret < 0) {
+		dev_err(&is->pdev->dev, "firmware request failed (%d)\n", ret);
+		return ret;
+	}
+	buf = is->memory.vaddr + is->setfile.base;
+	memcpy(buf, fw->data, fw->size);
+	fimc_is_mem_barrier();
+	is->setfile.size = fw->size;
+
+	pr_debug("mem vaddr: %p, setfile buf: %p\n", is->memory.vaddr, buf);
+
+	memcpy(is->fw.setfile_info,
+		fw->data + fw->size - FIMC_IS_SETFILE_INFO_LEN,
+		FIMC_IS_SETFILE_INFO_LEN - 1);
+
+	is->fw.setfile_info[FIMC_IS_SETFILE_INFO_LEN - 1] = '\0';
+	is->setfile.state = 1;
+
+	pr_debug("FIMC-IS setfile loaded: base: %#x, size: %zu B\n",
+		 is->setfile.base, fw->size);
+
+	release_firmware(fw);
+	return ret;
+}
+
+int fimc_is_cpu_set_power(struct fimc_is *is, int on)
+{
+	unsigned int timeout = FIMC_IS_POWER_ON_TIMEOUT;
+
+	if (on) {
+		/* Disable watchdog */
+		mcuctl_write(0, is, REG_WDT_ISP);
+
+		/* Cortex-A5 start address setting */
+		mcuctl_write(is->memory.paddr, is, MCUCTL_REG_BBOAR);
+
+		/* Enable and start Cortex-A5 */
+		pmuisp_write(0x18000, is, REG_PMU_ISP_ARM_OPTION);
+		pmuisp_write(0x1, is, REG_PMU_ISP_ARM_CONFIGURATION);
+	} else {
+		/* A5 power off */
+		pmuisp_write(0x10000, is, REG_PMU_ISP_ARM_OPTION);
+		pmuisp_write(0x0, is, REG_PMU_ISP_ARM_CONFIGURATION);
+
+		while (pmuisp_read(is, REG_PMU_ISP_ARM_STATUS) & 1) {
+			if (timeout == 0)
+				return -ETIME;
+			timeout--;
+			udelay(1);
+		}
+	}
+
+	return 0;
+}
+
+/* Wait until @bit in @is->state is set to @state in the interrupt handler. */
+int fimc_is_wait_event(struct fimc_is *is, unsigned long bit,
+		       unsigned int state, unsigned int timeout)
+{
+
+	int ret = wait_event_timeout(is->irq_queue,
+				     !state ^ test_bit(bit, &is->state),
+				     timeout);
+	if (!ret) {
+		dev_WARN(&is->pdev->dev, "%s() timed out\n", __func__);
+		return -ETIME;
+	}
+	return 0;
+}
+
+int fimc_is_start_firmware(struct fimc_is *is)
+{
+	struct device *dev = &is->pdev->dev;
+	int ret;
+
+	memcpy(is->memory.vaddr, is->fw.f_w->data, is->fw.f_w->size);
+	wmb();
+
+	ret = fimc_is_cpu_set_power(is, 1);
+	if (ret < 0)
+		return ret;
+
+	ret = fimc_is_wait_event(is, IS_ST_A5_PWR_ON, 1,
+				 msecs_to_jiffies(FIMC_IS_FW_LOAD_TIMEOUT));
+	if (ret < 0)
+		dev_err(dev, "FIMC-IS CPU power on failed\n");
+
+	return ret;
+}
+
+/* Allocate working memory for the FIMC-IS CPU */
+static int fimc_is_alloc_cpu_memory(struct fimc_is *is)
+{
+	struct device *dev = &is->pdev->dev;
+
+	is->memory.vaddr = dma_alloc_coherent(dev, FIMC_IS_CPU_MEM_SIZE,
+					      &is->memory.paddr, GFP_KERNEL);
+	if (is->memory.vaddr == NULL)
+		return -ENOMEM;
+
+	is->memory.size = FIMC_IS_CPU_MEM_SIZE;
+	memset(is->memory.vaddr, 0, is->memory.size);
+
+	dev_info(dev, "FIMC-IS CPU memory base: %#x\n", (u32)is->memory.paddr);
+
+	if (((u32)is->memory.paddr) & FIMC_IS_FW_ADDR_MASK) {
+		dev_err(dev, "invalid firmware memory alignment: %#x\n",
+			(u32)is->memory.paddr);
+		dma_free_coherent(dev, is->memory.size, is->memory.vaddr,
+				  is->memory.paddr);
+		return -EIO;
+	}
+
+	is->is_p_region = (struct is_region *)(is->memory.vaddr +
+				FIMC_IS_CPU_MEM_SIZE - FIMC_IS_REGION_SIZE);
+
+	is->is_dma_p_region = is->memory.paddr +
+				FIMC_IS_CPU_MEM_SIZE - FIMC_IS_REGION_SIZE;
+
+	is->is_shared_region = (struct is_share_region *)(is->memory.vaddr +
+				FIMC_IS_SHARED_REGION_OFFSET);
+	return 0;
+}
+
+static void fimc_is_free_cpu_memory(struct fimc_is *is)
+{
+	struct device *dev = &is->pdev->dev;
+
+	dma_free_coherent(dev, is->memory.size, is->memory.vaddr,
+			  is->memory.paddr);
+}
+
+static void fimc_is_load_firmware(const struct firmware *fw, void *context)
+{
+	struct fimc_is *is = context;
+	struct device *dev = &is->pdev->dev;
+	void *buf;
+	int ret;
+
+	if (fw == NULL) {
+		dev_err(dev, "firmware request failed\n");
+		return;
+	}
+	mutex_lock(&is->lock);
+
+	if (fw->size < FIMC_IS_FW_SIZE_MIN || fw->size > FIMC_IS_FW_SIZE_MAX) {
+		dev_err(dev, "wrong firmware size: %d\n", fw->size);
+		goto done;
+	}
+
+	is->fw.size = fw->size;
+
+	ret = fimc_is_alloc_cpu_memory(is);
+	if (ret < 0) {
+		dev_err(dev, "failed to allocate FIMC-IS CPU memory\n");
+		goto done;
+	}
+
+	memcpy(is->memory.vaddr, fw->data, fw->size);
+	wmb();
+
+	/* Read firmware description */
+	buf = (void *)(is->memory.vaddr + fw->size - FIMC_IS_FW_DESC_LEN);
+	memcpy(&is->fw.info, buf, FIMC_IS_FW_INFO_LEN);
+	is->fw.info[FIMC_IS_FW_INFO_LEN] = 0;
+
+	buf = (void *)(is->memory.vaddr + fw->size - FIMC_IS_FW_VER_LEN);
+	memcpy(&is->fw.version, buf, FIMC_IS_FW_VER_LEN);
+	is->fw.version[FIMC_IS_FW_VER_LEN - 1] = 0;
+
+	is->fw.state = 1;
+
+	dev_info(dev, "loaded firmware: %s, rev. %s\n",
+		 is->fw.info, is->fw.version);
+	dev_dbg(dev, "FW size: %d, paddr: %#x\n", fw->size, is->memory.paddr);
+
+	is->is_shared_region->chip_id = 0xe4412;
+	is->is_shared_region->chip_rev_no = 1;
+
+	fimc_is_mem_barrier();
+
+	/*
+	 * FIXME: The firmware is not being released for now, as it is
+	 * needed around for copying to the IS working memory every
+	 * time before the Cortex-A5 is restarted.
+	 */
+	if (is->fw.f_w)
+		release_firmware(is->fw.f_w);
+	is->fw.f_w = fw;
+done:
+	mutex_unlock(&is->lock);
+}
+
+static int fimc_is_request_firmware(struct fimc_is *is, const char *fw_name)
+{
+	return request_firmware_nowait(THIS_MODULE,
+				FW_ACTION_HOTPLUG, fw_name, &is->pdev->dev,
+				GFP_KERNEL, is, fimc_is_load_firmware);
+}
+
+/* General IS interrupt handler */
+static void fimc_is_general_irq_handler(struct fimc_is *is)
+{
+	is->i2h_cmd.cmd = mcuctl_read(is, MCUCTL_REG_ISSR(10));
+
+	switch (is->i2h_cmd.cmd) {
+	case FIMC_IS_IHC_GET_SENSOR_NUM:
+		fimc_is_hw_get_params(is, 1);
+		fimc_is_hw_wait_intmsr0_intmsd0(is);
+		fimc_is_hw_set_sensor_num(is);
+		pr_debug("ISP FW version: %#x\n", is->i2h_cmd.args[0]);
+		break;
+	case FIMC_IS_IHC_SET_FACE_MARK:
+	case FIMC_IS_IHC_FRAME_DONE:
+		fimc_is_hw_get_params(is, 2);
+		break;
+	case FIMC_IS_IHC_SET_SHOT_MARK:
+	case FIMC_IS_IHC_AA_DONE:
+	case FIMC_IS_REPLY_DONE:
+		fimc_is_hw_get_params(is, 3);
+		break;
+	case FIMC_IS_REPLY_NOT_DONE:
+		fimc_is_hw_get_params(is, 4);
+		break;
+	case FIMC_IS_IHC_NOT_READY:
+		break;
+	default:
+		pr_info("Unknown command: %#x\n", is->i2h_cmd.cmd);
+	}
+
+	fimc_is_fw_clear_irq1(is, 0);
+
+	switch (is->i2h_cmd.cmd) {
+	case FIMC_IS_IHC_GET_SENSOR_NUM:
+		fimc_is_hw_set_intgr0_gd0(is);
+		set_bit(IS_ST_A5_PWR_ON, &is->state);
+		break;
+
+	case FIMC_IS_IHC_SET_SHOT_MARK:
+		break;
+
+	case FIMC_IS_IHC_SET_FACE_MARK:
+		is->fd_header.count = is->i2h_cmd.args[0];
+		is->fd_header.index = is->i2h_cmd.args[1];
+		is->fd_header.offset = 0;
+		break;
+
+	case FIMC_IS_IHC_FRAME_DONE:
+		break;
+
+	case FIMC_IS_IHC_AA_DONE:
+		pr_debug("AA_DONE - %d, %d, %d\n", is->i2h_cmd.args[0],
+			 is->i2h_cmd.args[1], is->i2h_cmd.args[2]);
+		break;
+
+	case FIMC_IS_REPLY_DONE:
+		pr_debug("ISR_DONE: args[0]: %#x\n", is->i2h_cmd.args[0]);
+
+		switch (is->i2h_cmd.args[0]) {
+		case FIMC_IS_HIC_PREVIEW_STILL...FIMC_IS_HIC_CAPTURE_VIDEO:
+			/* Get CAC margin */
+			set_bit(IS_ST_CHANGE_MODE, &is->state);
+			is->isp.cac_margin_x = is->i2h_cmd.args[1];
+			is->isp.cac_margin_y = is->i2h_cmd.args[2];
+			pr_debug("CAC margin (x,y): (%d,%d)\n",
+				 is->isp.cac_margin_x, is->isp.cac_margin_y);
+			break;
+
+		case FIMC_IS_HIC_STREAM_ON:
+			clear_bit(IS_ST_STREAM_OFF, &is->state);
+			set_bit(IS_ST_STREAM_ON, &is->state);
+			break;
+
+		case FIMC_IS_HIC_STREAM_OFF:
+			clear_bit(IS_ST_STREAM_ON, &is->state);
+			set_bit(IS_ST_STREAM_OFF, &is->state);
+			break;
+
+		case FIMC_IS_HIC_SET_PARAMETER:
+			is->cfg_param[is->scenario_id].p_region_index1 = 0;
+			is->cfg_param[is->scenario_id].p_region_index2 = 0;
+			atomic_set(&is->cfg_param[is->scenario_id].p_region_num, 0);
+			set_bit(IS_ST_BLOCK_CMD_CLEARED, &is->state);
+			pr_debug("HIC_SET_PARAMETER\n");
+			break;
+
+		case FIMC_IS_HIC_GET_PARAMETER:
+			break;
+
+		case FIMC_IS_HIC_SET_TUNE:
+			break;
+
+		case FIMC_IS_HIC_GET_STATUS:
+			break;
+
+		case FIMC_IS_HIC_OPEN_SENSOR:
+			set_bit(IS_ST_OPEN_SENSOR, &is->state);
+			pr_debug("Data lanes: %d, settle line: %d\n",
+				 is->i2h_cmd.args[2], is->i2h_cmd.args[1]);
+			break;
+
+		case FIMC_IS_HIC_CLOSE_SENSOR:
+			clear_bit(IS_ST_OPEN_SENSOR, &is->state);
+			is->sensor_index = 0;
+			break;
+
+		case FIMC_IS_HIC_MSG_TEST:
+			pr_debug("Config MSG level completed\n");
+			break;
+
+		case FIMC_IS_HIC_POWER_DOWN:
+			clear_bit(IS_ST_PWR_SUBIP_ON, &is->state);
+			break;
+
+		case FIMC_IS_HIC_GET_SET_FILE_ADDR:
+			is->setfile.base = is->i2h_cmd.args[1];
+			set_bit(IS_ST_SETFILE_LOADED, &is->state);
+			break;
+
+		case FIMC_IS_HIC_LOAD_SET_FILE:
+			set_bit(IS_ST_SETFILE_LOADED, &is->state);
+			break;
+		}
+		break;
+
+	case FIMC_IS_REPLY_NOT_DONE:
+		pr_err("ISR_NDONE: %d: %#x, %s\n", is->i2h_cmd.args[0],
+		       is->i2h_cmd.args[1],
+		       fimc_is_strerr(is->i2h_cmd.args[1]));
+
+		if (is->i2h_cmd.args[1] & IS_ERROR_TIME_OUT_FLAG)
+			pr_err("IS_ERROR_TIME_OUT\n");
+
+		switch (is->i2h_cmd.args[1]) {
+		case IS_ERROR_SET_PARAMETER:
+			fimc_is_mem_barrier();
+		}
+
+		switch (is->i2h_cmd.args[0]) {
+		case FIMC_IS_HIC_SET_PARAMETER:
+			is->cfg_param[is->scenario_id].p_region_index1 = 0;
+			is->cfg_param[is->scenario_id].p_region_index2 = 0;
+			atomic_set(&is->cfg_param[is->scenario_id].p_region_num, 0);
+			set_bit(IS_ST_BLOCK_CMD_CLEARED, &is->state);
+			break;
+		}
+		break;
+
+	case FIMC_IS_IHC_NOT_READY:
+		pr_err("IS control sequence error: Not Ready\n");
+		break;
+	}
+
+	wake_up(&is->irq_queue);
+}
+
+static irqreturn_t fimc_is_irq_handler(int irq, void *priv)
+{
+	struct fimc_is *is = priv;
+	unsigned long flags;
+	u32 status;
+
+	spin_lock_irqsave(&is->slock, flags);
+	status = mcuctl_read(is, MCUCTL_REG_INTSR1);
+
+	if (status & FIMC_IS_INT_GENERAL)
+		fimc_is_general_irq_handler(is);
+
+	if (status & FIMC_IS_INT_ISP_FRAME_DONE)
+		fimc_isp_irq_handler(is);
+
+	spin_unlock_irqrestore(&is->slock, flags);
+	return IRQ_HANDLED;
+}
+
+static int fimc_is_hw_open_sensor(struct fimc_is *is,
+				  struct fimc_is_sensor *sensor)
+{
+	struct sensor_open_extended *soe = (void *)&is->is_p_region->shared;
+
+	fimc_is_hw_wait_intmsr0_intmsd0(is);
+
+	soe->self_calibration_mode = 1;
+	soe->actuator_type = 0;
+	soe->mipi_lane_num = 0;
+	soe->mclk = 0;
+	soe->mipi_speed	= 0;
+	soe->fast_open_sensor = 0;
+	soe->i2c_sclk = 88000000;
+
+	fimc_is_mem_barrier();
+
+	mcuctl_write(FIMC_IS_HIC_OPEN_SENSOR, is, MCUCTL_REG_ISSR(0));
+	mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1));
+	mcuctl_write(sensor->drvdata->id, is, MCUCTL_REG_ISSR(2));
+	mcuctl_write(sensor->i2c_bus, is, MCUCTL_REG_ISSR(3));
+	mcuctl_write(is->is_dma_p_region, is, MCUCTL_REG_ISSR(4));
+
+	fimc_is_hw_set_intgr0_gd0(is);
+
+	return fimc_is_wait_event(is, IS_ST_OPEN_SENSOR, 1,
+				  FIMC_IS_SENSOR_OPEN_TIMEOUT);
+}
+
+
+int fimc_is_hw_initialize(struct fimc_is *is)
+{
+	const int scenario_ids[] = {
+		IS_SC_PREVIEW_STILL, IS_SC_PREVIEW_VIDEO,
+		IS_SC_CAPTURE_STILL, IS_SC_CAPTURE_VIDEO
+	};
+	struct v4l2_subdev *sensor = &is->sensor->subdev;
+	struct device *dev = &is->pdev->dev;
+	u32 prev_id;
+	int i, ret;
+
+	/* Sensor power up */
+	ret = v4l2_subdev_call(sensor, core, s_power, 1);
+	if (ret < 0 && ret != -ENOIOCTLCMD)
+		return ret;
+
+	msleep(20);
+
+	/* Sensor initialization */
+	ret = fimc_is_hw_open_sensor(is, is->sensor);
+	if (ret < 0)
+		return ret;
+
+	/* Get the setfile address. */
+	fimc_is_hw_get_setfile_addr(is);
+
+	ret = fimc_is_wait_event(is, IS_ST_SETFILE_LOADED, 1,
+				 FIMC_IS_CONFIG_TIMEOUT);
+	if (ret < 0) {
+		dev_err(dev, "Get setfile address timed out\n");
+		return ret;
+	}
+	pr_debug("setfile.base: %#x\n", is->setfile.base);
+
+	/* Load the setfile. */
+	fimc_is_load_setfile(is, FIMC_IS_SETFILE_6A3);
+	clear_bit(IS_ST_SETFILE_LOADED, &is->state);
+	fimc_is_hw_load_setfile(is);
+	ret = fimc_is_wait_event(is, IS_ST_SETFILE_LOADED, 1,
+				 FIMC_IS_CONFIG_TIMEOUT);
+	if (ret < 0) {
+		dev_err(dev, "Loading setfile timed out\n");
+		return ret;
+	}
+
+	pr_debug("setfile: base: %#x, size: %d\n",
+		 is->setfile.base, is->setfile.size);
+	pr_info("FIMC-IS Setfile info: %s\n", is->fw.setfile_info);
+
+	/* Check magic number */
+	if (is->is_p_region->shared[MAX_SHARED_COUNT - 1] !=
+	    FIMC_IS_MAGIC_NUMBER) {
+		dev_err(dev, "Magic number error!\n");
+		return -EIO;
+	}
+
+	pr_debug("Parameter region paddr: %#x\n", is->is_dma_p_region);
+	pr_debug("Shared region paddr: %#x\n", is->memory.paddr +
+					      FIMC_IS_SHARED_REGION_OFFSET);
+	is->setfile.sub_index = 0;
+
+	/* Stream off */
+	fimc_is_hw_stream_off(is);
+	ret = fimc_is_wait_event(is, IS_ST_STREAM_OFF, 1,
+				 FIMC_IS_CONFIG_TIMEOUT);
+	if (ret < 0) {
+		dev_err(dev, "stream off timeout\n");
+		return ret;
+	}
+
+	/* Preserve previous mode */
+	prev_id = is->scenario_id;
+
+	/* Set initial parameter values */
+	for (i = 0; i < ARRAY_SIZE(scenario_ids); i++) {
+		is->scenario_id = scenario_ids[i];
+		fimc_is_set_initial_params(is);
+		ret = fimc_is_itf_s_param(is, true);
+		if (ret < 0) {
+			is->scenario_id = prev_id;
+			return ret;
+		}
+	}
+	is->scenario_id = prev_id;
+
+	set_bit(IS_ST_INIT_DONE, &is->state);
+	pr_info("Init sequence completed! (%d)\n", is->scenario_id);
+
+	return 0;
+}
+
+static int fimc_is_log_show(struct seq_file *s, void *data)
+{
+	struct fimc_is *is = s->private;
+	const u8 *buf = is->memory.vaddr + FIMC_IS_DEBUG_REGION_OFFSET;
+
+	if (is->memory.vaddr == NULL) {
+		dev_err(&is->pdev->dev, "Firmware memory is not initalized\n");
+		return -EIO;
+	}
+
+	seq_printf(s, "%s\n", buf);
+	return 0;
+}
+
+static int fimc_is_debugfs_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, fimc_is_log_show, inode->i_private);
+}
+
+static const struct file_operations fimc_is_debugfs_fops = {
+	.open		= fimc_is_debugfs_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static void fimc_is_debugfs_remove(struct fimc_is *is)
+{
+	debugfs_remove(is->debugfs_entry);
+	is->debugfs_entry = NULL;
+}
+
+static int fimc_is_debugfs_create(struct fimc_is *is)
+{
+	struct dentry *dentry;
+
+	is->debugfs_entry = debugfs_create_dir("fimc_is", NULL);
+
+	dentry = debugfs_create_file("fw_log", S_IRUGO, is->debugfs_entry,
+				     is, &fimc_is_debugfs_fops);
+	if (!dentry)
+		fimc_is_debugfs_remove(is);
+
+	return is->debugfs_entry == NULL ? -EIO : 0;
+}
+
+static int fimc_is_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct fimc_is *is;
+	struct resource res;
+	struct device_node *node;
+	int irq, ret;
+
+	is = devm_kzalloc(&pdev->dev, sizeof(*is), GFP_KERNEL);
+	if (!is)
+		return -ENOMEM;
+
+	is->pdev = pdev;
+
+	init_waitqueue_head(&is->irq_queue);
+	spin_lock_init(&is->slock);
+	mutex_init(&is->lock);
+
+	ret = of_address_to_resource(dev->of_node, 0, &res);
+	if (ret < 0)
+		return ret;
+
+	is->regs = devm_ioremap_resource(dev, &res);
+	if (IS_ERR(is->regs))
+		return PTR_ERR(is->regs);
+
+	node = of_get_child_by_name(dev->of_node, "pmu");
+	if (!node)
+		return -ENODEV;
+	is->pmu_regs = of_iomap(node, 0);
+	if (!is->pmu_regs)
+		return -ENOMEM;
+
+	irq = irq_of_parse_and_map(dev->of_node, 0);
+	if (irq < 0) {
+		dev_err(dev, "no irq found\n");
+		return irq;
+	}
+
+	ret = fimc_is_clk_get(is);
+	if (ret < 0)
+		return ret;
+
+	platform_set_drvdata(pdev, is);
+
+	ret = devm_request_irq(dev, irq, fimc_is_irq_handler, 0,
+						dev_name(dev), is);
+	if (ret < 0) {
+		dev_err(dev, "irq request failed\n");
+		goto err_clk;
+	}
+	pm_runtime_enable(dev);
+
+	ret = pm_runtime_get_sync(dev);
+	if (ret < 0)
+		goto err_sd;
+
+	is->alloc_ctx = vb2_dma_contig_init_ctx(dev);
+	if (IS_ERR(is->alloc_ctx)) {
+		ret = PTR_ERR(is->alloc_ctx);
+		goto err_pm;
+	}
+	/*
+	 * Register FIMC-IS V4L2 subdevs to this driver. The video nodes
+	 * will be created within the subdev's registered() callback.
+	 */
+	ret = fimc_is_attach_subdevs(is);
+	if (ret < 0)
+		goto err_vb;
+	/*
+	 * Set pinctrl default state - initialize ISP UART,
+	 * I2C0/1... pins.
+	 */
+	is->pctrl = devm_pinctrl_get_select_default(dev);
+	if (IS_ERR(is->pctrl)) {
+		ret = PTR_ERR(is->pctrl);
+		goto err_vb;
+	}
+
+	ret = fimc_is_debugfs_create(is);
+	if (ret < 0)
+		goto err_vb;
+
+	ret = fimc_is_request_firmware(is, FIMC_IS_FW_FILENAME);
+	if (ret < 0)
+		goto err_dfs;
+
+	pm_runtime_put(dev);
+
+	dev_dbg(dev, "FIMC-IS registered successfully\n");
+	return 0;
+
+err_dfs:
+	fimc_is_debugfs_remove(is);
+err_vb:
+	vb2_dma_contig_cleanup_ctx(is->alloc_ctx);
+err_pm:
+	pm_runtime_put(dev);
+err_sd:
+	fimc_is_unregister_subdevs(is);
+err_clk:
+	fimc_is_clk_put(is);
+	return ret;
+}
+
+static int fimc_is_runtime_resume(struct device *dev)
+{
+	struct fimc_is *is = dev_get_drvdata(dev);
+	return fimc_is_clk_enable(is);
+}
+
+static int fimc_is_runtime_suspend(struct device *dev)
+{
+	/* TODO: power down sequence */
+	struct fimc_is *is = dev_get_drvdata(dev);
+
+	fimc_is_clk_disable(is);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int fimc_is_resume(struct device *dev)
+{
+	/* TODO: */
+	return 0;
+}
+
+static int fimc_is_suspend(struct device *dev)
+{
+	/* TODO: */
+	return -EBUSY;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static int fimc_is_remove(struct platform_device *pdev)
+{
+	struct fimc_is *is = platform_get_drvdata(pdev);
+	struct device *dev = &pdev->dev;
+
+	pm_runtime_disable(dev);
+	pm_runtime_set_suspended(dev);
+	fimc_is_unregister_subdevs(is);
+	vb2_dma_contig_cleanup_ctx(is->alloc_ctx);
+	fimc_is_clk_put(is);
+	fimc_is_debugfs_remove(is);
+	release_firmware(is->fw.f_w);
+	fimc_is_free_cpu_memory(is);
+
+	return 0;
+}
+
+static const struct of_device_id fimc_is_of_match[] = {
+	{ .compatible = "samsung,exynos4212-fimc-is" },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, fimc_is_of_match);
+
+static const struct dev_pm_ops fimc_is_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(fimc_is_suspend, fimc_is_resume)
+	SET_RUNTIME_PM_OPS(fimc_is_runtime_suspend, fimc_is_runtime_resume,
+			   NULL)
+};
+
+static struct platform_driver fimc_is_driver = {
+	.probe		= fimc_is_probe,
+	.remove		= fimc_is_remove,
+	.driver = {
+		.of_match_table	= fimc_is_of_match,
+		.name		= FIMC_IS_DRV_NAME,
+		.owner		= THIS_MODULE,
+		.pm		= &fimc_is_pm_ops,
+	}
+};
+
+static int fimc_is_module_init(void)
+{
+	int ret;
+
+	ret = fimc_is_register_sensor_driver();
+	if (ret < 0)
+		return ret;
+
+	ret = fimc_is_register_i2c_driver();
+	if (ret < 0)
+		goto err_sens;
+
+	ret = platform_driver_register(&fimc_is_driver);
+	if (!ret)
+		return ret;
+
+	fimc_is_unregister_i2c_driver();
+err_sens:
+	fimc_is_unregister_sensor_driver();
+	return ret;
+}
+
+static void fimc_is_module_exit(void)
+{
+	platform_driver_unregister(&fimc_is_driver);
+	fimc_is_unregister_i2c_driver();
+	fimc_is_unregister_sensor_driver();
+}
+
+module_init(fimc_is_module_init);
+module_exit(fimc_is_module_exit);
+
+MODULE_ALIAS("platform:" FIMC_IS_DRV_NAME);
diff --git a/drivers/media/platform/s5p-fimc/fimc-is.h b/drivers/media/platform/s5p-fimc/fimc-is.h
new file mode 100644
index 0000000..da99694
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-is.h
@@ -0,0 +1,344 @@
+/*
+ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ *  Younghwan Joo <yhwan.joo@samsung.com>
+ *  Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef FIMC_IS_H_
+#define FIMC_IS_H_
+
+#include <asm/barrier.h>
+#include <linux/bug.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/sizes.h>
+#include <linux/irqreturn.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-ctrls.h>
+
+#include "fimc-isp.h"
+#include "fimc-is-command.h"
+#include "fimc-is-sensor.h"
+#include "fimc-is-param.h"
+#include "fimc-is-regs.h"
+
+#define FIMC_IS_DRV_NAME		"exynos4-fimc-is"
+
+#define FIMC_IS_FW_FILENAME		"fimc_is_fw.bin"
+#define FIMC_IS_SETFILE_6A3		"setfile.bin"
+
+#define FIMC_IS_MAX_CLOCKS		7
+#define FIMC_IS_FW_LOAD_TIMEOUT		1000 /* ms */
+
+#define FIMC_IS_SHUTDOWN_TIMEOUT	(3 * HZ)
+#define FIMC_IS_SHUTDOWN_TIMEOUT_SENSOR	(HZ)
+#define FIMC_IS_SHUTDOWN_TIMEOUT_AF	(3 * HZ)
+#define FIMC_IS_SSTREAM_TIMEOUT		(6 * HZ)
+#define FIMC_IS_POWER_ON_TIMEOUT	1000 /* us */
+
+#define FIMC_IS_SENSOR_NUM		2
+
+/* Memory definitions */
+#define FIMC_IS_CPU_MEM_SIZE		(0xa00000)
+#define FIMC_IS_CPU_BASE_MASK		((1 << 26) - 1)
+#define FIMC_IS_REGION_SIZE		0x5000
+
+#define FIMC_IS_DEBUG_REGION_OFFSET	0x0084b000
+#define FIMC_IS_SHARED_REGION_OFFSET	0x008c0000
+#define FIMC_IS_FW_INFO_LEN		31
+#define FIMC_IS_FW_VER_LEN		7
+#define FIMC_IS_FW_DESC_LEN		(FIMC_IS_FW_INFO_LEN + \
+					 FIMC_IS_FW_VER_LEN)
+#define FIMC_IS_SETFILE_INFO_LEN	39
+
+#define FIMC_IS_EXTRA_MEM_SIZE		(FIMC_IS_EXTRA_FW_SIZE + \
+					 FIMC_IS_EXTRA_SETFILE_SIZE + 0x1000)
+#define FIMC_IS_EXTRA_FW_SIZE		0x180000
+#define FIMC_IS_EXTRA_SETFILE_SIZE	0x4b000
+
+/* TODO: revisit */
+#define FIMC_IS_FW_ADDR_MASK		((1 << 26) - 1)
+#define FIMC_IS_FW_SIZE_MAX		(SZ_4M)
+#define FIMC_IS_FW_SIZE_MIN		(SZ_32K)
+
+/* Interrupt source */
+#define	FIMC_IS_INT_GENERAL		(1 << 0)
+#define	FIMC_IS_INT_ISP_FRAME_DONE	(1 << 1)
+
+/* The driver's internal state flags */
+enum {
+	IS_ST_IDLE,
+	IS_ST_FW_LOADED,
+	IS_ST_A5_PWR_ON,
+	IS_ST_OPEN_SENSOR,
+	IS_ST_SETFILE_LOADED,
+	IS_ST_INIT_DONE,
+	IS_ST_STREAM_ON,
+	IS_ST_STREAM_OFF,
+	IS_ST_CHANGE_MODE,
+	IS_ST_BLOCK_CMD_CLEARED,
+	IS_ST_SET_ZOOM,
+	IS_ST_PWR_ON = 20, /* <- is this needed ? */
+	IS_ST_PWR_SUBIP_ON,
+	IS_ST_END,
+};
+
+enum af_state {
+	FIMC_IS_AF_IDLE		= 0,
+	FIMC_IS_AF_SETCONFIG	= 1,
+	FIMC_IS_AF_RUNNING	= 2,
+	FIMC_IS_AF_LOCK		= 3,
+	FIMC_IS_AF_ABORT	= 4,
+	FIMC_IS_AF_FAILED	= 5,
+};
+
+enum af_lock_state {
+	FIMC_IS_AF_UNLOCKED	= 0,
+	FIMC_IS_AF_LOCKED	= 2
+};
+
+enum ae_lock_state {
+	FIMC_IS_AE_UNLOCKED	= 0,
+	FIMC_IS_AE_LOCKED	= 1
+};
+
+enum awb_lock_state {
+	FIMC_IS_AWB_UNLOCKED	= 0,
+	FIMC_IS_AWB_LOCKED	= 1
+};
+
+enum {
+	IS_METERING_CONFIG_CMD,
+	IS_METERING_CONFIG_WIN_POS_X,
+	IS_METERING_CONFIG_WIN_POS_Y,
+	IS_METERING_CONFIG_WIN_WIDTH,
+	IS_METERING_CONFIG_WIN_HEIGHT,
+	IS_METERING_CONFIG_MAX
+};
+
+struct is_setfile {
+	const struct firmware *info;
+	int state;
+	u32 sub_index;
+	u32 base;
+	size_t size;
+};
+
+struct is_fd_result_header {
+	u32 offset;
+	u32 count;
+	u32 index;
+	u32 curr_index;
+	u32 width;
+	u32 height;
+};
+
+struct is_af_info {
+	u16 mode;
+	u32 af_state;
+	u32 af_lock_state;
+	u32 ae_lock_state;
+	u32 awb_lock_state;
+	u16 pos_x;
+	u16 pos_y;
+	u16 prev_pos_x;
+	u16 prev_pos_y;
+	u16 use_af;
+};
+
+struct fimc_is_firmware {
+	const struct firmware *f_w;
+
+	dma_addr_t paddr;
+	void *vaddr;
+	unsigned int size;
+
+	char info[FIMC_IS_FW_INFO_LEN + 1];
+	char version[FIMC_IS_FW_VER_LEN + 1];
+	char setfile_info[FIMC_IS_SETFILE_INFO_LEN + 1];
+	u8 state;
+};
+
+struct fimc_is_memory {
+	/* physical base address */
+	dma_addr_t paddr;
+	/* virtual base address */
+	void *vaddr;
+	/* total length */
+	unsigned int size;
+};
+
+#define FIMC_IS_I2H_MAX_ARGS	12
+
+struct i2h_cmd {
+	u32 cmd;
+	u32 sensor_id;
+	u16 num_args;
+	u32 args[FIMC_IS_I2H_MAX_ARGS];
+};
+
+struct h2i_cmd {
+	u16 cmd_type;
+	u32 entry_id;
+};
+
+#define FIMC_IS_DEBUG_MSG	0x3f
+#define FIMC_IS_DEBUG_LEVEL	3
+
+struct fimc_is_setfile {
+	const struct firmware *info;
+	unsigned int state;
+	unsigned int size;
+	u32 sub_index;
+	u32 base;
+};
+
+struct is_config_param {
+	struct global_param		global;
+	struct sensor_param		sensor;
+	struct isp_param		isp;
+	struct drc_param		drc;
+	struct fd_param			fd;
+
+	atomic_t			p_region_num;
+	unsigned long			p_region_index1;
+	unsigned long			p_region_index2;
+};
+
+/**
+ * struct fimc_is - fimc-is data structure
+ * @pdev: pointer to FIMC-IS platform device
+ * @pinctrl:
+ * @v4l2_dev: pointer to top the level v4l2_device
+ * @vfd: video device node
+ * @fh: v4l2 file handle
+ * @alloc_ctx: videobuf2 memory allocator context
+ * @ctrl_handler: v4l2 control handler
+ * @slock: spinlock protecting this data structure and the hw registers
+ * @lock: mutex serializing video device and the subdev operations
+ * @clocks: FIMC-LITE gate clock
+ * @regs: MCUCTL mmapped registers region
+ * @regs: PMU ISP mmapped registers region
+ * @irq_queue: interrupt handling waitqueue
+ * @lpm: low power mode flag
+ * @state: internal driver's state flags
+ */
+struct fimc_is {
+	struct platform_device		*pdev;
+	struct pinctrl			*pctrl;
+	struct v4l2_device		*v4l2_dev;
+
+	struct fimc_is_firmware		fw;
+	struct fimc_is_memory		memory;
+	struct firmware 		*f_w;
+
+	struct fimc_isp			isp;
+	struct fimc_is_sensor		*sensor;
+	struct fimc_is_setfile		setfile;
+
+	struct vb2_alloc_ctx		*alloc_ctx;
+	struct v4l2_ctrl_handler	ctrl_handler;
+
+	struct mutex			lock;
+	spinlock_t			slock;
+
+	struct clk			*clocks[FIMC_IS_MAX_CLOCKS];
+	void __iomem			*regs;
+	void __iomem			*pmu_regs;
+	wait_queue_head_t		irq_queue;
+	u8				lpm;
+
+	unsigned long			state;
+	unsigned int			sensor_index;
+
+	struct i2h_cmd			i2h_cmd;
+	struct h2i_cmd			h2i_cmd;
+	struct is_fd_result_header	fd_header;
+
+	struct is_config_param		cfg_param[IS_SC_MAX];
+	struct is_region		*is_p_region;
+	dma_addr_t			is_dma_p_region;
+	struct is_share_region		*is_shared_region;
+	struct is_af_info		af;
+	u32				scenario_id;
+
+	struct dentry			*debugfs_entry;
+};
+
+static inline struct fimc_is *fimc_isp_to_is(struct fimc_isp *isp)
+{
+	return container_of(isp, struct fimc_is, isp);
+}
+
+static inline void fimc_is_mem_barrier(void)
+{
+	mb();
+}
+
+static inline void fimc_is_set_param_bit(struct fimc_is *is, int num)
+{
+	struct is_config_param *cfg = &is->cfg_param[is->scenario_id];
+
+	if (num >= 32)
+		set_bit(num - 32, &cfg->p_region_index2);
+	else
+		set_bit(num, &cfg->p_region_index1);
+}
+
+static inline void fimc_is_set_param_ctrl_cmd(struct fimc_is *is, int cmd)
+{
+	is->is_p_region->parameter.isp.control.cmd = cmd;
+}
+
+static inline void mcuctl_write(u32 v, struct fimc_is *is, unsigned int offset)
+{
+	writel(v, is->regs + offset);
+}
+
+static inline u32 mcuctl_read(struct fimc_is *is, unsigned int offset)
+{
+	return readl(is->regs + offset);
+}
+
+static inline void pmuisp_write(u32 v, struct fimc_is *is, unsigned int offset)
+{
+	writel(v, is->pmu_regs + offset);
+}
+
+static inline u32 pmuisp_read(struct fimc_is *is, unsigned int offset)
+{
+	return readl(is->pmu_regs + offset);
+}
+
+int fimc_is_wait_event(struct fimc_is *is, unsigned long bit,
+		       unsigned int state, unsigned int timeout);
+int fimc_is_cpu_set_power(struct fimc_is *is, int on);
+int fimc_is_start_firmware(struct fimc_is *is);
+int fimc_is_hw_initialize(struct fimc_is *is);
+void fimc_is_log_dump(const char *level, const void *buf, size_t len);
+
+#endif /* FIMC_IS_H_ */
diff --git a/drivers/media/platform/s5p-fimc/fimc-isp.c b/drivers/media/platform/s5p-fimc/fimc-isp.c
new file mode 100644
index 0000000..37c66e0
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-isp.c
@@ -0,0 +1,791 @@
+/*
+ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *
+ * Authors: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *          Younghwan Joo <yhwan.joo@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/printk.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/pm_qos.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "fimc-mdevice.h"
+#include "fimc-core.h"
+#include "fimc-isp-video.h"
+#include "fimc-is-command.h"
+#include "fimc-is-param.h"
+#include "fimc-is-regs.h"
+#include "fimc-is.h"
+
+static int debug = 10;
+module_param_named(debug_isp, debug, int, S_IRUGO | S_IWUSR);
+
+static const struct fimc_fmt fimc_isp_formats[FIMC_ISP_NUM_FORMATS] = {
+	{
+		.name		= "RAW8 (GRBG)",
+		.fourcc		= V4L2_PIX_FMT_SGRBG8,
+		.depth		= { 8 },
+		.color		= FIMC_FMT_RAW8,
+		.memplanes	= 1,
+		.mbus_code	= V4L2_MBUS_FMT_SGRBG8_1X8,
+	}, {
+		.name		= "RAW10 (GRBG)",
+		.fourcc		= V4L2_PIX_FMT_SGRBG10,
+		.depth		= { 10 },
+		.color		= FIMC_FMT_RAW10,
+		.memplanes	= 1,
+		.mbus_code	= V4L2_MBUS_FMT_SGRBG10_1X10,
+	}, {
+		.name		= "RAW12 (GRBG)",
+		.fourcc		= V4L2_PIX_FMT_SGRBG12,
+		.depth		= { 12 },
+		.color		= FIMC_FMT_RAW12,
+		.memplanes	= 1,
+		.mbus_code	= V4L2_MBUS_FMT_SGRBG12_1X12,
+	},
+};
+
+/**
+ * fimc_isp_find_format - lookup color format by fourcc or media bus code
+ * @pixelformat: fourcc to match, ignored if null
+ * @mbus_code: media bus code to match, ignored if null
+ * @index: index to the fimc_isp_formats array, ignored if negative
+ */
+const struct fimc_fmt *fimc_isp_find_format(const u32 *pixelformat,
+					const u32 *mbus_code, int index)
+{
+	const struct fimc_fmt *fmt, *def_fmt = NULL;
+	unsigned int i;
+	int id = 0;
+
+	if (index >= (int)ARRAY_SIZE(fimc_isp_formats))
+		return NULL;
+
+	for (i = 0; i < ARRAY_SIZE(fimc_isp_formats); ++i) {
+		fmt = &fimc_isp_formats[i];
+		if (pixelformat && fmt->fourcc == *pixelformat)
+			return fmt;
+		if (mbus_code && fmt->mbus_code == *mbus_code)
+			return fmt;
+		if (index == id)
+			def_fmt = fmt;
+		id++;
+	}
+	return def_fmt;
+}
+
+void fimc_isp_irq_handler(struct fimc_is *is)
+{
+	/* TODO: Add ISP DMA interrupt handler */
+}
+
+/* Capture subdev media entity operations */
+static int fimc_is_link_setup(struct media_entity *entity,
+				const struct media_pad *local,
+				const struct media_pad *remote, u32 flags)
+{
+	return 0;
+}
+
+static const struct media_entity_operations fimc_is_subdev_media_ops = {
+	.link_setup = fimc_is_link_setup,
+};
+
+static int fimc_is_subdev_enum_mbus_code(struct v4l2_subdev *sd,
+				struct v4l2_subdev_fh *fh,
+				struct v4l2_subdev_mbus_code_enum *code)
+{
+	const struct fimc_fmt *fmt;
+
+	fmt = fimc_isp_find_format(NULL, NULL, code->index);
+	if (!fmt)
+		return -EINVAL;
+	code->code = fmt->mbus_code;
+	return 0;
+}
+
+static int fimc_isp_subdev_get_fmt(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_fh *fh,
+				   struct v4l2_subdev_format *fmt)
+{
+	struct fimc_isp *isp = v4l2_get_subdevdata(sd);
+	struct fimc_is *is = fimc_isp_to_is(isp);
+	struct v4l2_mbus_framefmt *mf = &fmt->format;
+	struct v4l2_mbus_framefmt cur_fmt;
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+		mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+		fmt->format = *mf;
+		return 0;
+	}
+
+	mf->colorspace = V4L2_COLORSPACE_JPEG;
+
+	mutex_lock(&isp->subdev_lock);
+	__is_get_frame_size(is, &cur_fmt);
+
+	if (fmt->pad == FIMC_IS_SD_PAD_SINK) {
+		/* full camera input frame size */
+		mf->width = cur_fmt.width + 16;
+		mf->height = cur_fmt.height + 12;
+		mf->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+	} else {
+		/* crop size */
+		mf->width = cur_fmt.width;
+		mf->height = cur_fmt.height;
+		mf->code = V4L2_MBUS_FMT_YUV10_1X30;
+	}
+
+	mutex_unlock(&isp->subdev_lock);
+
+	v4l2_dbg(1, debug, sd, "%s: pad%d: fmt: 0x%x, %dx%d\n",
+		 __func__, fmt->pad, mf->code, mf->width, mf->height);
+
+	return 0;
+}
+
+static void __isp_subdev_try_format(struct fimc_isp *isp,
+				   struct v4l2_subdev_format *fmt)
+{
+	struct v4l2_mbus_framefmt *mf = &fmt->format;
+
+	if (fmt->pad == FIMC_IS_SD_PAD_SINK) {
+		v4l_bound_align_image(&mf->width, FIMC_ISP_SINK_WIDTH_MIN,
+				FIMC_ISP_SINK_WIDTH_MAX, 0,
+				&mf->height, FIMC_ISP_SINK_HEIGHT_MIN,
+				FIMC_ISP_SINK_HEIGHT_MAX, 0, 0);
+		isp->subdev_fmt = *mf;
+	} else {
+		/* Allow changing format only on sink pad */
+		/* FIXME: hard coded CAC margin */
+		mf->width = isp->subdev_fmt.width - 16;
+		mf->height = isp->subdev_fmt.height - 12;
+		mf->code = isp->subdev_fmt.code;
+	}
+}
+
+static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd,
+				   struct v4l2_subdev_fh *fh,
+				   struct v4l2_subdev_format *fmt)
+{
+	struct fimc_isp *isp = v4l2_get_subdevdata(sd);
+	struct fimc_is *is = fimc_isp_to_is(isp);
+	struct v4l2_mbus_framefmt *mf = &fmt->format;
+	int ret = 0;
+
+	v4l2_dbg(1, debug, sd, "%s: pad%d: code: 0x%x, %dx%d\n",
+		 __func__, fmt->pad, mf->code, mf->width, mf->height);
+
+	mf->colorspace = V4L2_COLORSPACE_JPEG;
+
+	mutex_lock(&isp->subdev_lock);
+	__isp_subdev_try_format(isp, fmt);
+
+	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+		mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+		*mf = fmt->format;
+		mutex_unlock(&isp->subdev_lock);
+		return 0;
+	}
+
+	if (sd->entity.stream_count == 0)
+		__is_set_frame_size(is, mf);
+	else
+		ret = -EBUSY;
+	mutex_unlock(&isp->subdev_lock);
+
+	return ret;
+}
+
+static int fimc_isp_subdev_s_stream(struct v4l2_subdev *sd, int on)
+{
+	struct fimc_isp *isp = v4l2_get_subdevdata(sd);
+	struct fimc_is *is = fimc_isp_to_is(isp);
+	int ret;
+
+	v4l2_dbg(1, debug, sd, "%s: on: %d\n", __func__, on);
+
+	if (!test_bit(IS_ST_INIT_DONE, &is->state))
+		return -EBUSY;
+
+	fimc_is_mem_barrier();
+
+	if (on) {
+		if (atomic_read(&is->cfg_param[is->scenario_id].p_region_num))
+			ret = fimc_is_itf_s_param(is, true);
+
+		v4l2_dbg(1, debug, sd, "changing mode to %d\n",
+						is->scenario_id);
+		ret = fimc_is_itf_mode_change(is);
+		if (ret)
+			return -EINVAL;
+
+		clear_bit(IS_ST_STREAM_ON, &is->state);
+		fimc_is_hw_stream_on(is);
+		ret = fimc_is_wait_event(is, IS_ST_STREAM_ON, 1,
+					 FIMC_IS_CONFIG_TIMEOUT);
+		if (ret < 0) {
+			v4l2_err(sd, "stream on timeout\n");
+			return ret;
+		}
+	} else {
+		clear_bit(IS_ST_STREAM_OFF, &is->state);
+		fimc_is_hw_stream_off(is);
+		ret = fimc_is_wait_event(is, IS_ST_STREAM_OFF, 1,
+					 FIMC_IS_CONFIG_TIMEOUT);
+		if (ret < 0) {
+			v4l2_err(sd, "stream off timeout\n");
+			return ret;
+		}
+		is->setfile.sub_index = 0;
+	}
+
+	return 0;
+}
+
+static int fimc_isp_subdev_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct fimc_isp *isp = v4l2_get_subdevdata(sd);
+	struct fimc_is *is = fimc_isp_to_is(isp);
+	int ret = 0;
+
+	pr_info("%s:%d: on: %d\n", __func__, __LINE__, on);
+
+	if (on) {
+		ret = pm_runtime_get_sync(&is->pdev->dev);
+		if (ret < 0)
+			return ret;
+		set_bit(IS_ST_PWR_ON, &is->state);
+
+		ret = fimc_is_start_firmware(is);
+		if (ret < 0) {
+			v4l2_err(sd, "FIMC-IS firmware booting failed\n");
+			pm_runtime_put(&is->pdev->dev);
+			return ret;
+		}
+		set_bit(IS_ST_PWR_SUBIP_ON, &is->state);
+
+		ret = fimc_is_hw_initialize(is);
+	} else {
+		/* Close sensor */
+		if (!test_bit(IS_ST_PWR_ON, &is->state)) {
+			fimc_is_hw_close_sensor(is, 0);
+			ret = wait_event_timeout(is->irq_queue,
+				 !test_bit(IS_ST_OPEN_SENSOR, &is->state),
+				 FIMC_IS_CONFIG_TIMEOUT);
+			if (!ret) {
+				v4l2_err(sd, "FIMC-IS close sensor timeout\n");
+				return -EINVAL;
+			}
+		}
+
+		/* SUB IP power off */
+		if (test_bit(IS_ST_PWR_SUBIP_ON, &is->state)) {
+			fimc_is_hw_subip_power_off(is);
+			ret = wait_event_timeout(is->irq_queue,
+				!test_bit(IS_ST_PWR_SUBIP_ON, &is->state),
+				FIMC_IS_CONFIG_TIMEOUT);
+			if (!ret) {
+				v4l2_err(sd, "FIMC-IS Close sensor timeout\n");
+				return -EINVAL;
+			}
+		}
+
+		fimc_is_cpu_set_power(is, 0);
+		pm_runtime_put_sync(&is->pdev->dev);
+
+		clear_bit(IS_ST_PWR_ON, &is->state);
+		clear_bit(IS_ST_INIT_DONE, &is->state);
+		is->state = 0;
+		is->cfg_param[is->scenario_id].p_region_index1 = 0;
+		is->cfg_param[is->scenario_id].p_region_index2 = 0;
+		set_bit(IS_ST_IDLE, &is->state);
+		wmb();
+	}
+
+	return ret;
+}
+
+static int fimc_isp_subdev_open(struct v4l2_subdev *sd,
+				struct v4l2_subdev_fh *fh)
+{
+	struct v4l2_mbus_framefmt fmt;
+	struct v4l2_mbus_framefmt *format;
+
+	format = v4l2_subdev_get_try_format(fh, FIMC_IS_SD_PAD_SINK);
+
+	fmt.colorspace = V4L2_COLORSPACE_SRGB;
+	fmt.code = fimc_isp_formats[0].mbus_code;
+	fmt.width = DEFAULT_PREVIEW_STILL_WIDTH + 16;
+	fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT + 12;
+	fmt.field = V4L2_FIELD_NONE;
+	*format = fmt;
+
+	format = v4l2_subdev_get_try_format(fh, FIMC_IS_SD_PAD_SRC_FIFO);
+	fmt.width = DEFAULT_PREVIEW_STILL_WIDTH;
+	fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT;
+	*format = fmt;
+
+	format = v4l2_subdev_get_try_format(fh, FIMC_IS_SD_PAD_SRC_DMA);
+	*format = fmt;
+
+	return 0;
+}
+
+static int fimc_isp_subdev_registered(struct v4l2_subdev *sd)
+{
+	struct fimc_isp *isp = v4l2_get_subdevdata(sd);
+	return fimc_isp_video_device_register(isp, sd->v4l2_dev);
+}
+
+static void fimc_isp_subdev_unregistered(struct v4l2_subdev *sd)
+{
+	struct fimc_isp *isp = v4l2_get_subdevdata(sd);
+	fimc_isp_video_device_unregister(isp);
+}
+
+static const struct v4l2_subdev_internal_ops fimc_is_subdev_internal_ops = {
+	.registered = fimc_isp_subdev_registered,
+	.unregistered = fimc_isp_subdev_unregistered,
+	.open = fimc_isp_subdev_open,
+};
+
+static const struct v4l2_subdev_pad_ops fimc_is_subdev_pad_ops = {
+	.enum_mbus_code = fimc_is_subdev_enum_mbus_code,
+	.get_fmt = fimc_isp_subdev_get_fmt,
+	.set_fmt = fimc_isp_subdev_set_fmt,
+};
+
+static const struct v4l2_subdev_video_ops fimc_is_subdev_video_ops = {
+	.s_stream = fimc_isp_subdev_s_stream,
+};
+
+static const struct v4l2_subdev_core_ops fimc_is_core_ops = {
+	.s_power = fimc_isp_subdev_s_power,
+};
+
+static struct v4l2_subdev_ops fimc_is_subdev_ops = {
+	.core = &fimc_is_core_ops,
+	.video = &fimc_is_subdev_video_ops,
+	.pad = &fimc_is_subdev_pad_ops,
+};
+
+static int __ctrl_set_white_balance(struct fimc_is *is, int value)
+{
+	switch (value) {
+	case V4L2_WHITE_BALANCE_AUTO:
+		__is_set_isp_awb(is, ISP_AWB_COMMAND_AUTO, 0);
+		break;
+	case V4L2_WHITE_BALANCE_DAYLIGHT:
+		__is_set_isp_awb(is, ISP_AWB_COMMAND_ILLUMINATION,
+					ISP_AWB_ILLUMINATION_DAYLIGHT);
+		break;
+	case V4L2_WHITE_BALANCE_CLOUDY:
+		__is_set_isp_awb(is, ISP_AWB_COMMAND_ILLUMINATION,
+					ISP_AWB_ILLUMINATION_CLOUDY);
+		break;
+	case V4L2_WHITE_BALANCE_INCANDESCENT:
+		__is_set_isp_awb(is, ISP_AWB_COMMAND_ILLUMINATION,
+					ISP_AWB_ILLUMINATION_TUNGSTEN);
+		break;
+	case V4L2_WHITE_BALANCE_FLUORESCENT:
+		__is_set_isp_awb(is, ISP_AWB_COMMAND_ILLUMINATION,
+					ISP_AWB_ILLUMINATION_FLUORESCENT);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int __ctrl_set_frame_rate(struct fimc_is *is, int value)
+{
+	int ret;
+
+	/*
+	 * The frame interval update needs to be done with the IS chain
+	 * streaming stopped. Disable streaming and re-enable if required.
+	 */
+	if (test_bit(IS_ST_STREAM_ON, &is->state)) {
+		fimc_is_set_param_ctrl_cmd(is, CONTROL_COMMAND_STOP);
+		fimc_is_set_param_bit(is, PARAM_ISP_CONTROL);
+		fimc_is_inc_param_num(is);
+		ret = fimc_is_itf_s_param(is, false);
+		if (ret < 0)
+			return ret;
+	}
+
+	__is_set_sensor(is, value);
+	ret = fimc_is_itf_s_param(is, true);
+
+	if (test_bit(IS_ST_STREAM_ON, &is->state)) {
+		fimc_is_set_param_ctrl_cmd(is, CONTROL_COMMAND_START);
+		fimc_is_set_param_bit(is, PARAM_ISP_CONTROL);
+		fimc_is_inc_param_num(is);
+		ret = fimc_is_itf_s_param(is, false);
+	}
+	return ret;
+}
+
+static int __ctrl_set_af_position(struct fimc_is *is, int x, int y)
+{
+	struct isp_param *isp = &is->cfg_param[is->scenario_id].isp;
+	struct param_otf_input *otf = &isp->otf_input;
+
+	if (x < 0 || x > otf->width || y < 0 || y > otf->height)
+		return -EINVAL;
+
+	is->af.pos_x = x;
+	is->af.pos_y = y;
+	return 0;
+}
+
+static int __ctrl_set_metering_window(struct fimc_is *is, struct v4l2_rect *r)
+{
+	/* FIXME: check if passed rectangle is within OTF window */
+
+	__is_set_isp_metering(is, IS_METERING_CONFIG_WIN_POS_X, r->left);
+	__is_set_isp_metering(is, IS_METERING_CONFIG_WIN_POS_Y, r->top);
+	__is_set_isp_metering(is, IS_METERING_CONFIG_WIN_WIDTH, r->width);
+	__is_set_isp_metering(is, IS_METERING_CONFIG_WIN_HEIGHT, r->height);
+
+	return 0;
+}
+
+static int __ctrl_set_aewb_lock(struct fimc_is *is,
+				      struct v4l2_ctrl *ctrl)
+{
+	bool awb_lock = ctrl->val & V4L2_LOCK_WHITE_BALANCE;
+	bool ae_lock = ctrl->val & V4L2_LOCK_EXPOSURE;
+	struct isp_param *isp = &is->is_p_region->parameter.isp;
+	int cmd, ret;
+
+	cmd = ae_lock ? ISP_AA_COMMAND_STOP : ISP_AA_COMMAND_START;
+	isp->aa.cmd = cmd;
+	isp->aa.target = ISP_AA_TARGET_AE;
+	fimc_is_set_param_bit(is, PARAM_ISP_AA);
+	fimc_is_inc_param_num(is);
+	is->af.ae_lock_state = ae_lock;
+	wmb();
+
+	ret = fimc_is_itf_s_param(is, false);
+	if (ret < 0)
+		return ret;
+
+	cmd = awb_lock ? ISP_AA_COMMAND_STOP : ISP_AA_COMMAND_START;
+	isp->aa.cmd = cmd;
+	isp->aa.target = ISP_AA_TARGET_AE;
+	fimc_is_set_param_bit(is, PARAM_ISP_AA);
+	fimc_is_inc_param_num(is);
+	is->af.awb_lock_state = awb_lock;
+	wmb();
+
+	return fimc_is_itf_s_param(is, false);
+}
+
+/* Supported manual ISO values */
+static const s64 iso_qmenu[] = {
+	50, 100, 200, 400, 800,
+};
+
+static int __ctrl_set_iso(struct fimc_is *is, int value)
+{
+	unsigned int idx, iso;
+
+	if (value == V4L2_ISO_SENSITIVITY_AUTO) {
+		__is_set_isp_iso(is, ISP_ISO_COMMAND_AUTO, 0);
+		return 0;
+	}
+	idx = is->isp.ctrls.iso->val;
+	if (idx >= ARRAY_SIZE(iso_qmenu))
+		return -EINVAL;
+
+	iso = iso_qmenu[idx];
+	__is_set_isp_iso(is, ISP_ISO_COMMAND_MANUAL, iso);
+	return 0;
+}
+
+static int __ctrl_set_metering(struct fimc_is *is, unsigned int value)
+{
+	unsigned int val;
+
+	switch (value) {
+	case V4L2_EXPOSURE_METERING_AVERAGE:
+		val = ISP_METERING_COMMAND_AVERAGE;
+		break;
+	case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED:
+		val = ISP_METERING_COMMAND_CENTER;
+		break;
+	case V4L2_EXPOSURE_METERING_SPOT:
+		val = ISP_METERING_COMMAND_SPOT;
+		break;
+	case V4L2_EXPOSURE_METERING_MATRIX:
+		val = ISP_METERING_COMMAND_MATRIX;
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	__is_set_isp_metering(is, IS_METERING_CONFIG_CMD, val);
+	return 0;
+}
+
+static int __ctrl_set_afc(struct fimc_is *is, int value)
+{
+	switch (value) {
+	case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED:
+		__is_set_isp_afc(is, ISP_AFC_COMMAND_DISABLE, 0);
+		break;
+	case V4L2_CID_POWER_LINE_FREQUENCY_50HZ:
+		__is_set_isp_afc(is, ISP_AFC_COMMAND_MANUAL, 50);
+		break;
+	case V4L2_CID_POWER_LINE_FREQUENCY_60HZ:
+		__is_set_isp_afc(is, ISP_AFC_COMMAND_MANUAL, 60);
+		break;
+	case V4L2_CID_POWER_LINE_FREQUENCY_AUTO:
+		__is_set_isp_afc(is, ISP_AFC_COMMAND_AUTO, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+#if 0
+static int __ctrl_set_flash_mode(struct fimc_is *is, int value)
+{
+	switch (value) {
+	case IS_FLASH_MODE_OFF:
+		__is_set_isp_flash(is, ISP_FLASH_COMMAND_DISABLE, 0);
+		break;
+	case IS_FLASH_MODE_AUTO:
+		__is_set_isp_flash(is, ISP_FLASH_COMMAND_AUTO, 0);
+		break;
+	case IS_FLASH_MODE_AUTO_REDEYE:
+		__is_set_isp_flash(is, ISP_FLASH_COMMAND_AUTO, 1);
+		break;
+	case IS_FLASH_MODE_ON:
+		__is_set_isp_flash(is, ISP_FLASH_COMMAND_MANUALON, 0);
+		break;
+	case IS_FLASH_MODE_TORCH:
+		__is_set_isp_flash(is, ISP_FLASH_COMMAND_TORCH, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+#endif
+
+static int __ctrl_set_image_effect(struct fimc_is *is, int value)
+{
+	/* FIXME: */
+	__is_set_isp_effect(is, value);
+	return 0;
+}
+
+static int fimc_is_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct fimc_isp *isp = ctrl_to_fimc_isp(ctrl);
+	struct fimc_is *is = fimc_isp_to_is(isp);
+	bool set_param = true;
+	int ret = 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_CONTRAST:
+		__is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_CONTRAST,
+				    ctrl->val);
+		break;
+
+	case V4L2_CID_SATURATION:
+		__is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_SATURATION,
+				    ctrl->val);
+		break;
+
+	case V4L2_CID_SHARPNESS:
+		__is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_SHARPNESS,
+				    ctrl->val);
+		break;
+
+	case V4L2_CID_EXPOSURE_ABSOLUTE:
+		__is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_EXPOSURE,
+				    ctrl->val);
+		break;
+
+	case V4L2_CID_BRIGHTNESS:
+		__is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_BRIGHTNESS,
+				    ctrl->val);
+		break;
+
+	case V4L2_CID_HUE:
+		__is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_HUE,
+				    ctrl->val);
+		break;
+
+	case V4L2_CID_EXPOSURE_METERING:
+		ret = __ctrl_set_metering(is, ctrl->val);
+		break;
+
+	case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
+		ret = __ctrl_set_white_balance(is, ctrl->val);
+		break;
+
+	case V4L2_CID_3A_LOCK:
+		ret = __ctrl_set_aewb_lock(is, ctrl);
+		set_param = false;
+		break;
+
+	case V4L2_CID_ISO_SENSITIVITY_AUTO:
+		ret = __ctrl_set_iso(is, ctrl->val);
+		break;
+
+	case V4L2_CID_POWER_LINE_FREQUENCY:
+		ret = __ctrl_set_afc(is, ctrl->val);
+		break;
+
+	case V4L2_CID_COLORFX:
+		__ctrl_set_image_effect(is, ctrl->val);
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (ret < 0) {
+		v4l2_err(&isp->subdev, "%s() failed, ctrl: %s, val: %d\n",
+			 __func__, ctrl->name, ctrl->val);
+		return ret;
+	}
+
+	if (set_param && test_bit(IS_ST_STREAM_ON, &is->state))
+		return fimc_is_itf_s_param(is, true);
+
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops fimc_isp_ctrl_ops = {
+	.s_ctrl	= fimc_is_s_ctrl,
+};
+
+int fimc_isp_subdev_create(struct fimc_isp *isp)
+{
+	const struct v4l2_ctrl_ops *ops = &fimc_isp_ctrl_ops;
+	struct v4l2_ctrl_handler *handler = &isp->ctrls.handler;
+	struct v4l2_subdev *sd = &isp->subdev;
+	struct fimc_isp_ctrls *ctrls = &isp->ctrls;
+	int ret;
+
+	mutex_init(&isp->subdev_lock);
+
+	v4l2_subdev_init(sd, &fimc_is_subdev_ops);
+	sd->grp_id = GRP_ID_FIMC_IS;
+	sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+	snprintf(sd->name, sizeof(sd->name), "FIMC-IS-ISP");
+
+	isp->subdev_pads[FIMC_IS_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+	isp->subdev_pads[FIMC_IS_SD_PAD_SRC_FIFO].flags = MEDIA_PAD_FL_SOURCE;
+	isp->subdev_pads[FIMC_IS_SD_PAD_SRC_DMA].flags = MEDIA_PAD_FL_SOURCE;
+	ret = media_entity_init(&sd->entity, FIMC_IS_SD_PADS_NUM,
+				isp->subdev_pads, 0);
+	if (ret)
+		return ret;
+
+	v4l2_ctrl_handler_init(handler, 20);
+
+	ctrls->saturation = v4l2_ctrl_new_std(handler, ops, V4L2_CID_SATURATION,
+						-2, 2, 1, 0);
+	ctrls->brightness = v4l2_ctrl_new_std(handler, ops, V4L2_CID_BRIGHTNESS,
+						-4, 4, 1, 0);
+	ctrls->contrast = v4l2_ctrl_new_std(handler, ops, V4L2_CID_CONTRAST,
+						-2, 2, 1, 0);
+	ctrls->sharpness = v4l2_ctrl_new_std(handler, ops, V4L2_CID_SHARPNESS,
+						-2, 2, 1, 0);
+	ctrls->hue = v4l2_ctrl_new_std(handler, ops, V4L2_CID_HUE,
+						-2, 2, 1, 0);
+
+	ctrls->auto_wb = v4l2_ctrl_new_std_menu(handler, ops,
+					V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
+					8, ~0x14e, V4L2_WHITE_BALANCE_AUTO);
+
+	ctrls->exposure = v4l2_ctrl_new_std(handler, ops,
+					V4L2_CID_EXPOSURE_ABSOLUTE,
+					-4, 4, 1, 0);
+
+	ctrls->exp_metering = v4l2_ctrl_new_std_menu(handler, ops,
+					V4L2_CID_EXPOSURE_METERING, 3,
+					~0xf, V4L2_EXPOSURE_METERING_AVERAGE);
+
+	v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_POWER_LINE_FREQUENCY,
+					V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
+					V4L2_CID_POWER_LINE_FREQUENCY_AUTO);
+	/* ISO sensitivity */
+	ctrls->auto_iso = v4l2_ctrl_new_std_menu(handler, ops,
+			V4L2_CID_ISO_SENSITIVITY_AUTO, 1, 0,
+			V4L2_ISO_SENSITIVITY_AUTO);
+
+	ctrls->iso = v4l2_ctrl_new_int_menu(handler, ops,
+			V4L2_CID_ISO_SENSITIVITY, ARRAY_SIZE(iso_qmenu) - 1,
+			ARRAY_SIZE(iso_qmenu)/2 - 1, iso_qmenu);
+
+	ctrls->aewb_lock = v4l2_ctrl_new_std(handler, ops,
+					V4L2_CID_3A_LOCK, 0, 0x3, 0, 0);
+
+	/* FIXME: Adjust the enabled controls mask according
+	   to the ISP capabilities */
+	v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_COLORFX,
+					V4L2_COLORFX_ANTIQUE,
+					0, V4L2_COLORFX_NONE);
+	if (handler->error) {
+		media_entity_cleanup(&sd->entity);
+		return handler->error;
+	}
+
+	ctrls->auto_iso->flags |= V4L2_CTRL_FLAG_VOLATILE |
+				  V4L2_CTRL_FLAG_UPDATE;
+	v4l2_ctrl_auto_cluster(2, &ctrls->auto_iso, 0, false);
+
+	sd->ctrl_handler = handler;
+	sd->internal_ops = &fimc_is_subdev_internal_ops;
+	sd->entity.ops = &fimc_is_subdev_media_ops;
+	v4l2_set_subdevdata(sd, isp);
+
+	return 0;
+}
+
+void fimc_isp_subdev_destroy(struct fimc_isp *isp)
+{
+	struct v4l2_subdev *sd = &isp->subdev;
+
+	v4l2_device_unregister_subdev(sd);
+	media_entity_cleanup(&sd->entity);
+	v4l2_ctrl_handler_free(&isp->ctrls.handler);
+	v4l2_set_subdevdata(sd, NULL);
+}
diff --git a/drivers/media/platform/s5p-fimc/fimc-isp.h b/drivers/media/platform/s5p-fimc/fimc-isp.h
new file mode 100644
index 0000000..654039e
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-isp.h
@@ -0,0 +1,205 @@
+/*
+ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *
+ * Authors: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *          Younghwan Joo <yhwan.joo@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef FIMC_ISP_H_
+#define FIMC_ISP_H_
+
+#include <asm/sizes.h>
+#include <linux/io.h>
+#include <linux/irqreturn.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <media/media-entity.h>
+#include <media/videobuf2-core.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+#include <media/s5p_fimc.h>
+
+#include "fimc-core.h"
+
+/* TODO: revisit these constraints */
+#define FIMC_ISP_SINK_WIDTH_MIN		(16 + 8)
+#define FIMC_ISP_SINK_HEIGHT_MIN	(12 + 8)
+#define FIMC_ISP_SOURCE_WIDTH_MIN	8
+#define FIMC_ISP_SOURC_HEIGHT_MIN	8
+/* FIXME: below are random numbers... */
+#define FIMC_ISP_SINK_WIDTH_MAX		(4000 - 16)
+#define FIMC_ISP_SINK_HEIGHT_MAX	(4000 + 12)
+#define FIMC_ISP_SOURCE_WIDTH_MAX	4000
+#define FIMC_ISP_SOURC_HEIGHT_MAX	4000
+
+#define FIMC_ISP_NUM_FORMATS		3
+#define FIMC_IS_REQ_BUFS_MIN		2
+
+#define FIMC_IS_SD_PAD_SINK		0
+#define FIMC_IS_SD_PAD_SRC_FIFO		1
+#define FIMC_IS_SD_PAD_SRC_DMA		2
+#define FIMC_IS_SD_PADS_NUM		3
+#define FIMC_IS_MAX_PLANES		1
+
+/**
+ * struct fimc_isp_frame - source/target frame properties
+ * @f_width: full pixel width
+ * @f_height: full pixel height
+ * @rect: crop/composition rectangle
+ */
+struct fimc_isp_frame {
+	u16 f_width;
+	u16 f_height;
+	struct v4l2_rect rect;
+};
+
+/**
+ * struct fimc_isp_buffer - video buffer structure
+ * @vb: vb2 buffer
+ * @list: list head for the buffers queue
+ * @paddr: precalculated physical address
+ */
+struct fimc_isp_buffer {
+	struct vb2_buffer vb;
+	struct list_head list;
+	dma_addr_t paddr;
+};
+
+struct fimc_isp_ctrls {
+	struct v4l2_ctrl_handler handler;
+	/* Internal mode selection */
+	struct v4l2_ctrl *scenario;
+	/* Frame rate */
+	struct v4l2_ctrl *fps;
+	/* Touch AF position */
+	struct v4l2_ctrl *af_position_x;
+	struct v4l2_ctrl *af_position_y;
+	/* Auto white balance */
+	struct v4l2_ctrl *auto_wb;
+	/* ISO sensitivity */
+	struct v4l2_ctrl *auto_iso;
+	struct v4l2_ctrl *iso;
+
+	struct v4l2_ctrl *contrast;
+	struct v4l2_ctrl *saturation;
+	struct v4l2_ctrl *sharpness;
+	/* Auto/manual exposure */
+	struct v4l2_ctrl *auto_exp;
+	/* Manual exposure value */
+	struct v4l2_ctrl *exposure;
+	/* Adjust - brightness */
+	struct v4l2_ctrl *brightness;
+	/* Adjust - hue */
+	struct v4l2_ctrl *hue;
+	/* Exposure metering mode */
+	struct v4l2_ctrl *exp_metering;
+	/* AFC */
+	struct v4l2_ctrl *afc;
+	/* AE/AWB lock/unlock */
+	struct v4l2_ctrl *aewb_lock;
+	/* AF */
+	struct v4l2_ctrl *focus_mode;
+	/* AF status */
+	struct v4l2_ctrl *af_status;
+};
+
+/**
+ * struct fimc_isp - fimc isp structure
+ * @pdev: pointer to FIMC-LITE platform device
+ * @variant: variant information for this IP
+ * @v4l2_dev: pointer to top the level v4l2_device
+ * @vfd: video device node
+ * @fh: v4l2 file handle
+ * @alloc_ctx: videobuf2 memory allocator context
+ * @subdev: FIMC-LITE subdev
+ * @vd_pad: media (sink) pad for the capture video node
+ * @subdev_pads: the subdev media pads
+ * @ctrl_handler: v4l2 control handler
+ * @test_pattern: test pattern controls
+ * @index: FIMC-LITE platform device index
+ * @pipeline: video capture pipeline data structure
+ * @slock: spinlock protecting this data structure and the hw registers
+ * @video_lock: mutex serializing video device and the subdev operations
+ * @clock: FIMC-LITE gate clock
+ * @regs: memory mapped io registers
+ * @irq_queue: interrupt handler waitqueue
+ * @fmt: pointer to color format description structure
+ * @payload: image size in bytes (w x h x bpp)
+ * @inp_frame: camera input frame structure
+ * @out_frame: DMA output frame structure
+ * @out_path: output data path (DMA or FIFO)
+ * @source_subdev_grp_id: source subdev group id
+ * @cac_margin_x: horizontal CAC margin in pixels
+ * @cac_margin_y: vertical CAC margin in pixels
+ * @state: driver state flags
+ * @pending_buf_q: pending buffers queue head
+ * @active_buf_q: the queue head of buffers scheduled in hardware
+ * @capture_vb_queue: vb2 buffers queue for ISP capture video node
+ * @active_buf_count: number of video buffers scheduled in hardware
+ * @frame_count: the captured frames counter
+ * @reqbufs_count: the number of buffers requested with REQBUFS ioctl
+ * @ref_count: driver's private reference counter
+ */
+struct fimc_isp {
+	struct platform_device		*pdev;
+	struct fimc_is_variant		*variant;
+	struct v4l2_device		*v4l2_dev;
+	struct video_device		vfd;
+	struct v4l2_fh			fh;
+	struct vb2_alloc_ctx		*alloc_ctx;
+	struct v4l2_subdev		subdev;
+	struct media_pad		vd_pad;
+	struct media_pad		subdev_pads[FIMC_IS_SD_PADS_NUM];
+	struct v4l2_mbus_framefmt	subdev_fmt;
+	struct v4l2_ctrl		*test_pattern;
+	struct fimc_pipeline		pipeline;
+	struct fimc_isp_ctrls		ctrls;
+
+	u32				index;
+	struct mutex			video_lock;
+	struct mutex			subdev_lock;
+	spinlock_t			slock;
+
+	wait_queue_head_t		irq_queue;
+
+	const struct fimc_fmt		*video_capture_format;
+	unsigned long			payload[FIMC_IS_MAX_PLANES];
+	struct fimc_isp_frame		inp_frame;
+	struct fimc_isp_frame		out_frame;
+	enum fimc_datapath		out_path;
+	unsigned int			source_subdev_grp_id;
+
+	unsigned int			cac_margin_x;
+	unsigned int 			cac_margin_y;
+
+	unsigned long			state;
+	struct list_head		pending_buf_q;
+	struct list_head		active_buf_q;
+	struct vb2_queue		capture_vb_queue;
+	unsigned int			frame_count;
+	unsigned int			reqbufs_count;
+	int				ref_count;
+};
+
+#define ctrl_to_fimc_isp(_ctrl) \
+	container_of(ctrl->handler, struct fimc_isp, ctrls.handler)
+
+struct fimc_is;
+
+int fimc_isp_subdev_create(struct fimc_isp *isp);
+void fimc_isp_subdev_destroy(struct fimc_isp *isp);
+void fimc_isp_irq_handler(struct fimc_is *is);
+int fimc_is_create_controls(struct fimc_isp *isp);
+int fimc_is_delete_controls(struct fimc_isp *isp);
+const struct fimc_fmt *fimc_isp_find_format(const u32 *pixelformat,
+					const u32 *mbus_code, int index);
+#endif /* FIMC_ISP_H_ */
-- 
1.7.9.5

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

* [RFC PATCH 2/8] s5p-fimc: Add FIMC-IS ISP I2C bus driver
  2013-03-11 19:44 [RFC PATCH 0/8] A V4L2 driver for Exynos4x12 Imaging Subsystem Sylwester Nawrocki
  2013-03-11 19:44 ` [RFC PATCH 1/8] s5p-fimc: Add Exynos4x12 FIMC-IS driver Sylwester Nawrocki
@ 2013-03-11 19:44 ` Sylwester Nawrocki
  2013-03-11 19:44 ` [RFC PATCH 3/8] s5p-fimc: Add FIMC-IS parameter region definitions Sylwester Nawrocki
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: Sylwester Nawrocki @ 2013-03-11 19:44 UTC (permalink / raw)
  To: linux-media
  Cc: kyungmin.park, myungjoo.ham, dh09.lee, shaik.samsung, arun.kk,
	a.hajda, linux-samsung-soc, devicetree-discuss, linux-arm-kernel,
	Sylwester Nawrocki

This patch adds the ISP I2C bus controller driver files.

Creating a standard I2C bus adapter, even if the driver doesn't
actually communicates with the hardware and it is instead used
by the ISP firmware running on the Cortex-A5, allows to use
standard hardware description in the device tree. As the sensor
would have actually had a standard V4L2 sub-device driver run
on the host CPU.

This approach allows to adapt the driver with a relatively small
effort should the Imaging Subsystem architecture change so that
the I2C bus is controlled by the host CPU, rather than the
internal FIMC-IS ARM CPU. The image sensor drivers can be
standard I2C client driver, as in case of most existing image
sensor driver.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/platform/s5p-fimc/fimc-is-i2c.c |   81 +++++++++++++++++++++++++
 drivers/media/platform/s5p-fimc/fimc-is-i2c.h |   15 +++++
 2 files changed, 96 insertions(+)
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-is-i2c.c
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-is-i2c.h

diff --git a/drivers/media/platform/s5p-fimc/fimc-is-i2c.c b/drivers/media/platform/s5p-fimc/fimc-is-i2c.c
new file mode 100644
index 0000000..d4c75dc
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-is-i2c.c
@@ -0,0 +1,81 @@
+/*
+ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <linux/module.h>
+#include <linux/of_i2c.h>
+#include <linux/platform_device.h>
+#include "fimc-is-i2c.h"
+
+/*
+ * An empty algorithm is used as the actual I2C bus controller driver
+ * is implemented in the FIMC-IS subsystem firmware and the host CPU
+ * doesn't touch the hardware.
+ */
+static const struct i2c_algorithm fimc_is_i2c_algorithm;
+
+static int fimc_is_i2c_probe(struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct i2c_adapter *i2c_adap;
+	int ret;
+
+	i2c_adap = devm_kzalloc(&pdev->dev, sizeof(*i2c_adap), GFP_KERNEL);
+
+	i2c_adap->dev.of_node = node;
+	i2c_adap->dev.parent = &pdev->dev;
+	strlcpy(i2c_adap->name, "exynos4x12-is-i2c", sizeof(i2c_adap->name));
+	i2c_adap->owner = THIS_MODULE;
+	i2c_adap->algo = &fimc_is_i2c_algorithm;
+	i2c_adap->class = I2C_CLASS_SPD;
+
+	ret = i2c_add_adapter(i2c_adap);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to add I2C bus %s\n",
+						node->full_name);
+		return ret;
+	}
+	of_i2c_register_devices(i2c_adap);
+
+	return 0;
+}
+
+static int fimc_is_i2c_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static const struct of_device_id fimc_is_i2c_of_match[] = {
+	{ .compatible = FIMC_IS_I2C_COMPATIBLE },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, fimc_is_i2c_of_match);
+
+static struct platform_driver fimc_is_i2c_driver = {
+	.probe		= fimc_is_i2c_probe,
+	.remove		= fimc_is_i2c_remove,
+	.driver = {
+		.of_match_table = fimc_is_i2c_of_match,
+		.name		= "fimc-is-i2c",
+		.owner		= THIS_MODULE,
+	}
+};
+
+int fimc_is_register_i2c_driver(void)
+{
+	return platform_driver_register(&fimc_is_i2c_driver);
+}
+
+void fimc_is_unregister_i2c_driver(void)
+{
+	platform_driver_unregister(&fimc_is_i2c_driver);
+}
+
diff --git a/drivers/media/platform/s5p-fimc/fimc-is-i2c.h b/drivers/media/platform/s5p-fimc/fimc-is-i2c.h
new file mode 100644
index 0000000..0d38d6b
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-is-i2c.h
@@ -0,0 +1,15 @@
+/*
+ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define FIMC_IS_I2C_COMPATIBLE	"samsung,exynos4212-i2c-isp"
+
+int fimc_is_register_i2c_driver(void);
+void fimc_is_unregister_i2c_driver(void);
-- 
1.7.9.5

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

* [RFC PATCH 3/8] s5p-fimc: Add FIMC-IS parameter region definitions
  2013-03-11 19:44 [RFC PATCH 0/8] A V4L2 driver for Exynos4x12 Imaging Subsystem Sylwester Nawrocki
  2013-03-11 19:44 ` [RFC PATCH 1/8] s5p-fimc: Add Exynos4x12 FIMC-IS driver Sylwester Nawrocki
  2013-03-11 19:44 ` [RFC PATCH 2/8] s5p-fimc: Add FIMC-IS ISP I2C bus driver Sylwester Nawrocki
@ 2013-03-11 19:44 ` Sylwester Nawrocki
  2013-03-11 19:44 ` [RFC PATCH 4/8] s5p-fimc: Add common FIMC-IS image sensor driver Sylwester Nawrocki
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: Sylwester Nawrocki @ 2013-03-11 19:44 UTC (permalink / raw)
  To: linux-media
  Cc: kyungmin.park, myungjoo.ham, dh09.lee, shaik.samsung, arun.kk,
	a.hajda, linux-samsung-soc, devicetree-discuss, linux-arm-kernel,
	Sylwester Nawrocki

This patch adds ISP processing parameters interface files.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/platform/s5p-fimc/fimc-is-param.c |  971 +++++++++++++++++++++
 drivers/media/platform/s5p-fimc/fimc-is-param.h | 1018 +++++++++++++++++++++++
 2 files changed, 1989 insertions(+)
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-is-param.c
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-is-param.h

diff --git a/drivers/media/platform/s5p-fimc/fimc-is-param.c b/drivers/media/platform/s5p-fimc/fimc-is-param.c
new file mode 100644
index 0000000..5674c3b
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-is-param.c
@@ -0,0 +1,971 @@
+/*
+ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *
+ * Authors: Younghwan Joo <yhwan.joo@samsung.com>
+ *          Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/firmware.h>
+#include <linux/gpio.h>
+#include <plat/gpio-cfg.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "fimc-is.h"
+#include "fimc-is-command.h"
+#include "fimc-is-errno.h"
+#include "fimc-is-param.h"
+#include "fimc-is-regs.h"
+#include "fimc-is-sensor.h"
+
+static void __hw_param_copy(void *dst, void *src)
+{
+	memcpy(dst, src, FIMC_IS_PARAM_MAX_SIZE);
+}
+
+void __fimc_is_hw_update_param_global_shotmode(struct fimc_is *is)
+{
+	struct param_global_shotmode *dst, *src;
+
+	dst = &is->is_p_region->parameter.global.shotmode;
+	src = &is->cfg_param[is->scenario_id].global.shotmode;
+	__hw_param_copy(dst, src);
+}
+
+void __fimc_is_hw_update_param_sensor_framerate(struct fimc_is *is)
+{
+	struct param_sensor_framerate *dst, *src;
+
+	dst = &is->is_p_region->parameter.sensor.frame_rate;
+	src = &is->cfg_param[is->scenario_id].sensor.frame_rate;
+	__hw_param_copy(dst, src);
+}
+
+int __fimc_is_hw_update_param(struct fimc_is *is, u32 offset)
+{
+	struct is_param_region *par = &is->is_p_region->parameter;
+	struct is_config_param *cfg = &is->cfg_param[is->scenario_id];
+
+	switch (offset) {
+	case PARAM_ISP_CONTROL:
+		__hw_param_copy(&par->isp.control, &cfg->isp.control);
+		break;
+
+	case PARAM_ISP_OTF_INPUT:
+		__hw_param_copy(&par->isp.otf_input, &cfg->isp.otf_input);
+		break;
+
+	case PARAM_ISP_DMA1_INPUT:
+		__hw_param_copy(&par->isp.dma1_input, &cfg->isp.dma1_input);
+		break;
+
+	case PARAM_ISP_DMA2_INPUT:
+		__hw_param_copy(&par->isp.dma2_input, &cfg->isp.dma2_input);
+		break;
+
+	case PARAM_ISP_AA:
+		__hw_param_copy(&par->isp.aa, &cfg->isp.aa);
+		break;
+
+	case PARAM_ISP_FLASH:
+		__hw_param_copy(&par->isp.flash, &cfg->isp.flash);
+		break;
+
+	case PARAM_ISP_AWB:
+		__hw_param_copy(&par->isp.awb, &cfg->isp.awb);
+		break;
+
+	case PARAM_ISP_IMAGE_EFFECT:
+		__hw_param_copy(&par->isp.effect, &cfg->isp.effect);
+		break;
+
+	case PARAM_ISP_ISO:
+		__hw_param_copy(&par->isp.iso, &cfg->isp.iso);
+		break;
+
+	case PARAM_ISP_ADJUST:
+		__hw_param_copy(&par->isp.adjust, &cfg->isp.adjust);
+		break;
+
+	case PARAM_ISP_METERING:
+		__hw_param_copy(&par->isp.metering, &cfg->isp.metering);
+		break;
+
+	case PARAM_ISP_AFC:
+		__hw_param_copy(&par->isp.afc, &cfg->isp.afc);
+		break;
+
+	case PARAM_ISP_OTF_OUTPUT:
+		__hw_param_copy(&par->isp.otf_output, &cfg->isp.otf_output);
+		break;
+
+	case PARAM_ISP_DMA1_OUTPUT:
+		__hw_param_copy(&par->isp.dma1_output, &cfg->isp.dma1_output);
+		break;
+
+	case PARAM_ISP_DMA2_OUTPUT:
+		__hw_param_copy(&par->isp.dma2_output, &cfg->isp.dma2_output);
+		break;
+
+	case PARAM_DRC_CONTROL:
+		__hw_param_copy(&par->drc.control, &cfg->drc.control);
+		break;
+
+	case PARAM_DRC_OTF_INPUT:
+		__hw_param_copy(&par->drc.otf_input, &cfg->drc.otf_input);
+		break;
+
+	case PARAM_DRC_DMA_INPUT:
+		__hw_param_copy(&par->drc.dma_input, &cfg->drc.dma_input);
+		break;
+
+	case PARAM_DRC_OTF_OUTPUT:
+		__hw_param_copy(&par->drc.otf_output, &cfg->drc.otf_output);
+		break;
+
+	case PARAM_FD_CONTROL:
+		__hw_param_copy(&par->fd.control, &cfg->fd.control);
+		break;
+
+	case PARAM_FD_OTF_INPUT:
+		__hw_param_copy(&par->fd.otf_input, &cfg->fd.otf_input);
+		break;
+
+	case PARAM_FD_DMA_INPUT:
+		__hw_param_copy(&par->fd.dma_input, &cfg->fd.dma_input);
+		break;
+
+	case PARAM_FD_CONFIG:
+		__hw_param_copy(&par->fd.config, &cfg->fd.config);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int __is_hw_update_params(struct fimc_is *is)
+{
+	unsigned long *p_index1, *p_index2;
+	int i, id, ret = 0;
+
+	id = is->scenario_id;
+	p_index1 = &is->cfg_param[id].p_region_index1;
+	p_index2 = &is->cfg_param[id].p_region_index2;
+
+	if (test_bit(PARAM_GLOBAL_SHOTMODE, p_index1))
+		__fimc_is_hw_update_param_global_shotmode(is);
+
+	if (test_bit(PARAM_SENSOR_FRAME_RATE, p_index1))
+		__fimc_is_hw_update_param_sensor_framerate(is);
+
+	for (i = PARAM_ISP_CONTROL; i < PARAM_DRC_CONTROL; i++) {
+		if (test_bit(i, p_index1))
+			ret = __fimc_is_hw_update_param(is, i);
+	}
+
+	for (i = PARAM_DRC_CONTROL; i < PARAM_SCALERC_CONTROL; i++) {
+		if (test_bit(i, p_index1))
+			ret = __fimc_is_hw_update_param(is, i);
+	}
+
+	for (i = PARAM_FD_CONTROL; i <= PARAM_FD_CONFIG; i++) {
+		if (test_bit((i - 32), p_index2))
+			ret = __fimc_is_hw_update_param(is, i);
+	}
+
+	return ret;
+}
+
+void __is_get_frame_size(struct fimc_is *is, struct v4l2_mbus_framefmt *mf)
+{
+	struct isp_param *isp;
+
+	isp = &is->cfg_param[is->scenario_id].isp;
+	mf->width = isp->otf_input.width;
+	mf->height = isp->otf_input.height;
+}
+
+void __is_set_frame_size(struct fimc_is *is, struct v4l2_mbus_framefmt *mf)
+{
+	struct isp_param *isp;
+	struct drc_param *drc;
+	struct fd_param *fd;
+	unsigned int mode;
+
+	mode = is->scenario_id;
+	isp = &is->cfg_param[mode].isp;
+	drc = &is->cfg_param[mode].drc;
+	fd = &is->cfg_param[mode].fd;
+
+	/* Update isp size info (OTF only) */
+	isp->otf_input.width = mf->width;
+	isp->otf_input.height = mf->height;
+	isp->otf_output.width = mf->width;
+	isp->otf_output.height = mf->height;
+	/* Update drc size info (OTF only) */
+	drc->otf_input.width = mf->width;
+	drc->otf_input.height = mf->height;
+	drc->otf_output.width = mf->width;
+	drc->otf_output.height = mf->height;
+	/* Update fd size info (OTF only) */
+	fd->otf_input.width = mf->width;
+	fd->otf_input.height = mf->height;
+
+	if (test_bit(PARAM_ISP_OTF_INPUT,
+		      &is->cfg_param[mode].p_region_index1))
+		return;
+
+	/* Update field */
+	fimc_is_set_param_bit(is, PARAM_ISP_OTF_INPUT);
+	fimc_is_inc_param_num(is);
+	fimc_is_set_param_bit(is, PARAM_ISP_OTF_OUTPUT);
+	fimc_is_inc_param_num(is);
+	fimc_is_set_param_bit(is, PARAM_DRC_OTF_INPUT);
+	fimc_is_inc_param_num(is);
+	fimc_is_set_param_bit(is, PARAM_DRC_OTF_OUTPUT);
+	fimc_is_inc_param_num(is);
+	fimc_is_set_param_bit(is, PARAM_FD_OTF_INPUT);
+	fimc_is_inc_param_num(is);
+}
+
+int fimc_is_hw_get_sensor_max_framerate(struct fimc_is *is)
+{
+	switch (is->sensor->drvdata->id) {
+	case FIMC_IS_SENSOR_ID_S5K6A3:
+		return 30;
+	default:
+		return 15;
+	}
+}
+
+void __is_set_sensor(struct fimc_is *is, int fps)
+{
+	struct sensor_param *sensor;
+	struct isp_param *isp;
+	unsigned long *p_index, mode;
+
+	mode = is->scenario_id;
+	p_index = &is->cfg_param[mode].p_region_index1;
+	sensor = &is->cfg_param[mode].sensor;
+	isp = &is->cfg_param[mode].isp;
+
+	if (fps == 0) {
+		sensor->frame_rate.frame_rate =
+				fimc_is_hw_get_sensor_max_framerate(is);
+		isp->otf_input.frametime_min = 0;
+		isp->otf_input.frametime_max = 66666;
+	} else {
+		sensor->frame_rate.frame_rate = fps;
+		isp->otf_input.frametime_min = 0;
+		isp->otf_input.frametime_max = (u32)1000000 / fps;
+	}
+
+	if (!test_bit(PARAM_SENSOR_FRAME_RATE, p_index)) {
+		fimc_is_set_param_bit(is, PARAM_SENSOR_FRAME_RATE);
+		fimc_is_inc_param_num(is);
+	}
+	if (!test_bit(PARAM_ISP_OTF_INPUT, p_index)) {
+		fimc_is_set_param_bit(is, PARAM_ISP_OTF_INPUT);
+		fimc_is_inc_param_num(is);
+	}
+}
+
+void __is_set_init_isp_aa(struct fimc_is *is)
+{
+	struct isp_param *isp;
+
+	isp = &is->cfg_param[is->scenario_id].isp;
+
+	isp->aa.cmd = ISP_AA_COMMAND_START;
+	isp->aa.target = ISP_AA_TARGET_AF | ISP_AA_TARGET_AE |
+			 ISP_AA_TARGET_AWB;
+	isp->aa.mode = 0;
+	isp->aa.scene = 0;
+	isp->aa.sleep = 0;
+	isp->aa.face = 0;
+	isp->aa.touch_x = 0;
+	isp->aa.touch_y = 0;
+	isp->aa.manual_af_setting = 0;
+	isp->aa.err = ISP_AF_ERROR_NONE;
+
+	fimc_is_set_param_bit(is, PARAM_ISP_AA);
+	fimc_is_inc_param_num(is);
+}
+
+#define get_is_cfg(is, mode) (&(is)->cfg_param[mode])
+
+void __is_set_isp_flash(struct fimc_is *is, u32 cmd, u32 redeye)
+{
+	struct is_config_param *cfg;
+	struct isp_param *isp;
+	unsigned int mode;
+
+	mode = is->scenario_id;
+	cfg = get_is_cfg(is, mode);
+
+	isp = &is->cfg_param[mode].isp;
+	isp->flash.cmd = cmd;
+	isp->flash.redeye = redeye;
+	isp->flash.err = ISP_FLASH_ERROR_NONE;
+
+	if (!test_bit(PARAM_ISP_FLASH, &cfg->p_region_index1)) {
+		fimc_is_set_param_bit(is, PARAM_ISP_FLASH);
+		fimc_is_inc_param_num(is);
+	}
+}
+
+void __is_set_isp_awb(struct fimc_is *is, u32 cmd, u32 val)
+{
+	struct isp_param *isp;
+	unsigned long *p_index, mode;
+
+	mode = is->scenario_id;
+	p_index = &is->cfg_param[mode].p_region_index1;
+	isp = &is->cfg_param[mode].isp;
+
+	isp->awb.cmd = cmd;
+	isp->awb.illumination = val;
+	isp->awb.err = ISP_AWB_ERROR_NONE;
+
+	if (!test_bit(PARAM_ISP_AWB, p_index)) {
+		fimc_is_set_param_bit(is, PARAM_ISP_AWB);
+		fimc_is_inc_param_num(is);
+	}
+}
+
+void __is_set_isp_effect(struct fimc_is *is, u32 cmd)
+{
+	struct isp_param *isp;
+	unsigned long *p_index, mode;
+
+	mode = is->scenario_id;
+	p_index = &is->cfg_param[mode].p_region_index1;
+	isp = &is->cfg_param[mode].isp;
+
+	isp->effect.cmd = cmd;
+	isp->effect.err = ISP_IMAGE_EFFECT_ERROR_NONE;
+
+	if (!test_bit(PARAM_ISP_IMAGE_EFFECT, p_index)) {
+		fimc_is_set_param_bit(is, PARAM_ISP_IMAGE_EFFECT);
+		fimc_is_inc_param_num(is);
+	}
+}
+
+void __is_set_isp_iso(struct fimc_is *is, u32 cmd, u32 val)
+{
+	struct isp_param *isp;
+	unsigned long *p_index, mode;
+
+	mode = is->scenario_id;
+	p_index = &is->cfg_param[mode].p_region_index1;
+	isp = &is->cfg_param[mode].isp;
+
+	isp->iso.cmd = cmd;
+	isp->iso.value = val;
+	isp->iso.err = ISP_ISO_ERROR_NONE;
+
+	if (!test_bit(PARAM_ISP_ISO, p_index)) {
+		fimc_is_set_param_bit(is, PARAM_ISP_ISO);
+		fimc_is_inc_param_num(is);
+	}
+}
+
+void __is_set_isp_adjust(struct fimc_is *is, u32 cmd, u32 val)
+{
+	unsigned int mode = is->scenario_id;
+	unsigned long *p_index;
+	struct isp_param *isp;
+
+	p_index = &is->cfg_param[mode].p_region_index1;
+	isp = &is->cfg_param[mode].isp;
+
+	switch (cmd) {
+	case ISP_ADJUST_COMMAND_MANUAL_CONTRAST:
+		isp->adjust.contrast = val;
+		break;
+	case ISP_ADJUST_COMMAND_MANUAL_SATURATION:
+		isp->adjust.saturation = val;
+		break;
+	case ISP_ADJUST_COMMAND_MANUAL_SHARPNESS:
+		isp->adjust.sharpness = val;
+		break;
+	case ISP_ADJUST_COMMAND_MANUAL_EXPOSURE:
+		isp->adjust.exposure = val;
+		break;
+	case ISP_ADJUST_COMMAND_MANUAL_BRIGHTNESS:
+		isp->adjust.brightness = val;
+		break;
+	case ISP_ADJUST_COMMAND_MANUAL_HUE:
+		isp->adjust.hue = val;
+		break;
+	case ISP_ADJUST_COMMAND_AUTO:
+		isp->adjust.contrast = 0;
+		isp->adjust.saturation = 0;
+		isp->adjust.sharpness = 0;
+		isp->adjust.exposure = 0;
+		isp->adjust.brightness = 0;
+		isp->adjust.hue = 0;
+		break;
+	}
+
+	if (!test_bit(PARAM_ISP_ADJUST, p_index)) {
+		isp->adjust.cmd = cmd;
+		isp->adjust.err = ISP_ADJUST_ERROR_NONE;
+		fimc_is_set_param_bit(is, PARAM_ISP_ADJUST);
+		fimc_is_inc_param_num(is);
+	} else {
+		isp->adjust.cmd |= cmd;
+	}
+}
+
+void __is_set_isp_metering(struct fimc_is *is, u32 id, u32 val)
+{
+	struct isp_param *isp;
+	unsigned long *p_index, mode;
+
+	mode = is->scenario_id;
+	p_index = &is->cfg_param[mode].p_region_index1;
+	isp = &is->cfg_param[mode].isp;
+
+	switch (id) {
+	case IS_METERING_CONFIG_CMD:
+		isp->metering.cmd = val;
+		break;
+	case IS_METERING_CONFIG_WIN_POS_X:
+		isp->metering.win_pos_x = val;
+		break;
+	case IS_METERING_CONFIG_WIN_POS_Y:
+		isp->metering.win_pos_y = val;
+		break;
+	case IS_METERING_CONFIG_WIN_WIDTH:
+		isp->metering.win_width = val;
+		break;
+	case IS_METERING_CONFIG_WIN_HEIGHT:
+		isp->metering.win_height = val;
+		break;
+	default:
+		return;
+	}
+
+	if (!test_bit(PARAM_ISP_METERING, p_index)) {
+		isp->metering.err = ISP_METERING_ERROR_NONE;
+		fimc_is_set_param_bit(is, PARAM_ISP_METERING);
+		fimc_is_inc_param_num(is);
+	}
+}
+
+void __is_set_isp_afc(struct fimc_is *is, u32 cmd, u32 val)
+{
+	struct isp_param *isp;
+	unsigned long *p_index, mode;
+
+	mode = is->scenario_id;
+	p_index = &is->cfg_param[mode].p_region_index1;
+	isp = &is->cfg_param[mode].isp;
+
+	isp->afc.cmd = cmd;
+	isp->afc.manual = val;
+	isp->afc.err = ISP_AFC_ERROR_NONE;
+
+	if (!test_bit(PARAM_ISP_AFC, p_index)) {
+		fimc_is_set_param_bit(is, PARAM_ISP_AFC);
+		fimc_is_inc_param_num(is);
+	}
+}
+
+void __is_set_drc_control(struct fimc_is *is, u32 val)
+{
+	struct drc_param *drc;
+	unsigned long *p_index, mode;
+
+	mode = is->scenario_id;
+	p_index = &is->cfg_param[mode].p_region_index1;
+	drc = &is->cfg_param[mode].drc;
+
+	drc->control.bypass = val;
+
+	if (!test_bit(PARAM_DRC_CONTROL, p_index)) {
+		fimc_is_set_param_bit(is, PARAM_DRC_CONTROL);
+		fimc_is_inc_param_num(is);
+	}
+}
+
+void __is_set_fd_control(struct fimc_is *is, u32 val)
+{
+	struct fd_param *fd;
+	unsigned long *p_index, mode;
+
+	mode = is->scenario_id;
+	p_index = &is->cfg_param[mode].p_region_index2;
+	fd = &is->cfg_param[mode].fd;
+
+	fd->control.cmd = val;
+
+	if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) {
+		fimc_is_set_param_bit(is, PARAM_FD_CONTROL);
+		fimc_is_inc_param_num(is);
+	}
+}
+
+void __is_set_fd_config_maxface(struct fimc_is *is, u32 val)
+{
+	struct fd_param *fd;
+	unsigned long *p_index, mode;
+
+	mode = is->scenario_id;
+	p_index = &is->cfg_param[mode].p_region_index2;
+	fd = &is->cfg_param[mode].fd;
+
+	fd->config.max_number = val;
+
+	if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) {
+		fd->config.cmd = FD_CONFIG_COMMAND_MAXIMUM_NUMBER;
+		fd->config.err = ERROR_FD_NONE;
+		fimc_is_set_param_bit(is, PARAM_FD_CONFIG);
+		fimc_is_inc_param_num(is);
+	} else {
+		fd->config.cmd |= FD_CONFIG_COMMAND_MAXIMUM_NUMBER;
+	}
+}
+
+void __is_set_fd_config_rollangle(struct fimc_is *is, u32 val)
+{
+	struct fd_param *fd;
+	unsigned long *p_index, mode;
+
+	mode = is->scenario_id;
+	p_index = &is->cfg_param[mode].p_region_index2;
+	fd = &is->cfg_param[mode].fd;
+
+	fd->config.roll_angle = val;
+
+	if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) {
+		fd->config.cmd = FD_CONFIG_COMMAND_ROLL_ANGLE;
+		fd->config.err = ERROR_FD_NONE;
+		fimc_is_set_param_bit(is, PARAM_FD_CONFIG);
+		fimc_is_inc_param_num(is);
+	} else {
+		fd->config.cmd |= FD_CONFIG_COMMAND_ROLL_ANGLE;
+	}
+}
+
+void __is_set_fd_config_yawangle(struct fimc_is *is, u32 val)
+{
+	struct fd_param *fd;
+	unsigned long *p_index, mode;
+
+	mode = is->scenario_id;
+	p_index = &is->cfg_param[mode].p_region_index2;
+	fd = &is->cfg_param[mode].fd;
+
+	fd->config.yaw_angle = val;
+
+	if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) {
+		fd->config.cmd = FD_CONFIG_COMMAND_YAW_ANGLE;
+		fd->config.err = ERROR_FD_NONE;
+		fimc_is_set_param_bit(is, PARAM_FD_CONFIG);
+		fimc_is_inc_param_num(is);
+	} else {
+		fd->config.cmd |= FD_CONFIG_COMMAND_YAW_ANGLE;
+	}
+}
+
+void __is_set_fd_config_smilemode(struct fimc_is *is, u32 val)
+{
+	struct fd_param *fd;
+	unsigned long *p_index, mode;
+
+	mode = is->scenario_id;
+	p_index = &is->cfg_param[mode].p_region_index2;
+	fd = &is->cfg_param[mode].fd;
+
+	fd->config.smile_mode = val;
+
+	if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) {
+		fd->config.cmd = FD_CONFIG_COMMAND_SMILE_MODE;
+		fd->config.err = ERROR_FD_NONE;
+		fimc_is_set_param_bit(is, PARAM_FD_CONFIG);
+		fimc_is_inc_param_num(is);
+	} else {
+		fd->config.cmd |= FD_CONFIG_COMMAND_SMILE_MODE;
+	}
+}
+
+void __is_set_fd_config_blinkmode(struct fimc_is *is, u32 val)
+{
+	struct fd_param *fd;
+	unsigned long *p_index, mode;
+
+	mode = is->scenario_id;
+	p_index = &is->cfg_param[mode].p_region_index2;
+	fd = &is->cfg_param[mode].fd;
+
+	fd->config.blink_mode = val;
+
+	if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) {
+		fd->config.cmd = FD_CONFIG_COMMAND_BLINK_MODE;
+		fd->config.err = ERROR_FD_NONE;
+		fimc_is_set_param_bit(is, PARAM_FD_CONFIG);
+		fimc_is_inc_param_num(is);
+	} else {
+		fd->config.cmd |= FD_CONFIG_COMMAND_BLINK_MODE;
+	}
+}
+
+void __is_set_fd_config_eyedetect(struct fimc_is *is, u32 val)
+{
+	struct fd_param *fd;
+	unsigned long *p_index, mode;
+
+	mode = is->scenario_id;
+	p_index = &is->cfg_param[mode].p_region_index2;
+	fd = &is->cfg_param[mode].fd;
+
+	fd->config.eye_detect = val;
+
+	if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) {
+		fd->config.cmd = FD_CONFIG_COMMAND_EYES_DETECT;
+		fd->config.err = ERROR_FD_NONE;
+		fimc_is_set_param_bit(is, PARAM_FD_CONFIG);
+		fimc_is_inc_param_num(is);
+	} else {
+		fd->config.cmd |= FD_CONFIG_COMMAND_EYES_DETECT;
+	}
+}
+
+void __is_set_fd_config_mouthdetect(struct fimc_is *is, u32 val)
+{
+	struct fd_param *fd;
+	unsigned long *p_index, mode;
+
+	mode = is->scenario_id;
+	p_index = &is->cfg_param[mode].p_region_index2;
+	fd = &is->cfg_param[mode].fd;
+
+	fd->config.mouth_detect = val;
+
+	if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) {
+		fd->config.cmd = FD_CONFIG_COMMAND_MOUTH_DETECT;
+		fd->config.err = ERROR_FD_NONE;
+		fimc_is_set_param_bit(is, PARAM_FD_CONFIG);
+		fimc_is_inc_param_num(is);
+	} else {
+		fd->config.cmd |= FD_CONFIG_COMMAND_MOUTH_DETECT;
+	}
+}
+
+void __is_set_fd_config_orientation(struct fimc_is *is, u32 val)
+{
+	struct fd_param *fd;
+	unsigned long *p_index, mode;
+
+	mode = is->scenario_id;
+	p_index = &is->cfg_param[mode].p_region_index2;
+	fd = &is->cfg_param[mode].fd;
+
+	fd->config.orientation = val;
+
+	if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) {
+		fd->config.cmd = FD_CONFIG_COMMAND_ORIENTATION;
+		fd->config.err = ERROR_FD_NONE;
+		fimc_is_set_param_bit(is, PARAM_FD_CONFIG);
+		fimc_is_inc_param_num(is);
+	} else {
+		fd->config.cmd |= FD_CONFIG_COMMAND_ORIENTATION;
+	}
+}
+
+void __is_set_fd_config_orientation_val(struct fimc_is *is, u32 val)
+{
+	struct fd_param *fd;
+	unsigned long *p_index, mode;
+
+	mode = is->scenario_id;
+	p_index = &is->cfg_param[mode].p_region_index2;
+	fd = &is->cfg_param[mode].fd;
+
+	fd->config.orientation_value = val;
+
+	if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) {
+		fd->config.cmd = FD_CONFIG_COMMAND_ORIENTATION_VALUE;
+		fd->config.err = ERROR_FD_NONE;
+		fimc_is_set_param_bit(is, PARAM_FD_CONFIG);
+		fimc_is_inc_param_num(is);
+	} else {
+		fd->config.cmd |= FD_CONFIG_COMMAND_ORIENTATION_VALUE;
+	}
+}
+
+void fimc_is_set_initial_params(struct fimc_is *is)
+{
+	struct global_param *global;
+	struct sensor_param *sensor;
+	struct isp_param *isp;
+	struct drc_param *drc;
+	struct fd_param *fd;
+	unsigned long *p_index1, *p_index2;
+	unsigned int mode;
+
+	mode = is->scenario_id;
+	global = &is->cfg_param[mode].global;
+	sensor = &is->cfg_param[mode].sensor;
+	isp = &is->cfg_param[mode].isp;
+	drc = &is->cfg_param[mode].drc;
+	fd = &is->cfg_param[mode].fd;
+	p_index1 = &is->cfg_param[mode].p_region_index1;
+	p_index2 = &is->cfg_param[mode].p_region_index2;
+
+	/* Global */
+	global->shotmode.cmd = 1;
+	fimc_is_set_param_bit(is, PARAM_GLOBAL_SHOTMODE);
+	fimc_is_inc_param_num(is);
+
+	/* ISP */
+	isp->control.cmd = CONTROL_COMMAND_START;
+	isp->control.bypass = CONTROL_BYPASS_DISABLE;
+	isp->control.err = CONTROL_ERROR_NONE;
+	fimc_is_set_param_bit(is, PARAM_ISP_CONTROL);
+	fimc_is_inc_param_num(is);
+
+	isp->otf_input.cmd = OTF_INPUT_COMMAND_ENABLE;
+	if (!test_bit(PARAM_ISP_OTF_INPUT, p_index1)) {
+		isp->otf_input.width = DEFAULT_PREVIEW_STILL_WIDTH;
+		isp->otf_input.height = DEFAULT_PREVIEW_STILL_HEIGHT;
+		fimc_is_set_param_bit(is, PARAM_ISP_OTF_INPUT);
+		fimc_is_inc_param_num(is);
+	}
+	if (is->sensor->test_pattern)
+		isp->otf_input.format = OTF_INPUT_FORMAT_STRGEN_COLORBAR_BAYER;
+	else
+		isp->otf_input.format = OTF_INPUT_FORMAT_BAYER;
+	isp->otf_input.bitwidth = 10;
+	isp->otf_input.order = OTF_INPUT_ORDER_BAYER_GR_BG;
+	isp->otf_input.crop_offset_x = 0;
+	isp->otf_input.crop_offset_y = 0;
+	isp->otf_input.err = OTF_INPUT_ERROR_NONE;
+
+	isp->dma1_input.cmd = DMA_INPUT_COMMAND_DISABLE;
+	isp->dma1_input.width = 0;
+	isp->dma1_input.height = 0;
+	isp->dma1_input.format = 0;
+	isp->dma1_input.bitwidth = 0;
+	isp->dma1_input.plane = 0;
+	isp->dma1_input.order = 0;
+	isp->dma1_input.buffer_number = 0;
+	isp->dma1_input.width = 0;
+	isp->dma1_input.err = DMA_INPUT_ERROR_NONE;
+	fimc_is_set_param_bit(is, PARAM_ISP_DMA1_INPUT);
+	fimc_is_inc_param_num(is);
+
+	isp->dma2_input.cmd = DMA_INPUT_COMMAND_DISABLE;
+	isp->dma2_input.width = 0;
+	isp->dma2_input.height = 0;
+	isp->dma2_input.format = 0;
+	isp->dma2_input.bitwidth = 0;
+	isp->dma2_input.plane = 0;
+	isp->dma2_input.order = 0;
+	isp->dma2_input.buffer_number = 0;
+	isp->dma2_input.width = 0;
+	isp->dma2_input.err = DMA_INPUT_ERROR_NONE;
+	fimc_is_set_param_bit(is, PARAM_ISP_DMA2_INPUT);
+	fimc_is_inc_param_num(is);
+
+	isp->aa.cmd = ISP_AA_COMMAND_START;
+	isp->aa.target = ISP_AA_TARGET_AE | ISP_AA_TARGET_AWB;
+	fimc_is_set_param_bit(is, PARAM_ISP_AA);
+	fimc_is_inc_param_num(is);
+
+	if (!test_bit(PARAM_ISP_FLASH, p_index1))
+		__is_set_isp_flash(is, ISP_FLASH_COMMAND_DISABLE,
+						ISP_FLASH_REDEYE_DISABLE);
+
+	if (!test_bit(PARAM_ISP_AWB, p_index1))
+		__is_set_isp_awb(is, ISP_AWB_COMMAND_AUTO, 0);
+
+	if (!test_bit(PARAM_ISP_IMAGE_EFFECT, p_index1))
+		__is_set_isp_effect(is, ISP_IMAGE_EFFECT_DISABLE);
+
+	if (!test_bit(PARAM_ISP_ISO, p_index1))
+		__is_set_isp_iso(is, ISP_ISO_COMMAND_AUTO, 0);
+
+	if (!test_bit(PARAM_ISP_ADJUST, p_index1)) {
+		__is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_CONTRAST, 0);
+		__is_set_isp_adjust(is,
+				ISP_ADJUST_COMMAND_MANUAL_SATURATION, 0);
+		__is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_SHARPNESS, 0);
+		__is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_EXPOSURE, 0);
+		__is_set_isp_adjust(is,
+				ISP_ADJUST_COMMAND_MANUAL_BRIGHTNESS, 0);
+		__is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_HUE, 0);
+	}
+
+	if (!test_bit(PARAM_ISP_METERING, p_index1)) {
+		__is_set_isp_metering(is, 0, ISP_METERING_COMMAND_CENTER);
+		__is_set_isp_metering(is, 1, 0);
+		__is_set_isp_metering(is, 2, 0);
+		__is_set_isp_metering(is, 3, 0);
+		__is_set_isp_metering(is, 4, 0);
+	}
+
+	if (!test_bit(PARAM_ISP_AFC, p_index1))
+		__is_set_isp_afc(is, ISP_AFC_COMMAND_AUTO, 0);
+
+	isp->otf_output.cmd = OTF_OUTPUT_COMMAND_ENABLE;
+	if (!test_bit(PARAM_ISP_OTF_OUTPUT, p_index1)) {
+		isp->otf_output.width = DEFAULT_PREVIEW_STILL_WIDTH;
+		isp->otf_output.height = DEFAULT_PREVIEW_STILL_HEIGHT;
+		fimc_is_set_param_bit(is, PARAM_ISP_OTF_OUTPUT);
+		fimc_is_inc_param_num(is);
+	}
+	isp->otf_output.format = OTF_OUTPUT_FORMAT_YUV444;
+	isp->otf_output.bitwidth = 12;
+	isp->otf_output.order = 0;
+	isp->otf_output.err = OTF_OUTPUT_ERROR_NONE;
+
+	if (!test_bit(PARAM_ISP_DMA1_OUTPUT, p_index1)) {
+		isp->dma1_output.cmd = DMA_OUTPUT_COMMAND_DISABLE;
+		isp->dma1_output.width = 0;
+		isp->dma1_output.height = 0;
+		isp->dma1_output.format = 0;
+		isp->dma1_output.bitwidth = 0;
+		isp->dma1_output.plane = 0;
+		isp->dma1_output.order = 0;
+		isp->dma1_output.buffer_number = 0;
+		isp->dma1_output.buffer_address = 0;
+		isp->dma1_output.notify_dma_done = 0;
+		isp->dma1_output.dma_out_mask = 0;
+		isp->dma1_output.err = DMA_OUTPUT_ERROR_NONE;
+		fimc_is_set_param_bit(is, PARAM_ISP_DMA1_OUTPUT);
+		fimc_is_inc_param_num(is);
+	}
+
+	if (!test_bit(PARAM_ISP_DMA2_OUTPUT, p_index1)) {
+		isp->dma2_output.cmd = DMA_OUTPUT_COMMAND_DISABLE;
+		isp->dma2_output.width = 0;
+		isp->dma2_output.height = 0;
+		isp->dma2_output.format = 0;
+		isp->dma2_output.bitwidth = 0;
+		isp->dma2_output.plane = 0;
+		isp->dma2_output.order = 0;
+		isp->dma2_output.buffer_number = 0;
+		isp->dma2_output.buffer_address = 0;
+		isp->dma2_output.notify_dma_done = 0;
+		isp->dma2_output.dma_out_mask = 0;
+		isp->dma2_output.err = DMA_OUTPUT_ERROR_NONE;
+		fimc_is_set_param_bit(is, PARAM_ISP_DMA2_OUTPUT);
+		fimc_is_inc_param_num(is);
+	}
+
+	/* Sensor */
+	if (!test_bit(PARAM_SENSOR_FRAME_RATE, p_index1)) {
+		if (!mode)
+			__is_set_sensor(is, 0);
+	}
+
+	/* DRC */
+	drc->control.cmd = CONTROL_COMMAND_START;
+	__is_set_drc_control(is, CONTROL_BYPASS_ENABLE);
+
+	drc->otf_input.cmd = OTF_INPUT_COMMAND_ENABLE;
+	if (!test_bit(PARAM_DRC_OTF_INPUT, p_index1)) {
+		drc->otf_input.width = DEFAULT_PREVIEW_STILL_WIDTH;
+		drc->otf_input.height = DEFAULT_PREVIEW_STILL_HEIGHT;
+		fimc_is_set_param_bit(is, PARAM_DRC_OTF_INPUT);
+		fimc_is_inc_param_num(is);
+	}
+	drc->otf_input.format = OTF_INPUT_FORMAT_YUV444;
+	drc->otf_input.bitwidth = 12;
+	drc->otf_input.order = 0;
+	drc->otf_input.err = OTF_INPUT_ERROR_NONE;
+
+	drc->dma_input.cmd = DMA_INPUT_COMMAND_DISABLE;
+	drc->dma_input.width = 0;
+	drc->dma_input.height = 0;
+	drc->dma_input.format = 0;
+	drc->dma_input.bitwidth = 0;
+	drc->dma_input.plane = 0;
+	drc->dma_input.order = 0;
+	drc->dma_input.buffer_number = 0;
+	drc->dma_input.width = 0;
+	drc->dma_input.err = DMA_INPUT_ERROR_NONE;
+	fimc_is_set_param_bit(is, PARAM_DRC_DMA_INPUT);
+	fimc_is_inc_param_num(is);
+
+	drc->otf_output.cmd = OTF_OUTPUT_COMMAND_ENABLE;
+	if (!test_bit(PARAM_DRC_OTF_OUTPUT, p_index1)) {
+		drc->otf_output.width = DEFAULT_PREVIEW_STILL_WIDTH;
+		drc->otf_output.height = DEFAULT_PREVIEW_STILL_HEIGHT;
+		fimc_is_set_param_bit(is, PARAM_DRC_OTF_OUTPUT);
+		fimc_is_inc_param_num(is);
+	}
+	drc->otf_output.format = OTF_OUTPUT_FORMAT_YUV444;
+	drc->otf_output.bitwidth = 8;
+	drc->otf_output.order = 0;
+	drc->otf_output.err = OTF_OUTPUT_ERROR_NONE;
+
+	/* FD */
+	__is_set_fd_control(is, CONTROL_COMMAND_STOP);
+	fd->control.bypass = CONTROL_BYPASS_DISABLE;
+
+	fd->otf_input.cmd = OTF_INPUT_COMMAND_ENABLE;
+	if (!test_bit((PARAM_FD_OTF_INPUT - 32), p_index2)) {
+		fd->otf_input.width = DEFAULT_PREVIEW_STILL_WIDTH;
+		fd->otf_input.height = DEFAULT_PREVIEW_STILL_HEIGHT;
+		fimc_is_set_param_bit(is, PARAM_FD_OTF_INPUT);
+		fimc_is_inc_param_num(is);
+	}
+	fd->otf_input.format = OTF_INPUT_FORMAT_YUV444;
+	fd->otf_input.bitwidth = 8;
+	fd->otf_input.order = 0;
+	fd->otf_input.err = OTF_INPUT_ERROR_NONE;
+
+	fd->dma_input.cmd = DMA_INPUT_COMMAND_DISABLE;
+	fd->dma_input.width = 0;
+	fd->dma_input.height = 0;
+	fd->dma_input.format = 0;
+	fd->dma_input.bitwidth = 0;
+	fd->dma_input.plane = 0;
+	fd->dma_input.order = 0;
+	fd->dma_input.buffer_number = 0;
+	fd->dma_input.width = 0;
+	fd->dma_input.err = DMA_INPUT_ERROR_NONE;
+	fimc_is_set_param_bit(is, PARAM_FD_DMA_INPUT);
+	fimc_is_inc_param_num(is);
+
+	__is_set_fd_config_maxface(is, 5);
+	__is_set_fd_config_rollangle(is, FD_CONFIG_ROLL_ANGLE_FULL);
+	__is_set_fd_config_yawangle(is, FD_CONFIG_YAW_ANGLE_45_90);
+	__is_set_fd_config_smilemode(is, FD_CONFIG_SMILE_MODE_DISABLE);
+	__is_set_fd_config_blinkmode(is, FD_CONFIG_BLINK_MODE_DISABLE);
+	__is_set_fd_config_eyedetect(is, FD_CONFIG_EYES_DETECT_ENABLE);
+	__is_set_fd_config_mouthdetect(is, FD_CONFIG_MOUTH_DETECT_DISABLE);
+	__is_set_fd_config_orientation(is, FD_CONFIG_ORIENTATION_DISABLE);
+	__is_set_fd_config_orientation_val(is, 0);
+}
diff --git a/drivers/media/platform/s5p-fimc/fimc-is-param.h b/drivers/media/platform/s5p-fimc/fimc-is-param.h
new file mode 100644
index 0000000..e9c8962
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-is-param.h
@@ -0,0 +1,1018 @@
+/*
+ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd.
+ *
+ * Authors: Younghwan Joo <yhwan.joo@samsung.com>
+ *	    Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef FIMC_IS_PARAM_H_
+#define FIMC_IS_PARAM_H_
+
+#include <linux/compiler.h>
+
+#define FIMC_IS_CONFIG_TIMEOUT		3000 /* ms */
+#define IS_DEFAULT_WIDTH		1280
+#define IS_DEFAULT_HEIGHT		720
+
+#define DEFAULT_PREVIEW_STILL_WIDTH	IS_DEFAULT_WIDTH
+#define DEFAULT_PREVIEW_STILL_HEIGHT	IS_DEFAULT_HEIGHT
+#define DEFAULT_CAPTURE_STILL_WIDTH	IS_DEFAULT_WIDTH
+#define DEFAULT_CAPTURE_STILL_HEIGHT	IS_DEFAULT_HEIGHT
+#define DEFAULT_PREVIEW_VIDEO_WIDTH	IS_DEFAULT_WIDTH
+#define DEFAULT_PREVIEW_VIDEO_HEIGHT	IS_DEFAULT_HEIGHT
+#define DEFAULT_CAPTURE_VIDEO_WIDTH	IS_DEFAULT_WIDTH
+#define DEFAULT_CAPTURE_VIDEO_HEIGHT	IS_DEFAULT_HEIGHT
+
+#define DEFAULT_PREVIEW_STILL_FRAMERATE	30
+#define DEFAULT_CAPTURE_STILL_FRAMERATE	15
+#define DEFAULT_PREVIEW_VIDEO_FRAMERATE	30
+#define DEFAULT_CAPTURE_VIDEO_FRAMERATE	30
+
+#define FIMC_IS_REGION_VER		124 /* IS REGION VERSION 1.24 */
+#define FIMC_IS_PARAM_SIZE		(FIMC_IS_REGION_SIZE + 1)
+#define FIMC_IS_MAGIC_NUMBER		0x01020304
+#define FIMC_IS_PARAM_MAX_SIZE		64 /* in bytes */
+#define FIMC_IS_PARAM_MAX_ENTRIES	(FIMC_IS_PARAM_MAX_SIZE / 4)
+
+/* The parameter bitmask bit definitions. */
+enum is_param_bit {
+	PARAM_GLOBAL_SHOTMODE,
+	PARAM_SENSOR_CONTROL,
+	PARAM_SENSOR_OTF_OUTPUT,
+	PARAM_SENSOR_FRAME_RATE,
+	PARAM_BUFFER_CONTROL,
+	PARAM_BUFFER_OTF_INPUT,
+	PARAM_BUFFER_OTF_OUTPUT,
+	PARAM_ISP_CONTROL,
+	PARAM_ISP_OTF_INPUT,
+	PARAM_ISP_DMA1_INPUT,
+	/* 10 */
+	PARAM_ISP_DMA2_INPUT,
+	PARAM_ISP_AA,
+	PARAM_ISP_FLASH,
+	PARAM_ISP_AWB,
+	PARAM_ISP_IMAGE_EFFECT,
+	PARAM_ISP_ISO,
+	PARAM_ISP_ADJUST,
+	PARAM_ISP_METERING,
+	PARAM_ISP_AFC,
+	PARAM_ISP_OTF_OUTPUT,
+	/* 20 */
+	PARAM_ISP_DMA1_OUTPUT,
+	PARAM_ISP_DMA2_OUTPUT,
+	PARAM_DRC_CONTROL,
+	PARAM_DRC_OTF_INPUT,
+	PARAM_DRC_DMA_INPUT,
+	PARAM_DRC_OTF_OUTPUT,
+	PARAM_SCALERC_CONTROL,
+	PARAM_SCALERC_OTF_INPUT,
+	PARAM_SCALERC_IMAGE_EFFECT,
+	PARAM_SCALERC_INPUT_CROP,
+	/* 30 */
+	PARAM_SCALERC_OUTPUT_CROP,
+	PARAM_SCALERC_OTF_OUTPUT,
+	PARAM_SCALERC_DMA_OUTPUT,
+	PARAM_ODC_CONTROL,
+	PARAM_ODC_OTF_INPUT,
+	PARAM_ODC_OTF_OUTPUT,
+	PARAM_DIS_CONTROL,
+	PARAM_DIS_OTF_INPUT,
+	PARAM_DIS_OTF_OUTPUT,
+	PARAM_TDNR_CONTROL,
+	/* 40 */
+	PARAM_TDNR_OTF_INPUT,
+	PARAM_TDNR_1ST_FRAME,
+	PARAM_TDNR_OTF_OUTPUT,
+	PARAM_TDNR_DMA_OUTPUT,
+	PARAM_SCALERP_CONTROL,
+	PARAM_SCALERP_OTF_INPUT,
+	PARAM_SCALERP_IMAGE_EFFECT,
+	PARAM_SCALERP_INPUT_CROP,
+	PARAM_SCALERP_OUTPUT_CROP,
+	PARAM_SCALERP_ROTATION,
+	/* 50 */
+	PARAM_SCALERP_FLIP,
+	PARAM_SCALERP_OTF_OUTPUT,
+	PARAM_SCALERP_DMA_OUTPUT,
+	PARAM_FD_CONTROL,
+	PARAM_FD_OTF_INPUT,
+	PARAM_FD_DMA_INPUT,
+	PARAM_FD_CONFIG,
+};
+
+/* Input */
+
+#define CONTROL_COMMAND_STOP			0
+#define CONTROL_COMMAND_START			1
+
+#define CONTROL_BYPASS_DISABLE			0
+#define CONTROL_BYPASS_ENABLE			1
+
+#define CONTROL_ERROR_NONE			0
+
+/* OTF (On-The-Fly) input interface commands */
+#define OTF_INPUT_COMMAND_DISABLE		0
+#define OTF_INPUT_COMMAND_ENABLE		1
+
+/* OTF input interface color formats */
+enum oft_input_fmt {
+	OTF_INPUT_FORMAT_BAYER			= 0, /* 1 channel */
+	OTF_INPUT_FORMAT_YUV444			= 1, /* 3 channels */
+	OTF_INPUT_FORMAT_YUV422			= 2, /* 3 channels */
+	OTF_INPUT_FORMAT_YUV420			= 3, /* 3 channels */
+	OTF_INPUT_FORMAT_STRGEN_COLORBAR_BAYER	= 10,
+	OTF_INPUT_FORMAT_BAYER_DMA		= 11,
+};
+
+#define OTF_INPUT_ORDER_BAYER_GR_BG		0
+
+/* OTF input error codes */
+#define OTF_INPUT_ERROR_NONE			0 /* Input setting is done */
+
+/* DMA input commands */
+#define DMA_INPUT_COMMAND_DISABLE		0
+#define DMA_INPUT_COMMAND_ENABLE		1
+
+/* DMA input color formats */
+enum dma_input_fmt {
+	DMA_INPUT_FORMAT_BAYER			= 0,
+	DMA_INPUT_FORMAT_YUV444			= 1,
+	DMA_INPUT_FORMAT_YUV422			= 2,
+	DMA_INPUT_FORMAT_YUV420			= 3,
+};
+
+enum dma_input_order {
+	/* (for DMA_INPUT_PLANE_3) */
+	DMA_INPUT_ORDER_NO	= 0,
+	/* (only valid at DMA_INPUT_PLANE_2) */
+	DMA_INPUT_ORDER_CbCr	= 1,
+	/* (only valid at DMA_INPUT_PLANE_2) */
+	DMA_INPUT_ORDER_CrCb	= 2,
+	/* (only valid at DMA_INPUT_PLANE_1 & DMA_INPUT_FORMAT_YUV444) */
+	DMA_INPUT_ORDER_YCbCr	= 3,
+	/* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */
+	DMA_INPUT_ORDER_YYCbCr	= 4,
+	/* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */
+	DMA_INPUT_ORDER_YCbYCr	= 5,
+	/* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */
+	DMA_INPUT_ORDER_YCrYCb	= 6,
+	/* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */
+	DMA_INPUT_ORDER_CbYCrY	= 7,
+	/* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */
+	DMA_INPUT_ORDER_CrYCbY	= 8,
+	/* (only valid at DMA_INPUT_FORMAT_BAYER) */
+	DMA_INPUT_ORDER_GR_BG	= 9
+};
+
+#define DMA_INPUT_ERROR_NONE			0 /* DMA input setting
+						     is done */
+/*
+ * Data output parameter definitions
+ */
+#define OTF_OUTPUT_CROP_DISABLE			0
+#define OTF_OUTPUT_CROP_ENABLE			1
+
+#define OTF_OUTPUT_COMMAND_DISABLE		0
+#define OTF_OUTPUT_COMMAND_ENABLE		1
+
+enum otf_output_fmt {
+	OTF_OUTPUT_FORMAT_YUV444		= 1,
+	OTF_OUTPUT_FORMAT_YUV422		= 2,
+	OTF_OUTPUT_FORMAT_YUV420		= 3,
+	OTF_OUTPUT_FORMAT_RGB			= 4,
+};
+
+#define OTF_OUTPUT_ORDER_BAYER_GR_BG		0
+
+#define OTF_OUTPUT_ERROR_NONE			0 /* Output Setting is done */
+
+#define DMA_OUTPUT_COMMAND_DISABLE		0
+#define DMA_OUTPUT_COMMAND_ENABLE		1
+
+enum dma_output_fmt {
+	DMA_OUTPUT_FORMAT_BAYER			= 0,
+	DMA_OUTPUT_FORMAT_YUV444		= 1,
+	DMA_OUTPUT_FORMAT_YUV422		= 2,
+	DMA_OUTPUT_FORMAT_YUV420		= 3,
+	DMA_OUTPUT_FORMAT_RGB			= 4,
+};
+
+enum dma_output_order {
+	DMA_OUTPUT_ORDER_NO		= 0,
+	/* for DMA_OUTPUT_PLANE_3 */
+	DMA_OUTPUT_ORDER_CbCr		= 1,
+	/* only valid at DMA_INPUT_PLANE_2) */
+	DMA_OUTPUT_ORDER_CrCb		= 2,
+	/* only valid at DMA_OUTPUT_PLANE_2) */
+	DMA_OUTPUT_ORDER_YYCbCr		= 3,
+	/* only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1 */
+	DMA_OUTPUT_ORDER_YCbYCr		= 4,
+	/* only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1 */
+	DMA_OUTPUT_ORDER_YCrYCb		= 5,
+	/* only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1 */
+	DMA_OUTPUT_ORDER_CbYCrY		= 6,
+	/* only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1 */
+	DMA_OUTPUT_ORDER_CrYCbY		= 7,
+	/* only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1 */
+	DMA_OUTPUT_ORDER_YCbCr		= 8,
+	/* only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1 */
+	DMA_OUTPUT_ORDER_CrYCb		= 9,
+	/* only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1 */
+	DMA_OUTPUT_ORDER_CrCbY		= 10,
+	/* only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1 */
+	DMA_OUTPUT_ORDER_CbYCr		= 11,
+	/* only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1 */
+	DMA_OUTPUT_ORDER_YCrCb		= 12,
+	/* only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1 */
+	DMA_OUTPUT_ORDER_CbCrY		= 13,
+	/* only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1 */
+	DMA_OUTPUT_ORDER_BGR		= 14,
+	/* only valid at DMA_OUTPUT_FORMAT_RGB */
+	DMA_OUTPUT_ORDER_GB_BG		= 15
+	/* only valid at DMA_OUTPUT_FORMAT_BAYER */
+};
+
+/* enum dma_output_notify_dma_done */
+#define DMA_OUTPUT_NOTIFY_DMA_DONE_DISABLE	0
+#define DMA_OUTPUT_NOTIFY_DMA_DONE_ENABLE	1
+
+/* DMA output error codes */
+#define DMA_OUTPUT_ERROR_NONE			0 /* DMA output setting
+						     is done */
+
+/* ----------------------  Global  ----------------------------------- */
+#define GLOBAL_SHOTMODE_ERROR_NONE		0 /* shot-mode setting
+						     is done */
+/* 3A lock commands */
+#define ISP_AA_COMMAND_START			0
+#define ISP_AA_COMMAND_STOP			1
+
+/* 3A lock target */
+#define ISP_AA_TARGET_AF			1
+#define ISP_AA_TARGET_AE			2
+#define ISP_AA_TARGET_AWB			4
+
+enum isp_af_mode {
+	ISP_AF_MODE_MANUAL			= 0,
+	ISP_AF_MODE_SINGLE			= 1,
+	ISP_AF_MODE_CONTINUOUS			= 2,
+	ISP_AF_MODE_TOUCH			= 3,
+	ISP_AF_MODE_SLEEP			= 4,
+	ISP_AF_MODE_INIT			= 5,
+	ISP_AF_MODE_SET_CENTER_WINDOW		= 6,
+	ISP_AF_MODE_SET_TOUCH_WINDOW		= 7
+};
+
+/* Face AF commands */
+#define ISP_AF_FACE_DISABLE			0
+#define ISP_AF_FACE_ENABLE			1
+
+/* AF range */
+#define ISP_AF_RANGE_NORMAL			0
+#define ISP_AF_RANGE_MACRO			1
+
+/* AF sleep */
+#define ISP_AF_SLEEP_OFF			0
+#define ISP_AF_SLEEP_ON				1
+
+/* Continuous AF commands */
+#define ISP_AF_CONTINUOUS_DISABLE		0
+#define ISP_AF_CONTINUOUS_ENABLE		1
+
+/* ISP AF error codes */
+#define ISP_AF_ERROR_NONE			0 /* AF mode change is done */
+#define ISP_AF_ERROR_NONE_LOCK_DONE		1 /* AF lock is done */
+
+/* Flash commands */
+#define ISP_FLASH_COMMAND_DISABLE		0
+#define ISP_FLASH_COMMAND_MANUAL_ON		1 /* (forced flash) */
+#define ISP_FLASH_COMMAND_AUTO			2
+#define ISP_FLASH_COMMAND_TORCH			3 /* 3 sec */
+
+/* Flash red-eye commads */
+#define ISP_FLASH_REDEYE_DISABLE		0
+#define ISP_FLASH_REDEYE_ENABLE			1
+
+/* Flash error codes */
+#define ISP_FLASH_ERROR_NONE			0 /* Flash setting is done */
+
+/* --------------------------  AWB  ------------------------------------ */
+enum isp_awb_command {
+	ISP_AWB_COMMAND_AUTO			= 0,
+	ISP_AWB_COMMAND_ILLUMINATION		= 1,
+	ISP_AWB_COMMAND_MANUAL			= 2
+};
+
+enum isp_awb_illumination {
+	ISP_AWB_ILLUMINATION_DAYLIGHT		= 0,
+	ISP_AWB_ILLUMINATION_CLOUDY		= 1,
+	ISP_AWB_ILLUMINATION_TUNGSTEN		= 2,
+	ISP_AWB_ILLUMINATION_FLUORESCENT	= 3
+};
+
+/* ISP AWN error codes */
+#define ISP_AWB_ERROR_NONE			0 /* AWB setting is done */
+
+/* --------------------------  Effect  ----------------------------------- */
+enum isp_imageeffect_command {
+	ISP_IMAGE_EFFECT_DISABLE		= 0,
+	ISP_IMAGE_EFFECT_MONOCHROME		= 1,
+	ISP_IMAGE_EFFECT_NEGATIVE_MONO		= 2,
+	ISP_IMAGE_EFFECT_NEGATIVE_COLOR		= 3,
+	ISP_IMAGE_EFFECT_SEPIA			= 4
+};
+
+/* Image effect error codes */
+#define ISP_IMAGE_EFFECT_ERROR_NONE		0 /* Image effect setting
+						     is done */
+/* ISO commands */
+#define ISP_ISO_COMMAND_AUTO			0
+#define ISP_ISO_COMMAND_MANUAL			1
+
+/* ISO error codes */
+#define ISP_ISO_ERROR_NONE			0 /* ISO setting is done */
+
+/* ISP adjust commands */
+#define ISP_ADJUST_COMMAND_AUTO			(0 << 0)
+#define ISP_ADJUST_COMMAND_MANUAL_CONTRAST	(1 << 0)
+#define ISP_ADJUST_COMMAND_MANUAL_SATURATION	(1 << 1)
+#define ISP_ADJUST_COMMAND_MANUAL_SHARPNESS	(1 << 2)
+#define ISP_ADJUST_COMMAND_MANUAL_EXPOSURE	(1 << 3)
+#define ISP_ADJUST_COMMAND_MANUAL_BRIGHTNESS	(1 << 4)
+#define ISP_ADJUST_COMMAND_MANUAL_HUE		(1 << 5)
+#define ISP_ADJUST_COMMAND_MANUAL_ALL		0x7f
+
+/* ISP adjustment error codes */
+#define ISP_ADJUST_ERROR_NONE			0 /* Adjust setting is done */
+
+/*
+ *  Exposure metering
+ */
+enum isp_metering_command {
+	ISP_METERING_COMMAND_AVERAGE	= 0,
+	ISP_METERING_COMMAND_SPOT	= 1,
+	ISP_METERING_COMMAND_MATRIX	= 2,
+	ISP_METERING_COMMAND_CENTER	= 3
+};
+
+/* ISP metering error codes */
+#define ISP_METERING_ERROR_NONE		0 /* Metering setting is done */
+
+/*
+ * AFC
+ */
+enum isp_afc_command {
+	ISP_AFC_COMMAND_DISABLE		= 0,
+	ISP_AFC_COMMAND_AUTO		= 1,
+	ISP_AFC_COMMAND_MANUAL		= 2,
+};
+
+#define ISP_AFC_MANUAL_50HZ		50
+#define ISP_AFC_MANUAL_60HZ		60
+
+/* ------------------------  SCENE MODE--------------------------------- */
+enum isp_scene_mode {
+	ISP_SCENE_NONE			= 0,
+	ISP_SCENE_PORTRAIT		= 1,
+	ISP_SCENE_LANDSCAPE		= 2,
+	ISP_SCENE_SPORTS		= 3,
+	ISP_SCENE_PARTYINDOOR		= 4,
+	ISP_SCENE_BEACHSNOW		= 5,
+	ISP_SCENE_SUNSET		= 6,
+	ISP_SCENE_DAWN			= 7,
+	ISP_SCENE_FALL			= 8,
+	ISP_SCENE_NIGHT			= 9,
+	ISP_SCENE_AGAINSTLIGHTWLIGHT	= 10,
+	ISP_SCENE_AGAINSTLIGHTWOLIGHT	= 11,
+	ISP_SCENE_FIRE			= 12,
+	ISP_SCENE_TEXT			= 13,
+	ISP_SCENE_CANDLE		= 14
+};
+
+/* AFC error codes */
+#define ISP_AFC_ERROR_NONE		0 /* AFC setting is done */
+
+/* ----------------------------  FD  ------------------------------------- */
+enum fd_config_command {
+	FD_CONFIG_COMMAND_MAXIMUM_NUMBER	= 0x1,
+	FD_CONFIG_COMMAND_ROLL_ANGLE		= 0x2,
+	FD_CONFIG_COMMAND_YAW_ANGLE		= 0x4,
+	FD_CONFIG_COMMAND_SMILE_MODE		= 0x8,
+	FD_CONFIG_COMMAND_BLINK_MODE		= 0x10,
+	FD_CONFIG_COMMAND_EYES_DETECT		= 0x20,
+	FD_CONFIG_COMMAND_MOUTH_DETECT		= 0x40,
+	FD_CONFIG_COMMAND_ORIENTATION		= 0x80,
+	FD_CONFIG_COMMAND_ORIENTATION_VALUE	= 0x100
+};
+
+enum fd_config_roll_angle {
+	FD_CONFIG_ROLL_ANGLE_BASIC		= 0,
+	FD_CONFIG_ROLL_ANGLE_PRECISE_BASIC	= 1,
+	FD_CONFIG_ROLL_ANGLE_SIDES		= 2,
+	FD_CONFIG_ROLL_ANGLE_PRECISE_SIDES	= 3,
+	FD_CONFIG_ROLL_ANGLE_FULL		= 4,
+	FD_CONFIG_ROLL_ANGLE_PRECISE_FULL	= 5,
+};
+
+enum fd_config_yaw_angle {
+	FD_CONFIG_YAW_ANGLE_0			= 0,
+	FD_CONFIG_YAW_ANGLE_45			= 1,
+	FD_CONFIG_YAW_ANGLE_90			= 2,
+	FD_CONFIG_YAW_ANGLE_45_90		= 3,
+};
+
+/* Smile mode configuration */
+#define FD_CONFIG_SMILE_MODE_DISABLE		0
+#define FD_CONFIG_SMILE_MODE_ENABLE		1
+
+/* Blink mode configuration */
+#define FD_CONFIG_BLINK_MODE_DISABLE		0
+#define FD_CONFIG_BLINK_MODE_ENABLE		1
+
+/* Eyes detection configuration */
+#define FD_CONFIG_EYES_DETECT_DISABLE		0
+#define FD_CONFIG_EYES_DETECT_ENABLE		1
+
+/* Mouth detection configuration */
+#define FD_CONFIG_MOUTH_DETECT_DISABLE		0
+#define FD_CONFIG_MOUTH_DETECT_ENABLE		1
+
+#define FD_CONFIG_ORIENTATION_DISABLE		0
+#define FD_CONFIG_ORIENTATION_ENABLE		1
+
+struct param_control {
+	u32 cmd;
+	u32 bypass;
+	u32 buffer_address;
+	u32 buffer_size;
+	u32 skip_frames; /* only valid at ISP */
+	u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 6];
+	u32 err;
+};
+
+struct param_otf_input {
+	u32 cmd;
+	u32 width;
+	u32 height;
+	u32 format;
+	u32 bitwidth;
+	u32 order;
+	u32 crop_offset_x;
+	u32 crop_offset_y;
+	u32 crop_width;
+	u32 crop_height;
+	u32 frametime_min;
+	u32 frametime_max;
+	u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 13];
+	u32 err;
+};
+
+struct param_dma_input {
+	u32 cmd;
+	u32 width;
+	u32 height;
+	u32 format;
+	u32 bitwidth;
+	u32 plane;
+	u32 order;
+	u32 buffer_number;
+	u32 buffer_address;
+	u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 10];
+	u32 err;
+};
+
+struct param_otf_output {
+	u32 cmd;
+	u32 width;
+	u32 height;
+	u32 format;
+	u32 bitwidth;
+	u32 order;
+	u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 7];
+	u32 err;
+};
+
+struct param_dma_output {
+	u32 cmd;
+	u32 width;
+	u32 height;
+	u32 format;
+	u32 bitwidth;
+	u32 plane;
+	u32 order;
+	u32 buffer_number;
+	u32 buffer_address;
+	u32 notify_dma_done;
+	u32 dma_out_mask;
+	u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 12];
+	u32 err;
+};
+
+struct param_global_shotmode {
+	u32 cmd;
+	u32 skip_frames;
+	u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 3];
+	u32 err;
+};
+
+struct param_sensor_framerate {
+	u32 frame_rate;
+	u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 2];
+	u32 err;
+};
+
+struct param_isp_aa {
+	u32 cmd;
+	u32 target;
+	u32 mode;
+	u32 scene;
+	u32 sleep;
+	u32 face;
+	u32 touch_x;
+	u32 touch_y;
+	u32 manual_af_setting;
+	u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 10];
+	u32 err;
+};
+
+struct param_isp_flash {
+	u32 cmd;
+	u32 redeye;
+	u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 3];
+	u32 err;
+};
+
+struct param_isp_awb {
+	u32 cmd;
+	u32 illumination;
+	u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 3];
+	u32 err;
+};
+
+struct param_isp_imageeffect {
+	u32 cmd;
+	u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 2];
+	u32 err;
+};
+
+struct param_isp_iso {
+	u32 cmd;
+	u32 value;
+	u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 3];
+	u32 err;
+};
+
+struct param_isp_adjust {
+	u32 cmd;
+	s32 contrast;
+	s32 saturation;
+	s32 sharpness;
+	s32 exposure;
+	s32 brightness;
+	s32 hue;
+	u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 8];
+	u32 err;
+};
+
+struct param_isp_metering {
+	u32 cmd;
+	u32 win_pos_x;
+	u32 win_pos_y;
+	u32 win_width;
+	u32 win_height;
+	u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 6];
+	u32 err;
+};
+
+struct param_isp_afc {
+	u32 cmd;
+	u32 manual;
+	u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 3];
+	u32 err;
+};
+
+struct param_scaler_imageeffect {
+	u32 cmd;
+	u32 arbitrary_cb;
+	u32 arbitrary_cr;
+	u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 4];
+	u32 err;
+};
+
+struct param_scaler_input_crop {
+	u32 cmd;
+	u32 crop_offset_x;
+	u32 crop_offset_y;
+	u32 crop_width;
+	u32 crop_height;
+	u32 in_width;
+	u32 in_height;
+	u32 out_width;
+	u32 out_height;
+	u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 10];
+	u32 err;
+};
+
+struct param_scaler_output_crop {
+	u32 cmd;
+	u32 crop_offset_x;
+	u32 crop_offset_y;
+	u32 crop_width;
+	u32 crop_height;
+	u32 out_format;
+	u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 7];
+	u32 err;
+};
+
+struct param_scaler_rotation {
+	u32 cmd;
+	u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 2];
+	u32 err;
+};
+
+struct param_scaler_flip {
+	u32 cmd;
+	u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 2];
+	u32 err;
+};
+
+struct param_3dnr_1stframe {
+	u32 cmd;
+	u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 2];
+	u32 err;
+};
+
+struct param_fd_config {
+	u32 cmd;
+	u32 max_number;
+	u32 roll_angle;
+	u32 yaw_angle;
+	u32 smile_mode;
+	u32 blink_mode;
+	u32 eye_detect;
+	u32 mouth_detect;
+	u32 orientation;
+	u32 orientation_value;
+	u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 11];
+	u32 err;
+};
+
+struct global_param {
+	struct param_global_shotmode	shotmode;
+};
+
+struct sensor_param {
+	struct param_control		control;
+	struct param_otf_output		otf_output;
+	struct param_sensor_framerate	frame_rate;
+} __packed;
+
+struct buffer_param {
+	struct param_control		control;
+	struct param_otf_input		otf_input;
+	struct param_otf_output		otf_output;
+} __packed;
+
+struct isp_param {
+	struct param_control		control;
+	struct param_otf_input		otf_input;
+	struct param_dma_input		dma1_input;
+	struct param_dma_input		dma2_input;
+	struct param_isp_aa		aa;
+	struct param_isp_flash		flash;
+	struct param_isp_awb		awb;
+	struct param_isp_imageeffect	effect;
+	struct param_isp_iso		iso;
+	struct param_isp_adjust		adjust;
+	struct param_isp_metering	metering;
+	struct param_isp_afc		afc;
+	struct param_otf_output		otf_output;
+	struct param_dma_output		dma1_output;
+	struct param_dma_output		dma2_output;
+} __packed;
+
+struct drc_param {
+	struct param_control		control;
+	struct param_otf_input		otf_input;
+	struct param_dma_input		dma_input;
+	struct param_otf_output		otf_output;
+} __packed;
+
+struct scalerc_param {
+	struct param_control		control;
+	struct param_otf_input		otf_input;
+	struct param_scaler_imageeffect	effect;
+	struct param_scaler_input_crop	input_crop;
+	struct param_scaler_output_crop	output_crop;
+	struct param_otf_output		otf_output;
+	struct param_dma_output		dma_output;
+} __packed;
+
+struct odc_param {
+	struct param_control		control;
+	struct param_otf_input		otf_input;
+	struct param_otf_output		otf_output;
+} __packed;
+
+struct dis_param {
+	struct param_control		control;
+	struct param_otf_output		otf_input;
+	struct param_otf_output		otf_output;
+} __packed;
+
+struct tdnr_param {
+	struct param_control		control;
+	struct param_otf_input		otf_input;
+	struct param_3dnr_1stframe	frame;
+	struct param_otf_output		otf_output;
+	struct param_dma_output		dma_output;
+} __packed;
+
+struct scalerp_param {
+	struct param_control		control;
+	struct param_otf_input		otf_input;
+	struct param_scaler_imageeffect	effect;
+	struct param_scaler_input_crop	input_crop;
+	struct param_scaler_output_crop	output_crop;
+	struct param_scaler_rotation	rotation;
+	struct param_scaler_flip	flip;
+	struct param_otf_output		otf_output;
+	struct param_dma_output		dma_output;
+} __packed;
+
+struct fd_param {
+	struct param_control		control;
+	struct param_otf_input		otf_input;
+	struct param_dma_input		dma_input;
+	struct param_fd_config		config;
+} __packed;
+
+struct is_param_region {
+	struct global_param		global;
+	struct sensor_param		sensor;
+	struct buffer_param		buf;
+	struct isp_param		isp;
+	struct drc_param		drc;
+	struct scalerc_param		scalerc;
+	struct odc_param		odc;
+	struct dis_param		dis;
+	struct tdnr_param		tdnr;
+	struct scalerp_param		scalerp;
+	struct fd_param			fd;
+} __packed;
+
+#define NUMBER_OF_GAMMA_CURVE_POINTS	32
+
+struct is_tune_sensor {
+	u32 exposure;
+	u32 analog_gain;
+	u32 frame_rate;
+	u32 actuator_position;
+};
+
+struct is_tune_gammacurve {
+	u32 num_pts_x[NUMBER_OF_GAMMA_CURVE_POINTS];
+	u32 num_pts_y_r[NUMBER_OF_GAMMA_CURVE_POINTS];
+	u32 num_pts_y_g[NUMBER_OF_GAMMA_CURVE_POINTS];
+	u32 num_pts_y_b[NUMBER_OF_GAMMA_CURVE_POINTS];
+};
+
+struct is_tune_isp {
+	/* Brightness level: range 0...100, default 7. */
+	u32 brightness_level;
+	/* Contrast level: range -127...127, default 0. */
+	s32 contrast_level;
+	/* Saturation level: range -127...127, default 0. */
+	s32 saturation_level;
+	s32 gamma_level;
+	struct is_tune_gammacurve gamma_curve[4];
+	/* Hue: range -127...127, default 0. */
+	s32 hue;
+	/* Sharpness blur: range -127...127, default 0. */
+	s32 sharpness_blur;
+	/* Despeckle : range -127~127, default : 0 */
+	s32 despeckle;
+	/* Edge color supression: range -127...127, default 0. */
+	s32 edge_color_supression;
+	/* Noise reduction: range -127...127, default 0. */
+	s32 noise_reduction;
+	/* (32 * 4 + 9) * 4 = 548 bytes */
+} __packed;
+
+struct is_tune_region {
+	struct is_tune_sensor sensor;
+	struct is_tune_isp isp;
+} __packed;
+
+struct rational {
+	u32 num;
+	u32 den;
+};
+
+struct srational {
+	s32 num;
+	s32 den;
+};
+
+#define FLASH_FIRED_SHIFT			0
+#define FLASH_NOT_FIRED				0
+#define FLASH_FIRED				1
+
+#define FLASH_STROBE_SHIFT			1
+#define FLASH_STROBE_NO_DETECTION		0
+#define FLASH_STROBE_RESERVED			1
+#define FLASH_STROBE_RETURN_LIGHT_NOT_DETECTED	2
+#define FLASH_STROBE_RETURN_LIGHT_DETECTED	3
+
+#define FLASH_MODE_SHIFT			3
+#define FLASH_MODE_UNKNOWN			0
+#define FLASH_MODE_COMPULSORY_FLASH_FIRING	1
+#define FLASH_MODE_COMPULSORY_FLASH_SUPPRESSION	2
+#define FLASH_MODE_AUTO_MODE			3
+
+#define FLASH_FUNCTION_SHIFT			5
+#define FLASH_FUNCTION_PRESENT			0
+#define FLASH_FUNCTION_NONE			1
+
+#define FLASH_RED_EYE_SHIFT			6
+#define FLASH_RED_EYE_DISABLED			0
+#define FLASH_RED_EYE_SUPPORTED			1
+
+enum apex_aperture_value {
+	F1_0	= 0,
+	F1_4	= 1,
+	F2_0	= 2,
+	F2_8	= 3,
+	F4_0	= 4,
+	F5_6	= 5,
+	F8_9	= 6,
+	F11_0	= 7,
+	F16_0	= 8,
+	F22_0	= 9,
+	F32_0	= 10,
+};
+
+struct exif_attribute {
+	struct rational exposure_time;
+	struct srational shutter_speed;
+	u32 iso_speed_rating;
+	u32 flash;
+	struct srational brightness;
+} __packed;
+
+struct is_frame_header {
+	u32 valid;
+	u32 bad_mark;
+	u32 captured;
+	u32 frame_number;
+	struct exif_attribute exif;
+} __packed;
+
+struct is_fd_rect {
+	u32 offset_x;
+	u32 offset_y;
+	u32 width;
+	u32 height;
+};
+
+struct is_face_marker {
+	u32 frame_number;
+	struct is_fd_rect face;
+	struct is_fd_rect left_eye;
+	struct is_fd_rect right_eye;
+	struct is_fd_rect mouth;
+	u32 roll_angle;
+	u32 yaw_angle;
+	u32 confidence;
+	s32 smile_level;
+	s32 blink_level;
+} __packed;
+
+#define MAX_FRAME_COUNT				8
+#define MAX_FRAME_COUNT_PREVIEW			4
+#define MAX_FRAME_COUNT_CAPTURE			1
+#define MAX_FACE_COUNT				16
+#define MAX_SHARED_COUNT			500
+
+struct is_region {
+	struct is_param_region parameter;
+	struct is_tune_region tune;
+	struct is_frame_header header[MAX_FRAME_COUNT];
+	struct is_face_marker face[MAX_FACE_COUNT];
+	u32 shared[MAX_SHARED_COUNT];
+} __packed;
+
+struct is_debug_frame_descriptor {
+	u32 sensor_frame_time;
+	u32 sensor_exposure_time;
+	s32 sensor_analog_gain;
+	/* monitor for AA */
+	u32 req_lei;
+
+	u32 next_next_lei_exp;
+	u32 next_next_lei_a_gain;
+	u32 next_next_lei_d_gain;
+	u32 next_next_lei_statlei;
+	u32 next_next_lei_lei;
+
+	u32 dummy0;
+};
+
+#define MAX_FRAMEDESCRIPTOR_CONTEXT_NUM	(30*20)	/* 600 frames */
+#define MAX_VERSION_DISPLAY_BUF	32
+
+struct is_share_region {
+	u32 frame_time;
+	u32 exposure_time;
+	s32 analog_gain;
+
+	u32 r_gain;
+	u32 g_gain;
+	u32 b_gain;
+
+	u32 af_position;
+	u32 af_status;
+	/* 0 : SIRC_ISP_CAMERA_AUTOFOCUSMESSAGE_NOMESSAGE */
+	/* 1 : SIRC_ISP_CAMERA_AUTOFOCUSMESSAGE_REACHED */
+	/* 2 : SIRC_ISP_CAMERA_AUTOFOCUSMESSAGE_UNABLETOREACH */
+	/* 3 : SIRC_ISP_CAMERA_AUTOFOCUSMESSAGE_LOST */
+	/* default : unknown */
+	u32 af_scene_type;
+
+	u32 frame_descp_onoff_control;
+	u32 frame_descp_update_done;
+	u32 frame_descp_idx;
+	u32 frame_descp_max_idx;
+	struct is_debug_frame_descriptor
+		dbg_frame_descp_ctx[MAX_FRAMEDESCRIPTOR_CONTEXT_NUM];
+
+	u32 chip_id;
+	u32 chip_rev_no;
+	u8 isp_fw_ver_no[MAX_VERSION_DISPLAY_BUF];
+	u8 isp_fw_ver_date[MAX_VERSION_DISPLAY_BUF];
+	u8 sirc_sdk_ver_no[MAX_VERSION_DISPLAY_BUF];
+	u8 sirc_sdk_rev_no[MAX_VERSION_DISPLAY_BUF];
+	u8 sirc_sdk_rev_date[MAX_VERSION_DISPLAY_BUF];
+} __packed;
+
+struct is_debug_control {
+	u32 write_point;	/* 0~ 500KB boundary */
+	u32 assert_flag;	/* 0: Not invoked, 1: Invoked */
+	u32 pabort_flag;	/* 0: Not invoked, 1: Invoked */
+	u32 dabort_flag;	/* 0: Not invoked, 1: Invoked */
+};
+
+struct sensor_open_extended {
+	u32 actuator_type;
+	u32 mclk;
+	u32 mipi_lane_num;
+	u32 mipi_speed;
+	/* Skip setfile loading when fast_open_sensor is not 0 */
+	u32 fast_open_sensor;
+	/* Activating sensor self calibration mode (6A3) */
+	u32 self_calibration_mode;
+	/* This field is to adjust I2c clock based on ACLK200 */
+	/* This value is varied in case of rev 0.2 */
+	u32 i2c_sclk;
+};
+
+#define fimc_is_inc_param_num(is) \
+	atomic_inc(&(is)->cfg_param[(is)->scenario_id].p_region_num)
+
+struct fimc_is;
+
+int fimc_is_hw_get_sensor_max_framerate(struct fimc_is *is);
+void fimc_is_set_initial_params(struct fimc_is *is);
+
+int  __is_hw_update_params(struct fimc_is *is);
+void __is_get_frame_size(struct fimc_is *is, struct v4l2_mbus_framefmt *mf);
+void __is_set_frame_size(struct fimc_is *is, struct v4l2_mbus_framefmt *mf);
+void __is_set_sensor(struct fimc_is *is, int fps);
+void __is_set_isp_aa_ae(struct fimc_is *is);
+void __is_set_isp_flash(struct fimc_is *is, u32 cmd, u32 redeye);
+void __is_set_isp_awb(struct fimc_is *is, u32 cmd, u32 val);
+void __is_set_isp_effect(struct fimc_is *is, u32 cmd);
+void __is_set_isp_iso(struct fimc_is *is, u32 cmd, u32 val);
+void __is_set_isp_adjust(struct fimc_is *is, u32 cmd, u32 val);
+void __is_set_isp_metering(struct fimc_is *is, u32 id, u32 val);
+void __is_set_isp_afc(struct fimc_is *is, u32 cmd, u32 val);
+void __is_set_drc_control(struct fimc_is *is, u32 val);
+void __is_set_fd_control(struct fimc_is *is, u32 val);
+void __is_set_fd_config_maxface(struct fimc_is *is, u32 val);
+void __is_set_fd_config_rollangle(struct fimc_is *is, u32 val);
+void __is_set_fd_config_yawangle(struct fimc_is *is, u32 val);
+void __is_set_fd_config_smilemode(struct fimc_is *is, u32 val);
+void __is_set_fd_config_blinkmode(struct fimc_is *is, u32 val);
+void __is_set_fd_config_eyedetect(struct fimc_is *is, u32 val);
+void __is_set_fd_config_mouthdetect(struct fimc_is *is, u32 val);
+void __is_set_fd_config_orientation(struct fimc_is *is, u32 val);
+void __is_set_fd_config_orientation_val(struct fimc_is *is, u32 val);
+void __is_set_isp_aa_af_mode(struct fimc_is *is, int cmd);
+void __is_set_isp_aa_af_start_stop(struct fimc_is *is, int cmd);
+
+#endif
-- 
1.7.9.5

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

* [RFC PATCH 4/8] s5p-fimc: Add common FIMC-IS image sensor driver
  2013-03-11 19:44 [RFC PATCH 0/8] A V4L2 driver for Exynos4x12 Imaging Subsystem Sylwester Nawrocki
                   ` (2 preceding siblings ...)
  2013-03-11 19:44 ` [RFC PATCH 3/8] s5p-fimc: Add FIMC-IS parameter region definitions Sylwester Nawrocki
@ 2013-03-11 19:44 ` Sylwester Nawrocki
  2013-03-11 19:44 ` [RFC PATCH 5/8] s5p-fimc: Add ISP video capture driver stubs Sylwester Nawrocki
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: Sylwester Nawrocki @ 2013-03-11 19:44 UTC (permalink / raw)
  To: linux-media
  Cc: kyungmin.park, myungjoo.ham, dh09.lee, shaik.samsung, arun.kk,
	a.hajda, linux-samsung-soc, devicetree-discuss, linux-arm-kernel,
	Sylwester Nawrocki

This subdev driver currently only handles an image sensor's
power supplies and reset signal. There is no any I2C communication
here as it is handled by the ISP's firmware.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/platform/s5p-fimc/fimc-is-sensor.c |  308 ++++++++++++++++++++++
 drivers/media/platform/s5p-fimc/fimc-is-sensor.h |   80 ++++++
 2 files changed, 388 insertions(+)
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-is-sensor.c
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-is-sensor.h

diff --git a/drivers/media/platform/s5p-fimc/fimc-is-sensor.c b/drivers/media/platform/s5p-fimc/fimc-is-sensor.c
new file mode 100644
index 0000000..151915c
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-is-sensor.c
@@ -0,0 +1,308 @@
+/*
+ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/memory.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <media/v4l2-subdev.h>
+
+#include "fimc-is.h"
+#include "fimc-is-sensor.h"
+
+#define DRIVER_NAME "FIMC-IS-SENSOR"
+
+static const char * const sensor_supply_names[] = {
+	"svdda",
+	"svddio",
+};
+
+static const struct v4l2_mbus_framefmt fimc_is_sensor_formats[] = {
+	{
+		.code = V4L2_MBUS_FMT_SGRBG10_1X10,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.field = V4L2_FIELD_NONE,
+	}
+};
+
+static struct fimc_is_sensor *sd_to_fimc_is_sensor(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct fimc_is_sensor, subdev);
+}
+
+static const struct v4l2_mbus_framefmt *find_sensor_format(
+	struct v4l2_mbus_framefmt *mf)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(fimc_is_sensor_formats); i++)
+		if (mf->code == fimc_is_sensor_formats[i].code)
+			return &fimc_is_sensor_formats[i];
+
+	return &fimc_is_sensor_formats[0];
+}
+
+static int fimc_is_sensor_enum_mbus_code(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->index >= ARRAY_SIZE(fimc_is_sensor_formats))
+		return -EINVAL;
+
+	code->code = fimc_is_sensor_formats[code->index].code;
+	return 0;
+}
+
+static void fimc_is_sensor_try_format(struct fimc_is_sensor *sensor,
+				      struct v4l2_mbus_framefmt *mf)
+{
+	const struct sensor_drv_data *dd = sensor->drvdata;
+	const struct v4l2_mbus_framefmt *fmt;
+
+	fmt = find_sensor_format(mf);
+	mf->code = fmt->code;
+	v4l_bound_align_image(&mf->width, 16 + 8, dd->width, 0,
+			      &mf->height, 12 + 8, dd->height, 0, 0);
+}
+
+static struct v4l2_mbus_framefmt *__fimc_is_sensor_get_format(
+		struct fimc_is_sensor *sensor, struct v4l2_subdev_fh *fh,
+		u32 pad, enum v4l2_subdev_format_whence which)
+{
+	if (which == V4L2_SUBDEV_FORMAT_TRY)
+		return fh ? v4l2_subdev_get_try_format(fh, pad) : NULL;
+
+	return &sensor->format;
+}
+
+static int fimc_is_sensor_set_fmt(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_format *fmt)
+{
+	struct fimc_is_sensor *sensor = sd_to_fimc_is_sensor(sd);
+	struct v4l2_mbus_framefmt *mf;
+
+	fimc_is_sensor_try_format(sensor, &fmt->format);
+
+	mf = __fimc_is_sensor_get_format(sensor, fh, fmt->pad, fmt->which);
+	if (mf) {
+		mutex_lock(&sensor->lock);
+		if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+			sensor->format = *mf;
+		mutex_unlock(&sensor->lock);
+	}
+	return 0;
+}
+
+static int fimc_is_sensor_get_fmt(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_fh *fh,
+				  struct v4l2_subdev_format *fmt)
+{
+	struct fimc_is_sensor *sensor = sd_to_fimc_is_sensor(sd);
+	struct v4l2_mbus_framefmt *mf;
+
+	mf = __fimc_is_sensor_get_format(sensor, fh, fmt->pad, fmt->which);
+
+	mutex_lock(&sensor->lock);
+	fmt->format = *mf;
+	mutex_unlock(&sensor->lock);
+	return 0;
+}
+
+static struct v4l2_subdev_pad_ops fimc_is_sensor_pad_ops = {
+	.enum_mbus_code	= fimc_is_sensor_enum_mbus_code,
+	.get_fmt	= fimc_is_sensor_get_fmt,
+	.set_fmt	= fimc_is_sensor_set_fmt,
+};
+
+static int fimc_is_sensor_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0);
+
+	*format		= fimc_is_sensor_formats[0];
+	format->width	= FIMC_IS_SENSOR_DEF_PIX_WIDTH;
+	format->height	= FIMC_IS_SENSOR_DEF_PIX_HEIGHT;
+
+	return 0;
+}
+
+static const struct v4l2_subdev_internal_ops fimc_is_sensor_sd_internal_ops = {
+	.open = fimc_is_sensor_open,
+};
+
+static int fimc_is_sensor_s_power(struct v4l2_subdev *sd, int on)
+{
+	struct fimc_is_sensor *sensor = v4l2_get_subdevdata(sd);
+	int gpio = sensor->gpio_reset;
+	int ret;
+
+	pr_debug("%s:%d: on: %d\n", __func__, __LINE__, on);
+
+	if (on) {
+		ret = regulator_bulk_enable(SENSOR_NUM_SUPPLIES,
+					    sensor->supplies);
+		if (gpio_is_valid(gpio)) {
+			gpio_set_value(gpio, 1);
+			usleep_range(600, 800);
+			gpio_set_value(gpio, 0);
+			usleep_range(10000, 11000);
+			gpio_set_value(gpio, 1);
+		}
+	} else {
+		if (gpio_is_valid(gpio))
+			gpio_set_value(gpio, 0);
+
+		ret = regulator_bulk_disable(SENSOR_NUM_SUPPLIES,
+					     sensor->supplies);
+	}
+
+	return ret;
+}
+
+static struct v4l2_subdev_core_ops fimc_is_sensor_core_ops = {
+	.s_power = fimc_is_sensor_s_power,
+};
+
+static struct v4l2_subdev_ops fimc_is_sensor_subdev_ops = {
+	.core = &fimc_is_sensor_core_ops,
+	.pad = &fimc_is_sensor_pad_ops,
+};
+
+static const struct of_device_id fimc_is_sensor_of_match[];
+
+static int fimc_is_sensor_probe(struct i2c_client *client,
+				const struct i2c_device_id *id)
+{
+	struct device *dev = &client->dev;
+	struct fimc_is_sensor *sensor;
+	const struct of_device_id *of_id;
+	struct v4l2_subdev *sd;
+	int gpio, i, ret;
+
+	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
+	if (!sensor)
+		return -ENOMEM;
+
+	mutex_init(&sensor->lock);
+	sensor->gpio_reset = -EINVAL;
+
+	gpio = of_get_gpio_flags(dev->of_node, 0, NULL); /* &of_flags); */
+	if (gpio_is_valid(gpio)) {
+		/* gpio->level = !(of_flags & OF_GPIO_ACTIVE_LOW); */
+		ret = gpio_request_one(gpio, GPIOF_OUT_INIT_LOW, DRIVER_NAME);
+		if (ret < 0)
+			return ret;
+	}
+	sensor->gpio_reset = gpio;
+
+	for (i = 0; i < SENSOR_NUM_SUPPLIES; i++)
+		sensor->supplies[i].supply = sensor_supply_names[i];
+
+	ret = devm_regulator_bulk_get(&client->dev, SENSOR_NUM_SUPPLIES,
+				      sensor->supplies);
+	if (ret < 0)
+		goto err_gpio;
+
+	of_id = of_match_node(fimc_is_sensor_of_match, dev->of_node);
+	if (!of_id) {
+		ret = -ENODEV;
+		goto err_reg;
+	}
+
+	sensor->drvdata = of_id->data;
+
+	sd = &sensor->subdev;
+	v4l2_i2c_subdev_init(sd, client, &fimc_is_sensor_subdev_ops);
+	snprintf(sd->name, sizeof(sd->name), sensor->drvdata->subdev_name);
+	sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+	sensor->format.code = fimc_is_sensor_formats[0].code;
+	sensor->format.width = FIMC_IS_SENSOR_DEF_PIX_WIDTH;
+	sensor->format.height = FIMC_IS_SENSOR_DEF_PIX_HEIGHT;
+
+	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
+	ret = media_entity_init(&sd->entity, 1, &sensor->pad, 0);
+	if (ret < 0)
+		goto err_reg;
+
+	v4l2_set_subdevdata(sd, sensor);
+
+	return 0;
+err_reg:
+	regulator_bulk_free(SENSOR_NUM_SUPPLIES, sensor->supplies);
+err_gpio:
+	if (gpio_is_valid(sensor->gpio_reset))
+		gpio_free(sensor->gpio_reset);
+	return ret;
+}
+
+static int fimc_is_sensor_remove(struct i2c_client *client)
+{
+	struct fimc_is_sensor *sensor;
+
+	regulator_bulk_free(SENSOR_NUM_SUPPLIES, sensor->supplies);
+	media_entity_cleanup(&sensor->subdev.entity);
+
+	return 0;
+}
+
+static const struct i2c_device_id fimc_is_sensor_ids[] = {
+	{ }
+};
+
+static const struct sensor_drv_data s5k6a3_drvdata = {
+	.id		= FIMC_IS_SENSOR_ID_S5K6A3,
+	.subdev_name	= "S5K6A3",
+	.width		= S5K6A3_SENSOR_WIDTH,
+	.height		= S5K6A3_SENSOR_HEIGHT,
+};
+
+static const struct of_device_id fimc_is_sensor_of_match[] = {
+	{
+		.compatible	= "samsung,s5k6a3",
+		.data		= &s5k6a3_drvdata,
+	},
+	{  }
+};
+MODULE_DEVICE_TABLE(of, fimc_is_sensor_of_match);
+
+static struct i2c_driver fimc_is_sensor_driver = {
+	.driver = {
+		.of_match_table	= fimc_is_sensor_of_match,
+		.name		= DRIVER_NAME,
+		.owner		= THIS_MODULE,
+	},
+	.probe		= fimc_is_sensor_probe,
+	.remove		= fimc_is_sensor_remove,
+	.id_table	= fimc_is_sensor_ids,
+};
+
+int fimc_is_register_sensor_driver(void)
+{
+	return i2c_add_driver(&fimc_is_sensor_driver);
+}
+
+void fimc_is_unregister_sensor_driver(void)
+{
+	i2c_del_driver(&fimc_is_sensor_driver);
+}
+
+MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
+MODULE_DESCRIPTION("Exynos4x12 FIMC-IS image sensor subdev driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/s5p-fimc/fimc-is-sensor.h b/drivers/media/platform/s5p-fimc/fimc-is-sensor.h
new file mode 100644
index 0000000..e80490e
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-is-sensor.h
@@ -0,0 +1,80 @@
+/*
+ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ *  Younghwan Joo <yhwan.joo@samsung.com>
+ *  Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef FIMC_IS_SENSOR_H_
+#define FIMC_IS_SENSOR_H_
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-subdev.h>
+
+#define FIMC_IS_SENSOR_OPEN_TIMEOUT	2000 /* ms */
+
+#define FIMC_IS_SENSOR_DEF_PIX_WIDTH	1296
+#define FIMC_IS_SENSOR_DEF_PIX_HEIGHT	732
+
+#define S5K6A3_SENSOR_WIDTH		1392
+#define S5K6A3_SENSOR_HEIGHT		1392
+
+#define SENSOR_NUM_SUPPLIES		2
+
+enum fimc_is_sensor_id {
+	FIMC_IS_SENSOR_ID_S5K3H2 = 1,
+	FIMC_IS_SENSOR_ID_S5K6A3,
+	FIMC_IS_SENSOR_ID_S5K4E5,
+	FIMC_IS_SENSOR_ID_S5K3H7,
+	FIMC_IS_SENSOR_ID_CUSTOM,
+	FIMC_IS_SENSOR_ID_END
+};
+
+#define IS_SENSOR_CTRL_BUS_I2C0		0
+#define IS_SENSOR_CTRL_BUS_I2C1		1
+
+struct sensor_drv_data {
+	enum fimc_is_sensor_id id;
+	const char * const subdev_name;
+	unsigned int width;
+	unsigned int height;
+};
+
+/**
+ * struct fimc_is_sensor - fimc-is sensor data structure
+ * @subdev: the image sensor's v4l2 subdev
+ * @pad: subdev media source pad
+ * @supplies: image sensor's voltage regulator supplies
+ * @gpio_reset: GPIO connected to the sensor's reset pin
+ * @drvdata: a pointer to the sensor's parameters data structure
+ * @i2c_bus: ISP I2C bus index (0...1)
+ * @test_pattern: true to enable video test pattern
+ * @lock: mutex protecting the structure's members below
+ * @format: media bus format at the sensor's source pad
+ */
+struct fimc_is_sensor {
+	struct v4l2_subdev subdev;
+	struct media_pad pad;
+	struct regulator_bulk_data supplies[SENSOR_NUM_SUPPLIES];
+	int gpio_reset;
+	const struct sensor_drv_data *drvdata;
+	unsigned int i2c_bus;
+	bool test_pattern;
+
+	struct mutex lock;
+	struct v4l2_mbus_framefmt format;
+};
+
+int fimc_is_register_sensor_driver(void);
+void fimc_is_unregister_sensor_driver(void);
+
+#endif /* FIMC_IS_SENSOR_H_ */
-- 
1.7.9.5

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

* [RFC PATCH 5/8] s5p-fimc: Add ISP video capture driver stubs
  2013-03-11 19:44 [RFC PATCH 0/8] A V4L2 driver for Exynos4x12 Imaging Subsystem Sylwester Nawrocki
                   ` (3 preceding siblings ...)
  2013-03-11 19:44 ` [RFC PATCH 4/8] s5p-fimc: Add common FIMC-IS image sensor driver Sylwester Nawrocki
@ 2013-03-11 19:44 ` Sylwester Nawrocki
  2013-03-12 14:44   ` Hans Verkuil
  2013-03-11 19:44 ` [RFC PATCH 6/8] fimc-is: Add Exynos4x12 FIMC-IS device tree bindings documentation Sylwester Nawrocki
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 14+ messages in thread
From: Sylwester Nawrocki @ 2013-03-11 19:44 UTC (permalink / raw)
  To: linux-media
  Cc: kyungmin.park, myungjoo.ham, dh09.lee, shaik.samsung, arun.kk,
	a.hajda, linux-samsung-soc, devicetree-discuss, linux-arm-kernel,
	Sylwester Nawrocki

This patch adds a video capture node for the FIMC-IS ISP IP block
and Makefile/Kconfig to actually enable the driver's compilation.

The ISP video capture driver is still a work in progress.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/platform/s5p-fimc/Kconfig          |   13 +
 drivers/media/platform/s5p-fimc/Makefile         |    4 +
 drivers/media/platform/s5p-fimc/fimc-isp-video.c |  414 ++++++++++++++++++++++
 drivers/media/platform/s5p-fimc/fimc-isp-video.h |   50 +++
 4 files changed, 481 insertions(+)
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-isp-video.c
 create mode 100644 drivers/media/platform/s5p-fimc/fimc-isp-video.h

diff --git a/drivers/media/platform/s5p-fimc/Kconfig b/drivers/media/platform/s5p-fimc/Kconfig
index c16b20d..1253e25 100644
--- a/drivers/media/platform/s5p-fimc/Kconfig
+++ b/drivers/media/platform/s5p-fimc/Kconfig
@@ -46,4 +46,17 @@ config VIDEO_EXYNOS_FIMC_LITE
 	  module will be called exynos-fimc-lite.
 endif
 
+if (SOC_EXYNOS4212 || SOC_EXYNOS4412) && OF && !ARCH_MULTIPLATFORM
+
+config VIDEO_EXYNOS4_FIMC_IS
+	tristate "EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver"
+	select VIDEOBUF2_DMA_CONTIG
+	help
+	  This is a V4L2 driver for Samsung EXYNOS4x12 SoC FIMC-IS
+	  (Imaging Subsystem).
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called exynos-fimc-is.
+endif
+
 endif # VIDEO_SAMSUNG_S5P_FIMC
diff --git a/drivers/media/platform/s5p-fimc/Makefile b/drivers/media/platform/s5p-fimc/Makefile
index 4648514..55b171a 100644
--- a/drivers/media/platform/s5p-fimc/Makefile
+++ b/drivers/media/platform/s5p-fimc/Makefile
@@ -1,7 +1,11 @@
 s5p-fimc-objs := fimc-core.o fimc-reg.o fimc-m2m.o fimc-capture.o fimc-mdevice.o
 exynos-fimc-lite-objs += fimc-lite-reg.o fimc-lite.o
+exynos-fimc-is-objs := fimc-is.o fimc-isp.o fimc-is-sensor.o fimc-is-regs.o
+exynos-fimc-is-objs += fimc-is-param.o fimc-is-errno.o fimc-is-i2c.o
+exynos-fimc-is-objs += fimc-isp-video.o
 s5p-csis-objs := mipi-csis.o
 
 obj-$(CONFIG_VIDEO_S5P_MIPI_CSIS)	+= s5p-csis.o
 obj-$(CONFIG_VIDEO_EXYNOS_FIMC_LITE)	+= exynos-fimc-lite.o
+obj-$(CONFIG_VIDEO_EXYNOS4_FIMC_IS)	+= exynos-fimc-is.o
 obj-$(CONFIG_VIDEO_S5P_FIMC)		+= s5p-fimc.o
diff --git a/drivers/media/platform/s5p-fimc/fimc-isp-video.c b/drivers/media/platform/s5p-fimc/fimc-isp-video.c
new file mode 100644
index 0000000..bdeacaa
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-isp-video.c
@@ -0,0 +1,414 @@
+/*
+ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/printk.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "fimc-mdevice.h"
+#include "fimc-core.h"
+#include "fimc-is.h"
+
+static int isp_video_capture_start_streaming(struct vb2_queue *q,
+					unsigned int count)
+{
+	/* TODO: start ISP output DMA */
+	return 0;
+}
+
+static int isp_video_capture_stop_streaming(struct vb2_queue *q)
+{
+	/* TODO: stop ISP output DMA */
+	return 0;
+}
+
+static int isp_video_capture_queue_setup(struct vb2_queue *vq,
+			const struct v4l2_format *pfmt,
+			unsigned int *num_buffers, unsigned int *num_planes,
+			unsigned int sizes[], void *allocators[])
+{
+	const struct v4l2_pix_format_mplane *pixm = NULL;
+	struct fimc_isp *isp = vq->drv_priv;
+	struct fimc_isp_frame *frame = &isp->out_frame;
+	const struct fimc_fmt *fmt = isp->video_capture_format;
+	unsigned long wh;
+	int i;
+
+	if (pfmt) {
+		pixm = &pfmt->fmt.pix_mp;
+		fmt = fimc_isp_find_format(&pixm->pixelformat, NULL, -1);
+		wh = pixm->width * pixm->height;
+	} else {
+		wh = frame->f_width * frame->f_height;
+	}
+
+	if (fmt == NULL)
+		return -EINVAL;
+
+	*num_planes = fmt->memplanes;
+
+	for (i = 0; i < fmt->memplanes; i++) {
+		unsigned int size = (wh * fmt->depth[i]) / 8;
+		if (pixm)
+			sizes[i] = max(size, pixm->plane_fmt[i].sizeimage);
+		else
+			sizes[i] = size;
+		allocators[i] = isp->alloc_ctx;
+	}
+
+	return 0;
+}
+
+static int isp_video_capture_buffer_prepare(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct fimc_isp *isp = vq->drv_priv;
+	int i;
+
+	if (isp->video_capture_format == NULL)
+		return -EINVAL;
+
+	for (i = 0; i < isp->video_capture_format->memplanes; i++) {
+		unsigned long size = isp->payload[i];
+
+		if (vb2_plane_size(vb, i) < size) {
+			v4l2_err(&isp->vfd,
+				 "User buffer too small (%ld < %ld)\n",
+				 vb2_plane_size(vb, i), size);
+			return -EINVAL;
+		}
+		vb2_set_plane_payload(vb, i, size);
+	}
+
+	return 0;
+}
+
+static void isp_video_capture_buffer_queue(struct vb2_buffer *vb)
+{
+	/* TODO: */
+}
+
+static void isp_video_lock(struct vb2_queue *vq)
+{
+	struct fimc_isp *isp = vb2_get_drv_priv(vq);
+	mutex_lock(&isp->video_lock);
+}
+
+static void isp_video_unlock(struct vb2_queue *vq)
+{
+	struct fimc_isp *isp = vb2_get_drv_priv(vq);
+	mutex_unlock(&isp->video_lock);
+}
+
+static const struct vb2_ops isp_video_capture_qops = {
+	.queue_setup	 = isp_video_capture_queue_setup,
+	.buf_prepare	 = isp_video_capture_buffer_prepare,
+	.buf_queue	 = isp_video_capture_buffer_queue,
+	.wait_prepare	 = isp_video_unlock,
+	.wait_finish	 = isp_video_lock,
+	.start_streaming = isp_video_capture_start_streaming,
+	.stop_streaming	 = isp_video_capture_stop_streaming,
+};
+
+static int isp_video_capture_open(struct file *file)
+{
+	struct fimc_isp *isp = video_drvdata(file);
+	int ret = 0;
+
+	if (mutex_lock_interruptible(&isp->video_lock))
+		return -ERESTARTSYS;
+
+	/* ret = pm_runtime_get_sync(&isp->pdev->dev); */
+	if (ret < 0)
+		goto done;
+
+	ret = v4l2_fh_open(file);
+	if (ret < 0)
+		goto done;
+
+	/* TODO: prepare video pipeline */
+done:
+	mutex_unlock(&isp->video_lock);
+	return ret;
+}
+
+static int isp_video_capture_close(struct file *file)
+{
+	struct fimc_isp *isp = video_drvdata(file);
+	int ret = 0;
+
+	mutex_lock(&isp->video_lock);
+
+	if (isp->out_path == FIMC_IO_DMA) {
+		/* TODO: stop capture, cleanup */
+	}
+
+	/* pm_runtime_put(&isp->pdev->dev); */
+
+	if (isp->ref_count == 0)
+		vb2_queue_release(&isp->capture_vb_queue);
+
+	ret = v4l2_fh_release(file);
+
+	mutex_unlock(&isp->video_lock);
+	return ret;
+}
+
+static unsigned int isp_video_capture_poll(struct file *file,
+				   struct poll_table_struct *wait)
+{
+	struct fimc_isp *isp = video_drvdata(file);
+	int ret;
+
+	mutex_lock(&isp->video_lock);
+	ret = vb2_poll(&isp->capture_vb_queue, file, wait);
+	mutex_unlock(&isp->video_lock);
+	return ret;
+}
+
+static int isp_video_capture_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct fimc_isp *isp = video_drvdata(file);
+	int ret;
+
+	if (mutex_lock_interruptible(&isp->video_lock))
+		return -ERESTARTSYS;
+
+	ret = vb2_mmap(&isp->capture_vb_queue, vma);
+	mutex_unlock(&isp->video_lock);
+
+	return ret;
+}
+
+static const struct v4l2_file_operations isp_video_capture_fops = {
+	.owner		= THIS_MODULE,
+	.open		= isp_video_capture_open,
+	.release	= isp_video_capture_close,
+	.poll		= isp_video_capture_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= isp_video_capture_mmap,
+};
+
+/*
+ * Video node ioctl operations
+ */
+static int fimc_isp_capture_querycap_capture(struct file *file, void *priv,
+					     struct v4l2_capability *cap)
+{
+
+	strlcpy(cap->driver, FIMC_IS_DRV_NAME, sizeof(cap->driver));
+	strlcpy(cap->card, FIMC_IS_DRV_NAME, sizeof(cap->card));
+	snprintf(cap->bus_info, sizeof(cap->bus_info),
+				"platform:exynos4x12-isp");
+
+	cap->device_caps = V4L2_CAP_STREAMING;
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+	return 0;
+}
+
+static int fimc_isp_capture_enum_fmt_mplane(struct file *file, void *priv,
+					    struct v4l2_fmtdesc *f)
+{
+	const struct fimc_fmt *fmt;
+
+	if (f->index >= FIMC_ISP_NUM_FORMATS)
+		return -EINVAL;
+
+	fmt = fimc_isp_find_format(NULL, NULL, f->index);
+	if (WARN_ON(fmt == NULL))
+		return -EINVAL;
+
+	strlcpy(f->description, fmt->name, sizeof(f->description));
+	f->pixelformat = fmt->fourcc;
+
+	return 0;
+}
+
+static int fimc_isp_capture_g_fmt_mplane(struct file *file, void *fh,
+					 struct v4l2_format *f)
+{
+	/* TODO:  */
+	return 0;
+}
+
+static int fimc_isp_capture_try_fmt(struct fimc_isp *isp,
+				    struct v4l2_pix_format_mplane *pixm,
+				    const struct fimc_fmt **ffmt)
+{
+	/* TODO: */
+	return 0;
+}
+
+static int fimc_isp_capture_try_fmt_mplane(struct file *file, void *fh,
+					   struct v4l2_format *f)
+{
+	struct fimc_isp *isp = video_drvdata(file);
+	return fimc_isp_capture_try_fmt(isp, &f->fmt.pix_mp, NULL);
+}
+
+static int fimc_isp_capture_s_fmt_mplane(struct file *file, void *priv,
+					 struct v4l2_format *f)
+{
+	/* TODO: */
+	return 0;
+}
+
+static int fimc_isp_pipeline_validate(struct fimc_isp *isp)
+{
+	/* TODO: */
+	return 0;
+}
+
+static int fimc_isp_capture_streamon(struct file *file, void *priv,
+				     enum v4l2_buf_type type)
+{
+	struct fimc_isp *isp = video_drvdata(file);
+	struct v4l2_subdev *sensor = isp->pipeline.subdevs[IDX_SENSOR];
+	struct fimc_pipeline *p = &isp->pipeline;
+	int ret;
+
+	/* TODO: check if the OTF interface is not running */
+
+	ret = media_entity_pipeline_start(&sensor->entity, p->m_pipeline);
+	if (ret < 0)
+		return ret;
+
+	ret = fimc_isp_pipeline_validate(isp);
+	if (ret) {
+		media_entity_pipeline_stop(&sensor->entity);
+		return ret;
+	}
+
+	return vb2_streamon(&isp->capture_vb_queue, type);
+}
+
+static int fimc_isp_capture_streamoff(struct file *file, void *priv,
+				      enum v4l2_buf_type type)
+{
+	struct fimc_isp *isp = video_drvdata(file);
+	struct v4l2_subdev *sd = isp->pipeline.subdevs[IDX_SENSOR];
+	int ret;
+
+	ret = vb2_streamoff(&isp->capture_vb_queue, type);
+	if (ret == 0)
+		media_entity_pipeline_stop(&sd->entity);
+	return ret;
+}
+
+static int fimc_isp_capture_reqbufs(struct file *file, void *priv,
+				    struct v4l2_requestbuffers *reqbufs)
+{
+	struct fimc_isp *isp = video_drvdata(file);
+	int ret;
+
+	reqbufs->count = max_t(u32, FIMC_IS_REQ_BUFS_MIN, reqbufs->count);
+	ret = vb2_reqbufs(&isp->capture_vb_queue, reqbufs);
+	if (!ret < 0)
+		isp->reqbufs_count = reqbufs->count;
+
+	return ret;
+}
+
+static const struct v4l2_ioctl_ops isp_video_capture_ioctl_ops = {
+	.vidioc_querycap		= fimc_isp_capture_querycap_capture,
+	.vidioc_enum_fmt_vid_cap_mplane	= fimc_isp_capture_enum_fmt_mplane,
+	.vidioc_try_fmt_vid_cap_mplane	= fimc_isp_capture_try_fmt_mplane,
+	.vidioc_s_fmt_vid_cap_mplane	= fimc_isp_capture_s_fmt_mplane,
+	.vidioc_g_fmt_vid_cap_mplane	= fimc_isp_capture_g_fmt_mplane,
+	.vidioc_reqbufs			= fimc_isp_capture_reqbufs,
+	.vidioc_querybuf		= vb2_ioctl_querybuf,
+	.vidioc_prepare_buf		= vb2_ioctl_prepare_buf,
+	.vidioc_create_bufs		= vb2_ioctl_create_bufs,
+	.vidioc_qbuf			= vb2_ioctl_qbuf,
+	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
+	.vidioc_streamon		= fimc_isp_capture_streamon,
+	.vidioc_streamoff		= fimc_isp_capture_streamoff,
+};
+
+int fimc_isp_video_device_register(struct fimc_isp *isp,
+				   struct v4l2_device *v4l2_dev)
+{
+	struct vb2_queue *q = &isp->capture_vb_queue;
+	struct video_device *vfd = &isp->vfd;
+	int ret;
+
+	mutex_init(&isp->video_lock);
+	INIT_LIST_HEAD(&isp->pending_buf_q);
+	INIT_LIST_HEAD(&isp->active_buf_q);
+
+	memset(vfd, 0, sizeof(*vfd));
+	snprintf(vfd->name, sizeof(vfd->name), "fimc-is-isp.capture");
+
+	isp->video_capture_format = fimc_isp_find_format(NULL, NULL, 0);
+	isp->out_path = FIMC_IO_DMA;
+	isp->ref_count = 0;
+	isp->reqbufs_count = 0;
+
+	memset(q, 0, sizeof(*q));
+	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	q->io_modes = VB2_MMAP;
+	q->ops = &isp_video_capture_qops;
+	q->mem_ops = &vb2_dma_contig_memops;
+	q->buf_struct_size = sizeof(struct flite_buffer);
+	q->drv_priv = isp;
+	q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+
+	ret = vb2_queue_init(q);
+	if (ret < 0)
+		return ret;
+
+	vfd->queue = q;
+	vfd->fops = &isp_video_capture_fops;
+	vfd->ioctl_ops = &isp_video_capture_ioctl_ops;
+	vfd->v4l2_dev = v4l2_dev;
+	vfd->minor = -1;
+	vfd->release = video_device_release_empty;
+	vfd->lock = &isp->video_lock;
+
+	isp->vd_pad.flags = MEDIA_PAD_FL_SINK;
+	ret = media_entity_init(&vfd->entity, 1, &isp->vd_pad, 0);
+	if (ret < 0)
+		return ret;
+
+	video_set_drvdata(vfd, isp);
+
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+	if (ret < 0) {
+		media_entity_cleanup(&vfd->entity);
+		return ret;
+	}
+
+	v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n",
+		  vfd->name, video_device_node_name(vfd));
+
+	return 0;
+}
+
+void fimc_isp_video_device_unregister(struct fimc_isp *isp)
+{
+	if (isp && video_is_registered(&isp->vfd)) {
+		video_unregister_device(&isp->vfd);
+		media_entity_cleanup(&isp->vfd.entity);
+	}
+}
diff --git a/drivers/media/platform/s5p-fimc/fimc-isp-video.h b/drivers/media/platform/s5p-fimc/fimc-isp-video.h
new file mode 100644
index 0000000..5378dd9
--- /dev/null
+++ b/drivers/media/platform/s5p-fimc/fimc-isp-video.h
@@ -0,0 +1,50 @@
+/*
+ * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef FIMC_ISP_VIDEO__
+#define FIMC_ISP_VIDEO__
+
+#include <media/videobuf2-core.h>
+#include "fimc-isp.h"
+
+int fimc_isp_video_device_register(struct fimc_isp *isp,
+				struct v4l2_device *v4l2_dev);
+void fimc_isp_video_device_unregister(struct fimc_isp *isp);
+
+static inline void fimc_is_active_queue_add(struct fimc_isp *isp,
+					 struct fimc_isp_buffer *buf)
+{
+	list_add_tail(&buf->list, &isp->active_buf_q);
+}
+
+static inline struct fimc_isp_buffer *fimc_is_active_queue_pop(
+					struct fimc_isp *isp)
+{
+	struct fimc_isp_buffer *buf = list_entry(isp->active_buf_q.next,
+					      struct fimc_isp_buffer, list);
+	list_del(&buf->list);
+	return buf;
+}
+
+static inline void fimc_is_pending_queue_add(struct fimc_isp *isp,
+					struct fimc_isp_buffer *buf)
+{
+	list_add_tail(&buf->list, &isp->pending_buf_q);
+}
+
+static inline struct fimc_isp_buffer *fimc_is_pending_queue_pop(
+					struct fimc_isp *isp)
+{
+	struct fimc_isp_buffer *buf = list_entry(isp->pending_buf_q.next,
+					      struct fimc_isp_buffer, list);
+	list_del(&buf->list);
+	return buf;
+}
+#endif /* FIMC_ISP_VIDEO__ */
-- 
1.7.9.5

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

* [RFC PATCH 6/8] fimc-is: Add Exynos4x12 FIMC-IS device tree bindings documentation
  2013-03-11 19:44 [RFC PATCH 0/8] A V4L2 driver for Exynos4x12 Imaging Subsystem Sylwester Nawrocki
                   ` (4 preceding siblings ...)
  2013-03-11 19:44 ` [RFC PATCH 5/8] s5p-fimc: Add ISP video capture driver stubs Sylwester Nawrocki
@ 2013-03-11 19:44 ` Sylwester Nawrocki
  2013-03-11 19:44 ` [RFC PATCH 7/8] s5p-fimc: Add fimc-is subdevs registration Sylwester Nawrocki
  2013-03-11 19:44 ` [RFC PATCH 8/8] s5p-fimc: Create media links for the FIMC-IS entities Sylwester Nawrocki
  7 siblings, 0 replies; 14+ messages in thread
From: Sylwester Nawrocki @ 2013-03-11 19:44 UTC (permalink / raw)
  To: linux-media
  Cc: kyungmin.park, myungjoo.ham, dh09.lee, shaik.samsung, arun.kk,
	a.hajda, linux-samsung-soc, devicetree-discuss, linux-arm-kernel,
	Sylwester Nawrocki

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 .../devicetree/bindings/media/exynos4-fimc-is.txt  |   41 ++++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/exynos4-fimc-is.txt

diff --git a/Documentation/devicetree/bindings/media/exynos4-fimc-is.txt b/Documentation/devicetree/bindings/media/exynos4-fimc-is.txt
new file mode 100644
index 0000000..ef994d1
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/exynos4-fimc-is.txt
@@ -0,0 +1,41 @@
+Exynos4x12 SoC series Imaging Subsystem (FIMC-IS)
+
+The FIMC-IS is an subsystem for processing image signal from an image sensor.
+The Exynos4x12 SoC series FIMC-IS V1.5 comprises of a dedicated ARM Cortex-A5
+processor, ISP, DRC and FD IP blocks and peripheral IPs such as I2C, SPI, UART
+bus controllers, Multi-PWM and ADC.
+
+fimc-is node
+------------
+
+Required properties:
+
+- compatible : should be "samsung,exynos4212-fimc-is" for Exynos4212 and
+	       Exynos4412 SoCs;
+- reg	     : physical base address and size of the device memory mapped
+	       registers;
+- interrupts : should contain FIMC-IS interrupts;
+
+The following are the FIMC-IS peripheral device nodes and can be specified
+either standalone or as fimc-is child nodes.
+
+pmu subnode
+-----------
+
+Required properties:
+ - reg	: should contain PMU physical base address of the memory mapped
+          registers and size, the value of size should be 0x3000.
+
+
+i2c-isp (ISP I2C bus controller) nodes
+------------------------------------------
+
+Required properties:
+
+- compatible : should be "samsung,exynos4212-i2c-isp" for Exynos4212 and
+	       Exynos4412 SoCs;
+- reg	     : physical base address and size of the device memory mapped
+	       registers;
+
+For the above nodes it is required to specify a pinctrl state named "default",
+according to the pinctrl bindings defined in ../pinctrl/pinctrl-bindings.txt.
-- 
1.7.9.5

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

* [RFC PATCH 7/8] s5p-fimc: Add fimc-is subdevs registration
  2013-03-11 19:44 [RFC PATCH 0/8] A V4L2 driver for Exynos4x12 Imaging Subsystem Sylwester Nawrocki
                   ` (5 preceding siblings ...)
  2013-03-11 19:44 ` [RFC PATCH 6/8] fimc-is: Add Exynos4x12 FIMC-IS device tree bindings documentation Sylwester Nawrocki
@ 2013-03-11 19:44 ` Sylwester Nawrocki
  2013-03-11 19:44 ` [RFC PATCH 8/8] s5p-fimc: Create media links for the FIMC-IS entities Sylwester Nawrocki
  7 siblings, 0 replies; 14+ messages in thread
From: Sylwester Nawrocki @ 2013-03-11 19:44 UTC (permalink / raw)
  To: linux-media
  Cc: kyungmin.park, myungjoo.ham, dh09.lee, shaik.samsung, arun.kk,
	a.hajda, linux-samsung-soc, devicetree-discuss, linux-arm-kernel,
	Sylwester Nawrocki

This patch allows to register FIMC-IS device represented by FIMC-IS-ISP
subdev to the top level media device driver. The use_isp platform data
structure field allows to select whether the fimc-is ISP subdev should
be tried to be registered or not.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/platform/s5p-fimc/fimc-mdevice.c |   51 ++++++++++++++++++++++--
 drivers/media/platform/s5p-fimc/fimc-mdevice.h |   15 +++++++
 2 files changed, 62 insertions(+), 4 deletions(-)

diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c
index e9e5337..1521dec 100644
--- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c
+++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c
@@ -31,6 +31,7 @@
 #include <media/s5p_fimc.h>
 
 #include "fimc-core.h"
+#include "fimc-is.h"
 #include "fimc-lite.h"
 #include "fimc-mdevice.h"
 #include "mipi-csis.h"
@@ -85,9 +86,11 @@ static void fimc_pipeline_prepare(struct fimc_pipeline *p,
 		case GRP_ID_FIMC:
 			/* No need to control FIMC subdev through subdev ops */
 			break;
+		case GRP_ID_FIMC_IS:
+			p->subdevs[IDX_IS_ISP] = sd;
+			break;
 		default:
-			pr_warn("%s: Unknown subdev grp_id: %#x\n",
-				__func__, sd->grp_id);
+			break;
 		}
 		me = &sd->entity;
 		if (me->num_pads == 1)
@@ -291,6 +294,7 @@ static void fimc_md_unregister_sensor(struct v4l2_subdev *sd)
 
 	if (!client)
 		return;
+
 	v4l2_device_unregister_subdev(sd);
 
 	if (!client->dev.of_node) {
@@ -341,7 +345,11 @@ static int fimc_md_of_add_sensor(struct fimc_md *fmd,
 		goto mod_put;
 
 	v4l2_set_subdev_hostdata(sd, si);
-	sd->grp_id = GRP_ID_SENSOR;
+	if (si->pdata.fimc_bus_type == FIMC_BUS_TYPE_ISP_WRITEBACK)
+		sd->grp_id = GRP_ID_FIMC_IS_SENSOR;
+	else
+		sd->grp_id = GRP_ID_SENSOR;
+
 	si->subdev = sd;
 	v4l2_info(&fmd->v4l2_dev, "Registered sensor subdevice: %s (%d)\n",
 		  sd->name, fmd->num_sensors);
@@ -360,7 +368,7 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
 				   struct device_node *port,
 				   unsigned int index)
 {
-	struct device_node *rem, *endpoint;
+	struct device_node *rem, *endpoint, *np;
 	struct fimc_source_info *pd;
 	struct v4l2_of_endpoint bus_cfg;
 	u32 tmp, reg = 0;
@@ -415,6 +423,18 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
 		v4l2_err(&fmd->v4l2_dev, "Wrong port id (%u) at node %s\n",
 			 reg, rem->full_name);
 	}
+	/*
+	 * For FIMC-IS handled sensors, that are placed under fimc-is-i2c
+	 * device node, FIMC is connected to the FIMC-IS through its ISP
+	 * Writeback input. Sensors are attached to the FIMC-LITE hostdata
+	 * interface directly or through MIPI-CSIS, depending on the external
+	 * media bus used. This needs to be handled in a more reliable way,
+	 * not by just checking parent's node name.
+	 */
+	if ((np = of_get_parent(rem)) && !of_node_cmp(np->name, "i2c-isp"))
+		pd->fimc_bus_type = FIMC_BUS_TYPE_ISP_WRITEBACK;
+	else
+		pd->fimc_bus_type = pd->sensor_bus_type;
 
 	ret = fimc_md_of_add_sensor(fmd, rem, index);
 	of_node_put(rem);
@@ -607,6 +627,22 @@ static int register_csis_entity(struct fimc_md *fmd,
 	return ret;
 }
 
+static int register_fimc_is_entity(struct fimc_md *fmd, struct fimc_is *is)
+{
+	struct v4l2_subdev *sd = &is->isp.subdev;
+	int ret;
+
+	ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
+	if (ret) {
+		v4l2_err(&fmd->v4l2_dev,
+			 "Failed to register FIMC-ISP (%d)\n", ret);
+		return ret;
+	}
+
+	fmd->fimc_is = is;
+	return 0;
+}
+
 static int fimc_md_register_platform_entity(struct fimc_md *fmd,
 					    struct platform_device *pdev,
 					    int plat_entity)
@@ -634,6 +670,9 @@ static int fimc_md_register_platform_entity(struct fimc_md *fmd,
 		case IDX_CSIS:
 			ret = register_csis_entity(fmd, pdev, drvdata);
 			break;
+		case IDX_IS_ISP:
+			ret = register_fimc_is_entity(fmd, drvdata);
+			break;
 		default:
 			ret = -ENODEV;
 		}
@@ -697,6 +736,8 @@ static int fimc_md_register_of_platform_entities(struct fimc_md *fmd,
 		/* If driver of any entity isn't ready try all again later. */
 		if (!strcmp(node->name, CSIS_OF_NODE_NAME))
 			plat_entity = IDX_CSIS;
+		else if	(!strcmp(node->name, FIMC_IS_OF_NODE_NAME))
+			plat_entity = IDX_IS_ISP;
 		else if (!strcmp(node->name, FIMC_LITE_OF_NODE_NAME))
 			plat_entity = IDX_FLITE;
 		else if	(!strcmp(node->name, FIMC_OF_NODE_NAME))
@@ -1271,6 +1312,8 @@ static int fimc_md_probe(struct platform_device *pdev)
 	v4l2_dev->notify = fimc_sensor_notify;
 	strlcpy(v4l2_dev->name, "s5p-fimc-md", sizeof(v4l2_dev->name));
 
+	fmd->use_isp = fimc_md_is_isp_available(dev->of_node);
+
 	ret = v4l2_device_register(dev, &fmd->v4l2_dev);
 	if (ret < 0) {
 		v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret);
diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.h b/drivers/media/platform/s5p-fimc/fimc-mdevice.h
index a827bf9..52a8ecb 100644
--- a/drivers/media/platform/s5p-fimc/fimc-mdevice.h
+++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.h
@@ -12,6 +12,7 @@
 #include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <linux/mutex.h>
+#include <linux/of.h>
 #include <linux/pinctrl/consumer.h>
 #include <media/media-device.h>
 #include <media/media-entity.h>
@@ -81,6 +82,8 @@ struct fimc_sensor_info {
  * @camclk: external sensor clock information
  * @fimc: array of registered fimc devices
  * @pmf: handle to the CAMCLK clock control FIMC helper device
+ * @fimc_is: fimc-is data structure
+ * @use_isp: set to true when FIMC-IS subsystem is used
  * @media_dev: top level media device
  * @v4l2_dev: top level v4l2_device holding up the subdevs
  * @pdev: platform device this media device is hooked up into
@@ -99,6 +102,8 @@ struct fimc_md {
 	struct fimc_lite *fimc_lite[FIMC_LITE_MAX_DEVS];
 	struct fimc_dev *fimc[FIMC_MAX_DEVS];
 	struct device *pmf;
+	struct fimc_is *fimc_is;
+	bool use_isp;
 	struct media_device media_dev;
 	struct v4l2_device v4l2_dev;
 	struct platform_device *pdev;
@@ -137,4 +142,14 @@ static inline void fimc_md_graph_unlock(struct fimc_dev *fimc)
 
 int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on);
 
+#ifdef CONFIG_OF
+static inline bool fimc_md_is_isp_available(struct device_node *node)
+{
+	node = of_get_child_by_name(node, FIMC_IS_OF_NODE_NAME);
+	return node ? of_device_is_available(node) : false;
+}
+#else
+#define fimc_md_is_isp_available(node) (false)
+#endif /* CONFIG_OF */
+
 #endif
-- 
1.7.9.5

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

* [RFC PATCH 8/8] s5p-fimc: Create media links for the FIMC-IS entities
  2013-03-11 19:44 [RFC PATCH 0/8] A V4L2 driver for Exynos4x12 Imaging Subsystem Sylwester Nawrocki
                   ` (6 preceding siblings ...)
  2013-03-11 19:44 ` [RFC PATCH 7/8] s5p-fimc: Add fimc-is subdevs registration Sylwester Nawrocki
@ 2013-03-11 19:44 ` Sylwester Nawrocki
  7 siblings, 0 replies; 14+ messages in thread
From: Sylwester Nawrocki @ 2013-03-11 19:44 UTC (permalink / raw)
  To: linux-media
  Cc: kyungmin.park, myungjoo.ham, dh09.lee, shaik.samsung, arun.kk,
	a.hajda, linux-samsung-soc, devicetree-discuss, linux-arm-kernel,
	Sylwester Nawrocki

Create disabled links from the FIMC-LITE subdevs to the FIMC-IS-ISP
subdev and from FIMC-IS-ISP to all FIMC subdevs.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/platform/s5p-fimc/fimc-mdevice.c |   78 +++++++++++++++++++-----
 1 file changed, 62 insertions(+), 16 deletions(-)

diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c
index 1521dec..5304da5 100644
--- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c
+++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c
@@ -807,9 +807,17 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
 	struct fimc_sensor_info *s_info = NULL;
 	struct media_entity *sink;
 	unsigned int flags = 0;
-	int ret, i;
+	int i, ret = 0;
 
-	for (i = 0; i < FIMC_MAX_DEVS; i++) {
+	if (sensor) {
+		s_info = v4l2_get_subdev_hostdata(sensor);
+		/* Skip direct FIMC links in the logical FIMC-IS sensor path */
+		if (s_info && s_info->pdata.fimc_bus_type ==
+		    FIMC_BUS_TYPE_ISP_WRITEBACK)
+			ret = 1;
+	}
+
+	for (i = 0; !ret && i < FIMC_MAX_DEVS; i++) {
 		if (!fmd->fimc[i])
 			continue;
 		/*
@@ -838,7 +846,7 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
 
 		if (flags == 0 || sensor == NULL)
 			continue;
-		s_info = v4l2_get_subdev_hostdata(sensor);
+
 		if (!WARN_ON(s_info == NULL)) {
 			unsigned long irq_flags;
 			spin_lock_irqsave(&fmd->slock, irq_flags);
@@ -851,25 +859,20 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
 		if (!fmd->fimc_lite[i])
 			continue;
 
-		if (link_mask & (1 << (i + FIMC_MAX_DEVS)))
-			flags = MEDIA_LNK_FL_ENABLED;
-		else
-			flags = 0;
-
 		sink = &fmd->fimc_lite[i]->subdev.entity;
 		ret = media_entity_create_link(source, pad, sink,
-					       FLITE_SD_PAD_SINK, flags);
+					       FLITE_SD_PAD_SINK, 0);
 		if (ret)
 			return ret;
 
 		/* Notify FIMC-LITE subdev entity */
 		ret = media_entity_call(sink, link_setup, &sink->pads[0],
-					&source->pads[pad], flags);
+					&source->pads[pad], 0);
 		if (ret)
 			break;
 
-		v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]\n",
-			  source->name, flags ? '=' : '-', sink->name);
+		v4l2_info(&fmd->v4l2_dev, "created link [%s] -> [%s]\n",
+			  source->name, sink->name);
 	}
 	return 0;
 }
@@ -878,26 +881,59 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
 static int __fimc_md_create_flite_source_links(struct fimc_md *fmd)
 {
 	struct media_entity *source, *sink;
-	unsigned int flags = MEDIA_LNK_FL_ENABLED;
 	int i, ret = 0;
 
 	for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
 		struct fimc_lite *fimc = fmd->fimc_lite[i];
+
 		if (fimc == NULL)
 			continue;
+
 		source = &fimc->subdev.entity;
 		sink = &fimc->vfd.entity;
 		/* FIMC-LITE's subdev and video node */
 		ret = media_entity_create_link(source, FLITE_SD_PAD_SOURCE_DMA,
-					       sink, 0, flags);
+					       sink, 0, 0);
+		if (ret)
+			break;
+		/* Link from FIMC-LITE to IS-ISP subdev */
+		sink = &fmd->fimc_is->isp.subdev.entity;
+		ret = media_entity_create_link(source, FLITE_SD_PAD_SOURCE_ISP,
+					       sink, 0, 0);
 		if (ret)
 			break;
-		/* TODO: create links to other entities */
 	}
 
 	return ret;
 }
 
+/* Create FIMC-IS links */
+static int __fimc_md_create_fimc_is_links(struct fimc_md *fmd)
+{
+	struct media_entity *source, *sink;
+	int i, ret;
+
+	source = &fmd->fimc_is->isp.subdev.entity;
+
+	for (i = 0; i < FIMC_MAX_DEVS; i++) {
+		if (fmd->fimc[i] == NULL)
+			continue;
+
+		/* Link from IS-ISP subdev to FIMC */
+		sink = &fmd->fimc[i]->vid_cap.subdev.entity;
+		ret = media_entity_create_link(source, FIMC_IS_SD_PAD_SRC_FIFO,
+					       sink, FIMC_SD_PAD_SINK_FIFO, 0);
+		if (ret)
+			return ret;
+	}
+
+	/* Link from IS-ISP subdev to is.isp capture video node */
+	sink = &fmd->fimc_is->isp.vfd.entity;
+	ret = media_entity_create_link(source, FIMC_IS_SD_PAD_SRC_DMA,
+					       sink, 0, 0);
+	return ret;
+}
+
 /**
  * fimc_md_create_links - create default links between registered entities
  *
@@ -980,6 +1016,7 @@ static int fimc_md_create_links(struct fimc_md *fmd)
 	for (i = 0; i < CSIS_MAX_ENTITIES; i++) {
 		if (fmd->csis[i].sd == NULL)
 			continue;
+
 		source = &fmd->csis[i].sd->entity;
 		pad = CSIS_PAD_SOURCE;
 		sensor = csi_sensors[i];
@@ -994,15 +1031,24 @@ static int fimc_md_create_links(struct fimc_md *fmd)
 	for (i = 0; i < FIMC_MAX_DEVS; i++) {
 		if (!fmd->fimc[i])
 			continue;
+
 		source = &fmd->fimc[i]->vid_cap.subdev.entity;
 		sink = &fmd->fimc[i]->vid_cap.vfd.entity;
+
 		ret = media_entity_create_link(source, FIMC_SD_PAD_SOURCE,
 					      sink, 0, flags);
 		if (ret)
 			break;
 	}
 
-	return __fimc_md_create_flite_source_links(fmd);
+	ret = __fimc_md_create_flite_source_links(fmd);
+	if (ret < 0)
+		return ret;
+
+	if (fmd->use_isp)
+		ret = __fimc_md_create_fimc_is_links(fmd);
+
+	return ret;
 }
 
 /*
-- 
1.7.9.5

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

* Re: [RFC PATCH 1/8] s5p-fimc: Add Exynos4x12 FIMC-IS driver
  2013-03-11 19:44 ` [RFC PATCH 1/8] s5p-fimc: Add Exynos4x12 FIMC-IS driver Sylwester Nawrocki
@ 2013-03-12 14:27   ` Hans Verkuil
  2013-03-17 19:38     ` Sylwester Nawrocki
  0 siblings, 1 reply; 14+ messages in thread
From: Hans Verkuil @ 2013-03-12 14:27 UTC (permalink / raw)
  To: Sylwester Nawrocki
  Cc: linux-media, kyungmin.park, myungjoo.ham, dh09.lee,
	shaik.samsung, arun.kk, a.hajda, linux-samsung-soc,
	devicetree-discuss, linux-arm-kernel

On Mon 11 March 2013 20:44:45 Sylwester Nawrocki wrote:
> This patch adds a set of core files of the Exynos4x12 FIMC-IS
> V4L2 driver. This includes main functionality like allocating
> memory, loading the firmware, FIMC-IS register interface and
> host CPU <-> IS command and error code definitions.
> 
> The driver currently exposes a single subdev named FIMC-IS-ISP,
> which corresponds to the FIMC-IS ISP and DRC IP blocks.
> 
> The FIMC-IS-ISP subdev currently supports only a subset of user
> controls. For other controls we need several extensions at the
> V4L2 API. The supported standard controls are:
> brightness, contrast, saturation, hue, sharpness, 3a_lock,
> exposure_time_absolute, white_balance_auto_preset,
> iso_sensitivity, iso_sensitivity_auto, exposure_metering_mode.
> Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---

<snip most of the patch>

> +
> +/* Supported manual ISO values */
> +static const s64 iso_qmenu[] = {
> +	50, 100, 200, 400, 800,
> +};
> +
> +static int __ctrl_set_iso(struct fimc_is *is, int value)
> +{
> +	unsigned int idx, iso;
> +
> +	if (value == V4L2_ISO_SENSITIVITY_AUTO) {
> +		__is_set_isp_iso(is, ISP_ISO_COMMAND_AUTO, 0);
> +		return 0;
> +	}
> +	idx = is->isp.ctrls.iso->val;
> +	if (idx >= ARRAY_SIZE(iso_qmenu))
> +		return -EINVAL;
> +
> +	iso = iso_qmenu[idx];
> +	__is_set_isp_iso(is, ISP_ISO_COMMAND_MANUAL, iso);
> +	return 0;
> +}
> +
> +static int __ctrl_set_metering(struct fimc_is *is, unsigned int value)
> +{
> +	unsigned int val;
> +
> +	switch (value) {
> +	case V4L2_EXPOSURE_METERING_AVERAGE:
> +		val = ISP_METERING_COMMAND_AVERAGE;
> +		break;
> +	case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED:
> +		val = ISP_METERING_COMMAND_CENTER;
> +		break;
> +	case V4L2_EXPOSURE_METERING_SPOT:
> +		val = ISP_METERING_COMMAND_SPOT;
> +		break;
> +	case V4L2_EXPOSURE_METERING_MATRIX:
> +		val = ISP_METERING_COMMAND_MATRIX;
> +		break;
> +	default:
> +		return -EINVAL;
> +	};
> +
> +	__is_set_isp_metering(is, IS_METERING_CONFIG_CMD, val);
> +	return 0;
> +}
> +
> +static int __ctrl_set_afc(struct fimc_is *is, int value)
> +{
> +	switch (value) {
> +	case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED:
> +		__is_set_isp_afc(is, ISP_AFC_COMMAND_DISABLE, 0);
> +		break;
> +	case V4L2_CID_POWER_LINE_FREQUENCY_50HZ:
> +		__is_set_isp_afc(is, ISP_AFC_COMMAND_MANUAL, 50);
> +		break;
> +	case V4L2_CID_POWER_LINE_FREQUENCY_60HZ:
> +		__is_set_isp_afc(is, ISP_AFC_COMMAND_MANUAL, 60);
> +		break;
> +	case V4L2_CID_POWER_LINE_FREQUENCY_AUTO:
> +		__is_set_isp_afc(is, ISP_AFC_COMMAND_AUTO, 0);
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +#if 0
> +static int __ctrl_set_flash_mode(struct fimc_is *is, int value)
> +{
> +	switch (value) {
> +	case IS_FLASH_MODE_OFF:
> +		__is_set_isp_flash(is, ISP_FLASH_COMMAND_DISABLE, 0);
> +		break;
> +	case IS_FLASH_MODE_AUTO:
> +		__is_set_isp_flash(is, ISP_FLASH_COMMAND_AUTO, 0);
> +		break;
> +	case IS_FLASH_MODE_AUTO_REDEYE:
> +		__is_set_isp_flash(is, ISP_FLASH_COMMAND_AUTO, 1);
> +		break;
> +	case IS_FLASH_MODE_ON:
> +		__is_set_isp_flash(is, ISP_FLASH_COMMAND_MANUALON, 0);
> +		break;
> +	case IS_FLASH_MODE_TORCH:
> +		__is_set_isp_flash(is, ISP_FLASH_COMMAND_TORCH, 0);
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +#endif
> +
> +static int __ctrl_set_image_effect(struct fimc_is *is, int value)
> +{
> +	/* FIXME: */
> +	__is_set_isp_effect(is, value);
> +	return 0;
> +}
> +
> +static int fimc_is_s_ctrl(struct v4l2_ctrl *ctrl)
> +{
> +	struct fimc_isp *isp = ctrl_to_fimc_isp(ctrl);
> +	struct fimc_is *is = fimc_isp_to_is(isp);
> +	bool set_param = true;
> +	int ret = 0;
> +
> +	switch (ctrl->id) {
> +	case V4L2_CID_CONTRAST:
> +		__is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_CONTRAST,
> +				    ctrl->val);
> +		break;
> +
> +	case V4L2_CID_SATURATION:
> +		__is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_SATURATION,
> +				    ctrl->val);
> +		break;
> +
> +	case V4L2_CID_SHARPNESS:
> +		__is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_SHARPNESS,
> +				    ctrl->val);
> +		break;
> +
> +	case V4L2_CID_EXPOSURE_ABSOLUTE:
> +		__is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_EXPOSURE,
> +				    ctrl->val);
> +		break;
> +
> +	case V4L2_CID_BRIGHTNESS:
> +		__is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_BRIGHTNESS,
> +				    ctrl->val);
> +		break;
> +
> +	case V4L2_CID_HUE:
> +		__is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_HUE,
> +				    ctrl->val);
> +		break;
> +
> +	case V4L2_CID_EXPOSURE_METERING:
> +		ret = __ctrl_set_metering(is, ctrl->val);
> +		break;
> +
> +	case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
> +		ret = __ctrl_set_white_balance(is, ctrl->val);
> +		break;
> +
> +	case V4L2_CID_3A_LOCK:
> +		ret = __ctrl_set_aewb_lock(is, ctrl);
> +		set_param = false;
> +		break;
> +
> +	case V4L2_CID_ISO_SENSITIVITY_AUTO:
> +		ret = __ctrl_set_iso(is, ctrl->val);
> +		break;
> +
> +	case V4L2_CID_POWER_LINE_FREQUENCY:
> +		ret = __ctrl_set_afc(is, ctrl->val);
> +		break;
> +
> +	case V4L2_CID_COLORFX:
> +		__ctrl_set_image_effect(is, ctrl->val);
> +		break;
> +
> +	default:
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +	if (ret < 0) {
> +		v4l2_err(&isp->subdev, "%s() failed, ctrl: %s, val: %d\n",
> +			 __func__, ctrl->name, ctrl->val);
> +		return ret;
> +	}
> +
> +	if (set_param && test_bit(IS_ST_STREAM_ON, &is->state))
> +		return fimc_is_itf_s_param(is, true);
> +
> +	return 0;
> +}
> +
> +static const struct v4l2_ctrl_ops fimc_isp_ctrl_ops = {
> +	.s_ctrl	= fimc_is_s_ctrl,
> +};
> +
> +int fimc_isp_subdev_create(struct fimc_isp *isp)
> +{
> +	const struct v4l2_ctrl_ops *ops = &fimc_isp_ctrl_ops;
> +	struct v4l2_ctrl_handler *handler = &isp->ctrls.handler;
> +	struct v4l2_subdev *sd = &isp->subdev;
> +	struct fimc_isp_ctrls *ctrls = &isp->ctrls;
> +	int ret;
> +
> +	mutex_init(&isp->subdev_lock);
> +
> +	v4l2_subdev_init(sd, &fimc_is_subdev_ops);
> +	sd->grp_id = GRP_ID_FIMC_IS;
> +	sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
> +	snprintf(sd->name, sizeof(sd->name), "FIMC-IS-ISP");
> +
> +	isp->subdev_pads[FIMC_IS_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
> +	isp->subdev_pads[FIMC_IS_SD_PAD_SRC_FIFO].flags = MEDIA_PAD_FL_SOURCE;
> +	isp->subdev_pads[FIMC_IS_SD_PAD_SRC_DMA].flags = MEDIA_PAD_FL_SOURCE;
> +	ret = media_entity_init(&sd->entity, FIMC_IS_SD_PADS_NUM,
> +				isp->subdev_pads, 0);
> +	if (ret)
> +		return ret;
> +
> +	v4l2_ctrl_handler_init(handler, 20);
> +
> +	ctrls->saturation = v4l2_ctrl_new_std(handler, ops, V4L2_CID_SATURATION,
> +						-2, 2, 1, 0);
> +	ctrls->brightness = v4l2_ctrl_new_std(handler, ops, V4L2_CID_BRIGHTNESS,
> +						-4, 4, 1, 0);
> +	ctrls->contrast = v4l2_ctrl_new_std(handler, ops, V4L2_CID_CONTRAST,
> +						-2, 2, 1, 0);
> +	ctrls->sharpness = v4l2_ctrl_new_std(handler, ops, V4L2_CID_SHARPNESS,
> +						-2, 2, 1, 0);
> +	ctrls->hue = v4l2_ctrl_new_std(handler, ops, V4L2_CID_HUE,
> +						-2, 2, 1, 0);
> +
> +	ctrls->auto_wb = v4l2_ctrl_new_std_menu(handler, ops,
> +					V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
> +					8, ~0x14e, V4L2_WHITE_BALANCE_AUTO);
> +
> +	ctrls->exposure = v4l2_ctrl_new_std(handler, ops,
> +					V4L2_CID_EXPOSURE_ABSOLUTE,
> +					-4, 4, 1, 0);
> +
> +	ctrls->exp_metering = v4l2_ctrl_new_std_menu(handler, ops,
> +					V4L2_CID_EXPOSURE_METERING, 3,
> +					~0xf, V4L2_EXPOSURE_METERING_AVERAGE);
> +
> +	v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_POWER_LINE_FREQUENCY,
> +					V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
> +					V4L2_CID_POWER_LINE_FREQUENCY_AUTO);
> +	/* ISO sensitivity */
> +	ctrls->auto_iso = v4l2_ctrl_new_std_menu(handler, ops,
> +			V4L2_CID_ISO_SENSITIVITY_AUTO, 1, 0,
> +			V4L2_ISO_SENSITIVITY_AUTO);
> +
> +	ctrls->iso = v4l2_ctrl_new_int_menu(handler, ops,
> +			V4L2_CID_ISO_SENSITIVITY, ARRAY_SIZE(iso_qmenu) - 1,
> +			ARRAY_SIZE(iso_qmenu)/2 - 1, iso_qmenu);
> +
> +	ctrls->aewb_lock = v4l2_ctrl_new_std(handler, ops,
> +					V4L2_CID_3A_LOCK, 0, 0x3, 0, 0);
> +
> +	/* FIXME: Adjust the enabled controls mask according
> +	   to the ISP capabilities */
> +	v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_COLORFX,
> +					V4L2_COLORFX_ANTIQUE,
> +					0, V4L2_COLORFX_NONE);
> +	if (handler->error) {
> +		media_entity_cleanup(&sd->entity);
> +		return handler->error;
> +	}
> +
> +	ctrls->auto_iso->flags |= V4L2_CTRL_FLAG_VOLATILE |
> +				  V4L2_CTRL_FLAG_UPDATE;

Why would auto_iso be volatile? I would expect the iso to be volatile
(in which case the 'false' argument below would be 'true'). Also,
v4l2_ctrl_auto_cluster already sets the UPDATE flag.

> +	v4l2_ctrl_auto_cluster(2, &ctrls->auto_iso, 0, false);
> +
> +	sd->ctrl_handler = handler;
> +	sd->internal_ops = &fimc_is_subdev_internal_ops;
> +	sd->entity.ops = &fimc_is_subdev_media_ops;
> +	v4l2_set_subdevdata(sd, isp);
> +
> +	return 0;
> +}
> +
> +void fimc_isp_subdev_destroy(struct fimc_isp *isp)
> +{
> +	struct v4l2_subdev *sd = &isp->subdev;
> +
> +	v4l2_device_unregister_subdev(sd);
> +	media_entity_cleanup(&sd->entity);
> +	v4l2_ctrl_handler_free(&isp->ctrls.handler);
> +	v4l2_set_subdevdata(sd, NULL);
> +}
> diff --git a/drivers/media/platform/s5p-fimc/fimc-isp.h b/drivers/media/platform/s5p-fimc/fimc-isp.h
> new file mode 100644
> index 0000000..654039e
> --- /dev/null
> +++ b/drivers/media/platform/s5p-fimc/fimc-isp.h
> @@ -0,0 +1,205 @@
> +/*
> + * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
> + *
> + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> + *
> + * Authors: Sylwester Nawrocki <s.nawrocki@samsung.com>
> + *          Younghwan Joo <yhwan.joo@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +#ifndef FIMC_ISP_H_
> +#define FIMC_ISP_H_
> +
> +#include <asm/sizes.h>
> +#include <linux/io.h>
> +#include <linux/irqreturn.h>
> +#include <linux/platform_device.h>
> +#include <linux/sched.h>
> +#include <linux/spinlock.h>
> +#include <linux/types.h>
> +#include <linux/videodev2.h>
> +
> +#include <media/media-entity.h>
> +#include <media/videobuf2-core.h>
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-mediabus.h>
> +#include <media/s5p_fimc.h>
> +
> +#include "fimc-core.h"
> +
> +/* TODO: revisit these constraints */
> +#define FIMC_ISP_SINK_WIDTH_MIN		(16 + 8)
> +#define FIMC_ISP_SINK_HEIGHT_MIN	(12 + 8)
> +#define FIMC_ISP_SOURCE_WIDTH_MIN	8
> +#define FIMC_ISP_SOURC_HEIGHT_MIN	8
> +/* FIXME: below are random numbers... */
> +#define FIMC_ISP_SINK_WIDTH_MAX		(4000 - 16)
> +#define FIMC_ISP_SINK_HEIGHT_MAX	(4000 + 12)
> +#define FIMC_ISP_SOURCE_WIDTH_MAX	4000
> +#define FIMC_ISP_SOURC_HEIGHT_MAX	4000
> +
> +#define FIMC_ISP_NUM_FORMATS		3
> +#define FIMC_IS_REQ_BUFS_MIN		2
> +
> +#define FIMC_IS_SD_PAD_SINK		0
> +#define FIMC_IS_SD_PAD_SRC_FIFO		1
> +#define FIMC_IS_SD_PAD_SRC_DMA		2
> +#define FIMC_IS_SD_PADS_NUM		3
> +#define FIMC_IS_MAX_PLANES		1
> +
> +/**
> + * struct fimc_isp_frame - source/target frame properties
> + * @f_width: full pixel width
> + * @f_height: full pixel height
> + * @rect: crop/composition rectangle
> + */
> +struct fimc_isp_frame {
> +	u16 f_width;
> +	u16 f_height;
> +	struct v4l2_rect rect;
> +};
> +
> +/**
> + * struct fimc_isp_buffer - video buffer structure
> + * @vb: vb2 buffer
> + * @list: list head for the buffers queue
> + * @paddr: precalculated physical address
> + */
> +struct fimc_isp_buffer {
> +	struct vb2_buffer vb;
> +	struct list_head list;
> +	dma_addr_t paddr;
> +};
> +
> +struct fimc_isp_ctrls {
> +	struct v4l2_ctrl_handler handler;
> +	/* Internal mode selection */
> +	struct v4l2_ctrl *scenario;
> +	/* Frame rate */
> +	struct v4l2_ctrl *fps;
> +	/* Touch AF position */
> +	struct v4l2_ctrl *af_position_x;
> +	struct v4l2_ctrl *af_position_y;
> +	/* Auto white balance */
> +	struct v4l2_ctrl *auto_wb;
> +	/* ISO sensitivity */
> +	struct v4l2_ctrl *auto_iso;
> +	struct v4l2_ctrl *iso;

I suggest putting this in an anonymous struct:

	struct { /* Auto ISO control cluster */
		struct v4l2_ctrl *auto_iso;
		struct v4l2_ctrl *iso;
	};

That way you visually emphasize that these belong together and that you
shouldn't move them around.

> +
> +	struct v4l2_ctrl *contrast;
> +	struct v4l2_ctrl *saturation;
> +	struct v4l2_ctrl *sharpness;
> +	/* Auto/manual exposure */
> +	struct v4l2_ctrl *auto_exp;
> +	/* Manual exposure value */
> +	struct v4l2_ctrl *exposure;
> +	/* Adjust - brightness */
> +	struct v4l2_ctrl *brightness;
> +	/* Adjust - hue */
> +	struct v4l2_ctrl *hue;
> +	/* Exposure metering mode */
> +	struct v4l2_ctrl *exp_metering;
> +	/* AFC */
> +	struct v4l2_ctrl *afc;
> +	/* AE/AWB lock/unlock */
> +	struct v4l2_ctrl *aewb_lock;
> +	/* AF */
> +	struct v4l2_ctrl *focus_mode;
> +	/* AF status */
> +	struct v4l2_ctrl *af_status;
> +};
> +
> +/**
> + * struct fimc_isp - fimc isp structure
> + * @pdev: pointer to FIMC-LITE platform device
> + * @variant: variant information for this IP
> + * @v4l2_dev: pointer to top the level v4l2_device
> + * @vfd: video device node
> + * @fh: v4l2 file handle
> + * @alloc_ctx: videobuf2 memory allocator context
> + * @subdev: FIMC-LITE subdev
> + * @vd_pad: media (sink) pad for the capture video node
> + * @subdev_pads: the subdev media pads
> + * @ctrl_handler: v4l2 control handler
> + * @test_pattern: test pattern controls
> + * @index: FIMC-LITE platform device index
> + * @pipeline: video capture pipeline data structure
> + * @slock: spinlock protecting this data structure and the hw registers
> + * @video_lock: mutex serializing video device and the subdev operations
> + * @clock: FIMC-LITE gate clock
> + * @regs: memory mapped io registers
> + * @irq_queue: interrupt handler waitqueue
> + * @fmt: pointer to color format description structure
> + * @payload: image size in bytes (w x h x bpp)
> + * @inp_frame: camera input frame structure
> + * @out_frame: DMA output frame structure
> + * @out_path: output data path (DMA or FIFO)
> + * @source_subdev_grp_id: source subdev group id
> + * @cac_margin_x: horizontal CAC margin in pixels
> + * @cac_margin_y: vertical CAC margin in pixels
> + * @state: driver state flags
> + * @pending_buf_q: pending buffers queue head
> + * @active_buf_q: the queue head of buffers scheduled in hardware
> + * @capture_vb_queue: vb2 buffers queue for ISP capture video node
> + * @active_buf_count: number of video buffers scheduled in hardware
> + * @frame_count: the captured frames counter
> + * @reqbufs_count: the number of buffers requested with REQBUFS ioctl
> + * @ref_count: driver's private reference counter
> + */
> +struct fimc_isp {
> +	struct platform_device		*pdev;
> +	struct fimc_is_variant		*variant;
> +	struct v4l2_device		*v4l2_dev;
> +	struct video_device		vfd;
> +	struct v4l2_fh			fh;
> +	struct vb2_alloc_ctx		*alloc_ctx;
> +	struct v4l2_subdev		subdev;
> +	struct media_pad		vd_pad;
> +	struct media_pad		subdev_pads[FIMC_IS_SD_PADS_NUM];
> +	struct v4l2_mbus_framefmt	subdev_fmt;
> +	struct v4l2_ctrl		*test_pattern;
> +	struct fimc_pipeline		pipeline;
> +	struct fimc_isp_ctrls		ctrls;
> +
> +	u32				index;
> +	struct mutex			video_lock;
> +	struct mutex			subdev_lock;
> +	spinlock_t			slock;
> +
> +	wait_queue_head_t		irq_queue;
> +
> +	const struct fimc_fmt		*video_capture_format;
> +	unsigned long			payload[FIMC_IS_MAX_PLANES];
> +	struct fimc_isp_frame		inp_frame;
> +	struct fimc_isp_frame		out_frame;
> +	enum fimc_datapath		out_path;
> +	unsigned int			source_subdev_grp_id;
> +
> +	unsigned int			cac_margin_x;
> +	unsigned int 			cac_margin_y;
> +
> +	unsigned long			state;
> +	struct list_head		pending_buf_q;
> +	struct list_head		active_buf_q;
> +	struct vb2_queue		capture_vb_queue;
> +	unsigned int			frame_count;
> +	unsigned int			reqbufs_count;
> +	int				ref_count;
> +};
> +
> +#define ctrl_to_fimc_isp(_ctrl) \
> +	container_of(ctrl->handler, struct fimc_isp, ctrls.handler)
> +
> +struct fimc_is;
> +
> +int fimc_isp_subdev_create(struct fimc_isp *isp);
> +void fimc_isp_subdev_destroy(struct fimc_isp *isp);
> +void fimc_isp_irq_handler(struct fimc_is *is);
> +int fimc_is_create_controls(struct fimc_isp *isp);
> +int fimc_is_delete_controls(struct fimc_isp *isp);
> +const struct fimc_fmt *fimc_isp_find_format(const u32 *pixelformat,
> +					const u32 *mbus_code, int index);
> +#endif /* FIMC_ISP_H_ */
> 

Otherwise this patch looks very clean and I really have no other comments.

Regards,

	Hans

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

* Re: [RFC PATCH 5/8] s5p-fimc: Add ISP video capture driver stubs
  2013-03-11 19:44 ` [RFC PATCH 5/8] s5p-fimc: Add ISP video capture driver stubs Sylwester Nawrocki
@ 2013-03-12 14:44   ` Hans Verkuil
  2013-03-17 21:03     ` Sylwester Nawrocki
  0 siblings, 1 reply; 14+ messages in thread
From: Hans Verkuil @ 2013-03-12 14:44 UTC (permalink / raw)
  To: Sylwester Nawrocki
  Cc: linux-media, kyungmin.park, myungjoo.ham, dh09.lee,
	shaik.samsung, arun.kk, a.hajda, linux-samsung-soc,
	devicetree-discuss, linux-arm-kernel

On Mon 11 March 2013 20:44:49 Sylwester Nawrocki wrote:
> This patch adds a video capture node for the FIMC-IS ISP IP block
> and Makefile/Kconfig to actually enable the driver's compilation.
> 
> The ISP video capture driver is still a work in progress.
> 
> Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  drivers/media/platform/s5p-fimc/Kconfig          |   13 +
>  drivers/media/platform/s5p-fimc/Makefile         |    4 +
>  drivers/media/platform/s5p-fimc/fimc-isp-video.c |  414 ++++++++++++++++++++++
>  drivers/media/platform/s5p-fimc/fimc-isp-video.h |   50 +++
>  4 files changed, 481 insertions(+)
>  create mode 100644 drivers/media/platform/s5p-fimc/fimc-isp-video.c
>  create mode 100644 drivers/media/platform/s5p-fimc/fimc-isp-video.h
> 
> diff --git a/drivers/media/platform/s5p-fimc/Kconfig b/drivers/media/platform/s5p-fimc/Kconfig
> index c16b20d..1253e25 100644
> --- a/drivers/media/platform/s5p-fimc/Kconfig
> +++ b/drivers/media/platform/s5p-fimc/Kconfig
> @@ -46,4 +46,17 @@ config VIDEO_EXYNOS_FIMC_LITE
>  	  module will be called exynos-fimc-lite.
>  endif
>  
> +if (SOC_EXYNOS4212 || SOC_EXYNOS4412) && OF && !ARCH_MULTIPLATFORM
> +
> +config VIDEO_EXYNOS4_FIMC_IS
> +	tristate "EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver"
> +	select VIDEOBUF2_DMA_CONTIG
> +	help
> +	  This is a V4L2 driver for Samsung EXYNOS4x12 SoC FIMC-IS
> +	  (Imaging Subsystem).
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called exynos-fimc-is.
> +endif
> +
>  endif # VIDEO_SAMSUNG_S5P_FIMC
> diff --git a/drivers/media/platform/s5p-fimc/Makefile b/drivers/media/platform/s5p-fimc/Makefile
> index 4648514..55b171a 100644
> --- a/drivers/media/platform/s5p-fimc/Makefile
> +++ b/drivers/media/platform/s5p-fimc/Makefile
> @@ -1,7 +1,11 @@
>  s5p-fimc-objs := fimc-core.o fimc-reg.o fimc-m2m.o fimc-capture.o fimc-mdevice.o
>  exynos-fimc-lite-objs += fimc-lite-reg.o fimc-lite.o
> +exynos-fimc-is-objs := fimc-is.o fimc-isp.o fimc-is-sensor.o fimc-is-regs.o
> +exynos-fimc-is-objs += fimc-is-param.o fimc-is-errno.o fimc-is-i2c.o
> +exynos-fimc-is-objs += fimc-isp-video.o
>  s5p-csis-objs := mipi-csis.o
>  
>  obj-$(CONFIG_VIDEO_S5P_MIPI_CSIS)	+= s5p-csis.o
>  obj-$(CONFIG_VIDEO_EXYNOS_FIMC_LITE)	+= exynos-fimc-lite.o
> +obj-$(CONFIG_VIDEO_EXYNOS4_FIMC_IS)	+= exynos-fimc-is.o
>  obj-$(CONFIG_VIDEO_S5P_FIMC)		+= s5p-fimc.o
> diff --git a/drivers/media/platform/s5p-fimc/fimc-isp-video.c b/drivers/media/platform/s5p-fimc/fimc-isp-video.c
> new file mode 100644
> index 0000000..bdeacaa
> --- /dev/null
> +++ b/drivers/media/platform/s5p-fimc/fimc-isp-video.c
> @@ -0,0 +1,414 @@
> +/*
> + * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
> + *
> + * Copyright (C) 2013 Samsung Electronics Co., Ltd.
> + * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/delay.h>
> +#include <linux/errno.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/types.h>
> +#include <linux/printk.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/slab.h>
> +#include <linux/videodev2.h>
> +
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-ioctl.h>
> +#include <media/videobuf2-core.h>
> +#include <media/videobuf2-dma-contig.h>
> +
> +#include "fimc-mdevice.h"
> +#include "fimc-core.h"
> +#include "fimc-is.h"
> +
> +static int isp_video_capture_start_streaming(struct vb2_queue *q,
> +					unsigned int count)
> +{
> +	/* TODO: start ISP output DMA */
> +	return 0;
> +}
> +
> +static int isp_video_capture_stop_streaming(struct vb2_queue *q)
> +{
> +	/* TODO: stop ISP output DMA */
> +	return 0;
> +}
> +
> +static int isp_video_capture_queue_setup(struct vb2_queue *vq,
> +			const struct v4l2_format *pfmt,
> +			unsigned int *num_buffers, unsigned int *num_planes,
> +			unsigned int sizes[], void *allocators[])
> +{
> +	const struct v4l2_pix_format_mplane *pixm = NULL;
> +	struct fimc_isp *isp = vq->drv_priv;
> +	struct fimc_isp_frame *frame = &isp->out_frame;
> +	const struct fimc_fmt *fmt = isp->video_capture_format;
> +	unsigned long wh;
> +	int i;
> +
> +	if (pfmt) {
> +		pixm = &pfmt->fmt.pix_mp;
> +		fmt = fimc_isp_find_format(&pixm->pixelformat, NULL, -1);
> +		wh = pixm->width * pixm->height;
> +	} else {
> +		wh = frame->f_width * frame->f_height;
> +	}
> +
> +	if (fmt == NULL)
> +		return -EINVAL;
> +
> +	*num_planes = fmt->memplanes;
> +
> +	for (i = 0; i < fmt->memplanes; i++) {
> +		unsigned int size = (wh * fmt->depth[i]) / 8;
> +		if (pixm)
> +			sizes[i] = max(size, pixm->plane_fmt[i].sizeimage);
> +		else
> +			sizes[i] = size;
> +		allocators[i] = isp->alloc_ctx;
> +	}
> +
> +	return 0;
> +}
> +
> +static int isp_video_capture_buffer_prepare(struct vb2_buffer *vb)
> +{
> +	struct vb2_queue *vq = vb->vb2_queue;
> +	struct fimc_isp *isp = vq->drv_priv;
> +	int i;
> +
> +	if (isp->video_capture_format == NULL)
> +		return -EINVAL;
> +
> +	for (i = 0; i < isp->video_capture_format->memplanes; i++) {
> +		unsigned long size = isp->payload[i];
> +
> +		if (vb2_plane_size(vb, i) < size) {
> +			v4l2_err(&isp->vfd,
> +				 "User buffer too small (%ld < %ld)\n",
> +				 vb2_plane_size(vb, i), size);
> +			return -EINVAL;
> +		}
> +		vb2_set_plane_payload(vb, i, size);
> +	}
> +
> +	return 0;
> +}
> +
> +static void isp_video_capture_buffer_queue(struct vb2_buffer *vb)
> +{
> +	/* TODO: */
> +}
> +
> +static void isp_video_lock(struct vb2_queue *vq)
> +{
> +	struct fimc_isp *isp = vb2_get_drv_priv(vq);
> +	mutex_lock(&isp->video_lock);
> +}
> +
> +static void isp_video_unlock(struct vb2_queue *vq)
> +{
> +	struct fimc_isp *isp = vb2_get_drv_priv(vq);
> +	mutex_unlock(&isp->video_lock);
> +}
> +
> +static const struct vb2_ops isp_video_capture_qops = {
> +	.queue_setup	 = isp_video_capture_queue_setup,
> +	.buf_prepare	 = isp_video_capture_buffer_prepare,
> +	.buf_queue	 = isp_video_capture_buffer_queue,
> +	.wait_prepare	 = isp_video_unlock,
> +	.wait_finish	 = isp_video_lock,
> +	.start_streaming = isp_video_capture_start_streaming,
> +	.stop_streaming	 = isp_video_capture_stop_streaming,
> +};
> +
> +static int isp_video_capture_open(struct file *file)
> +{
> +	struct fimc_isp *isp = video_drvdata(file);
> +	int ret = 0;
> +
> +	if (mutex_lock_interruptible(&isp->video_lock))
> +		return -ERESTARTSYS;
> +
> +	/* ret = pm_runtime_get_sync(&isp->pdev->dev); */
> +	if (ret < 0)
> +		goto done;
> +
> +	ret = v4l2_fh_open(file);
> +	if (ret < 0)
> +		goto done;
> +
> +	/* TODO: prepare video pipeline */
> +done:
> +	mutex_unlock(&isp->video_lock);
> +	return ret;
> +}
> +
> +static int isp_video_capture_close(struct file *file)
> +{
> +	struct fimc_isp *isp = video_drvdata(file);
> +	int ret = 0;
> +
> +	mutex_lock(&isp->video_lock);
> +
> +	if (isp->out_path == FIMC_IO_DMA) {
> +		/* TODO: stop capture, cleanup */
> +	}
> +
> +	/* pm_runtime_put(&isp->pdev->dev); */
> +
> +	if (isp->ref_count == 0)
> +		vb2_queue_release(&isp->capture_vb_queue);
> +
> +	ret = v4l2_fh_release(file);
> +
> +	mutex_unlock(&isp->video_lock);
> +	return ret;
> +}
> +
> +static unsigned int isp_video_capture_poll(struct file *file,
> +				   struct poll_table_struct *wait)
> +{
> +	struct fimc_isp *isp = video_drvdata(file);
> +	int ret;
> +
> +	mutex_lock(&isp->video_lock);
> +	ret = vb2_poll(&isp->capture_vb_queue, file, wait);
> +	mutex_unlock(&isp->video_lock);
> +	return ret;
> +}
> +
> +static int isp_video_capture_mmap(struct file *file, struct vm_area_struct *vma)
> +{
> +	struct fimc_isp *isp = video_drvdata(file);
> +	int ret;
> +
> +	if (mutex_lock_interruptible(&isp->video_lock))
> +		return -ERESTARTSYS;
> +
> +	ret = vb2_mmap(&isp->capture_vb_queue, vma);
> +	mutex_unlock(&isp->video_lock);
> +
> +	return ret;
> +}
> +
> +static const struct v4l2_file_operations isp_video_capture_fops = {
> +	.owner		= THIS_MODULE,
> +	.open		= isp_video_capture_open,
> +	.release	= isp_video_capture_close,
> +	.poll		= isp_video_capture_poll,
> +	.unlocked_ioctl	= video_ioctl2,
> +	.mmap		= isp_video_capture_mmap,

Can't you use the helper functions vb2_fop_open/release/poll/mmap here?

> +};
> +
> +/*
> + * Video node ioctl operations
> + */
> +static int fimc_isp_capture_querycap_capture(struct file *file, void *priv,
> +					     struct v4l2_capability *cap)
> +{
> +
> +	strlcpy(cap->driver, FIMC_IS_DRV_NAME, sizeof(cap->driver));
> +	strlcpy(cap->card, FIMC_IS_DRV_NAME, sizeof(cap->card));
> +	snprintf(cap->bus_info, sizeof(cap->bus_info),
> +				"platform:exynos4x12-isp");
> +
> +	cap->device_caps = V4L2_CAP_STREAMING;
> +	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
> +
> +	return 0;
> +}
> +
> +static int fimc_isp_capture_enum_fmt_mplane(struct file *file, void *priv,
> +					    struct v4l2_fmtdesc *f)
> +{
> +	const struct fimc_fmt *fmt;
> +
> +	if (f->index >= FIMC_ISP_NUM_FORMATS)
> +		return -EINVAL;
> +
> +	fmt = fimc_isp_find_format(NULL, NULL, f->index);
> +	if (WARN_ON(fmt == NULL))
> +		return -EINVAL;
> +
> +	strlcpy(f->description, fmt->name, sizeof(f->description));
> +	f->pixelformat = fmt->fourcc;
> +
> +	return 0;
> +}
> +
> +static int fimc_isp_capture_g_fmt_mplane(struct file *file, void *fh,
> +					 struct v4l2_format *f)
> +{
> +	/* TODO:  */
> +	return 0;
> +}
> +
> +static int fimc_isp_capture_try_fmt(struct fimc_isp *isp,
> +				    struct v4l2_pix_format_mplane *pixm,
> +				    const struct fimc_fmt **ffmt)
> +{
> +	/* TODO: */
> +	return 0;
> +}
> +
> +static int fimc_isp_capture_try_fmt_mplane(struct file *file, void *fh,
> +					   struct v4l2_format *f)
> +{
> +	struct fimc_isp *isp = video_drvdata(file);
> +	return fimc_isp_capture_try_fmt(isp, &f->fmt.pix_mp, NULL);
> +}
> +
> +static int fimc_isp_capture_s_fmt_mplane(struct file *file, void *priv,
> +					 struct v4l2_format *f)
> +{
> +	/* TODO: */
> +	return 0;
> +}
> +
> +static int fimc_isp_pipeline_validate(struct fimc_isp *isp)
> +{
> +	/* TODO: */
> +	return 0;
> +}
> +
> +static int fimc_isp_capture_streamon(struct file *file, void *priv,
> +				     enum v4l2_buf_type type)
> +{
> +	struct fimc_isp *isp = video_drvdata(file);
> +	struct v4l2_subdev *sensor = isp->pipeline.subdevs[IDX_SENSOR];
> +	struct fimc_pipeline *p = &isp->pipeline;
> +	int ret;
> +
> +	/* TODO: check if the OTF interface is not running */
> +
> +	ret = media_entity_pipeline_start(&sensor->entity, p->m_pipeline);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = fimc_isp_pipeline_validate(isp);
> +	if (ret) {
> +		media_entity_pipeline_stop(&sensor->entity);
> +		return ret;
> +	}
> +
> +	return vb2_streamon(&isp->capture_vb_queue, type);
> +}
> +
> +static int fimc_isp_capture_streamoff(struct file *file, void *priv,
> +				      enum v4l2_buf_type type)
> +{
> +	struct fimc_isp *isp = video_drvdata(file);
> +	struct v4l2_subdev *sd = isp->pipeline.subdevs[IDX_SENSOR];
> +	int ret;
> +
> +	ret = vb2_streamoff(&isp->capture_vb_queue, type);
> +	if (ret == 0)
> +		media_entity_pipeline_stop(&sd->entity);
> +	return ret;
> +}
> +
> +static int fimc_isp_capture_reqbufs(struct file *file, void *priv,
> +				    struct v4l2_requestbuffers *reqbufs)
> +{
> +	struct fimc_isp *isp = video_drvdata(file);
> +	int ret;
> +
> +	reqbufs->count = max_t(u32, FIMC_IS_REQ_BUFS_MIN, reqbufs->count);
> +	ret = vb2_reqbufs(&isp->capture_vb_queue, reqbufs);

You probably want to call vb2_ioctl_reqbufs here since that does additional
ownership checks that vb2_reqbufs doesn't.

The same is true for vb2_ioctl_streamon/off, BTW.

> +	if (!ret < 0)
> +		isp->reqbufs_count = reqbufs->count;
> +
> +	return ret;
> +}
> +
> +static const struct v4l2_ioctl_ops isp_video_capture_ioctl_ops = {
> +	.vidioc_querycap		= fimc_isp_capture_querycap_capture,
> +	.vidioc_enum_fmt_vid_cap_mplane	= fimc_isp_capture_enum_fmt_mplane,
> +	.vidioc_try_fmt_vid_cap_mplane	= fimc_isp_capture_try_fmt_mplane,
> +	.vidioc_s_fmt_vid_cap_mplane	= fimc_isp_capture_s_fmt_mplane,
> +	.vidioc_g_fmt_vid_cap_mplane	= fimc_isp_capture_g_fmt_mplane,
> +	.vidioc_reqbufs			= fimc_isp_capture_reqbufs,
> +	.vidioc_querybuf		= vb2_ioctl_querybuf,
> +	.vidioc_prepare_buf		= vb2_ioctl_prepare_buf,
> +	.vidioc_create_bufs		= vb2_ioctl_create_bufs,
> +	.vidioc_qbuf			= vb2_ioctl_qbuf,
> +	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
> +	.vidioc_streamon		= fimc_isp_capture_streamon,
> +	.vidioc_streamoff		= fimc_isp_capture_streamoff,
> +};
> +
> +int fimc_isp_video_device_register(struct fimc_isp *isp,
> +				   struct v4l2_device *v4l2_dev)
> +{
> +	struct vb2_queue *q = &isp->capture_vb_queue;
> +	struct video_device *vfd = &isp->vfd;
> +	int ret;
> +
> +	mutex_init(&isp->video_lock);
> +	INIT_LIST_HEAD(&isp->pending_buf_q);
> +	INIT_LIST_HEAD(&isp->active_buf_q);
> +
> +	memset(vfd, 0, sizeof(*vfd));
> +	snprintf(vfd->name, sizeof(vfd->name), "fimc-is-isp.capture");
> +
> +	isp->video_capture_format = fimc_isp_find_format(NULL, NULL, 0);
> +	isp->out_path = FIMC_IO_DMA;
> +	isp->ref_count = 0;
> +	isp->reqbufs_count = 0;
> +
> +	memset(q, 0, sizeof(*q));
> +	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
> +	q->io_modes = VB2_MMAP;
> +	q->ops = &isp_video_capture_qops;
> +	q->mem_ops = &vb2_dma_contig_memops;
> +	q->buf_struct_size = sizeof(struct flite_buffer);
> +	q->drv_priv = isp;
> +	q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
> +
> +	ret = vb2_queue_init(q);
> +	if (ret < 0)
> +		return ret;
> +
> +	vfd->queue = q;
> +	vfd->fops = &isp_video_capture_fops;
> +	vfd->ioctl_ops = &isp_video_capture_ioctl_ops;
> +	vfd->v4l2_dev = v4l2_dev;
> +	vfd->minor = -1;
> +	vfd->release = video_device_release_empty;
> +	vfd->lock = &isp->video_lock;
> +
> +	isp->vd_pad.flags = MEDIA_PAD_FL_SINK;
> +	ret = media_entity_init(&vfd->entity, 1, &isp->vd_pad, 0);
> +	if (ret < 0)
> +		return ret;
> +
> +	video_set_drvdata(vfd, isp);
> +
> +	ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
> +	if (ret < 0) {
> +		media_entity_cleanup(&vfd->entity);
> +		return ret;
> +	}
> +
> +	v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n",
> +		  vfd->name, video_device_node_name(vfd));
> +
> +	return 0;
> +}
> +
> +void fimc_isp_video_device_unregister(struct fimc_isp *isp)
> +{
> +	if (isp && video_is_registered(&isp->vfd)) {
> +		video_unregister_device(&isp->vfd);
> +		media_entity_cleanup(&isp->vfd.entity);
> +	}
> +}

Regards,

	Hans

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

* Re: [RFC PATCH 1/8] s5p-fimc: Add Exynos4x12 FIMC-IS driver
  2013-03-12 14:27   ` Hans Verkuil
@ 2013-03-17 19:38     ` Sylwester Nawrocki
  0 siblings, 0 replies; 14+ messages in thread
From: Sylwester Nawrocki @ 2013-03-17 19:38 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Sylwester Nawrocki, linux-media, kyungmin.park, myungjoo.ham,
	dh09.lee, shaik.samsung, arun.kk, a.hajda, linux-samsung-soc,
	devicetree-discuss, linux-arm-kernel

Hi Hans,

On 03/12/2013 03:27 PM, Hans Verkuil wrote:
> On Mon 11 March 2013 20:44:45 Sylwester Nawrocki wrote:
[...]
>> +
>> +/* Supported manual ISO values */
>> +static const s64 iso_qmenu[] = {
>> +	50, 100, 200, 400, 800,
>> +};
>> +
>> +static int __ctrl_set_iso(struct fimc_is *is, int value)
>> +{
>> +	unsigned int idx, iso;
>> +
>> +	if (value == V4L2_ISO_SENSITIVITY_AUTO) {
>> +		__is_set_isp_iso(is, ISP_ISO_COMMAND_AUTO, 0);
>> +		return 0;
>> +	}
>> +	idx = is->isp.ctrls.iso->val;
>> +	if (idx>= ARRAY_SIZE(iso_qmenu))
>> +		return -EINVAL;
>> +
>> +	iso = iso_qmenu[idx];
>> +	__is_set_isp_iso(is, ISP_ISO_COMMAND_MANUAL, iso);
>> +	return 0;
>> +}
[...]
>> +int fimc_isp_subdev_create(struct fimc_isp *isp)
>> +{
>> +	const struct v4l2_ctrl_ops *ops =&fimc_isp_ctrl_ops;
>> +	struct v4l2_ctrl_handler *handler =&isp->ctrls.handler;
>> +	struct v4l2_subdev *sd =&isp->subdev;
>> +	struct fimc_isp_ctrls *ctrls =&isp->ctrls;
>> +	int ret;
>> +
>> +	mutex_init(&isp->subdev_lock);
>> +
>> +	v4l2_subdev_init(sd,&fimc_is_subdev_ops);
>> +	sd->grp_id = GRP_ID_FIMC_IS;
>> +	sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
>> +	snprintf(sd->name, sizeof(sd->name), "FIMC-IS-ISP");
>> +
>> +	isp->subdev_pads[FIMC_IS_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
>> +	isp->subdev_pads[FIMC_IS_SD_PAD_SRC_FIFO].flags = MEDIA_PAD_FL_SOURCE;
>> +	isp->subdev_pads[FIMC_IS_SD_PAD_SRC_DMA].flags = MEDIA_PAD_FL_SOURCE;
>> +	ret = media_entity_init(&sd->entity, FIMC_IS_SD_PADS_NUM,
>> +				isp->subdev_pads, 0);
>> +	if (ret)
>> +		return ret;
>> +
>> +	v4l2_ctrl_handler_init(handler, 20);
>> +
>> +	ctrls->saturation = v4l2_ctrl_new_std(handler, ops, V4L2_CID_SATURATION,
>> +						-2, 2, 1, 0);
>> +	ctrls->brightness = v4l2_ctrl_new_std(handler, ops, V4L2_CID_BRIGHTNESS,
>> +						-4, 4, 1, 0);
>> +	ctrls->contrast = v4l2_ctrl_new_std(handler, ops, V4L2_CID_CONTRAST,
>> +						-2, 2, 1, 0);
>> +	ctrls->sharpness = v4l2_ctrl_new_std(handler, ops, V4L2_CID_SHARPNESS,
>> +						-2, 2, 1, 0);
>> +	ctrls->hue = v4l2_ctrl_new_std(handler, ops, V4L2_CID_HUE,
>> +						-2, 2, 1, 0);
>> +
>> +	ctrls->auto_wb = v4l2_ctrl_new_std_menu(handler, ops,
>> +					V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
>> +					8, ~0x14e, V4L2_WHITE_BALANCE_AUTO);
>> +
>> +	ctrls->exposure = v4l2_ctrl_new_std(handler, ops,
>> +					V4L2_CID_EXPOSURE_ABSOLUTE,
>> +					-4, 4, 1, 0);
>> +
>> +	ctrls->exp_metering = v4l2_ctrl_new_std_menu(handler, ops,
>> +					V4L2_CID_EXPOSURE_METERING, 3,
>> +					~0xf, V4L2_EXPOSURE_METERING_AVERAGE);
>> +
>> +	v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_POWER_LINE_FREQUENCY,
>> +					V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
>> +					V4L2_CID_POWER_LINE_FREQUENCY_AUTO);
>> +	/* ISO sensitivity */
>> +	ctrls->auto_iso = v4l2_ctrl_new_std_menu(handler, ops,
>> +			V4L2_CID_ISO_SENSITIVITY_AUTO, 1, 0,
>> +			V4L2_ISO_SENSITIVITY_AUTO);
>> +
>> +	ctrls->iso = v4l2_ctrl_new_int_menu(handler, ops,
>> +			V4L2_CID_ISO_SENSITIVITY, ARRAY_SIZE(iso_qmenu) - 1,
>> +			ARRAY_SIZE(iso_qmenu)/2 - 1, iso_qmenu);
>> +
>> +	ctrls->aewb_lock = v4l2_ctrl_new_std(handler, ops,
>> +					V4L2_CID_3A_LOCK, 0, 0x3, 0, 0);
>> +
>> +	/* FIXME: Adjust the enabled controls mask according
>> +	   to the ISP capabilities */
>> +	v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_COLORFX,
>> +					V4L2_COLORFX_ANTIQUE,
>> +					0, V4L2_COLORFX_NONE);
>> +	if (handler->error) {
>> +		media_entity_cleanup(&sd->entity);
>> +		return handler->error;
>> +	}
>> +
>> +	ctrls->auto_iso->flags |= V4L2_CTRL_FLAG_VOLATILE |
>> +				  V4L2_CTRL_FLAG_UPDATE;
>
> Why would auto_iso be volatile? I would expect the iso to be volatile
> (in which case the 'false' argument below would be 'true'). Also,
> v4l2_ctrl_auto_cluster already sets the UPDATE flag.

Thanks for spotting this. I should have removed this flags set up
since the g_volatile_ctrl op is not currently supported and as far
as I know the firmware doesn't support reading actual ISO value in
auto mode. I'll need to check if there are any commands available
for that.

Anyway auto_iso is not supposed to have the flags set up like this
and that also tells me that I need to inspect my other driver where
this code originally came from. :)

>> +	v4l2_ctrl_auto_cluster(2,&ctrls->auto_iso, 0, false);
>> +
>> +	sd->ctrl_handler = handler;
>> +	sd->internal_ops =&fimc_is_subdev_internal_ops;
>> +	sd->entity.ops =&fimc_is_subdev_media_ops;
>> +	v4l2_set_subdevdata(sd, isp);
>> +
>> +	return 0;
>> +}

>> diff --git a/drivers/media/platform/s5p-fimc/fimc-isp.h b/drivers/media/platform/s5p-fimc/fimc-isp.h
>> new file mode 100644
>> index 0000000..654039e
>> --- /dev/null
>> +++ b/drivers/media/platform/s5p-fimc/fimc-isp.h
>> @@ -0,0 +1,205 @@
[...]
>> +struct fimc_isp_ctrls {
>> +	struct v4l2_ctrl_handler handler;
>> +	/* Internal mode selection */
>> +	struct v4l2_ctrl *scenario;
>> +	/* Frame rate */
>> +	struct v4l2_ctrl *fps;
>> +	/* Touch AF position */
>> +	struct v4l2_ctrl *af_position_x;
>> +	struct v4l2_ctrl *af_position_y;
>> +	/* Auto white balance */
>> +	struct v4l2_ctrl *auto_wb;
>> +	/* ISO sensitivity */
>> +	struct v4l2_ctrl *auto_iso;
>> +	struct v4l2_ctrl *iso;
>
> I suggest putting this in an anonymous struct:
>
> 	struct { /* Auto ISO control cluster */
> 		struct v4l2_ctrl *auto_iso;
> 		struct v4l2_ctrl *iso;
> 	};
>
> That way you visually emphasize that these belong together and that you
> shouldn't move them around.

Agreed. I'll make them grouped in separate structs wherever a cluster
is used.

>> +	struct v4l2_ctrl *contrast;
>> +	struct v4l2_ctrl *saturation;
>> +	struct v4l2_ctrl *sharpness;
>> +	/* Auto/manual exposure */
>> +	struct v4l2_ctrl *auto_exp;
>> +	/* Manual exposure value */
>> +	struct v4l2_ctrl *exposure;
>> +	/* Adjust - brightness */
>> +	struct v4l2_ctrl *brightness;
>> +	/* Adjust - hue */
>> +	struct v4l2_ctrl *hue;
>> +	/* Exposure metering mode */
>> +	struct v4l2_ctrl *exp_metering;
>> +	/* AFC */
>> +	struct v4l2_ctrl *afc;
>> +	/* AE/AWB lock/unlock */
>> +	struct v4l2_ctrl *aewb_lock;
>> +	/* AF */
>> +	struct v4l2_ctrl *focus_mode;
>> +	/* AF status */
>> +	struct v4l2_ctrl *af_status;
>> +};
[...]
>
> Otherwise this patch looks very clean and I really have no other comments.

Thanks a lot for a prompt review!

--

Regards,
Sylwester

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

* Re: [RFC PATCH 5/8] s5p-fimc: Add ISP video capture driver stubs
  2013-03-12 14:44   ` Hans Verkuil
@ 2013-03-17 21:03     ` Sylwester Nawrocki
  2013-03-18 12:51       ` Hans Verkuil
  0 siblings, 1 reply; 14+ messages in thread
From: Sylwester Nawrocki @ 2013-03-17 21:03 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Sylwester Nawrocki, linux-media, kyungmin.park, myungjoo.ham,
	dh09.lee, shaik.samsung, arun.kk, a.hajda, linux-samsung-soc,
	devicetree-discuss, linux-arm-kernel

On 03/12/2013 03:44 PM, Hans Verkuil wrote:
> On Mon 11 March 2013 20:44:49 Sylwester Nawrocki wrote:
[...]
>> +static int isp_video_capture_open(struct file *file)
>> +{
>> +	struct fimc_isp *isp = video_drvdata(file);
>> +	int ret = 0;
>> +
>> +	if (mutex_lock_interruptible(&isp->video_lock))
>> +		return -ERESTARTSYS;
>> +
>> +	/* ret = pm_runtime_get_sync(&isp->pdev->dev); */
>> +	if (ret<  0)
>> +		goto done;
>> +
>> +	ret = v4l2_fh_open(file);
>> +	if (ret<  0)
>> +		goto done;
>> +
>> +	/* TODO: prepare video pipeline */
>> +done:
>> +	mutex_unlock(&isp->video_lock);
>> +	return ret;
>> +}
>> +
>> +static int isp_video_capture_close(struct file *file)
>> +{
>> +	struct fimc_isp *isp = video_drvdata(file);
>> +	int ret = 0;
>> +
>> +	mutex_lock(&isp->video_lock);
>> +
>> +	if (isp->out_path == FIMC_IO_DMA) {
>> +		/* TODO: stop capture, cleanup */
>> +	}
>> +
>> +	/* pm_runtime_put(&isp->pdev->dev); */
>> +
>> +	if (isp->ref_count == 0)
>> +		vb2_queue_release(&isp->capture_vb_queue);
>> +
>> +	ret = v4l2_fh_release(file);
>> +
>> +	mutex_unlock(&isp->video_lock);
>> +	return ret;
>> +}
>> +
>> +static unsigned int isp_video_capture_poll(struct file *file,
>> +				   struct poll_table_struct *wait)
>> +{
>> +	struct fimc_isp *isp = video_drvdata(file);
>> +	int ret;
>> +
>> +	mutex_lock(&isp->video_lock);
>> +	ret = vb2_poll(&isp->capture_vb_queue, file, wait);
>> +	mutex_unlock(&isp->video_lock);
>> +	return ret;
>> +}
>> +
>> +static int isp_video_capture_mmap(struct file *file, struct vm_area_struct *vma)
>> +{
>> +	struct fimc_isp *isp = video_drvdata(file);
>> +	int ret;
>> +
>> +	if (mutex_lock_interruptible(&isp->video_lock))
>> +		return -ERESTARTSYS;
>> +
>> +	ret = vb2_mmap(&isp->capture_vb_queue, vma);
>> +	mutex_unlock(&isp->video_lock);
>> +
>> +	return ret;
>> +}
>> +
>> +static const struct v4l2_file_operations isp_video_capture_fops = {
>> +	.owner		= THIS_MODULE,
>> +	.open		= isp_video_capture_open,
>> +	.release	= isp_video_capture_close,
>> +	.poll		= isp_video_capture_poll,
>> +	.unlocked_ioctl	= video_ioctl2,
>> +	.mmap		= isp_video_capture_mmap,
>
> Can't you use the helper functions vb2_fop_open/release/poll/mmap here?

It seems vb2_fop_mmap/poll can be used directly, open(), release() are
a bit more complicated as some media pipeline operations need to
additionally be done within these callbacks. There is no vb2_fop_open(),
and AFAICS v4l2_fh_open() is sufficient and intended as open() helper.
For the next iteration I have used vb2_fop_release(), called indirectly,
as it nicely simplifies things a bit.

BTW, shouldn't vb2_fop_release() also be taking the lock ? Actually it is
more useful for me in current form, but the drivers that directly assign
it to struct v4l2_file_operations::open might be in trouble, unless I'm
missing something.

>> +};
>> +
>> +/*
>> + * Video node ioctl operations
>> + */
[...]
>> +static int fimc_isp_capture_streamon(struct file *file, void *priv,
>> +				     enum v4l2_buf_type type)
>> +{
>> +	struct fimc_isp *isp = video_drvdata(file);
>> +	struct v4l2_subdev *sensor = isp->pipeline.subdevs[IDX_SENSOR];
>> +	struct fimc_pipeline *p =&isp->pipeline;
>> +	int ret;
>> +
>> +	/* TODO: check if the OTF interface is not running */
>> +
>> +	ret = media_entity_pipeline_start(&sensor->entity, p->m_pipeline);
>> +	if (ret<  0)
>> +		return ret;
>> +
>> +	ret = fimc_isp_pipeline_validate(isp);
>> +	if (ret) {
>> +		media_entity_pipeline_stop(&sensor->entity);
>> +		return ret;
>> +	}
>> +
>> +	return vb2_streamon(&isp->capture_vb_queue, type);
>> +}
>> +
>> +static int fimc_isp_capture_streamoff(struct file *file, void *priv,
>> +				      enum v4l2_buf_type type)
>> +{
>> +	struct fimc_isp *isp = video_drvdata(file);
>> +	struct v4l2_subdev *sd = isp->pipeline.subdevs[IDX_SENSOR];
>> +	int ret;
>> +
>> +	ret = vb2_streamoff(&isp->capture_vb_queue, type);
>> +	if (ret == 0)
>> +		media_entity_pipeline_stop(&sd->entity);
>> +	return ret;
>> +}
>> +
>> +static int fimc_isp_capture_reqbufs(struct file *file, void *priv,
>> +				    struct v4l2_requestbuffers *reqbufs)
>> +{
>> +	struct fimc_isp *isp = video_drvdata(file);
>> +	int ret;
>> +
>> +	reqbufs->count = max_t(u32, FIMC_IS_REQ_BUFS_MIN, reqbufs->count);
>> +	ret = vb2_reqbufs(&isp->capture_vb_queue, reqbufs);
>
> You probably want to call vb2_ioctl_reqbufs here since that does additional
> ownership checks that vb2_reqbufs doesn't.

Yes, thanks for the suggestion. That was actually helpful, previously
it wasn't immediately clear to me one can still take advantage of those
vb2_ioctl_* helpers, mainly have the ownership handling in the core,
and have some handlers assigned directly to v4l2_ioctl_ops an some called
indirectly from the driver's own callbacks, should they need something
else that is done in the helpers.

I found those helpers really useful, especially in drivers that need to
support several video nodes. Lots of boilerplate can be eliminated. And
also vb2_ops_wait_prepare/finish are a simple and nice improvement.

> The same is true for vb2_ioctl_streamon/off, BTW.

Indeed. I have already applied all possible helpers for the next iteration.

I need to yet resolve an issue with locking order, as I previously missed
that media_entity_pipeline_start/stop() also takes the graph mutex.

And currently the driver is supposed to take the graph mutex first and
then the video mutex. Since the link_notify callback of the media device
is called with the graph mutex already held.

The only solution I came up so far is to provide unlocked versions of
media_entity_pipeline_start/stop().

Ideally using video mutex in link_notify() callback should not be needed,
but there are things done there needed for backward video device
compatibility.

--

Regards,
Sylwester

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

* Re: [RFC PATCH 5/8] s5p-fimc: Add ISP video capture driver stubs
  2013-03-17 21:03     ` Sylwester Nawrocki
@ 2013-03-18 12:51       ` Hans Verkuil
  0 siblings, 0 replies; 14+ messages in thread
From: Hans Verkuil @ 2013-03-18 12:51 UTC (permalink / raw)
  To: Sylwester Nawrocki
  Cc: Sylwester Nawrocki, linux-media, kyungmin.park, myungjoo.ham,
	dh09.lee, shaik.samsung, arun.kk, a.hajda, linux-samsung-soc,
	devicetree-discuss, linux-arm-kernel

On Sun March 17 2013 22:03:38 Sylwester Nawrocki wrote:
> On 03/12/2013 03:44 PM, Hans Verkuil wrote:
> > On Mon 11 March 2013 20:44:49 Sylwester Nawrocki wrote:
> [...]
> >> +static int isp_video_capture_open(struct file *file)
> >> +{
> >> +	struct fimc_isp *isp = video_drvdata(file);
> >> +	int ret = 0;
> >> +
> >> +	if (mutex_lock_interruptible(&isp->video_lock))
> >> +		return -ERESTARTSYS;
> >> +
> >> +	/* ret = pm_runtime_get_sync(&isp->pdev->dev); */
> >> +	if (ret<  0)
> >> +		goto done;
> >> +
> >> +	ret = v4l2_fh_open(file);
> >> +	if (ret<  0)
> >> +		goto done;
> >> +
> >> +	/* TODO: prepare video pipeline */
> >> +done:
> >> +	mutex_unlock(&isp->video_lock);
> >> +	return ret;
> >> +}
> >> +
> >> +static int isp_video_capture_close(struct file *file)
> >> +{
> >> +	struct fimc_isp *isp = video_drvdata(file);
> >> +	int ret = 0;
> >> +
> >> +	mutex_lock(&isp->video_lock);
> >> +
> >> +	if (isp->out_path == FIMC_IO_DMA) {
> >> +		/* TODO: stop capture, cleanup */
> >> +	}
> >> +
> >> +	/* pm_runtime_put(&isp->pdev->dev); */
> >> +
> >> +	if (isp->ref_count == 0)
> >> +		vb2_queue_release(&isp->capture_vb_queue);
> >> +
> >> +	ret = v4l2_fh_release(file);
> >> +
> >> +	mutex_unlock(&isp->video_lock);
> >> +	return ret;
> >> +}
> >> +
> >> +static unsigned int isp_video_capture_poll(struct file *file,
> >> +				   struct poll_table_struct *wait)
> >> +{
> >> +	struct fimc_isp *isp = video_drvdata(file);
> >> +	int ret;
> >> +
> >> +	mutex_lock(&isp->video_lock);
> >> +	ret = vb2_poll(&isp->capture_vb_queue, file, wait);
> >> +	mutex_unlock(&isp->video_lock);
> >> +	return ret;
> >> +}
> >> +
> >> +static int isp_video_capture_mmap(struct file *file, struct vm_area_struct *vma)
> >> +{
> >> +	struct fimc_isp *isp = video_drvdata(file);
> >> +	int ret;
> >> +
> >> +	if (mutex_lock_interruptible(&isp->video_lock))
> >> +		return -ERESTARTSYS;
> >> +
> >> +	ret = vb2_mmap(&isp->capture_vb_queue, vma);
> >> +	mutex_unlock(&isp->video_lock);
> >> +
> >> +	return ret;
> >> +}
> >> +
> >> +static const struct v4l2_file_operations isp_video_capture_fops = {
> >> +	.owner		= THIS_MODULE,
> >> +	.open		= isp_video_capture_open,
> >> +	.release	= isp_video_capture_close,
> >> +	.poll		= isp_video_capture_poll,
> >> +	.unlocked_ioctl	= video_ioctl2,
> >> +	.mmap		= isp_video_capture_mmap,
> >
> > Can't you use the helper functions vb2_fop_open/release/poll/mmap here?
> 
> It seems vb2_fop_mmap/poll can be used directly, open(), release() are
> a bit more complicated as some media pipeline operations need to
> additionally be done within these callbacks. There is no vb2_fop_open(),
> and AFAICS v4l2_fh_open() is sufficient and intended as open() helper.

That's correct. Sorry for the misinformation about the non-existant
vb2_fop_open.

> For the next iteration I have used vb2_fop_release(), called indirectly,
> as it nicely simplifies things a bit.
> 
> BTW, shouldn't vb2_fop_release() also be taking the lock ? Actually it is
> more useful for me in current form, but the drivers that directly assign
> it to struct v4l2_file_operations::open might be in trouble, unless I'm
> missing something.

I don't see where a lock would be needed. I don't see any concurrency here.
Nobody else can mess with the queue as long as they are not the owner.

> 
> >> +};
> >> +
> >> +/*
> >> + * Video node ioctl operations
> >> + */
> [...]
> >> +static int fimc_isp_capture_streamon(struct file *file, void *priv,
> >> +				     enum v4l2_buf_type type)
> >> +{
> >> +	struct fimc_isp *isp = video_drvdata(file);
> >> +	struct v4l2_subdev *sensor = isp->pipeline.subdevs[IDX_SENSOR];
> >> +	struct fimc_pipeline *p =&isp->pipeline;
> >> +	int ret;
> >> +
> >> +	/* TODO: check if the OTF interface is not running */
> >> +
> >> +	ret = media_entity_pipeline_start(&sensor->entity, p->m_pipeline);
> >> +	if (ret<  0)
> >> +		return ret;
> >> +
> >> +	ret = fimc_isp_pipeline_validate(isp);
> >> +	if (ret) {
> >> +		media_entity_pipeline_stop(&sensor->entity);
> >> +		return ret;
> >> +	}
> >> +
> >> +	return vb2_streamon(&isp->capture_vb_queue, type);
> >> +}
> >> +
> >> +static int fimc_isp_capture_streamoff(struct file *file, void *priv,
> >> +				      enum v4l2_buf_type type)
> >> +{
> >> +	struct fimc_isp *isp = video_drvdata(file);
> >> +	struct v4l2_subdev *sd = isp->pipeline.subdevs[IDX_SENSOR];
> >> +	int ret;
> >> +
> >> +	ret = vb2_streamoff(&isp->capture_vb_queue, type);
> >> +	if (ret == 0)
> >> +		media_entity_pipeline_stop(&sd->entity);
> >> +	return ret;
> >> +}
> >> +
> >> +static int fimc_isp_capture_reqbufs(struct file *file, void *priv,
> >> +				    struct v4l2_requestbuffers *reqbufs)
> >> +{
> >> +	struct fimc_isp *isp = video_drvdata(file);
> >> +	int ret;
> >> +
> >> +	reqbufs->count = max_t(u32, FIMC_IS_REQ_BUFS_MIN, reqbufs->count);
> >> +	ret = vb2_reqbufs(&isp->capture_vb_queue, reqbufs);
> >
> > You probably want to call vb2_ioctl_reqbufs here since that does additional
> > ownership checks that vb2_reqbufs doesn't.
> 
> Yes, thanks for the suggestion. That was actually helpful, previously
> it wasn't immediately clear to me one can still take advantage of those
> vb2_ioctl_* helpers, mainly have the ownership handling in the core,
> and have some handlers assigned directly to v4l2_ioctl_ops an some called
> indirectly from the driver's own callbacks, should they need something
> else that is done in the helpers.
> 
> I found those helpers really useful, especially in drivers that need to
> support several video nodes. Lots of boilerplate can be eliminated. And
> also vb2_ops_wait_prepare/finish are a simple and nice improvement.

Glad to hear!

I still think there are some more improvements that could be made with some
helper functions and perhaps some more fields: most (all?) drivers need a
list for their active buffers, so I really think adding a struct list to
vb2_buffer and a list for active buffers + a spinlock to vb2_queue would
help.

Helper functions could then be added to handle that queue and also to set
the timestamp and sequence fields. I would need to think more about the
details, but after using vb2 for a while I see a lot of shared code between
the various drivers.

Regards,

	Hans

> > The same is true for vb2_ioctl_streamon/off, BTW.
> 
> Indeed. I have already applied all possible helpers for the next iteration.
> 
> I need to yet resolve an issue with locking order, as I previously missed
> that media_entity_pipeline_start/stop() also takes the graph mutex.
> 
> And currently the driver is supposed to take the graph mutex first and
> then the video mutex. Since the link_notify callback of the media device
> is called with the graph mutex already held.
> 
> The only solution I came up so far is to provide unlocked versions of
> media_entity_pipeline_start/stop().
> 
> Ideally using video mutex in link_notify() callback should not be needed,
> but there are things done there needed for backward video device
> compatibility.
> 
> --
> 
> Regards,
> Sylwester
> 

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

end of thread, other threads:[~2013-03-18 12:51 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-03-11 19:44 [RFC PATCH 0/8] A V4L2 driver for Exynos4x12 Imaging Subsystem Sylwester Nawrocki
2013-03-11 19:44 ` [RFC PATCH 1/8] s5p-fimc: Add Exynos4x12 FIMC-IS driver Sylwester Nawrocki
2013-03-12 14:27   ` Hans Verkuil
2013-03-17 19:38     ` Sylwester Nawrocki
2013-03-11 19:44 ` [RFC PATCH 2/8] s5p-fimc: Add FIMC-IS ISP I2C bus driver Sylwester Nawrocki
2013-03-11 19:44 ` [RFC PATCH 3/8] s5p-fimc: Add FIMC-IS parameter region definitions Sylwester Nawrocki
2013-03-11 19:44 ` [RFC PATCH 4/8] s5p-fimc: Add common FIMC-IS image sensor driver Sylwester Nawrocki
2013-03-11 19:44 ` [RFC PATCH 5/8] s5p-fimc: Add ISP video capture driver stubs Sylwester Nawrocki
2013-03-12 14:44   ` Hans Verkuil
2013-03-17 21:03     ` Sylwester Nawrocki
2013-03-18 12:51       ` Hans Verkuil
2013-03-11 19:44 ` [RFC PATCH 6/8] fimc-is: Add Exynos4x12 FIMC-IS device tree bindings documentation Sylwester Nawrocki
2013-03-11 19:44 ` [RFC PATCH 7/8] s5p-fimc: Add fimc-is subdevs registration Sylwester Nawrocki
2013-03-11 19:44 ` [RFC PATCH 8/8] s5p-fimc: Create media links for the FIMC-IS entities Sylwester Nawrocki

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).