diff mbox

[v3,07/10] V4L2 ISP driver patchset for Intel Moorestown Camera Imaging Subsystem

Message ID 33AB447FBD802F4E932063B962385B351E895DA0@shsmsx501.ccr.corp.intel.com (mailing list archive)
State RFC
Headers show

Commit Message

Xiaolin Zhang May 19, 2010, 3:15 a.m. UTC
None
diff mbox

Patch

diff --git a/drivers/media/video/mrstisp/__mrstisp_private_ioctl.c b/drivers/media/video/mrstisp/__mrstisp_private_ioctl.c
new file mode 100644
index 0000000..146418a
--- /dev/null
+++ b/drivers/media/video/mrstisp/__mrstisp_private_ioctl.c
@@ -0,0 +1,215 @@ 
+/*
+ * Support for Moorestown Langwell Camera Imaging ISP subsystem.
+ *
+ * Copyright (c) 2009 Intel Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ *
+ * Xiaolin Zhang <xiaolin.zhang@intel.com>
+ */
+
+#include "mrstisp_stdinc.h"
+
+static void print_bls_cfg(struct ci_isp_config *isp_cfg)
+{
+       struct ci_isp_bls_config *bls_cfg = &isp_cfg->bls_cfg;
+
+       dprintk(4, "print_bls_cfg:");
+       dprintk(4, "enable_automatic:%d", (bls_cfg->enable_automatic ? 1 : 0));
+       dprintk(4, "disable_h:%d", (bls_cfg->disable_h ? 1 : 0));
+       dprintk(4, "disable_v:%d", (bls_cfg->disable_v ? 1 : 0));
+       dprintk(4, "enable_window1:%d",
+               (bls_cfg->isp_bls_window1.enable_window ? 1 : 0));
+       dprintk(4, "start_h:%d", (int)bls_cfg->isp_bls_window1.start_h);
+       dprintk(4, "stop_h:%d", (int)bls_cfg->isp_bls_window1.stop_h);
+       dprintk(4, "start_v:%d", (int)bls_cfg->isp_bls_window1.start_v);
+       dprintk(4, "stop_v:%d", (int)bls_cfg->isp_bls_window1.stop_v);
+       dprintk(4, "enable_window2: %d",
+               (bls_cfg->isp_bls_window2.enable_window ? 1 : 0));
+       dprintk(4, "start_h%d", (int)bls_cfg->isp_bls_window2.start_h);
+       dprintk(4, "stop_h%d", (int)bls_cfg->isp_bls_window2.stop_h);
+       dprintk(4, "start_v%d", (int)bls_cfg->isp_bls_window2.start_v);
+       dprintk(4, "stop_v%d", (int)bls_cfg->isp_bls_window2.stop_v);
+       dprintk(4, "bls_samples%d", (int)bls_cfg->bls_samples);
+       dprintk(4, "fixed_a0x%02x", (int)bls_cfg->bls_subtraction.fixed_a);
+       dprintk(4, "fixed_b0x%02x", (int)bls_cfg->bls_subtraction.fixed_b);
+       dprintk(4, "fixed_c0x%02x", (int)bls_cfg->bls_subtraction.fixed_c);
+       dprintk(4, "fixed_d0x%02x", (int)bls_cfg->bls_subtraction.fixed_d);
+       dprintk(4, "\n");
+}
+
+static int mrst_isp_set_cfg(struct file *file, void *priv,
+                           struct ci_pl_system_config *arg)
+{
+       struct video_device *dev = video_devdata(file);
+       struct mrst_isp_device *isp = video_get_drvdata(dev);
+
+       if (arg == NULL) {
+               eprintk("NULL pointer of arg");
+               return 0;
+       }
+       mutex_lock(&isp->mutex);
+       memcpy(&isp->sys_conf.isp_cfg, &arg->isp_cfg,
+                    sizeof(struct ci_isp_config));
+
+       print_bls_cfg(&isp->sys_conf.isp_cfg);
+       mutex_unlock(&isp->mutex);
+
+       isp->sys_conf.isp_hal_enable = 1;
+       return 0;
+}
+
+/* for buffer sharing between CI and VA */
+static int mrst_isp_get_frame_info(struct file *file, void *priv,
+                                  struct ci_frame_info *arg)
+{
+       struct video_device *dev = video_devdata(file);
+       struct mrst_isp_device *isp = video_get_drvdata(dev);
+
+       mutex_lock(&isp->mutex);
+       arg->width = isp->bufwidth;
+       arg->height = isp->bufheight;
+       arg->fourcc = isp->pixelformat;
+       arg->stride = isp->bufwidth; /* should be 64 bit alignment*/
+       arg->offset = arg->frame_id * PAGE_ALIGN(isp->frame_size);
+
+       dprintk(2, "w=%d, h=%d, 4cc =%x, stride=%d, offset=%d,fsize=%d",
+               arg->width, arg->height, arg->fourcc, arg->stride,
+               arg->offset, isp->frame_size);
+       mutex_unlock(&isp->mutex);
+       return 0;
+}
+
+static int mrst_isp_set_jpg_enc_ratio(struct file *file, void *priv, int *arg)
+{
+       struct video_device *dev = video_devdata(file);
+       struct mrst_isp_device *isp = video_get_drvdata(dev);
+
+       dprintk(2, "set jpg compression ratio is %d", *arg);
+       mutex_lock(&isp->mutex);
+       isp->sys_conf.isp_cfg.jpeg_enc_ratio = *arg;
+       mutex_unlock(&isp->mutex);
+
+       return 0;
+}
+
+int mrst_isp_get_isp_mem_info(struct file *file, void *priv,
+                             struct ci_isp_mem_info *arg)
+{
+       u32 ret = 0;
+       struct video_device *dev = video_devdata(file);
+       struct mrst_isp_device *isp = video_get_drvdata(dev);
+
+       mutex_lock(&isp->mutex);
+       arg->isp_bar0_pa = isp->mb0;
+       arg->isp_bar0_size = isp->mb0_size;
+       arg->isp_bar1_pa = isp->mb1;
+       arg->isp_bar1_size = isp->mb1_size;
+       mutex_unlock(&isp->mutex);
+
+       return ret;
+}
+
+int mrst_isp_create_jpg_review_frame(struct file *file, void *priv,
+                                    struct v4l2_jpg_review_buffer *arg)
+{
+       struct video_device *dev = video_devdata(file);
+       struct mrst_isp_device *isp = video_get_drvdata(dev);
+
+       u32 width = arg->width;
+       u32 height = arg->height;
+       u32 pix_fmt = arg->pix_fmt;
+       u32 jpg_frame = arg->jpg_frame;
+
+       static struct v4l2_jpg_review_buffer *jpg_review;
+
+       jpg_review = &isp->sys_conf.jpg_review;
+
+       if (width > 640 || height > 480 || width < 32 || height < 16) {
+               eprintk("unsupported resolution: %d * %d", width, height);
+               return -EINVAL;
+       }
+
+       if (jpg_frame >= isp->num_frames) {
+               eprintk("error jpeg frame id");
+               return -1;
+       }
+
+       jpg_review->width = width;
+       jpg_review->height = height;
+       jpg_review->pix_fmt = pix_fmt;
+       jpg_review->jpg_frame = jpg_frame;
+
+       switch (arg->pix_fmt) {
+       case V4L2_PIX_FMT_YUV422P:
+               jpg_review->bytesperline = width * 2;
+               jpg_review->frame_size = width * height * 2;
+               break;
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YVU420:
+       case V4L2_PIX_FMT_NV12:
+               jpg_review->bytesperline = width * 3/2;
+               jpg_review->frame_size = width * height * 3/2;
+               break;
+       default:
+               eprintk("unsupported pix_fmt: %d", arg->pix_fmt);
+               return -EINVAL;
+       }
+
+       jpg_review->offset = isp->mb1_size - 640*480*2;
+       isp->sys_conf.jpg_review_enable = 1;
+
+       /* set user space data */
+       arg->bytesperline = jpg_review->bytesperline;
+       arg->frame_size = jpg_review->frame_size;
+       arg->offset = jpg_review->offset;
+
+       return 0;
+}
+
+/* isp private ioctl for libci */
+long mrst_isp_vidioc_default(struct file *file, void *fh,
+                            int cmd, void *arg)
+{
+       void *priv = file->private_data;
+
+       switch (cmd) {
+       case VIDIOC_GET_ISP_MEM_INFO:
+               return mrst_isp_get_isp_mem_info(file, priv,
+                                                (struct ci_isp_mem_info *)arg);
+
+       case VIDIOC_SET_SYS_CFG:
+               return mrst_isp_set_cfg(file, priv,
+                                       (struct ci_pl_system_config *)arg);
+
+       case VIDIOC_SET_JPG_ENC_RATIO:
+               return mrst_isp_set_jpg_enc_ratio(file, priv, (int *)arg);
+
+       case ISP_IOCTL_GET_FRAME_INFO:
+               return mrst_isp_get_frame_info(file, priv,
+                                              (struct ci_frame_info *)arg);
+
+       case VIDIOC_CREATE_JPG_REVIEW_BUF:
+               return mrst_isp_create_jpg_review_frame(file, priv,
+                                       (struct v4l2_jpg_review_buffer *)arg);
+       default:
+               v4l_print_ioctl("lnw_isp", cmd);
+               dprintk(2, "VIDIOC_SET_SYS_CFG = %x", VIDIOC_SET_SYS_CFG);
+               return -EINVAL;
+       }
+
+       return 0;
+}
diff --git a/drivers/media/video/mrstisp/mrstisp_main.c b/drivers/media/video/mrstisp/mrstisp_main.c
new file mode 100644
index 0000000..e596985
--- /dev/null
+++ b/drivers/media/video/mrstisp/mrstisp_main.c
@@ -0,0 +1,2743 @@ 
+/*
+ * Support for Moorestown Langwell Camera Imaging ISP subsystem.
+ *
+ * Copyright (c) 2009 Intel Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ *
+ * Xiaolin Zhang <xiaolin.zhang@intel.com>
+ */
+
+#include "mrstisp_stdinc.h"
+#include "ci_isp_fmts_common.h"
+
+#define GPIO_SCLK_25   44
+#define GPIO_STDBY1_PIN        48
+#define GPIO_STDBY2_PIN        49
+#define GPIO_RESET_PIN 50
+#define GPIO_AF_PD     95
+
+int mrstisp_debug;
+module_param(mrstisp_debug, int, 0644);
+
+static int frame_cnt;
+static long mipi_error_num;
+static u32 mipi_error_flag;
+static long isp_error_num;
+static u32 isp_error_flag;
+static unsigned long jiffies_start;
+static int mipi_flag;
+
+void intel_timer_start(void)
+{
+       jiffies_start = jiffies;
+}
+void intel_timer_stop(void)
+{
+       jiffies_start = 0;
+}
+unsigned long intel_get_micro_sec(void)
+{
+       unsigned long time_diff = 0;
+
+       time_diff = jiffies - jiffies_start;
+
+       return jiffies_to_msecs(time_diff);
+}
+
+
+static inline struct mrst_isp_device *to_isp(struct v4l2_device *dev)
+{
+       return container_of(dev, struct mrst_isp_device, v4l2_dev);
+}
+
+static struct mrst_camera mrst_camera_table[] = {
+       {
+               .type = MRST_CAMERA_SOC,
+               .name = "ov2650",
+               .sensor_addr = 0x30,
+       },
+       {
+               .type = MRST_CAMERA_SOC,
+               .name = "ov9665",
+               .sensor_addr = 0x30,
+       },
+       {
+               .type = MRST_CAMERA_RAW,
+               .name = "ov5630",
+               .sensor_addr = 0x36,
+               .motor_name = "ov5630_motor",
+               .motor_addr = (0x18 >> 1),
+       },
+       {
+               .type = MRST_CAMERA_RAW,
+               .name = "s5k4e1",
+               .sensor_addr = 0x36,
+               .motor_name = "s5k4e1_motor",
+               .motor_addr = (0x18 >> 1),
+       },
+};
+
+#define N_CAMERA (ARRAY_SIZE(mrst_camera_table))
+
+struct videobuf_dma_contig_memory {
+       u32 magic;
+       void *vaddr;
+       dma_addr_t dma_handle;
+       unsigned long size;
+       int is_userptr;
+};
+
+#define MAGIC_DC_MEM 0x0733ac61
+#define MAGIC_CHECK(is, should)                                                    \
+       if (unlikely((is) != (should))) {                                   \
+               pr_err("magic mismatch: %x expected %x\n", (is), (should)); \
+               BUG();                                                      \
+       }
+/* flag to determine whether to do the handler of mblk_line irq */
+int mrst_isp_to_do_mblk_line;
+unsigned char *mrst_isp_regs;
+
+static inline struct ci_sensor_config *to_sensor_config(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct ci_sensor_config, sd);
+}
+
+/* g45-th20-b5 gamma out curve with enhanced black level */
+static struct ci_isp_gamma_out_curve g45_th20_b5 = {
+       {
+        0x0000, 0x0014, 0x003C, 0x0064,
+        0x00A0, 0x0118, 0x0171, 0x01A7,
+        0x01D8, 0x0230, 0x027A, 0x02BB,
+        0x0323, 0x0371, 0x03AD, 0x03DB,
+        0x03FF}
+       ,
+       0
+};
+
+static void print_snr_cfg(struct ci_sensor_config *cfg)
+{
+       dprintk(2, "bus width = %x", cfg->bus_width);
+       dprintk(2, "mode = %x", cfg->mode);
+       dprintk(2, "field_inv = %x", cfg->field_inv);
+       dprintk(2, "field_sel = %x", cfg->field_sel);
+       dprintk(2, "ycseq = %x", cfg->ycseq);
+       dprintk(2, "conv422 = %x", cfg->conv422);
+       dprintk(2, "bpat = %x", cfg->bpat);
+       dprintk(2, "hpol = %x", cfg->hpol);
+       dprintk(2, "vpol = %x", cfg->vpol);
+       dprintk(2, "edge = %x", cfg->edge);
+       dprintk(2, "bls = %x", cfg->bls);
+       dprintk(2, "gamma = %x", cfg->gamma);
+       dprintk(2, "cconv = %x", cfg->cconv);
+       dprintk(2, "res = %x", cfg->res);
+       dprintk(2, "blc = %x", cfg->blc);
+       dprintk(2, "agc = %x", cfg->agc);
+       dprintk(2, "awb = %x", cfg->awb);
+       dprintk(2, "aec = %x", cfg->aec);
+       dprintk(2, "cie_profile = %x", cfg->cie_profile);
+       dprintk(2, "flicker_freq = %x", cfg->flicker_freq);
+       dprintk(2, "smia_mode = %x", cfg->smia_mode);
+       dprintk(2, "mipi_mode = %x", cfg->mipi_mode);
+       dprintk(2, "type = %x", cfg->type);
+       dprintk(2, "name = %s", cfg->name);
+}
+
+static int mrst_isp_defcfg_all_load(struct ci_isp_config *isp_config)
+{
+       /* demosaic mode */
+       isp_config->demosaic_mode = CI_ISP_DEMOSAIC_ENHANCED;
+
+       /* bpc */
+       isp_config->bpc_cfg.bp_corr_type = CI_ISP_BP_CORR_DIRECT;
+       isp_config->bpc_cfg.bp_corr_rep = CI_ISP_BP_CORR_REP_NB;
+       isp_config->bpc_cfg.bp_corr_mode = CI_ISP_BP_CORR_HOT_DEAD_EN;
+       isp_config->bpc_cfg.bp_abs_hot_thres = 496;
+       isp_config->bpc_cfg.bp_abs_dead_thres = 20;
+       isp_config->bpc_cfg.bp_dev_hot_thres = 328;
+       isp_config->bpc_cfg.bp_dev_dead_thres = 328;
+       isp_config->bpd_cfg.bp_dead_thres = 1;
+
+       /* WB */
+       isp_config->wb_config.mrv_wb_mode = CI_ISP_AWB_AUTO;
+       isp_config->wb_config.mrv_wb_sub_mode = CI_ISP_AWB_AUTO_ON;
+       isp_config->wb_config.awb_pca_damping = 16;
+       isp_config->wb_config.awb_prior_exp_damping = 12;
+       isp_config->wb_config.awb_pca_push_damping = 16;
+       isp_config->wb_config.awb_prior_exp_push_damping = 12;
+       isp_config->wb_config.awb_auto_max_y = 254;
+       isp_config->wb_config.awb_push_max_y = 250;
+       isp_config->wb_config.awb_measure_max_y = 200;
+       isp_config->wb_config.awb_underexp_det = 10;
+       isp_config->wb_config.awb_push_underexp_det = 170;
+
+       /* CAC */
+       isp_config->cac_config.hsize = 2048;
+       isp_config->cac_config.vsize = 1536;
+       isp_config->cac_config.hcenter_offset = 0;
+       isp_config->cac_config.vcenter_offset = 0;
+       isp_config->cac_config.hclip_mode = 1;
+       isp_config->cac_config.vclip_mode = 2;
+       isp_config->cac_config.ablue = 24;
+       isp_config->cac_config.ared = 489;
+       isp_config->cac_config.bblue = 450;
+       isp_config->cac_config.bred = 53;
+       isp_config->cac_config.cblue = 40;
+       isp_config->cac_config.cred = 479;
+       isp_config->cac_config.aspect_ratio = 0.000000;
+
+       /* BLS */
+       isp_config->bls_cfg.enable_automatic = 0;
+       isp_config->bls_cfg.disable_h = 0;
+       isp_config->bls_cfg.disable_v = 0;
+       isp_config->bls_cfg.isp_bls_window1.enable_window = 0;
+       isp_config->bls_cfg.isp_bls_window1.start_h = 0;
+       isp_config->bls_cfg.isp_bls_window1.stop_h = 0;
+       isp_config->bls_cfg.isp_bls_window1.start_v = 0;
+       isp_config->bls_cfg.isp_bls_window1.stop_v = 0;
+       isp_config->bls_cfg.isp_bls_window2.enable_window = 0;
+       isp_config->bls_cfg.isp_bls_window2.start_h = 0;
+       isp_config->bls_cfg.isp_bls_window2.stop_h = 0;
+       isp_config->bls_cfg.isp_bls_window2.start_v = 0;
+       isp_config->bls_cfg.isp_bls_window2.stop_v = 0;
+       isp_config->bls_cfg.bls_samples = 5;
+       isp_config->bls_cfg.bls_subtraction.fixed_a = 0x100;
+       isp_config->bls_cfg.bls_subtraction.fixed_b = 0x100;
+       isp_config->bls_cfg.bls_subtraction.fixed_c = 0x100;
+       isp_config->bls_cfg.bls_subtraction.fixed_d = 0x100;
+
+       /* AF */
+       isp_config->af_cfg.wnd_pos_a.hoffs = 874;
+       isp_config->af_cfg.wnd_pos_a.voffs = 618;
+       isp_config->af_cfg.wnd_pos_a.hsize = 300;
+       isp_config->af_cfg.wnd_pos_a.vsize = 300;
+       isp_config->af_cfg.wnd_pos_b.hoffs = 0;
+       isp_config->af_cfg.wnd_pos_b.voffs = 0;
+       isp_config->af_cfg.wnd_pos_b.hsize = 0;
+       isp_config->af_cfg.wnd_pos_b.vsize = 0;
+       isp_config->af_cfg.wnd_pos_c.hoffs = 0;
+       isp_config->af_cfg.wnd_pos_c.voffs = 0;
+       isp_config->af_cfg.wnd_pos_c.hsize = 0;
+       isp_config->af_cfg.wnd_pos_c.vsize = 0;
+       isp_config->af_cfg.threshold = 0x00000000;
+
+       /* color */
+       isp_config->color.contrast = 128;
+       isp_config->color.brightness = 0;
+       isp_config->color.saturation = 128;
+       isp_config->color.hue = 0;
+
+       /* Img Effect */
+       isp_config->img_eff_cfg.mode = CI_ISP_IE_MODE_OFF;
+       isp_config->img_eff_cfg.color_sel = 4;
+       isp_config->img_eff_cfg.color_thres = 128;
+       isp_config->img_eff_cfg.tint_cb = 108;
+       isp_config->img_eff_cfg.tint_cr = 141;
+       isp_config->img_eff_cfg.mat_emboss.coeff_11 = 2;
+       isp_config->img_eff_cfg.mat_emboss.coeff_12 = 1;
+       isp_config->img_eff_cfg.mat_emboss.coeff_13 = 0;
+       isp_config->img_eff_cfg.mat_emboss.coeff_21 = 1;
+       isp_config->img_eff_cfg.mat_emboss.coeff_22 = 0;
+       isp_config->img_eff_cfg.mat_emboss.coeff_23 = -1;
+       isp_config->img_eff_cfg.mat_emboss.coeff_31 = 0;
+       isp_config->img_eff_cfg.mat_emboss.coeff_32 = -1;
+       isp_config->img_eff_cfg.mat_emboss.coeff_33 = -2;
+       isp_config->img_eff_cfg.mat_sketch.coeff_11 = -1;
+       isp_config->img_eff_cfg.mat_sketch.coeff_12 = -1;
+       isp_config->img_eff_cfg.mat_sketch.coeff_13 = -1;
+       isp_config->img_eff_cfg.mat_sketch.coeff_21 = -1;
+       isp_config->img_eff_cfg.mat_sketch.coeff_22 = 8;
+       isp_config->img_eff_cfg.mat_sketch.coeff_23 = -1;
+       isp_config->img_eff_cfg.mat_sketch.coeff_31 = -1;
+       isp_config->img_eff_cfg.mat_sketch.coeff_32 = -1;
+       isp_config->img_eff_cfg.mat_sketch.coeff_33 = -1;
+
+       isp_config->flags.bls = 0;
+       isp_config->flags.lsc = 0;
+       isp_config->flags.bpc = 0;
+       isp_config->flags.awb = 0;
+       isp_config->flags.aec = 0;
+       isp_config->flags.af = 0;
+       isp_config->flags.cp = 0;
+       isp_config->flags.gamma = 0;
+       isp_config->flags.cconv = 0;
+       isp_config->flags.demosaic = 0;
+       isp_config->flags.gamma2 = 0;
+       isp_config->flags.isp_filters = 0;
+       isp_config->flags.cac = 0;
+       isp_config->flags.cconv_basic = 0;
+       isp_config->demosaic_th = 4;
+
+       isp_config->view_finder.flags = VFFLAG_HWRGB;
+
+       isp_config->afm_mode = 1;
+       isp_config->filter_level_noise_reduc = 4;
+       isp_config->filter_level_sharp = 4;
+
+       isp_config->jpeg_enc_ratio = 1;
+
+       return 0;
+}
+
+static void mrst_isp_update_marvinvfaddr(struct mrst_isp_device *isp,
+                                     u32 buffer_base,
+                                     enum ci_isp_conf_update_time update_time)
+{
+       struct ci_isp_mi_path_conf isp_mi_path_conf;
+       struct ci_isp_mi_path_conf isp_sf_mi_path_conf;
+       static struct v4l2_jpg_review_buffer *jpg_review;
+       u32 bufsize = 0;
+       u32 w;
+       u32 h;
+
+       jpg_review = &isp->sys_conf.jpg_review;
+       memset(&isp_mi_path_conf, 0, sizeof(struct ci_isp_mi_path_conf));
+       memset(&isp_sf_mi_path_conf, 0, sizeof(struct ci_isp_mi_path_conf));
+
+       w = isp_mi_path_conf.llength = isp->bufwidth;
+       h = isp_mi_path_conf.ypic_height = isp->bufheight;
+       isp_mi_path_conf.ypic_width = isp->bufwidth;
+
+       if (isp->sys_conf.jpg_review_enable) {
+
+               /* for self path, JPEG review */
+               isp_sf_mi_path_conf.ypic_width = jpg_review->width;
+               isp_sf_mi_path_conf.llength = jpg_review->width;
+               isp_sf_mi_path_conf.ypic_height = jpg_review->height;
+
+               bufsize = jpg_review->width * jpg_review->height;
+
+               /* buffer size in bytes */
+               switch (jpg_review->pix_fmt) {
+               case V4L2_PIX_FMT_YUV420:
+               case V4L2_PIX_FMT_YVU420:
+                       dprintk(3, "VF yuv420 fmt");
+                       isp_sf_mi_path_conf.ybuffer.size = bufsize;
+                       isp_sf_mi_path_conf.cb_buffer.size = bufsize/4;
+                       isp_sf_mi_path_conf.cr_buffer.size = bufsize/4;
+                       break;
+
+               case V4L2_PIX_FMT_YUV422P:
+                       dprintk(3, "VF yuv422 fmt");
+                       isp_sf_mi_path_conf.ybuffer.size = bufsize;
+                       isp_sf_mi_path_conf.cb_buffer.size = bufsize/2;
+                       isp_sf_mi_path_conf.cr_buffer.size = bufsize/2;
+                       break;
+
+               case V4L2_PIX_FMT_NV12:
+                       dprintk(3, "VF nv12 fmt");
+                       isp_sf_mi_path_conf.ybuffer.size = bufsize;
+                       isp_sf_mi_path_conf.cb_buffer.size = bufsize/2;
+                       isp_sf_mi_path_conf.cr_buffer.size = 0;
+                       break;
+
+               default:
+                       printk(KERN_ERR "mrstisp: no support jpg review fmt\n");
+                       break;
+               }
+
+               /* buffer address */
+               if (isp_sf_mi_path_conf.ybuffer.size != 0) {
+                       isp_sf_mi_path_conf.ybuffer.pucbuffer =
+                           (u8 *)(unsigned long)
+                           isp->mb1 + isp->mb1_size - 640*480*2;
+               }
+
+               if (isp_sf_mi_path_conf.cb_buffer.size != 0) {
+                       isp_sf_mi_path_conf.cb_buffer.pucbuffer =
+                               isp_sf_mi_path_conf.ybuffer.pucbuffer +
+                               isp_sf_mi_path_conf.ybuffer.size;
+               }
+
+               if (isp_sf_mi_path_conf.cr_buffer.size != 0) {
+                       isp_sf_mi_path_conf.cr_buffer.pucbuffer =
+                               isp_sf_mi_path_conf.cb_buffer.pucbuffer +
+                               isp_sf_mi_path_conf.cb_buffer.size;
+               }
+
+               if (jpg_review->pix_fmt == V4L2_PIX_FMT_YVU420) {
+                       isp_sf_mi_path_conf.cr_buffer.pucbuffer =
+                               isp_sf_mi_path_conf.ybuffer.pucbuffer +
+                               isp_sf_mi_path_conf.ybuffer.size;
+                       isp_sf_mi_path_conf.cb_buffer.pucbuffer =
+                               isp_sf_mi_path_conf.cr_buffer.pucbuffer +
+                               isp_sf_mi_path_conf.cr_buffer.size;
+               }
+
+       }
+
+       if (isp->pixelformat == V4L2_PIX_FMT_YUV420 ||
+               isp->pixelformat == V4L2_PIX_FMT_YVU420 ||
+               isp->pixelformat == V4L2_PIX_FMT_YUV422P ||
+               isp->pixelformat == V4L2_PIX_FMT_NV12) {
+               bufsize = w*h;
+       } else
+               bufsize = isp->frame_size;
+
+       /* buffer size in bytes */
+       switch (isp->pixelformat) {
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YVU420:
+               dprintk(3, "yuv420 fmt");
+               isp_mi_path_conf.ybuffer.size = bufsize;
+               isp_mi_path_conf.cb_buffer.size = bufsize/4;
+               isp_mi_path_conf.cr_buffer.size = bufsize/4;
+               break;
+       case V4L2_PIX_FMT_YUV422P:
+               dprintk(3, "yuv422 fmt");
+               isp_mi_path_conf.ybuffer.size = bufsize;
+               isp_mi_path_conf.cb_buffer.size = bufsize/2;
+               isp_mi_path_conf.cr_buffer.size = bufsize/2;
+               break;
+       case V4L2_PIX_FMT_NV12:
+               dprintk(3, "nv12 fmt");
+               isp_mi_path_conf.ybuffer.size = bufsize;
+               isp_mi_path_conf.cb_buffer.size = bufsize/2;
+               isp_mi_path_conf.cr_buffer.size = 0;
+               break;
+       default:
+               dprintk(3, "jpeg and rgb fmt");
+               isp_mi_path_conf.ybuffer.size = bufsize;
+               isp_mi_path_conf.cb_buffer.size = 0;
+               isp_mi_path_conf.cr_buffer.size = 0;
+               break;
+       }
+
+       /* buffer address */
+       if (isp_mi_path_conf.ybuffer.size != 0) {
+               isp_mi_path_conf.ybuffer.pucbuffer =
+                   (u8 *)(unsigned long) buffer_base;
+       }
+
+       if (isp_mi_path_conf.cb_buffer.size != 0) {
+               isp_mi_path_conf.cb_buffer.pucbuffer =
+                       isp_mi_path_conf.ybuffer.pucbuffer +
+                       isp_mi_path_conf.ybuffer.size;
+       }
+
+       if (isp_mi_path_conf.cr_buffer.size != 0) {
+               isp_mi_path_conf.cr_buffer.pucbuffer =
+                       isp_mi_path_conf.cb_buffer.pucbuffer +
+                       isp_mi_path_conf.cb_buffer.size;
+       }
+
+       if (isp->pixelformat == V4L2_PIX_FMT_YVU420) {
+               isp_mi_path_conf.cr_buffer.pucbuffer =
+                       isp_mi_path_conf.ybuffer.pucbuffer +
+                       isp_mi_path_conf.ybuffer.size;
+               isp_mi_path_conf.cb_buffer.pucbuffer =
+                       isp_mi_path_conf.cr_buffer.pucbuffer +
+                       isp_mi_path_conf.cr_buffer.size;
+       }
+
+       if (isp->sys_conf.isp_cfg.view_finder.flags & VFFLAG_USE_MAINPATH) {
+               ci_isp_mif_set_main_buffer(&isp_mi_path_conf, update_time);
+               if (isp->pixelformat == V4L2_PIX_FMT_JPEG)
+                       if (isp->sys_conf.jpg_review_enable)
+                               ci_isp_mif_set_self_buffer(
+                                   &isp_sf_mi_path_conf, update_time);
+       } else {
+               ci_isp_mif_set_self_buffer(&isp_mi_path_conf, update_time);
+       }
+}
+
+static int mrst_isp_setup_viewfinder_path(struct mrst_isp_device *isp,
+                                         struct ci_sensor_config *isi_config,
+                                         int zoom)
+{
+       int error = CI_STATUS_SUCCESS;
+       struct ci_isp_datapath_desc dp_main;
+       struct ci_isp_datapath_desc dp_self;
+       struct ci_isp_rect self_rect;
+       u16 isi_hsize;
+       u16 isi_vsize;
+       int jpe_scale;
+       struct ci_pl_system_config *sys_conf = &isp->sys_conf;
+       struct ci_isp_config *config = &sys_conf->isp_cfg;
+       struct v4l2_jpg_review_buffer *jpg_review = &sys_conf->jpg_review;
+       u32 dp_mode;
+
+       if (sys_conf->isp_cfg.flags.ycbcr_full_range)
+               jpe_scale = false;
+       else
+               jpe_scale = true;
+
+       memset(&dp_main, 0, sizeof(struct ci_isp_datapath_desc));
+       memset(&dp_self, 0, sizeof(struct ci_isp_datapath_desc));
+
+       self_rect.x = 0;
+       self_rect.y = 0;
+       self_rect.w = isp->bufwidth;
+       self_rect.h = isp->bufheight;
+
+       if (isp->pixelformat == V4L2_PIX_FMT_JPEG) {
+
+               dprintk(1, "jpeg fmt");
+
+               dp_main.flags = CI_ISP_DPD_ENABLE | CI_ISP_DPD_MODE_ISPJPEG;
+               config->view_finder.flags |= VFFLAG_USE_MAINPATH;
+
+               dp_main.out_w = (u16) isp->bufwidth;
+               dp_main.out_h = (u16) isp->bufheight;
+
+               if (isp->sys_conf.jpg_review_enable) {
+
+                       dprintk(1, "jpg_review enabled in VF");
+
+                       self_rect.w = jpg_review->width;
+                       self_rect.h = jpg_review->height;
+
+                       dp_self.flags = (CI_ISP_DPD_ENABLE
+                                        | CI_ISP_DPD_MODE_ISPYC);
+                       if (jpg_review->pix_fmt == V4L2_PIX_FMT_YUV420 ||
+                               jpg_review->pix_fmt == V4L2_PIX_FMT_YVU420)
+                               dp_self.flags |= CI_ISP_DPD_YUV_420
+                                   | CI_ISP_DPD_CSS_V2;
+                       else if (jpg_review->pix_fmt == V4L2_PIX_FMT_YUV422P)
+                               dp_self.flags |= CI_ISP_DPD_YUV_422;
+                       else if (jpg_review->pix_fmt == V4L2_PIX_FMT_NV12)
+                               dp_self.flags |= CI_ISP_DPD_YUV_NV12
+                                   | CI_ISP_DPD_CSS_V2;
+                       else if (jpg_review->pix_fmt == V4L2_PIX_FMT_YUYV)
+                               dp_self.flags |= CI_ISP_DPD_YUV_YUYV;
+
+                       dprintk(1, "dp_self.flags is 0x%x", dp_self.flags);
+               }
+
+       } else if (isp->pixelformat == INTEL_PIX_FMT_RAW08) {
+
+               dp_main.flags = CI_ISP_DPD_ENABLE | CI_ISP_DPD_MODE_ISPRAW;
+               config->view_finder.flags |= VFFLAG_USE_MAINPATH;
+
+               /*just take the output of the sensor without any resizing*/
+               dp_main.flags |= CI_ISP_DPD_NORESIZE;
+               ci_sensor_res2size(isi_config->res,
+                                        &(dp_main.out_w), &(dp_main.out_h));
+
+               dprintk(1, "RAW08 dp_main.flags is 0x%x", dp_main.flags);
+
+       } else if (isp->pixelformat == INTEL_PIX_FMT_RAW10
+                  || isp->pixelformat == INTEL_PIX_FMT_RAW12) {
+
+               dp_main.flags = (CI_ISP_DPD_ENABLE
+                                | CI_ISP_DPD_MODE_ISPRAW_16B);
+               config->view_finder.flags |= VFFLAG_USE_MAINPATH;
+
+               /*just take the output of the sensor without any resizing*/
+               dp_main.flags |= CI_ISP_DPD_NORESIZE;
+               ci_sensor_res2size(isi_config->res,
+                                        &(dp_main.out_w), &(dp_main.out_h));
+
+               dprintk(1, "RAW10 dp_main.flags is 0x%x", dp_main.flags);
+
+       } else if (isp->bufwidth >= 32 && isp->bufheight >= 16) {
+
+               dp_main.flags = (CI_ISP_DPD_ENABLE | CI_ISP_DPD_MODE_ISPYC);
+               dp_main.out_w = (u16) isp->bufwidth;
+               dp_main.out_h = (u16) isp->bufheight;
+               config->view_finder.flags |= VFFLAG_USE_MAINPATH;
+
+               if (isp->pixelformat == V4L2_PIX_FMT_YUV420 ||
+                       isp->pixelformat == V4L2_PIX_FMT_YVU420)
+                       dp_main.flags |= CI_ISP_DPD_YUV_420 | CI_ISP_DPD_CSS_V2;
+               else if (isp->pixelformat == V4L2_PIX_FMT_YUV422P)
+                       dp_main.flags |= CI_ISP_DPD_YUV_422;
+               else if (isp->pixelformat == V4L2_PIX_FMT_NV12) {
+                       /* to use crop set crop_flag first */
+                       dp_main.flags |= CI_ISP_DPD_YUV_NV12;
+                       if (!crop_flag)
+                               dp_main.flags |= CI_ISP_DPD_CSS_V2;
+               } else if (isp->pixelformat == V4L2_PIX_FMT_YUYV)
+                       dp_main.flags |= CI_ISP_DPD_YUV_YUYV;
+
+               dprintk(1, "YUV dp_main.flags is 0x%x", dp_main.flags);
+
+       } else {
+               dprintk(1, "wrong setting");
+       }
+
+       dprintk(1, "sensor_res = %x", isi_config->res);
+
+       ci_sensor_res2size(isi_config->res, &isi_hsize, &isi_vsize);
+       dprintk(1, "self path: w:%d, h:%d; sensor: w:%d, h:%d",
+               self_rect.w, self_rect.h, isi_hsize, isi_vsize);
+       dprintk(1, "main path: out_w:%d, out_h:%d ",
+               dp_main.out_w, dp_main.out_h);
+
+       /* no stretching/squeezing */
+       if (dp_self.flags && CI_ISP_DPD_ENABLE)
+               dp_self.flags |= CI_ISP_DPD_KEEPRATIO;
+       else
+               dp_main.flags |= CI_ISP_DPD_KEEPRATIO;
+
+       /* prepare datapath, 640x480, can changed to the bufsize */
+       dp_self.out_w = (u16) self_rect.w;
+       dp_self.out_h = (u16) self_rect.h;
+
+       if (sys_conf->isp_cfg.view_finder.flags & VFFLAG_HWRGB) {
+               /* YCbCr to RGB conversion in hardware */
+               if (isp->pixelformat == V4L2_PIX_FMT_RGB565)
+                       dp_self.flags |= CI_ISP_DPD_HWRGB_565;
+               if (isp->pixelformat == V4L2_PIX_FMT_BGR32)
+                       dp_self.flags |= CI_ISP_DPD_HWRGB_888;
+       }
+
+       if (sys_conf->isp_cfg.view_finder.flags & VFFLAG_MIRROR)
+               dp_self.flags |= CI_ISP_DPD_H_FLIP;
+
+
+       if (sys_conf->isp_cfg.view_finder.flags & VFFLAG_V_FLIP)
+               dp_self.flags |= CI_ISP_DPD_V_FLIP;
+
+
+       if (sys_conf->isp_cfg.view_finder.flags & VFFLAG_ROT90_CCW)
+               dp_self.flags |= CI_ISP_DPD_90DEG_CCW;
+
+       /* setup self & main path with zoom */
+       if (zoom < 0)
+               zoom = sys_conf->isp_cfg.view_finder.zoom;
+
+       if (sys_conf->isp_cfg.view_finder.flags & VFFLAG_USE_MAINPATH) {
+               /* For RAW snapshots, we have to bypass the ISP too */
+               dp_mode = dp_main.flags & CI_ISP_DPD_MODE_MASK;
+               if ((dp_mode == CI_ISP_DPD_MODE_ISPRAW) ||
+                       (dp_mode == CI_ISP_DPD_MODE_ISPRAW_16B)) {
+                       struct ci_sensor_config isi_conf;
+                       isi_conf = *isi_config;
+                       isi_conf.mode = SENSOR_MODE_PICT;
+                       error = ci_isp_set_input_aquisition(&isi_conf);
+                       if (error != CI_STATUS_SUCCESS)
+                               eprintk("33");
+               }
+       }
+       /* to use crop mode, set crop_flag */
+       if (crop_flag)
+               dp_main.flags |= CI_ISP_DPD_NORESIZE;
+
+       error = ci_datapath_isp(sys_conf, isi_config, &dp_main, &dp_self, zoom);
+       if (error != CI_STATUS_SUCCESS) {
+               printk(KERN_ERR "mrstisp: failed to setup marvins datapath\n");
+               return error;
+       }
+
+       return error;
+}
+
+static int mrst_isp_init_mrv_image_effects(struct ci_pl_system_config *sys_conf,
+                                          int enable)
+{
+       int res;
+
+       if (enable && sys_conf->isp_cfg.img_eff_cfg.mode
+           != CI_ISP_IE_MODE_OFF) {
+               res = ci_isp_ie_set_config(&(sys_conf->isp_cfg.img_eff_cfg));
+               if (res != CI_STATUS_SUCCESS)
+                       printk(KERN_ERR "mrstisp: error setting ie config\n");
+       } else {
+               ci_isp_ie_set_config(NULL);
+               res = CI_STATUS_SUCCESS;
+       }
+
+       return res;
+}
+
+static int mrst_isp_init_mrvisp_lensshade(struct ci_pl_system_config *sys_conf,
+                                         int enable)
+{
+       if (enable) {
+               ci_isp_set_ls_correction(&sys_conf->isp_cfg.lsc_cfg);
+               ci_isp_ls_correction_on_off(1);
+       } else {
+               ci_isp_ls_correction_on_off(0);
+       }
+       return CI_STATUS_SUCCESS;
+}
+
+static int mrst_isp_init_mrvisp_badpixel(const struct ci_pl_system_config
+                                        *sys_conf, int enable)
+{
+       if ((enable) && (sys_conf->isp_cfg.flags.bpc)) {
+               ci_bp_init(&sys_conf->isp_cfg.bpc_cfg,
+                                &sys_conf->isp_cfg.bpd_cfg);
+       } else {
+               ci_bp_end(&sys_conf->isp_cfg.bpc_cfg);
+               ci_isp_set_bp_correction(NULL);
+               ci_isp_set_bp_detection(NULL);
+       }
+       return CI_STATUS_SUCCESS;
+}
+
+static int mrst_isp_init_mrv_ispfilter(const struct ci_pl_system_config
+                                      *sys_conf, int enable)
+{
+       int res;
+
+       if ((enable) && (sys_conf->isp_cfg.flags.isp_filters)) {
+               ci_isp_activate_filter(true);
+               res = ci_isp_set_filter_params(sys_conf->isp_cfg.
+                                              filter_level_noise_reduc,
+                                              sys_conf->isp_cfg.
+                                              filter_level_sharp);
+               if (res != CI_STATUS_SUCCESS)
+                       printk(KERN_ERR "mrstisp: error set filter param\n");
+       } else {
+               ci_isp_activate_filter(false);
+               res = CI_STATUS_SUCCESS;
+       }
+
+       return res;
+}
+
+static int mrst_isp_initbls(const struct ci_pl_system_config *sys_conf)
+{
+       struct ci_isp_bls_config *bls_config =
+           (struct ci_isp_bls_config *)&sys_conf->isp_cfg.bls_cfg;
+       return ci_isp_bls_set_config(bls_config);
+}
+
+static int mrst_isp_dp_init(struct ci_pl_system_config *sys_conf,
+                           struct ci_sensor_config *isi_config)
+{
+       int error;
+       u8 words_per_pixel;
+
+       /* base initialisation of Marvin */
+       ci_isp_init();
+
+       /* setup input acquisition according to image sensor settings */
+       print_snr_cfg(isi_config);
+       error = ci_isp_set_input_aquisition(isi_config);
+       if (error) {
+               printk(KERN_ERR "mrstisp: error setting input acquisition\n");
+               return error;
+       }
+
+       /* setup functional blocks for Bayer pattern processing */
+       if (ci_isp_select_path(isi_config, &words_per_pixel)
+           == CI_ISP_PATH_BAYER) {
+
+               /* black level */
+               if (sys_conf->isp_cfg.flags.bls) {
+                       error = mrst_isp_initbls(sys_conf);
+                       if (error != CI_STATUS_SUCCESS) {
+                               printk(KERN_ERR "mrstisp: error set bls\n");
+                               return error;
+                       }
+               } else {
+                       ci_isp_bls_set_config(NULL);
+               }
+
+               /* gamma */
+               if (sys_conf->isp_cfg.flags.gamma2) {
+                       dprintk(1, "setting gamma 2 ");
+                       ci_isp_set_gamma2(&g45_th20_b5);
+               } else {
+                       dprintk(1, "no setting gamma 2 ");
+                       ci_isp_set_gamma2(NULL);
+               }
+
+               /* demosaic */
+               ci_isp_set_demosaic(sys_conf->isp_cfg.demosaic_mode,
+                                   sys_conf->isp_cfg.demosaic_th);
+
+               /* color convertion */
+               if (sys_conf->isp_cfg.flags.cconv) {
+                       if (!sys_conf->isp_cfg.flags.cconv_basic) {
+                               mrst_isp_set_color_conversion_ex();
+                               if (error != CI_STATUS_SUCCESS) {
+                                       printk(KERN_ERR "mrstisp: error set"
+                                              " color conversion\n");
+                                       return error;
+                               }
+                       }
+               }
+
+               /* af setting */
+               if (sys_conf->isp_cfg.flags.af)
+                       ci_isp_set_auto_focus(&sys_conf->isp_cfg.af_cfg);
+               else
+                       ci_isp_set_auto_focus(NULL);
+
+               /* filter */
+               mrst_isp_init_mrv_ispfilter(sys_conf, true);
+
+       }
+
+       ci_isp_col_set_color_processing(NULL);
+
+       /* configure image effects */
+       mrst_isp_init_mrv_image_effects(sys_conf, true);
+
+       /* configure lens shading correction */
+       if (strcmp(isi_config->name, "s5k4e1") == 0
+           && (isi_config->res == SENSOR_RES_720P
+               || isi_config->res == SENSOR_RES_QXGA_PLUS)) {
+               dprintk(1, "enabling lsc for kmot 720p and qsxga\n");
+               mrst_isp_init_mrvisp_lensshade(sys_conf, true);
+       } else
+               mrst_isp_init_mrvisp_lensshade(sys_conf,
+                                              sys_conf->isp_cfg.flags.lsc);
+
+       /* configure bad pixel detection/correction */
+       mrst_isp_init_mrvisp_badpixel(sys_conf, true);
+
+       return CI_STATUS_SUCCESS;
+}
+
+int ci_jpe_encode(struct mrst_isp_device *intel,
+                 enum ci_isp_conf_update_time update_time,
+                 enum ci_isp_jpe_enc_mode mrv_jpe_encMode)
+{
+       u32 mipi_data_id = 1;
+       struct isp_register *mrv_reg =
+           (struct isp_register *) MEM_MRV_REG_BASE;
+
+       ci_isp_jpe_prep_enc(mrv_jpe_encMode);
+
+       if (to_sensor_config(intel->sensor_curr)->mipi_mode) {
+               ci_isp_start(1, update_time);
+               v4l2_subdev_call(intel->sensor_curr, video, s_stream, 1);
+               if (mipi_flag)
+                       while (mipi_data_id)
+                               mipi_data_id =
+                                        REG_READ_EX(mrv_reg->mipi_cur_data_id);
+               mipi_flag = 0;
+
+       } else
+               ci_isp_start(1, update_time);
+
+       return ci_isp_jpe_wait_for_encode_done(intel);
+}
+
+/* capture one frame */
+u32 ci_jpe_capture(struct mrst_isp_device *isp,
+                  enum ci_isp_conf_update_time update_time)
+{
+       int retval = CI_STATUS_SUCCESS;
+
+       /* generate header */
+       retval = ci_isp_jpe_generate_header(isp, MRV_JPE_HEADER_MODE_JFIF);
+       if (retval != CI_STATUS_SUCCESS)
+               return 0;
+
+       /* now encode JPEG */
+       retval = ci_jpe_encode(isp, update_time, CI_ISP_JPE_SINGLE_SHOT);
+       if (retval != CI_STATUS_SUCCESS)
+               return 0;
+
+       return 0;
+}
+
+static int mrst_ci_capture(struct mrst_isp_device *isp)
+{
+       u32 bufbase;
+       u32 mipi_data_id = 1;
+       struct videobuf_buffer *vb;
+       struct isp_register *mrv_reg =
+           (struct isp_register *) MEM_MRV_REG_BASE;
+
+       bufbase = videobuf_to_dma_contig(isp->active);
+       mrst_isp_update_marvinvfaddr(isp, bufbase, CI_ISP_CFG_UPDATE_IMMEDIATE);
+       ci_isp_mif_reset_offsets(CI_ISP_CFG_UPDATE_IMMEDIATE);
+
+       ci_isp_reset_interrupt_status();
+       mrst_isp_enable_interrupt(isp);
+
+       switch (isp->pixelformat) {
+       case V4L2_PIX_FMT_JPEG:
+               mrst_isp_disable_interrupt(isp);
+               ci_isp_jpe_init_ex(isp->bufwidth, isp->bufheight,
+                                  isp->sys_conf.isp_cfg.jpeg_enc_ratio,
+                                  true);
+               ci_jpe_capture(isp, CI_ISP_CFG_UPDATE_FRAME_SYNC);
+
+               vb = isp->active;
+               vb->size = ci_isp_mif_get_byte_cnt();
+               vb->state = VIDEOBUF_DONE;
+               do_gettimeofday(&vb->ts);
+               vb->field_count++;
+               wake_up(&vb->done);
+               isp->active = NULL;
+
+               dprintk(2, "countcount = %lx", vb->size);
+               break;
+       case INTEL_PIX_FMT_RAW08:
+       case INTEL_PIX_FMT_RAW10:
+       case INTEL_PIX_FMT_RAW12:
+               mrst_isp_disable_interrupt(isp);
+               ci_isp_start(1, CI_ISP_CFG_UPDATE_FRAME_SYNC);
+               ci_isp_wait_for_frame_end(isp);
+
+               /* update captured frame status */
+               vb = isp->active;
+               vb->state = VIDEOBUF_DONE;
+               do_gettimeofday(&vb->ts);
+               vb->field_count++;
+               wake_up(&vb->done);
+               isp->active = NULL;
+               dprintk(3, "captured  index = %d", vb->i);
+               break;
+       default:
+               ci_isp_start(0, CI_ISP_CFG_UPDATE_FRAME_SYNC);
+               if (mipi_flag &&
+                   (to_sensor_config(isp->sensor_curr))->mipi_mode) {
+                       while (mipi_data_id) {
+                               mipi_data_id =
+                                   REG_READ_EX(mrv_reg->mipi_cur_data_id);
+                               dprintk(5, "mipi_cur_data_id = %x",
+                                       mipi_data_id);
+                       }
+                       mipi_flag = 0;
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+                       unsigned int *size)
+{
+       struct mrst_isp_fh  *fh = vq->priv_data;
+       struct mrst_isp_device *isp  = fh->dev;
+
+       u32 w = isp->bufwidth;
+       u32 h = isp->bufheight;
+       u32 depth = isp->depth;
+       u32 fourcc = isp->pixelformat;
+
+       if (fourcc == V4L2_PIX_FMT_JPEG) {
+               *size = PAGE_ALIGN((isp->mb1_size
+                                   - 640*480*2)/(*count)) - PAGE_SIZE;
+       } else if (fourcc == INTEL_PIX_FMT_RAW08
+                  || fourcc == INTEL_PIX_FMT_RAW10
+                  || fourcc == INTEL_PIX_FMT_RAW12) {
+               *size = (w * h * depth)/8;
+       } else {
+               *size = (w * h * depth)/8;
+       }
+
+       isp->frame_size = *size;
+       isp->num_frames = *count;
+
+       if (0 == *count)
+               *count = 3;
+
+       while (*size * *count > isp->mb1_size)
+               (*count)--;
+
+       dprintk(1, "count=%d, size=%d", *count, *size);
+       return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct mrst_isp_buffer *buf)
+{
+       struct videobuf_buffer *vb = &buf->vb;
+
+       dprintk(1, "(vb=0x%p) baddr = 0x%08lx bsize = %d", vb,
+               vb->baddr, vb->bsize);
+
+       videobuf_dma_contig_free(vq, vb);
+
+       buf->vb.state = VIDEOBUF_NEEDS_INIT;
+       dprintk(1, "free_buffer: freed");
+}
+
+static int buffer_prepare(struct videobuf_queue *vq,
+                         struct videobuf_buffer *vb, enum v4l2_field field)
+{
+       struct mrst_isp_fh     *fh  = vq->priv_data;
+       struct mrst_isp_device *isp = fh->dev;
+       struct mrst_isp_buffer *buf = container_of(vb, struct mrst_isp_buffer,
+                                                  vb);
+       int ret;
+
+       if (vb->width != isp->bufwidth || vb->height != isp->bufheight
+          || vb->field != field) {
+               vb->width  = isp->bufwidth;
+               vb->height = isp->bufheight;
+               vb->field  = field;
+               vb->state = VIDEOBUF_NEEDS_INIT;
+       }
+
+       vb->size = isp->frame_size;
+
+       if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+               ret = videobuf_iolock(vq, vb, NULL);
+               if (ret)
+                       goto fail;
+               vb->state = VIDEOBUF_PREPARED;
+       }
+
+       return 0;
+
+fail:
+       printk(KERN_ERR "mrstisp: error calling videobuf_iolock");
+       free_buffer(vq, buf);
+       return ret;
+}
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+       struct mrst_isp_fh        *fh   = vq->priv_data;
+       struct mrst_isp_device       *isp  = fh->dev;
+       u32 bufbase;
+
+       vb->state = VIDEOBUF_QUEUED;
+       dprintk(1, "buffer %d in buffer querue", vb->i);
+       if (isp->stopflag) {
+               list_add_tail(&vb->queue, &isp->capture);
+               if (isp->active) {
+                       bufbase = videobuf_to_dma_contig(vb);
+                       mrst_isp_update_marvinvfaddr(isp, bufbase,
+                                        CI_ISP_CFG_UPDATE_FRAME_SYNC);
+               } else {
+                       isp->active = vb;
+                       mrst_isp_enable_interrupt(isp);
+               }
+               isp->stopflag = 0;
+       } else if (!isp->active) {
+               dprintk(1, "no active queue");
+               isp->active = vb;
+               isp->active->state = VIDEOBUF_ACTIVE;
+               mrst_isp_to_do_mblk_line = 1;
+               mrst_ci_capture(isp);
+       } else {
+               dprintk(1, "capture to active queue");
+               list_add_tail(&vb->queue, &isp->capture);
+       }
+
+       return;
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+                          struct videobuf_buffer *vb)
+{
+       struct mrst_isp_buffer *buf = container_of(vb,
+                                                  struct mrst_isp_buffer, vb);
+       free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops mrst_isp_videobuf_qops = {
+       .buf_setup      = buffer_setup,
+       .buf_prepare    = buffer_prepare,
+       .buf_queue      = buffer_queue,
+       .buf_release    = buffer_release,
+};
+
+static int mrst_isp_open(struct file *file)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct mrst_isp_device *isp = video_get_drvdata(vdev);
+       struct mrst_isp_fh *fh = NULL;
+       struct v4l2_format sensor_format;
+       struct v4l2_mbus_framefmt framefmt;
+       int ret;
+
+       if (!isp) {
+               printk(KERN_ERR "null in mrst_isp_open\n");
+               return -ENODEV;
+       }
+
+       dprintk(2, "open = %d", isp->open);
+       mutex_lock(&isp->mutex);
+    if (isp->open == 0) {
+               if (isp->sensor_soc) {
+                       dprintk(0, "cur senfor soc");
+                       isp->sensor_curr = isp->sensor_soc;
+               } else {
+                       dprintk(0, "cur sensor raw");
+                       isp->sensor_curr = isp->sensor_raw;
+               }
+       }
+       ++isp->open;
+
+       ret = v4l2_subdev_call(isp->sensor_curr, video, g_mbus_fmt,
+                              &framefmt);
+       if (ret) {
+               printk(KERN_ERR "can't get current pix from sensor!\n");
+               ret = -EINVAL;
+               goto exit_unlock;
+       }
+
+       sensor_format.fmt.pix.width = framefmt.width;
+       sensor_format.fmt.pix.height = framefmt.height;
+
+       dprintk(1, "current sensor format: %d x %d",
+               sensor_format.fmt.pix.width,
+               sensor_format.fmt.pix.height);
+
+       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+       if (NULL == fh) {
+               printk(KERN_ERR "no mem for fh \n");
+               ret = -ENOMEM;
+               goto exit_unlock;
+       }
+
+       file->private_data = fh;
+       fh->dev = isp;
+
+       videobuf_queue_dma_contig_init(&fh->vb_q, &mrst_isp_videobuf_qops,
+                                      vdev->parent, &isp->lock,
+                                      V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                                      V4L2_FIELD_NONE,
+                                      sizeof(struct mrst_isp_buffer), fh);
+
+exit_unlock:
+       mutex_unlock(&isp->mutex);
+       return 0;
+}
+
+static int mrst_isp_close(struct file *file)
+{
+       struct video_device *dev = video_devdata(file);
+       struct mrst_isp_device *isp = video_get_drvdata(dev);
+       struct mrst_isp_fh  *fh = file->private_data;
+       unsigned long flags;
+
+       mutex_lock(&isp->mutex);
+       --isp->open;
+       dprintk(2, "close = %d", isp->open);
+       if (isp->open == 0)
+               if (isp->streaming == 1) {
+                       videobuf_streamoff(&fh->vb_q);
+                       isp->streaming = 0;
+                       isp->buffer_required = 0;
+                       isp->stopflag = 0;
+
+                       spin_lock_irqsave(&isp->lock, flags);
+                       INIT_LIST_HEAD(&isp->capture);
+                       isp->active = NULL;
+                       isp->next = NULL;
+                       isp->sys_conf.isp_hal_enable = 0;
+                       isp->sys_conf.jpg_review_enable = 0;
+                       spin_unlock_irqrestore(&isp->lock, flags);
+
+                       ci_isp_stop(CI_ISP_CFG_UPDATE_FRAME_SYNC);
+                       v4l2_subdev_call(isp->sensor_curr, video, s_stream, 0);
+                       /* sensor standby */
+                       if (isp->sensor_curr) {
+                               if (to_sensor_config(isp->sensor_curr)->type ==
+                                                SENSOR_TYPE_SOC)
+                                       gpio_set_value(GPIO_STDBY1_PIN, 0);
+                               else
+                                       gpio_set_value(GPIO_STDBY2_PIN, 0);
+                       }
+                       isp->sensor_curr = NULL;
+               }
+
+       kfree(file->private_data);
+
+       mutex_unlock(&isp->mutex);
+
+       if (isp->open == 0)
+               frame_cnt = 0;
+
+       return 0;
+}
+
+static void mrst_isp_videobuf_vm_open(struct vm_area_struct *vma)
+{
+       struct videobuf_mapping *map = vma->vm_private_data;
+
+       dprintk(2, "vm_open %p [count=%u,vma=%08lx-%08lx]\n",
+               map, map->count, vma->vm_start, vma->vm_end);
+
+       map->count++;
+}
+
+static void mrst_isp_videobuf_vm_close(struct vm_area_struct *vma)
+{
+       struct videobuf_mapping *map = vma->vm_private_data;
+       struct videobuf_queue *q = map->q;
+       int i;
+
+       dprintk(2, "vm_close %p [count=%u,vma=%08lx-%08lx]\n",
+               map, map->count, vma->vm_start, vma->vm_end);
+
+       map->count--;
+       if (0 == map->count) {
+               struct videobuf_dma_contig_memory *mem;
+
+               dprintk(2, "munmap %p q=%p\n", map, q);
+               mutex_lock(&q->vb_lock);
+
+               /* We need first to cancel streams, before unmapping */
+               if (q->streaming)
+                       videobuf_queue_cancel(q);
+
+               for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+                       if (NULL == q->bufs[i])
+                               continue;
+
+                       if (q->bufs[i]->map != map)
+                               continue;
+
+                       mem = q->bufs[i]->priv;
+                       if (mem) {
+                               MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
+                               dprintk(2, "buf[%d] freeing %p\n",
+                                       i, mem->vaddr);
+                               mem->vaddr = NULL;
+                       }
+
+                       q->bufs[i]->map   = NULL;
+                       q->bufs[i]->baddr = 0;
+               }
+
+               kfree(map);
+
+               mutex_unlock(&q->vb_lock);
+       }
+}
+
+static struct vm_operations_struct mrst_isp_videobuf_vm_ops = {
+       .open     = mrst_isp_videobuf_vm_open,
+       .close    = mrst_isp_videobuf_vm_close,
+};
+
+/* fixme: for simple reason, dma_contig allocate the frame buffer by itself
+ * internally. while mrstisp dosn't have the MMU which require a big chunk of
+ * phyical memory. this chunk of memory is reversed by the IA FW and the
+ * physical memory start address is located in the PCI BAR1 (isp->mb1)
+ * configuration space. this is a tempoary solution and will add this kind of
+ * (pre-allocatted memory) support to the video buffer management.
+ */
+static int mrst_isp_mmap_mapper(struct videobuf_queue *q,
+                                 struct vm_area_struct *vma)
+{
+       struct videobuf_dma_contig_memory *mem;
+       struct videobuf_mapping *map;
+       unsigned int first;
+       int retval;
+       unsigned long size, offset = vma->vm_pgoff << PAGE_SHIFT;
+
+       struct mrst_isp_fh  *fh = q->priv_data;
+       struct mrst_isp_device *isp  = fh->dev;
+
+       if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED))
+               return -EINVAL;
+
+       /* look for first buffer to map */
+       for (first = 0; first < VIDEO_MAX_FRAME; first++) {
+               if (!q->bufs[first])
+                       continue;
+
+               if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)
+                       continue;
+               if (q->bufs[first]->boff == offset) {
+                       dprintk(1, "buff id %d is mapped", first);
+                       break;
+               }
+       }
+       if (VIDEO_MAX_FRAME == first) {
+               eprintk("invalid user space offset [offset=0x%lx]", offset);
+               return -EINVAL;
+       }
+
+       /* create mapping + update buffer list */
+       map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
+       if (!map)
+               return -ENOMEM;
+
+       q->bufs[first]->map = map;
+       map->start = vma->vm_start;
+       map->end = vma->vm_end;
+       map->q = q;
+
+       q->bufs[first]->baddr = vma->vm_start;
+
+       mem = q->bufs[first]->priv;
+       BUG_ON(!mem);
+       MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
+
+       mem->size = PAGE_ALIGN(q->bufs[first]->bsize);
+       mem->dma_handle = isp->mb1 + (mem->size * first);
+       mem->vaddr = (void *)0x1;
+
+       if (mem->size > isp->mb1_size) {
+               eprintk("to big size, can not be mmapped");
+               return -EINVAL;
+       }
+
+       /* Try to remap memory */
+       size = vma->vm_end - vma->vm_start;
+       size = (size < mem->size) ? size : mem->size;
+
+       dprintk(1, "vm_end - vm_start = %ld, mem-size = %ld", size, mem->size);
+
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+       retval = remap_pfn_range(vma, vma->vm_start,
+                                mem->dma_handle >> PAGE_SHIFT,
+                                size, vma->vm_page_prot);
+       if (retval) {
+               eprintk("mmap: remap failed with error %d. ", retval);
+               goto error;
+       }
+
+       vma->vm_ops          = &mrst_isp_videobuf_vm_ops;
+       vma->vm_flags       |= VM_DONTEXPAND;
+       vma->vm_private_data = map;
+
+       dprintk(1, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
+               map, q, vma->vm_start, vma->vm_end,
+               (long int) q->bufs[first]->bsize,
+               vma->vm_pgoff, first);
+
+       mrst_isp_videobuf_vm_open(vma);
+
+       return 0;
+
+error:
+       kfree(map);
+       return -ENOMEM;
+}
+
+int mrst_isp_videobuf_mmap_mapper(struct videobuf_queue *q,
+                        struct vm_area_struct *vma)
+{
+       MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+
+       mutex_lock(&q->vb_lock);
+       mrst_isp_mmap_mapper(q, vma);
+       q->is_mmapped = 1;
+       mutex_unlock(&q->vb_lock);
+
+       return 0;
+}
+static int mrst_isp_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       int ret;
+       int map_by_myself;
+       struct mrst_isp_fh  *fh;
+       struct video_device *dev = video_devdata(file);
+       struct mrst_isp_device *isp = video_get_drvdata(dev);
+       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+       unsigned long size = vma->vm_end-vma->vm_start;
+       unsigned long page;
+
+       /* temporarily put here */
+       if (isp->open > 1) {
+               printk(KERN_ERR "ISP already opened...");
+               return -EINVAL;
+       }
+
+       fh = file->private_data;
+
+       if (!(vma->vm_flags & (VM_WRITE | VM_READ))
+           || !(vma->vm_flags & VM_SHARED)) {
+               printk(KERN_ERR "mrstisp: wrong vma flag");
+               return -EINVAL;
+       }
+
+       /* to check whether if it is ISP bar 0 map */
+       if (offset == isp->mb0_size + isp->mb1_size) {
+               dprintk(1, "---- map bar0 ----");
+               page = isp->mb0;
+               map_by_myself = 1;
+       } else if (offset == 0 && size == isp->mb1_size) {
+               dprintk(1, "---- map bar1 ----");
+               page = isp->mb1;
+               map_by_myself = 1;
+       } else if (isp->pixelformat == V4L2_PIX_FMT_JPEG
+                  && isp->sys_conf.jpg_review_enable == 1
+                  && offset == isp->sys_conf.jpg_review.offset) {
+               dprintk(1, "---- map jpeg review buffer----");
+               page = isp->mb1 + isp->sys_conf.jpg_review.offset;
+               map_by_myself = 1;
+       } else {
+               dprintk(1, "----map one certain buffer----");
+               map_by_myself = 0;
+       }
+
+       if (map_by_myself) {
+               vma->vm_flags |= VM_IO;
+               vma->vm_flags |= VM_RESERVED;   /* avoid to swap out this VMA */
+
+               page = page >> PAGE_SHIFT;
+
+               if (remap_pfn_range(vma, vma->vm_start, page, size,
+                                   PAGE_SHARED)) {
+                       printk(KERN_ERR "fail to put MMAP buffer to user space\n");
+                       return -EAGAIN;
+               }
+
+               return 0;
+       }
+
+       if (size > isp->num_frames * PAGE_ALIGN(isp->frame_size)) {
+               eprintk("length is larger than num * size");
+               return -EINVAL;
+       }
+
+       ret = mrst_isp_videobuf_mmap_mapper(&fh->vb_q, vma);
+
+       dprintk(1, "vma start=0x%08lx, size=%ld, offset=%ld ret=%d",
+               (unsigned long)vma->vm_start,
+               (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
+               (unsigned long)offset, ret);
+
+       return ret;
+}
+
+static int mrst_isp_g_fmt_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct video_device *dev = video_devdata(file);
+       struct mrst_isp_device *isp = video_get_drvdata(dev);
+       int ret;
+
+       if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               f->fmt.pix.width = isp->bufwidth;
+               f->fmt.pix.height = isp->bufheight;
+               f->fmt.pix.pixelformat = isp->pixelformat;
+               f->fmt.pix.bytesperline = (f->fmt.pix.width * isp->depth) >> 3;
+               f->fmt.pix.sizeimage = f->fmt.pix.height
+                   * f->fmt.pix.bytesperline;
+               f->fmt.pix.field = V4L2_FIELD_NONE;
+               switch (f->fmt.pix.pixelformat) {
+               case V4L2_PIX_FMT_BGR32:
+               case V4L2_PIX_FMT_RGB565:
+               case INTEL_PIX_FMT_RAW08:
+               case INTEL_PIX_FMT_RAW10:
+               case INTEL_PIX_FMT_RAW12:
+                       f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
+                       break;
+               case V4L2_PIX_FMT_JPEG:
+                       f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
+                       break;
+               default:
+                       f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+                       break;
+               }
+               ret = 0;
+       } else {
+               ret = -EINVAL;
+       }
+
+       dprintk(1, "get fmt %d x %d ", f->fmt.pix.width, f->fmt.pix.height);
+       return ret;
+}
+
+static struct intel_fmt *fmt_by_fourcc(unsigned int fourcc)
+{
+       unsigned int i;
+
+       for (i = 0; i < NUM_FORMATS; i++)
+               if (fmts[i].fourcc == fourcc)
+                       return fmts+i;
+       return NULL;
+}
+
+static int mrst_isp_try_fmt_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct video_device *dev = video_devdata(file);
+       struct mrst_isp_device *isp = video_get_drvdata(dev);
+       struct intel_fmt *fmt;
+       struct v4l2_mbus_framefmt framefmt;
+       int w, h;
+       int ret;
+
+       mutex_lock(&isp->mutex);
+
+       fmt = fmt_by_fourcc(f->fmt.pix.pixelformat);
+       if (NULL == fmt && f->fmt.pix.pixelformat != V4L2_PIX_FMT_MPEG) {
+               printk(KERN_ERR "mrstisp: fmt not found\n");
+               ret = -EINVAL;
+               goto exit_unlock;
+       }
+
+       framefmt.width = f->fmt.pix.width;
+       framefmt.height = f->fmt.pix.height;
+
+       dprintk(1, "sensor name %s: before w = %d, h = %d",
+               isp->sensor_curr->name, framefmt.width, framefmt.height);
+
+       ret = v4l2_subdev_call(isp->sensor_curr, video,
+                                               try_mbus_fmt, &framefmt);
+       if (ret)
+               goto exit_unlock;
+
+       f->fmt.pix.width = framefmt.width;
+       f->fmt.pix.height = framefmt.height;
+
+       w = f->fmt.pix.width;
+       h = f->fmt.pix.height;
+
+       if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565 ||
+           f->fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32) {
+               if (w < INTEL_MIN_WIDTH)
+                       w = INTEL_MIN_WIDTH;
+               if (w > INTEL_MAX_WIDTH)
+                       w = INTEL_MAX_WIDTH;
+               if (h < INTEL_MIN_HEIGHT)
+                       h = INTEL_MIN_HEIGHT;
+               if (h > INTEL_MAX_HEIGHT)
+                       h = INTEL_MAX_HEIGHT;
+               f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
+       } else {
+               if (w < INTEL_MIN_WIDTH)
+                       w = INTEL_MIN_WIDTH;
+               if (w > INTEL_MAX_WIDTH_MP)
+                       w = INTEL_MAX_WIDTH_MP;
+               if (h < INTEL_MIN_HEIGHT)
+                       h = INTEL_MIN_HEIGHT;
+               if (h > INTEL_MAX_HEIGHT_MP)
+                       h = INTEL_MAX_HEIGHT_MP;
+               f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+       }
+
+       f->fmt.pix.width = w;
+       f->fmt.pix.height = h;
+
+       f->fmt.pix.field = V4L2_FIELD_NONE;
+       f->fmt.pix.bytesperline = (w * h)/8;
+       if (fmt)
+               f->fmt.pix.sizeimage = (w * h * fmt->depth)/8;
+       if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG)
+               f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
+       f->fmt.pix.priv = 0;
+
+       dprintk(3, "after w = %d, h = %d", w, h);
+       ret = 0;
+
+exit_unlock:
+       mutex_unlock(&isp->mutex);
+
+       return ret;
+}
+
+static int mrst_isp_s_fmt_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct video_device *dev = video_devdata(file);
+       struct mrst_isp_device *isp = video_get_drvdata(dev);
+       struct intel_fmt *fmt;
+       struct v4l2_mbus_framefmt framefmt;
+       int ret;
+       unsigned int width_o, height_o;
+       unsigned short width_sensor, height_sensor;
+       unsigned int w, h;
+
+       mipi_flag = 1;
+
+       w = f->fmt.pix.width;
+       h = f->fmt.pix.height;
+
+       if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565 ||
+           f->fmt.pix.pixelformat == V4L2_PIX_FMT_BGR32) {
+               if (w < INTEL_MIN_WIDTH)
+                       w = INTEL_MIN_WIDTH;
+               if (w > INTEL_MAX_WIDTH)
+                       w = INTEL_MAX_WIDTH;
+               if (h < INTEL_MIN_HEIGHT)
+                       h = INTEL_MIN_HEIGHT;
+               if (h > INTEL_MAX_HEIGHT)
+                       h = INTEL_MAX_HEIGHT;
+               f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
+       } else {
+               if (w < INTEL_MIN_WIDTH)
+                       w = INTEL_MIN_WIDTH;
+               if (w > INTEL_MAX_WIDTH_MP)
+                       w = INTEL_MAX_WIDTH_MP;
+               if (h < INTEL_MIN_HEIGHT)
+                       h = INTEL_MIN_HEIGHT;
+               if (h > INTEL_MAX_HEIGHT_MP)
+                       h = INTEL_MAX_HEIGHT_MP;
+               f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+       }
+
+       f->fmt.pix.width = w;
+       f->fmt.pix.height = h;
+
+       width_o = f->fmt.pix.width;
+       height_o = f->fmt.pix.height;
+
+       ci_sensor_res2size(to_sensor_config(isp->sensor_curr)->res,
+                                &width_sensor, &height_sensor);
+
+       ret = mrst_isp_try_fmt_cap(file, priv, f);
+       if (0 != ret) {
+               printk(KERN_ERR "mrstisp: set format failed\n");
+               return ret;
+       }
+
+       /* init v4l2_mbus_framefmt */
+       framefmt.width = f->fmt.pix.width;
+       framefmt.height = f->fmt.pix.height;
+       framefmt.field =  f->fmt.pix.field;
+       framefmt.colorspace = f->fmt.pix.colorspace;
+
+       /* set fmt for only sensor */
+       if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_MPEG) {
+               /* wakeup senosr first */
+               if (to_sensor_config(isp->sensor_curr)->type == SENSOR_TYPE_SOC)
+                       gpio_set_value(GPIO_STDBY1_PIN, 0);
+               else
+                       gpio_set_value(GPIO_STDBY2_PIN, 0);
+
+               ret = v4l2_subdev_call(isp->sensor_curr, video,
+                                                       s_mbus_fmt, &framefmt);
+               dprintk(1, "set fmt only for sensor (%d x %d)",
+                       f->fmt.pix.width, f->fmt.pix.height);
+               return ret;
+       }
+
+       if (isp->sys_conf.isp_hal_enable) {
+               /* set fmt for isp */
+               mutex_lock(&isp->mutex);
+               fmt = fmt_by_fourcc(f->fmt.pix.pixelformat);
+
+               isp->pixelformat = fmt->fourcc;
+               isp->depth = fmt->depth;
+
+               dprintk(1, "sensor (%d x %d)", width_sensor, height_sensor);
+               if (width_o < f->fmt.pix.width &&
+                   height_o < f->fmt.pix.height) {
+                       isp->bufwidth = width_o;
+                       isp->bufheight = height_o;
+               } else if (width_sensor < f->fmt.pix.width &&
+                          height_sensor < f->fmt.pix.height) {
+                       isp->bufwidth = width_sensor;
+                       isp->bufheight = height_sensor;
+                       f->fmt.pix.width = width_sensor;
+                       f->fmt.pix.height = height_sensor;
+               } else {
+                       isp->bufwidth = f->fmt.pix.width;
+                       isp->bufheight = f->fmt.pix.height;
+               }
+
+               if (to_sensor_config(isp->sensor_curr)->res ==
+                               SENSOR_RES_VGA_PLUS)
+                       if (isp->bufwidth >= VGA_SIZE_H &&
+                                       isp->bufheight >= VGA_SIZE_V) {
+                               isp->bufwidth = VGA_SIZE_H;
+                               isp->bufheight = VGA_SIZE_V;
+                       }
+
+               mutex_unlock(&isp->mutex);
+
+               dprintk(1, "set fmt only to isp: w %d, h%d, "
+                       "fourcc: %lx", isp->bufwidth,
+                       isp->bufheight, fmt->fourcc);
+       } else {
+               /* set fmt for both isp and sensor */
+               mutex_lock(&isp->mutex);
+               fmt = fmt_by_fourcc(f->fmt.pix.pixelformat);
+
+               isp->pixelformat = fmt->fourcc;
+               isp->depth = fmt->depth;
+               isp->bufwidth = width_o;
+               isp->bufheight = height_o;
+
+               mutex_unlock(&isp->mutex);
+
+               dprintk(1, "set fmt for isp : w%d, h%d, fourcc: %lx",
+                       isp->bufwidth, isp->bufheight, fmt->fourcc);
+               dprintk(1, "set fmt for sesnro : w%d, h%d, fourcc: %lx",
+                       f->fmt.pix.width, f->fmt.pix.height, fmt->fourcc);
+
+               /* wakeup senosr first */
+               if (to_sensor_config(isp->sensor_curr)->type == SENSOR_TYPE_SOC)
+                       gpio_set_value(GPIO_STDBY1_PIN, 0);
+               else
+                       gpio_set_value(GPIO_STDBY2_PIN, 0);
+
+               ret = v4l2_subdev_call(isp->sensor_curr, video,
+                                                       s_mbus_fmt, &framefmt);
+       }
+
+       return ret;
+}
+
+static int mrst_isp_enum_framesizes(struct file *file, void *priv,
+                                   struct v4l2_frmsizeenum *arg)
+{
+       struct video_device *dev = video_devdata(file);
+       struct mrst_isp_device *isp = video_get_drvdata(dev);
+       int ret;
+
+       ret = v4l2_subdev_call(isp->sensor_curr, video, enum_framesizes, arg);
+       return ret;
+}
+
+static int mrst_isp_enum_frameintervals(struct file *file, void *priv,
+                                       struct v4l2_frmivalenum *arg)
+{
+       struct video_device *dev = video_devdata(file);
+       struct mrst_isp_device *isp = video_get_drvdata(dev);
+       int ret;
+
+       ret = v4l2_subdev_call(isp->sensor_curr, video, enum_frameintervals,
+                              arg);
+       return ret;
+}
+
+static int mrst_isp_queryctrl(struct file *file, void *priv,
+       struct v4l2_queryctrl *c)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct mrst_isp_device *isp = video_get_drvdata(vdev);
+
+       if (!v4l2_subdev_call(isp->sensor_curr, core, queryctrl, c))
+               return 0;
+       else if (!v4l2_subdev_call(isp->motor, core, queryctrl, c))
+               return 0;
+
+       return -EINVAL;
+}
+
+static int mrst_isp_g_ctrl(struct file *file, void *priv,
+                          struct v4l2_control *c)
+{
+       struct video_device *dev = video_devdata(file);
+       struct mrst_isp_device *isp = video_get_drvdata(dev);
+       int ret;
+
+       if (c->id == V4L2_CID_FOCUS_ABSOLUTE) {
+               ret = v4l2_subdev_call(isp->motor, core, g_ctrl, c);
+               dprintk(2, "get focus from motor : %d", c->value);
+               return ret;
+       } else {
+               ret = v4l2_subdev_call(isp->sensor_curr, core, g_ctrl, c);
+               dprintk(2, "get other cotrol from senrsor : %d", c->value);
+               return ret;
+       }
+}
+
+static int mrst_isp_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
+{
+       struct video_device *dev = video_devdata(file);
+       struct mrst_isp_device *isp = video_get_drvdata(dev);
+
+       if (c->id == V4L2_CID_FOCUS_ABSOLUTE) {
+               dprintk(2, "setting focus %d to motor", c->value);
+               return v4l2_subdev_call(isp->motor, core, s_ctrl, c);
+       } else {
+               dprintk(2, "setting other ctrls, value = %d", c->value);
+               return v4l2_subdev_call(isp->sensor_curr, core, s_ctrl, c);
+       }
+}
+
+static int mrst_isp_index_to_camera(struct mrst_isp_device *isp, u32 index)
+{
+       int camera = MRST_CAMERA_NONE;
+
+       if (isp->sensor_soc && isp->sensor_raw) {
+               switch (index) {
+               case 0:
+                       camera = isp->sensor_soc_index;
+                       break;
+               case 1:
+                       camera = isp->sensor_raw_index;
+                       break;
+               }
+       } else if (isp->sensor_soc) {
+               switch (index) {
+               case 0:
+                       camera = isp->sensor_soc_index;
+                       break;
+               }
+       } else if (isp->sensor_raw) {
+               switch (index) {
+               case 0:
+                       camera = isp->sensor_raw_index;
+                       break;
+               }
+       }
+
+       return camera;
+}
+
+static int mrst_isp_enum_input(struct file *file, void *priv,
+                           struct v4l2_input *i)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct mrst_isp_device *isp = video_get_drvdata(vdev);
+       int camera;
+
+       camera = mrst_isp_index_to_camera(isp, i->index);
+       if (MRST_CAMERA_NONE == camera)
+               return -EINVAL;
+
+       i->type = V4L2_INPUT_TYPE_CAMERA;
+       i->std = V4L2_STD_UNKNOWN;
+       strlcpy(i->name, mrst_camera_table[camera].name, sizeof(i->name));
+
+       return 0;
+}
+
+static int mrst_isp_g_input(struct file *file, void *priv, unsigned int *i)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct mrst_isp_device *isp = video_get_drvdata(vdev);
+
+       if (isp->sensor_soc && isp->sensor_raw)
+               if (isp->sensor_curr == isp->sensor_soc)
+                       *i = 0;
+               else
+                       *i = 1;
+       else
+               *i = 0;
+
+       return 0;
+}
+
+static int mrst_isp_s_input(struct file *file, void *priv, unsigned int i)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct mrst_isp_device *isp = video_get_drvdata(vdev);
+
+       int camera;
+
+       if (isp->streaming) {
+               printk(KERN_WARNING "VIDIOC_S_INPUT error: ISP is streaming\n");
+               return -EBUSY;
+       }
+
+       camera = mrst_isp_index_to_camera(isp, i);
+       if (MRST_CAMERA_NONE == camera)
+               return -EINVAL;
+
+       if (mrst_camera_table[camera].type == MRST_CAMERA_SOC)
+               isp->sensor_curr = isp->sensor_soc;
+       else
+               isp->sensor_curr = isp->sensor_raw;
+
+       dprintk(1, "set sensor %s as input", isp->sensor_curr->name);
+
+       return 0;
+}
+
+static int mrst_isp_g_ext_ctrls(struct file *file,
+                            void *fh,
+                            struct v4l2_ext_controls *c)
+{
+       struct video_device *dev = video_devdata(file);
+       struct mrst_isp_device *isp = video_get_drvdata(dev);
+
+       int ret = -EINVAL;
+
+       if (c->ctrl_class != V4L2_CTRL_CLASS_CAMERA) {
+               printk(KERN_ERR "Invalid control class\n");
+               return ret;
+       }
+
+       c->error_idx = 0;
+       if (isp->motor) {
+               ret = v4l2_subdev_call(isp->motor, core, g_ext_ctrls, c);
+               if (c->error_idx) {
+                       printk(KERN_ERR "mrst: error call g_ext_ctrls\n");
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int mrst_isp_s_ext_ctrls(struct file *file, void *fh,
+                            struct v4l2_ext_controls *c)
+{
+       struct video_device *dev = video_devdata(file);
+       struct mrst_isp_device *isp = video_get_drvdata(dev);
+
+       int ret = -EINVAL;
+
+       if (c->ctrl_class != V4L2_CTRL_CLASS_CAMERA) {
+               printk(KERN_INFO "Invalid control class\n");
+               return ret;
+       }
+
+       c->error_idx = 0;
+       if (isp->motor) {
+               ret = v4l2_subdev_call(isp->motor, core, s_ext_ctrls, c);
+               if (c->error_idx) {
+                       printk(KERN_ERR "mrst: error call s_ext_ctrls\n");
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int mrst_isp_querycap(struct file *file, void  *priv,
+       struct v4l2_capability *cap)
+{
+       struct video_device *dev = video_devdata(file);
+
+       strlcpy(cap->driver, DRIVER_NAME, sizeof(cap->driver));
+       strlcpy(cap->card, dev->name, sizeof(cap->card));
+
+       cap->version = INTEL_VERSION(0, 5, 0);
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+       return 0;
+}
+
+static int mrst_isp_cropcap(struct file *file, void *priv,
+                                       struct v4l2_cropcap *cap)
+{
+       struct video_device *dev = video_devdata(file);
+       struct mrst_isp_device *isp = video_get_drvdata(dev);
+
+       if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       cap->bounds.left = 0;
+       cap->bounds.top = 0;
+       cap->bounds.width = isp->bufwidth;
+       cap->bounds.height = isp->bufheight;
+       cap->defrect = cap->bounds;
+       cap->pixelaspect.numerator   = 1;
+       cap->pixelaspect.denominator = 1;
+
+       return 0;
+}
+
+static int mrst_isp_enum_fmt_cap(struct file *file, void  *priv,
+                                       struct v4l2_fmtdesc *f)
+{
+       struct video_device *dev = video_devdata(file);
+       struct mrst_isp_device *isp = video_get_drvdata(dev);
+
+       unsigned int index;
+
+       index = f->index;
+
+       if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       if (isp->sensor_curr == isp->sensor_soc)
+               if (index >= 8)
+                       return -EINVAL;
+       if (index >= sizeof(fmts) / sizeof(*fmts))
+               return -EINVAL;
+
+       f->index = index;
+       f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       strlcpy(f->description, fmts[index].name,
+               sizeof(f->description));
+       f->pixelformat = fmts[index].fourcc;
+       if (fmts[index].fourcc == V4L2_PIX_FMT_JPEG)
+               f->flags = V4L2_FMT_FLAG_COMPRESSED;
+
+       return 0;
+
+}
+
+#define ALIGN4(x)       ((((long)(x)) & 0x3) == 0)
+
+static int mrst_isp_reqbufs(struct file *file, void *priv,
+               struct v4l2_requestbuffers *req)
+{
+       int ret;
+       struct mrst_isp_fh  *fh = file->private_data;
+       struct video_device *dev = video_devdata(file);
+       struct mrst_isp_device *isp = video_get_drvdata(dev);
+
+       if (req->count == 0)
+               return 0;
+
+       if (req->memory != V4L2_MEMORY_MMAP) {
+               eprintk("wrong memory type");
+               return -EINVAL;
+       }
+       ret = videobuf_reqbufs(&fh->vb_q, req);
+       if (ret)
+               eprintk("err calling videobuf_reqbufs ret = %d", ret);
+
+       if (!ret)
+               isp->buffer_required = 1;
+
+       return ret;
+}
+
+static int mrst_isp_querybuf(struct file *file, void *priv,
+                                       struct v4l2_buffer *buf)
+{
+       int ret;
+       struct mrst_isp_fh  *fh = file->private_data;
+
+       ret = videobuf_querybuf(&fh->vb_q, buf);
+       return ret;
+}
+
+static int mrst_isp_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       int ret;
+       struct mrst_isp_fh  *fh = file->private_data;
+
+       ret = videobuf_qbuf(&fh->vb_q, buf);
+       /* identify which video buffer was q-ed */
+       if (ret == 0)
+               fh->qbuf_flag |= (1<<buf->index);
+       dprintk(1, "q-ed index = %d", buf->index);
+
+       return ret;
+}
+
+static int mrst_isp_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+       int ret;
+       struct mrst_isp_fh  *fh = file->private_data;
+
+       if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (b->memory != V4L2_MEMORY_MMAP)
+               return -EINVAL;
+       if (fh->qbuf_flag == 0) {
+               dprintk(1, "no buffer can be dq-ed\n");
+               return -EINVAL;
+       }
+
+       ret = videobuf_dqbuf(&fh->vb_q, b, 0);
+       if (ret == 0)
+               fh->qbuf_flag &= ~(1<<b->index);
+
+       ++frame_cnt;
+
+       dprintk(1, "dq-ed index = %d", b->index);
+       return ret;
+}
+
+static int mrst_isp_streamon(struct file *file, void *priv,
+                            enum v4l2_buf_type type)
+{
+       struct mrst_isp_fh  *fh = file->private_data;
+       struct video_device *dev = video_devdata(file);
+       struct mrst_isp_device *isp = video_get_drvdata(dev);
+       int ret;
+
+       if (!isp->buffer_required) {
+               eprintk("buffer is not required, can not stream on ");
+               return -EINVAL;
+       }
+
+       dprintk(2, "gamma2 = %d", isp->sys_conf.isp_cfg.flags.gamma2);
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       mutex_lock(&isp->mutex);
+
+       if (!to_sensor_config(isp->sensor_curr)->mipi_mode)
+               v4l2_subdev_call(isp->sensor_curr, video, s_stream, 1);
+
+       mrst_isp_dp_init(&isp->sys_conf, to_sensor_config(isp->sensor_curr));
+       mrst_isp_setup_viewfinder_path(isp,
+                                      to_sensor_config(isp->sensor_curr), -1);
+
+       ret = videobuf_streamon(&fh->vb_q);
+       isp->streaming = 1;
+
+       mutex_unlock(&isp->mutex);
+
+       dprintk(1, "isp->active = %p", isp->active);
+       return ret;
+}
+
+static int mrst_isp_streamoff(struct file *file, void *priv,
+                             enum v4l2_buf_type type)
+{
+       struct mrst_isp_fh  *fh = file->private_data;
+       struct video_device *dev = video_devdata(file);
+       struct mrst_isp_device *isp = video_get_drvdata(dev);
+
+       unsigned long flags;
+       int ret;
+
+       if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       mutex_lock(&isp->mutex);
+
+       ret = videobuf_streamoff(&fh->vb_q);
+       dprintk(1, "ret of videobuf_streamoff = %d", ret);
+       isp->streaming = 0;
+
+       spin_lock_irqsave(&isp->lock, flags);
+       INIT_LIST_HEAD(&isp->capture);
+       isp->active = NULL;
+       isp->next = NULL;
+       isp->stopflag = 0;
+       isp->sys_conf.isp_hal_enable = 0;
+       isp->sys_conf.jpg_review_enable = 0;
+       isp->sys_conf.isp_cfg.img_eff_cfg.mode = CI_ISP_IE_MODE_OFF;
+       isp->sys_conf.isp_cfg.jpeg_enc_ratio = 1;
+
+       spin_unlock_irqrestore(&isp->lock, flags);
+
+       v4l2_subdev_call(isp->sensor_curr, video, s_stream, 0);
+
+       /* sensor standby */
+       if (isp->sensor_curr) {
+               if (to_sensor_config(isp->sensor_curr)->type == SENSOR_TYPE_SOC)
+                       gpio_set_value(GPIO_STDBY1_PIN, 0);
+               else
+                       gpio_set_value(GPIO_STDBY2_PIN, 0);
+       }
+
+       ci_isp_stop(CI_ISP_CFG_UPDATE_FRAME_SYNC);
+
+       mutex_unlock(&isp->mutex);
+       return ret;
+}
+
+static const struct v4l2_file_operations mrst_isp_fops = {
+       .owner = THIS_MODULE,
+       .open = mrst_isp_open,
+       .release = mrst_isp_close,
+       .mmap = mrst_isp_mmap,
+       .ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops mrst_isp_ioctl_ops = {
+       .vidioc_querycap                = mrst_isp_querycap,
+       .vidioc_enum_fmt_vid_cap        = mrst_isp_enum_fmt_cap,
+       .vidioc_g_fmt_vid_cap           = mrst_isp_g_fmt_cap,
+       .vidioc_try_fmt_vid_cap         = mrst_isp_try_fmt_cap,
+       .vidioc_s_fmt_vid_cap           = mrst_isp_s_fmt_cap,
+       .vidioc_cropcap                 = mrst_isp_cropcap,
+       .vidioc_reqbufs                 = mrst_isp_reqbufs,
+       .vidioc_querybuf                = mrst_isp_querybuf,
+       .vidioc_qbuf                    = mrst_isp_qbuf,
+       .vidioc_dqbuf                   = mrst_isp_dqbuf,
+       .vidioc_enum_input              = mrst_isp_enum_input,
+       .vidioc_g_input                 = mrst_isp_g_input,
+       .vidioc_s_input                 = mrst_isp_s_input,
+       .vidioc_queryctrl               = mrst_isp_queryctrl,
+       .vidioc_streamon                = mrst_isp_streamon,
+       .vidioc_streamoff               = mrst_isp_streamoff,
+       .vidioc_g_ctrl                  = mrst_isp_g_ctrl,
+       .vidioc_s_ctrl                  = mrst_isp_s_ctrl,
+       .vidioc_enum_framesizes         = mrst_isp_enum_framesizes,
+       .vidioc_enum_frameintervals     = mrst_isp_enum_frameintervals,
+       .vidioc_g_ext_ctrls             = mrst_isp_g_ext_ctrls,
+       .vidioc_s_ext_ctrls             = mrst_isp_s_ext_ctrls,
+       /* fixme: private ioctls */
+       .vidioc_default                 = mrst_isp_vidioc_default,
+};
+
+static struct video_device mrst_isp_vdev = {
+       .name                           = "mrst_isp",
+       .minor                          = -1,
+       .fops                           = &mrst_isp_fops,
+       .ioctl_ops                      = &mrst_isp_ioctl_ops,
+       .release                        = video_device_release_empty,
+};
+
+static int mrst_ci_sensor_probe(struct mrst_isp_device *isp)
+{
+       struct v4l2_subdev *sensor = NULL, *motor = NULL;
+       struct ci_sensor_config *info_soc = NULL, *info_raw = NULL;
+       int i;
+       char *name;
+       u8 addr;
+
+       isp->adapter_sensor = i2c_get_adapter(MRST_I2C_BUS_SENSOR);
+       if (NULL == isp->adapter_sensor) {
+               printk(KERN_ERR "mrstisp: no sensor i2c adapter\n");
+               return -ENODEV;
+       }
+
+       dprintk(1, "got sensor i2c adapter: %s", isp->adapter_sensor->name);
+
+       gpio_request(GPIO_STDBY1_PIN, "Sensor Standby1");
+       gpio_request(GPIO_STDBY2_PIN, "Sensor Standby2");
+       gpio_request(GPIO_RESET_PIN, "Sensor Reset");
+       gpio_request(GPIO_SCLK_25, "Sensor clock");
+       gpio_request(95, "Camera Motor");
+
+       /* Enable sensor related GPIO in system */
+       gpio_direction_output(GPIO_STDBY1_PIN, 0);
+       gpio_direction_output(GPIO_STDBY2_PIN, 0);
+       gpio_direction_output(GPIO_RESET_PIN, 1);
+       gpio_direction_output(GPIO_SCLK_25, 0);
+
+       for (i = 0; i < N_CAMERA; i++) {
+               name = mrst_camera_table[i].name;
+               addr = mrst_camera_table[i].sensor_addr;
+               if (mrst_camera_table[i].type == MRST_CAMERA_SOC) {
+                       /* wakeup soc senosr first */
+                       gpio_set_value(GPIO_STDBY1_PIN, 0);
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31))
+                       sensor = v4l2_i2c_new_subdev(&isp->v4l2_dev,
+                                                    isp->adapter_sensor,
+                                                    name, name, addr);
+#else
+                       sensor = v4l2_i2c_new_subdev(&isp->v4l2_dev,
+                                                    isp->adapter_sensor,
+                                                    name, name, addr, NULL);
+#endif
+                       /* standby soc senosr first */
+                       gpio_set_value(GPIO_STDBY1_PIN, 1);
+
+                       if (sensor == NULL) {
+                               dprintk(2, "sensor %s not found", name);
+                               continue;
+                       }
+                       isp->sensor_soc = sensor;
+                       isp->sensor_soc_index = i;
+                       dprintk(0, "soc camera sensor %s-%s successfully found",
+                               name, sensor->name);
+               }
+
+               if (mrst_camera_table[i].type == MRST_CAMERA_RAW) {
+                       /* wakeup raw senosr first */
+                       gpio_set_value(GPIO_STDBY2_PIN, 0);
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31))
+                       sensor = v4l2_i2c_new_subdev(&isp->v4l2_dev,
+                                                    isp->adapter_sensor,
+                                                    name, name, addr);
+#else
+                       sensor = v4l2_i2c_new_subdev(&isp->v4l2_dev,
+                                                    isp->adapter_sensor,
+                                                    name, name, addr, NULL);
+#endif
+                       /* standby raw senosr first */
+                       gpio_set_value(GPIO_STDBY2_PIN, 1);
+
+                       if (sensor == NULL) {
+                               dprintk(2, "sensor %s not found", name);
+                               continue;
+                       }
+                       isp->sensor_raw = sensor;
+                       isp->sensor_raw_index = i;
+                       dprintk(0, "raw camera sensor %s successfully found",
+                               name);
+
+                       name = mrst_camera_table[i].motor_name;
+                       addr = mrst_camera_table[i].motor_addr;
+                       /* wakeup ov5630 af hw first */
+                       if (!strcmp(name, "ov5630_motor"))
+                               gpio_direction_output(GPIO_AF_PD, 1);
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31))
+                       motor = v4l2_i2c_new_subdev(&isp->v4l2_dev,
+                                                   isp->adapter_sensor,
+                                                   name, name, addr);
+#else
+                       motor = v4l2_i2c_new_subdev(&isp->v4l2_dev,
+                                                   isp->adapter_sensor,
+                                                   name, name, addr, NULL);
+#endif
+
+                       if (motor == NULL)
+                               dprintk(2, "motor %s not found", name);
+                       else {
+                               isp->motor = motor;
+                               dprintk(0, "motor %s successfully found", name);
+                       }
+               }
+       }
+
+       if (!isp->sensor_soc && !isp->sensor_raw) {
+               dprintk(0, "no camera sensor device attached");
+               return -ENODEV;
+       } else {
+               if (isp->sensor_raw) {
+                       info_raw = to_sensor_config(isp->sensor_raw);
+                       name = mrst_camera_table[isp->sensor_raw_index].name;
+                       strlcpy(info_raw->name, name, strlen(name) + 1);
+                       dprintk(1, "raw camera sensor %s", info_raw->name);
+                       mrstisp_snr_conf_init(info_raw);
+               }
+               if (isp->sensor_soc) {
+                       info_soc = to_sensor_config(isp->sensor_soc);
+                       name = mrst_camera_table[isp->sensor_soc_index].name;
+                       strlcpy(info_soc->name, name, strlen(name) + 1);
+                       dprintk(1, "soc camera sensor %s", info_soc->name);
+                       mrstisp_snr_conf_init(info_soc);
+                       isp->sensor_curr = isp->sensor_soc;
+               } else
+                       isp->sensor_curr = isp->sensor_raw;
+               return 0;
+       }
+}
+
+static int mrst_ci_flash_probe(struct mrst_isp_device *isp)
+{
+       struct v4l2_subdev *flash = NULL;
+       char *name = "mrst_camera_flash";
+
+       gpio_request(45, "Camera Flash");
+       gpio_direction_output(45, 0);
+
+       isp->adapter_flash = i2c_get_adapter(MRST_I2C_BUS_FLASH);
+       if (NULL == isp->adapter_flash) {
+               dprintk(0, "no flash i2c adapter\n");
+               return -ENODEV;
+       }
+
+       dprintk(1, "got flash i2c adapter: %s", isp->adapter_flash->name);
+
+#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31))
+       flash = v4l2_i2c_new_subdev(&isp->v4l2_dev,
+                                   isp->adapter_flash,
+                                   name, name, 0x53);
+#else
+       flash = v4l2_i2c_new_subdev(&isp->v4l2_dev,
+                                   isp->adapter_flash,
+                                   name, name, 0x53, NULL);
+#endif
+
+       if (flash == NULL) {
+               dprintk(0, "no flash IC found\n");
+               return -ENODEV;
+       }
+
+       dprintk(0, "flash IC found");
+       return 0;
+}
+
+static irqreturn_t mrst_isp_irq_handler(int this_irq, void *dev_id)
+{
+       struct isp_register *mrv_reg =
+           (struct isp_register *) MEM_MRV_REG_BASE;
+       struct mrst_isp_device *isp = dev_id;
+       struct videobuf_buffer *vb;
+       unsigned long flags;
+
+       u32     mi_mask = ci_isp_get_frame_end_irq_mask_isp();
+       u32     isp_mask = MRV_ISP_RIS_DATA_LOSS_MASK
+           | MRV_ISP_RIS_PIC_SIZE_ERR_MASK;
+       u32     jpe_status_mask = MRV_JPE_ALL_STAT_MASK;
+       u32     jpe_error_mask = MRV_JPE_ALL_ERR_MASK;
+       u32     mblk_line_mask = MRV_MI_MBLK_LINE_MASK;
+
+       u32     isp_irq;
+       u32     mi_irq;
+       u32     jpe_status_irq;
+       u32     jpe_error_irq;
+       u32     mipi_irq;
+       u32     mblk_line;
+       u32     bufbase;
+
+       isp_irq = REG_READ_EX(mrv_reg->isp_ris) & isp_mask;
+       mi_irq = REG_READ_EX(mrv_reg->mi_ris) & mi_mask;
+
+       mblk_line = REG_READ_EX(mrv_reg->mi_ris) & mblk_line_mask;
+
+       jpe_status_irq = REG_READ_EX(mrv_reg->jpe_status_ris) & jpe_status_mask;
+       jpe_error_irq = REG_READ_EX(mrv_reg->jpe_error_ris) & jpe_error_mask;
+
+       mipi_irq = REG_READ_EX(mrv_reg->mipi_ris) & 0x00f00000;
+
+       dprintk(3, "IRQ: mblk_line = %x, mi_irq = %x, jpe_status_irq = %x,"
+               " jpe_error_irq = %x, isp_irq = %x", mblk_line, mi_irq,
+               jpe_status_irq, jpe_error_irq, isp_irq);
+
+       if (!(isp_irq | mi_irq | jpe_status_irq | jpe_error_irq | mblk_line
+             | mipi_irq)) {
+               dprintk(2, "unknown interrupt");
+               return IRQ_HANDLED;
+       }
+
+       REG_SET_SLICE_EX(mrv_reg->isp_icr, MRV_ISP_ICR_ALL, ON);
+       REG_SET_SLICE_EX(mrv_reg->mi_icr, MRV_MI_ALLIRQS, ON);
+       REG_SET_SLICE_EX(mrv_reg->jpe_error_icr, MRV_JPE_ALL_ERR, ON);
+       REG_SET_SLICE_EX(mrv_reg->jpe_status_icr, MRV_JPE_ALL_STAT, ON);
+       REG_WRITE_EX(mrv_reg->mipi_icr, 0xffffffff);
+
+       if (isp_irq) {
+               /* Currently we don't reset hardware even error detect */
+               dprintk(3, "ISP error IRQ received %x", isp_irq);
+               isp_error_num++;
+               isp_error_flag |= isp_irq;
+               return IRQ_HANDLED;
+       }
+
+       if (mipi_irq) {
+               dprintk(3, "error in mipi_irq %x", mipi_irq);
+               mipi_error_num++;
+               mipi_error_flag |= mipi_irq;
+               return IRQ_HANDLED;
+       }
+
+       if (mblk_line && mrst_isp_to_do_mblk_line) {
+               REG_SET_SLICE(mrv_reg->mi_imsc, MRV_MI_MBLK_LINE, OFF);
+               dprintk(3, "enter mblk_line irq");
+
+               if (!(isp->active && !isp->next)) {
+                       dprintk(3, "wrong isq status");
+                       if (isp->active)
+                               dprintk(2, "actie->i = %d", isp->active->i);
+                       else
+                               dprintk(2, "actie = NULL");
+                       if (isp->next)
+                               dprintk(2, "next->i = %d", isp->next->i);
+                       else
+                               dprintk(2, "next = NULL");
+                       return IRQ_HANDLED;
+               }
+
+               spin_lock_irqsave(&isp->lock, flags);
+
+               if (!list_empty(&isp->capture)) {
+                       isp->next = list_entry(isp->capture.next,
+                                              struct videobuf_buffer, queue);
+                       isp->next->state = VIDEOBUF_ACTIVE;
+                       bufbase = videobuf_to_dma_contig(isp->next);
+                       mrst_isp_update_marvinvfaddr(isp, bufbase,
+                                            CI_ISP_CFG_UPDATE_FRAME_SYNC);
+                       dprintk(1, "updating new addr, next = %d",
+                               isp->next->i);
+               } else {
+                       isp->stopflag = 1;
+                       dprintk(1, "stop isp");
+               }
+
+               mrst_isp_to_do_mblk_line = 0;
+
+               spin_unlock_irqrestore(&isp->lock, flags);
+
+       }
+
+       if (mi_irq && isp->pixelformat != V4L2_PIX_FMT_JPEG &&
+           !jpe_status_irq) {
+               dprintk(1, "view finding case");
+
+               if (!isp->active) {
+                       dprintk(0, "no active queue, You should not go here");
+                       mrst_isp_to_do_mblk_line = 1;
+                       REG_SET_SLICE(mrv_reg->mi_imsc, MRV_MI_MBLK_LINE, ON);
+                       return IRQ_HANDLED;
+               }
+
+               spin_lock_irqsave(&isp->lock, flags);
+
+               /* update captured frame status */
+               vb = isp->active;
+               /* vb->size = ci_isp_mif_get_byte_cnt(); */
+               /* if this buffer has been dq-ed, set nothing to state*/
+               if (vb->state != VIDEOBUF_IDLE)
+                       vb->state = VIDEOBUF_DONE;
+               vb->field_count++;
+
+               isp->active = NULL;
+               dprintk(1, "buf %d size = %lx", vb->i, vb->size);
+               do_gettimeofday(&vb->ts);
+               wake_up(&vb->done);
+
+               if (!isp->next) {
+                       if (!list_empty(&isp->capture)) {
+                               isp->active = list_entry(isp->capture.next,
+                                                struct videobuf_buffer, queue);
+                               list_del_init(&isp->active->queue);
+                               isp->active->state = VIDEOBUF_ACTIVE;
+                               dprintk(3, "start next frame %d",
+                                       isp->active->i);
+                               mrst_isp_to_do_mblk_line = 1;
+                               REG_SET_SLICE(mrv_reg->mi_imsc,
+                                             MRV_MI_MBLK_LINE, ON);
+                       } else {
+                               mrst_isp_to_do_mblk_line = 1;
+                               REG_SET_SLICE(mrv_reg->mi_imsc,
+                                                MRV_MI_MBLK_LINE, ON);
+                               mrst_isp_disable_interrupt(isp);
+                               dprintk(3, "no frame right now");
+                       }
+               } else {
+                       isp->active = isp->next;
+                       list_del_init(&isp->next->queue);
+                       isp->next = NULL;
+                       dprintk(1, "active = next = %d, next = NULL",
+                               isp->active->i);
+                       mrst_isp_to_do_mblk_line = 1;
+                       REG_SET_SLICE(mrv_reg->mi_imsc, MRV_MI_MBLK_LINE, ON);
+               }
+
+               spin_unlock_irqrestore(&isp->lock, flags);
+               return IRQ_HANDLED;
+       }
+
+       if (jpe_status_irq) {
+               dprintk(2, "jpeg capture case");
+               if (!isp->active)
+                       return IRQ_HANDLED;
+
+               spin_lock_irqsave(&isp->lock, flags);
+
+               vb = isp->active;
+               vb->size = ci_isp_mif_get_byte_cnt();
+               vb->state = VIDEOBUF_DONE;
+               do_gettimeofday(&vb->ts);
+               vb->field_count++;
+               wake_up(&vb->done);
+               isp->active = NULL;
+
+               dprintk(2, "index =%d, bufsize = %lx", vb->i, vb->size);
+
+               spin_unlock_irqrestore(&isp->lock, flags);
+
+               return IRQ_HANDLED;
+       }
+
+       if (jpe_error_irq)
+               dprintk(2, "entered jpe_error_irq");
+
+       return IRQ_HANDLED;
+}
+
+static void __devexit mrst_isp_pci_remove(struct pci_dev *pdev)
+{
+       struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
+       struct mrst_isp_device *isp = to_isp(v4l2_dev);
+
+       ci_isp_stop(CI_ISP_CFG_UPDATE_FRAME_SYNC);
+       mrst_isp_disable_interrupt(isp);
+
+       free_irq(pdev->irq, isp);
+
+       if (isp->vdev) {
+               dprintk(2, "isp->vdev = %p", isp->vdev);
+               video_unregister_device(isp->vdev);
+       }
+
+       dma_release_declared_memory(&pdev->dev);
+       iounmap(isp->regs);
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       v4l2_device_unregister(&isp->v4l2_dev);
+       kfree(isp);
+
+}
+
+static int __devinit mrst_isp_pci_probe(struct pci_dev *pdev,
+                                       const struct pci_device_id *pci_id)
+{
+       struct mrst_isp_device *isp;
+       unsigned int start = 0;
+       unsigned int len = 0;
+       int ret = 0;
+
+       /* alloc device struct */
+       isp = kzalloc(sizeof(struct mrst_isp_device), GFP_KERNEL);
+       if (NULL == isp) {
+               printk(KERN_ERR "mrstisp: fail to kzalloc mrst_isp_device\n");
+               ret = -ENOMEM;
+               goto exit;
+       }
+
+       /* register v4l2 device */
+       ret = v4l2_device_register(&pdev->dev, &isp->v4l2_dev);
+       if (ret) {
+               printk(KERN_ERR "mrstisp: fail to register v4l2 device\n");
+               goto exit_free_isp;
+       }
+
+       /* PCI operations */
+       ret = pci_enable_device(pdev);
+       if (ret) {
+               printk(KERN_ERR "mrstisp: can't enable isp\n");
+               goto exit_unregister_v4l2;
+       }
+
+       pci_set_master(pdev);
+
+       ret = pci_request_regions(pdev, "mrst isp");
+       if (ret) {
+               printk(KERN_ERR "mrstisp: can't request regions\n");
+               goto exit_disable_isp;
+       }
+
+       /* mem bar 0 */
+       start = isp->mb0 = pci_resource_start(pdev, 0);
+       len = isp->mb0_size = pci_resource_len(pdev, 0);
+
+       isp->regs = ioremap_nocache(start, len);
+       mrst_isp_regs = isp->regs;
+       if (isp->regs == NULL) {
+               printk(KERN_ERR "mrstisp: fail to ioremap isp registers\n");
+               goto exit_release_regions;
+       }
+
+       dprintk(1, "isp mb0 = %lx, mb0_size = %lx, regs = %p",
+               isp->mb0, isp->mb0_size, isp->regs);
+
+       /* mem bar 1 */
+       start = isp->mb1 = pci_resource_start(pdev, 1);
+       len = isp->mb1_size = pci_resource_len(pdev, 1);
+
+       dprintk(1, "isp mb1 = %lx, mb1_size = %lx", isp->mb1, isp->mb1_size);
+
+       ret = dma_declare_coherent_memory(&pdev->dev, start,
+                                         start, len,
+                                         DMA_MEMORY_MAP);
+       if (!ret) {
+               dprintk(0, "failed to declare dma memory");
+               ret = -ENXIO;
+               goto exit_iounmap;
+       }
+
+       /* init device struct */
+       INIT_LIST_HEAD(&isp->capture);
+       spin_lock_init(&isp->lock);
+       mutex_init(&isp->mutex);
+
+       pci_read_config_word(pdev, PCI_VENDOR_ID, &isp->vendorID);
+       pci_read_config_word(pdev, PCI_DEVICE_ID, &isp->deviceID);
+
+       mrst_isp_defcfg_all_load(&isp->sys_conf.isp_cfg);
+
+       isp->bufwidth = 640;
+       isp->bufheight = 480;
+       isp->depth = 12;
+       isp->pixelformat = V4L2_PIX_FMT_YVU420;
+       isp->streaming = 0;
+       isp->buffer_required = 0;
+
+
+       /* probe sensor */
+       ret = mrst_ci_sensor_probe(isp);
+       if (ret) {
+               dprintk(0, "failed to sensor probe\n");
+               goto exit_dma_release;
+       }
+
+       /* regiter video device */
+       isp->vdev = &mrst_isp_vdev;
+       isp->vdev->parent = &pdev->dev;
+       video_set_drvdata(isp->vdev, isp);
+
+       ret = video_register_device(isp->vdev, VFL_TYPE_GRABBER, -1);
+       if (ret) {
+               dprintk(0, "fail to register video deivice");
+               goto exit_dma_release;
+       }
+
+       dprintk(0, "registered dev/video%d", isp->vdev->num);
+       dprintk(0, "isp->vdev = %p", isp->vdev);
+
+#if IRQ
+       /* request irq */
+       ret = request_irq(pdev->irq, mrst_isp_irq_handler, IRQF_SHARED,
+                         "mrst_camera_imaging", isp);
+       if (ret) {
+               dprintk(0, "fail to request irq");
+               goto exit_unregister_video;
+       }
+
+       mrst_isp_disable_interrupt(isp);
+#endif
+
+       /* probe flash */
+       mrst_ci_flash_probe(isp);
+
+       mrst_isp_to_do_mblk_line = 0;
+
+       dprintk(0, "mrstisp driver module successfully loaded");
+       return 0;
+
+exit_unregister_video:
+       video_unregister_device(isp->vdev);
+exit_dma_release:
+       dma_release_declared_memory(&pdev->dev);
+exit_iounmap:
+       iounmap(isp->regs);
+exit_release_regions:
+       pci_release_regions(pdev);
+exit_disable_isp:
+       pci_disable_device(pdev);
+exit_unregister_v4l2:
+       v4l2_device_unregister(&isp->v4l2_dev);
+exit_free_isp:
+       kfree(isp);
+exit:
+       return ret;
+}
+
+#ifdef CONFIG_PM
+static int mrst_isp_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       int ret;
+
+       ci_isp_off();
+
+       ret = pci_save_state(pdev);
+       if (ret) {
+               printk(KERN_ERR "mrstisp: pci_save_state failed %d\n", ret);
+               return ret;
+       }
+
+       ret = pci_set_power_state(pdev, PCI_D3cold);
+       if (ret) {
+               printk(KERN_ERR "mrstisp: fail to set power state\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int mrst_isp_pci_resume(struct pci_dev *pdev)
+{
+       int ret;
+       pci_set_power_state(pdev, PCI_D0);
+       pci_restore_state(pdev);
+
+       ret = pci_enable_device(pdev);
+       if (ret) {
+               printk(KERN_ERR "mrstisp: fail to enable device in resume\n");
+               return ret;
+       }
+
+       ci_isp_init();
+       return 0;
+}
+#endif
+
+static struct pci_device_id mrst_isp_pci_tbl[] __devinitdata = {
+       { PCI_DEVICE(0x8086, 0x080B) },
+       {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, mrst_isp_pci_tbl);
+
+static struct pci_driver mrst_isp_pci_driver = {
+       .name = "mrstisp",
+       .id_table = mrst_isp_pci_tbl,
+       .probe = mrst_isp_pci_probe,
+       .remove = mrst_isp_pci_remove,
+       #ifdef CONFIG_PM
+       .suspend = mrst_isp_pci_suspend,
+       .resume = mrst_isp_pci_resume,
+       #endif
+};
+
+static int __init mrst_isp_pci_init(void)
+{
+       int ret;
+       ret = pci_register_driver(&mrst_isp_pci_driver);
+       if (ret) {
+               printk(KERN_ERR "mrstisp: Unable to register driver\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static void __exit mrst_isp_pci_exit(void)
+{
+       pci_unregister_driver(&mrst_isp_pci_driver);
+}
+
+module_init(mrst_isp_pci_init);
+module_exit(mrst_isp_pci_exit);
+
+MODULE_DESCRIPTION("Intel Moorestown ISP driver");
+MODULE_AUTHOR("Xiaolin Zhang <xiaolin.zhang@intel.com>");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("video");
+