new file mode 100644
@@ -0,0 +1,10 @@
+config VIDEO_MRST_ISP
+ tristate "Moorstown Marvin - ISP Driver"
+ depends on VIDEO_V4L2
+ select VIDEOBUF_DMA_CONTIG
+ default y
+ ---help---
+ Say Y here if you want support for cameras based on the Intel Moorestown platform.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mrstisp.ko.
new file mode 100644
@@ -0,0 +1,7 @@
+mrstisp-objs := mrstisp_main.o mrstisp_hw.o mrstisp_isp.o \
+ mrstisp_dp.o mrstisp_mif.o mrstisp_jpe.o \
+ __mrstisp_private_ioctl.o
+
+obj-$(CONFIG_VIDEO_MRST_ISP) += mrstisp.o
+
+EXTRA_CFLAGS += -I$(src)/../include -I$(src)/include
new file mode 100644
@@ -0,0 +1,225 @@
+/*
+ * 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);
+
+ WARN_ON(priv != file->private_data);
+
+ 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);
+
+ WARN_ON(priv != file->private_data);
+
+ 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);
+
+ WARN_ON(priv != file->private_data);
+
+ 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);
+
+ WARN_ON(priv != file->private_data);
+
+ 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;
+
+ WARN_ON(priv != file->private_data);
+
+ 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;
+}
new file mode 100644
@@ -0,0 +1,2656 @@
+/*
+ * 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
+
+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 */
+ if (jpg_review->pix_fmt == V4L2_PIX_FMT_YUV420
+ || jpg_review->pix_fmt == 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;
+
+ } else if (jpg_review->pix_fmt == 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;
+
+ } else if (jpg_review->pix_fmt == 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;
+
+ } else {
+ printk(KERN_ERR "mrstisp: no support jpg review fmt\n");
+ }
+
+ /* 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 */
+ if (isp->pixelformat == V4L2_PIX_FMT_YUV420
+ || isp->pixelformat == 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;
+ } else if (isp->pixelformat == 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;
+ } else if (isp->pixelformat == 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;
+ } else {
+
+ 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;
+ }
+
+ /* 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;
+ (void)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;
+ (void)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);
+
+ (void)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;
+ }
+
+ DBG_leaving;
+ 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 {
+ (void)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) && (sys_conf->isp_cfg.flags.lsc)) {
+ 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)) {
+ (void)ci_bp_init(&sys_conf->isp_cfg.bpc_cfg,
+ &sys_conf->isp_cfg.bpd_cfg);
+ } else {
+ (void)ci_bp_end(&sys_conf->isp_cfg.bpc_cfg);
+ (void)ci_isp_set_bp_correction(NULL);
+ (void)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_init_mrvisp_cac(const struct ci_pl_system_config *sys_conf,
+ int enable)
+{
+ return 0;
+}
+
+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);
+
+ /* cac */
+ mrst_isp_init_mrvisp_cac(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 */
+ mrst_isp_init_mrvisp_lensshade(sys_conf, true);
+
+ /* configure bad pixel detection/correction */
+ mrst_isp_init_mrvisp_badpixel(sys_conf, true);
+
+ DBG_leaving;
+ 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)
+{
+ ci_isp_jpe_prep_enc(mrv_jpe_encMode);
+ 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);
+
+ if (isp->pixelformat == 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);
+ } else if (isp->pixelformat == INTEL_PIX_FMT_RAW08
+ || isp->pixelformat == INTEL_PIX_FMT_RAW10
+ || isp->pixelformat == 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);
+ } else {
+ 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;
+ }
+
+ }
+
+ 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;
+
+ vb->state = VIDEOBUF_QUEUED;
+ dprintk(1, "buffer %d in buffer querue", vb->i);
+ 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;
+ 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_fmt,
+ &sensor_format);
+ if (ret) {
+ printk(KERN_ERR "can't get current pix from sensor!\n");
+ ret = -EINVAL;
+ goto exit_unlock;
+ }
+
+ 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;
+
+ 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);
+ isp->sensor_curr = NULL;
+ }
+
+ kfree(file->private_data);
+
+ mutex_unlock(&isp->mutex);
+
+ if (isp->open == 0)
+ frame_cnt = 0;
+
+ DBG_leaving;
+ return 0;
+}
+
+static ssize_t mrst_isp_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ 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,
+};
+
+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;
+
+ WARN_ON(priv != file->private_data);
+
+ 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;
+ ret = 0;
+ } else {
+ ret = -EINVAL;
+ }
+
+ dprintk(1, "get fmt %d x %d ", f->fmt.pix.width, f->fmt.pix.height);
+ DBG_leaving;
+ 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;
+ int w, h;
+ int ret;
+
+ WARN_ON(priv != file->private_data);
+
+ 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;
+ }
+
+ w = f->fmt.pix.width;
+ h = f->fmt.pix.height;
+
+ dprintk(1, "sensor name %s: before w = %d, h = %d",
+ isp->sensor_curr->name, w, h);
+
+ ret = v4l2_subdev_call(isp->sensor_curr, video, try_fmt, f);
+ if (ret)
+ goto exit_unlock;
+
+
+ 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);
+
+ DBG_leaving;
+ 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;
+ int ret;
+ unsigned int width_o, height_o;
+ unsigned short width_sensor, height_sensor;
+ unsigned int w, h;
+
+ WARN_ON(priv != file->private_data);
+
+ 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;
+
+ (void)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;
+ }
+
+ /* set fmt for only sensor */
+ if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_MPEG) {
+ ret = v4l2_subdev_call(isp->sensor_curr, video, s_fmt, f);
+ 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);
+
+ ret = v4l2_subdev_call(isp->sensor_curr, video, s_fmt, f);
+ }
+
+ 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;
+
+ WARN_ON(priv != file->private_data);
+ 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;
+
+ WARN_ON(priv != file->private_data);
+
+ 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);
+
+ WARN_ON(priv != file->private_data);
+
+ 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;
+
+ WARN_ON(priv != file->private_data);
+
+ 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;
+
+ WARN_ON(priv != file->private_data);
+
+ 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;
+ strcpy(i->name, mrst_camera_table[camera].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);
+
+ WARN_ON(priv != file->private_data);
+
+ 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_s_std(struct file *filp, void *priv, v4l2_std_id *a)
+{
+ 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);
+
+ WARN_ON(priv != file->private_data);
+
+ 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;
+ else {
+ 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);
+
+ WARN_ON(priv != file->private_data);
+
+ 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;
+
+ WARN_ON(priv != 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;
+
+ WARN_ON(priv != 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;
+
+ WARN_ON(priv != 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);
+ WARN_ON(priv != file->private_data);
+
+ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ mutex_lock(&isp->mutex);
+
+ 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;
+
+ WARN_ON(priv != file->private_data);
+
+ 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->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);
+
+ ci_isp_stop(CI_ISP_CFG_UPDATE_FRAME_SYNC);
+ v4l2_subdev_call(isp->sensor_curr, video, s_stream, 0);
+
+ 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,
+ .read = mrst_isp_read,
+ .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_s_std = mrst_isp_s_std,
+ .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;
+ 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) {
+#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
+ 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) {
+#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
+
+ 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;
+
+#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_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 {
+ ci_isp_stop(CI_ISP_CFG_UPDATE_FRAME_SYNC);
+ dprintk(0, "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");
+ ci_isp_stop(CI_ISP_CFG_UPDATE_IMMEDIATE);
+ return IRQ_HANDLED;
+ }
+
+ spin_lock_irqsave(&isp->lock, flags);
+
+ /* update captured frame status */
+ vb = isp->active;
+ dprintk(1, "buf %d size = %lx", vb->i, vb->size);
+ vb->state = VIDEOBUF_DONE;
+ do_gettimeofday(&vb->ts);
+ vb->field_count++;
+ wake_up(&vb->done);
+ isp->active = NULL;
+
+ 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;
+ mrst_ci_capture(isp);
+ 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 {
+ 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");
+