rk312x camera : oneframe v0.1.9,pingpong v0.1.9
[firefly-linux-kernel-4.4.55.git] / drivers / media / video / rk29_camera_oneframe.c
index bcdbbe41e93fde973afbe13683183fe43ee92ace..8470b12681ae3b6f93e7834385c0aefa63893408 100755 (executable)
@@ -9,7 +9,7 @@
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  */
-
+#ifdef CONFIG_ARCH_RK29
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/io.h>
 #include <media/v4l2-dev.h>
 #include <media/videobuf-dma-contig.h>
 #include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
 #include <mach/rk29-ipp.h>
-
+#include <asm/cacheflush.h>
 
 static int debug;
-module_param(debug, int, S_IRUGO|S_IWUSR);
+module_param(debug, int, S_IRUGO|S_IWUSR|S_IWGRP);
 
 #define dprintk(level, fmt, arg...) do {                       \
        if (debug >= level)                                     \
        printk(KERN_WARNING"rk29xx_camera: " fmt , ## arg); } while (0)
 
 #define RK29CAMERA_TR(format, ...) printk(KERN_ERR format, ## __VA_ARGS__)
-#define RK29CAMERA_DG(format, ...) dprintk(0, format, ## __VA_ARGS__)
+#define RK29CAMERA_DG(format, ...) dprintk(1, format, ## __VA_ARGS__)
 
 // VIP Reg Offset
 #define RK29_VIP_AHBR_CTRL                0x00
@@ -125,8 +126,43 @@ module_param(debug, int, S_IRUGO|S_IWUSR);
 #define read_grf_reg(addr) __raw_readl(addr+RK29_GRF_BASE)
 #define mask_grf_reg(addr, msk, val)    write_vip_reg(addr, (val)|((~(msk))&read_vip_reg(addr)))
 
+#ifdef CONFIG_VIDEO_RK29_DIGITALZOOM_IPP_OFF
+#define CAM_WORKQUEUE_IS_EN()   ((pcdev->host_width != pcdev->icd->user_width) || (pcdev->host_height != pcdev->icd->user_height)\
+                                  || (pcdev->icd_cb.sensor_cb))
+#define CAM_IPPWORK_IS_EN()     ((pcdev->host_width != pcdev->icd->user_width) || (pcdev->host_height != pcdev->icd->user_height))                                  
+#else
+#define CAM_WORKQUEUE_IS_EN()   (true)
+#define CAM_IPPWORK_IS_EN()     ((pcdev->zoominfo.a.c.width != pcdev->icd->user_width) || (pcdev->zoominfo.a.c.height != pcdev->icd->user_height))
+#endif
 //Configure Macro
-#define RK29_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 1)
+/*
+*            Driver Version Note
+*
+*v0.0.x : this driver is 2.6.32 kernel driver;
+*v0.1.x : this driver is 3.0.8 kernel driver;
+*v0.2.x : this driver is rk30 3.0.8 kernel driver;
+*v0.3.x : this driver is camera-isp driver;
+*
+*v0.x.1 : this driver first support rk2918;
+*v0.x.2 : fix this driver support v4l2 format is V4L2_PIX_FMT_NV12 and V4L2_PIX_FMT_NV16,is not V4L2_PIX_FMT_YUV420 
+*         and V4L2_PIX_FMT_YUV422P;
+*v0.x.3 : this driver support VIDIOC_ENUM_FRAMEINTERVALS;
+*v0.x.4 : this driver support digital zoom;
+*v0.x.5 : this driver support test framerate and query framerate from board file configuration;
+*v0.x.6 : this driver improve test framerate method;
+*v0.x.7 : this driver product resolution by IPP crop and scale, which user request but sensor can't support;
+*         note: this version is only provide yifang client, which is not official version;
+*v0.x.8 : this driver and rk29_camera.c support upto 3 back-sensors and upto 3 front-sensors;
+*v0.x.9 : camera io code is compatible for rk29xx and rk30xx
+*v0.x.a : fix error when calculate crop left-top point coordinate;
+*         note: this version provided as patch camera_patch_v1.1
+*v0.x.b : fix sensor autofocus thread may in running when reinit sensor if sensor haven't stream on in first init;
+*v0.x.c : fix work queue havn't been finished after close device;
+*v0.x.d : fix error when calculate crop left-top point coordinate;
+*v0.x.f : fix struct rk29_camera_work may be reentrant.
+*v0.x.11: add support zoom by arm;
+*/
+#define RK29_CAM_VERSION_CODE KERNEL_VERSION(0, 1, 0x11)
 
 /* limit to rk29 hardware capabilities */
 #define RK29_CAM_BUS_PARAM   (SOCAM_MASTER |\
@@ -147,6 +183,7 @@ module_param(debug, int, S_IRUGO|S_IWUSR);
 #define RK29_CAM_H_MAX        2764
 #define RK29_CAM_FRAME_INVAL_INIT 3
 #define RK29_CAM_FRAME_INVAL_DC 3          /* ddl@rock-chips.com :  */
+#define RK29_CAM_FRAME_MEASURE  5
 
 #define RK29_CAM_AXI   0
 #define RK29_CAM_AHB   1
@@ -154,21 +191,13 @@ module_param(debug, int, S_IRUGO|S_IWUSR);
 
 extern void videobuf_dma_contig_free(struct videobuf_queue *q, struct videobuf_buffer *buf);
 extern dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf);
-extern void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
-            struct videobuf_queue_ops *ops,
-            struct device *dev,
-            spinlock_t *irqlock,
-            enum v4l2_buf_type type,
-            enum v4l2_field field,
-            unsigned int msize,
-            void *priv);
 
 /* buffer for one video frame */
 struct rk29_buffer
 {
     /* common v4l buffer stuff -- must be first */
     struct videobuf_buffer vb;
-    const struct soc_camera_data_format        *fmt;
+    enum v4l2_mbus_pixelcode   code;
     int                        inwork;
 };
 enum rk29_camera_reg_state
@@ -191,7 +220,33 @@ struct rk29_camera_work
        struct videobuf_buffer *vb;
        struct rk29_camera_dev *pcdev;
        struct work_struct work;
+    struct list_head queue;
+    unsigned int index;
+};
+struct rk29_camera_frmivalenum
+{
+    struct v4l2_frmivalenum fival;
+    struct rk29_camera_frmivalenum *nxt;
+};
+struct rk29_camera_frmivalinfo
+{
+    struct soc_camera_device *icd;
+    struct rk29_camera_frmivalenum *fival_list;
+};
+struct rk29_camera_zoominfo
+{
+    struct semaphore sem;
+    struct v4l2_crop a;
+    int zoom_rate;
 };
+#if CAMERA_VIDEOBUF_ARM_ACCESS
+struct rk29_camera_vbinfo
+{
+    unsigned int phy_addr;
+    void __iomem *vir_addr;
+    unsigned int size;
+};
+#endif
 struct rk29_camera_dev
 {
     struct soc_camera_host     soc_host;
@@ -207,41 +262,72 @@ struct rk29_camera_dev
        struct clk *hclk_cpu_display;
        struct clk *vip_slave;
 
-    struct clk *vip;
+       struct clk *vip_out;
        struct clk *vip_input;
        struct clk *vip_bus;
 
        struct clk *hclk_disp_matrix;
        struct clk *vip_matrix;
 
+       struct clk *pd_display;
+
     void __iomem *base;
        void __iomem *grf_base;
     int frame_inval;           /* ddl@rock-chips.com : The first frames is invalidate  */
     unsigned int irq;
        unsigned int fps;
+    unsigned long frame_interval;
        unsigned int pixfmt;
        unsigned int vipmem_phybase;
+    void __iomem *vipmem_virbase;
        unsigned int vipmem_size;
        unsigned int vipmem_bsize;
+#if CAMERA_VIDEOBUF_ARM_ACCESS    
+    struct rk29_camera_vbinfo *vbinfo;
+    unsigned int vbinfo_count;
+#endif    
        int host_width;
        int host_height;
+    int icd_width;
+    int icd_height;
 
     struct rk29camera_platform_data *pdata;
     struct resource            *res;
 
     struct list_head   capture;
-
+    struct rk29_camera_zoominfo zoominfo;
+    
     spinlock_t         lock;
 
     struct videobuf_buffer     *active;
-       struct videobuf_queue *vb_vidq_ptr;
        struct rk29_camera_reg reginfo_suspend;
        struct workqueue_struct *camera_wq;
        struct rk29_camera_work *camera_work;
+    struct list_head camera_work_queue;
+    spinlock_t camera_work_lock;
        unsigned int camera_work_count;
        struct hrtimer fps_timer;
        struct work_struct camera_reinit_work;
+    int icd_init;
+    rk29_camera_sensor_cb_s icd_cb;
+    struct rk29_camera_frmivalinfo icd_frmival[2];
+};
+
+static const struct v4l2_queryctrl rk29_camera_controls[] =
+{
+       #ifdef CONFIG_VIDEO_RK29_DIGITALZOOM_IPP_ON
+    {
+        .id            = V4L2_CID_ZOOM_ABSOLUTE,
+        .type          = V4L2_CTRL_TYPE_INTEGER,
+        .name          = "DigitalZoom Control",
+        .minimum       = 100,
+        .maximum       = 300,
+        .step          = 5,
+        .default_value = 100,
+    },
+    #endif
 };
+
 static DEFINE_MUTEX(camera_lock);
 static const char *rk29_cam_driver_description = "RK29_Camera";
 static struct rk29_camera_dev *rk29_camdev_info_ptr;
@@ -258,37 +344,73 @@ static int rk29_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
     struct soc_camera_device *icd = vq->priv_data;
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
     struct rk29_camera_dev *pcdev = ici->priv;
-    int bytes_per_pixel = (icd->current_fmt->depth + 7) >> 3;
+    int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+                                               icd->current_fmt->host_fmt);
+    int bytes_per_line_host = soc_mbus_bytes_per_line(pcdev->host_width,
+                                               icd->current_fmt->host_fmt);
+    int i;
+    struct rk29_camera_work *wk;
 
     dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
 
-       /* planar capture requires Y, U and V buffers to be page aligned */
-    *size = PAGE_ALIGN(icd->user_width* icd->user_height * bytes_per_pixel);                               /* Y pages UV pages, yuv422*/
-       pcdev->vipmem_bsize = PAGE_ALIGN(pcdev->host_width * pcdev->host_height * bytes_per_pixel);
-
-       if ((pcdev->host_width != pcdev->icd->user_width) || (pcdev->host_height != pcdev->icd->user_height)) {
-
-               if (*count > pcdev->vipmem_size/pcdev->vipmem_bsize) {    /* Buffers must be limited, when this resolution is genered by IPP */
-                       *count = pcdev->vipmem_size/pcdev->vipmem_bsize;
-               }
+       if (bytes_per_line < 0)
+               return bytes_per_line;
 
+       /* planar capture requires Y, U and V buffers to be page aligned */
+       *size = PAGE_ALIGN(bytes_per_line*icd->user_height);       /* Y pages UV pages, yuv422*/
+       pcdev->vipmem_bsize = PAGE_ALIGN(bytes_per_line_host * pcdev->host_height);
+
+
+       if (CAM_WORKQUEUE_IS_EN()) {
+        #ifdef CONFIG_VIDEO_RK29_DIGITALZOOM_IPP_OFF
+        if (CAM_IPPWORK_IS_EN()) 
+        #endif
+        {
+            BUG_ON(pcdev->vipmem_size<pcdev->vipmem_bsize);
+               if (*count > pcdev->vipmem_size/pcdev->vipmem_bsize) {    /* Buffers must be limited, when this resolution is genered by IPP */
+                       *count = pcdev->vipmem_size/pcdev->vipmem_bsize;
+               }
+        }
                if ((pcdev->camera_work_count != *count) && pcdev->camera_work) {
                        kfree(pcdev->camera_work);
                        pcdev->camera_work = NULL;
-                       pcdev->camera_work_count = 0;
+                       pcdev->camera_work_count = 0;            
                }
 
                if (pcdev->camera_work == NULL) {
-                       pcdev->camera_work = kmalloc(sizeof(struct rk29_camera_work)*(*count), GFP_KERNEL);
+                       pcdev->camera_work = wk = kzalloc(sizeof(struct rk29_camera_work)*(*count), GFP_KERNEL);
                        if (pcdev->camera_work == NULL) {
                                RK29CAMERA_TR("\n %s kmalloc fail\n", __FUNCTION__);
                                BUG();
                        }
-                       pcdev->camera_work_count = *count;
+            INIT_LIST_HEAD(&pcdev->camera_work_queue);
+
+            for (i=0; i<(*count); i++) {
+                wk->index = i;                
+                list_add_tail(&wk->queue, &pcdev->camera_work_queue);
+                wk++; 
+            }
+                       pcdev->camera_work_count = (*count);
                }
+#if CAMERA_VIDEOBUF_ARM_ACCESS
+        if (pcdev->vbinfo && (pcdev->vbinfo_count != *count)) {
+            kfree(pcdev->vbinfo);
+            pcdev->vbinfo = NULL;
+            pcdev->vbinfo_count = 0x00;
+        }
+
+        if (pcdev->vbinfo == NULL) {
+            pcdev->vbinfo = kzalloc(sizeof(struct rk29_camera_vbinfo)*(*count), GFP_KERNEL);
+            if (pcdev->vbinfo == NULL) {
+                               RK29CAMERA_TR("\n %s vbinfo kmalloc fail\n", __FUNCTION__);
+                               BUG();
+                       }
+                       pcdev->vbinfo_count = *count;
+        }
+#endif        
        }
 
-    RK29CAMERA_DG("%s..%d.. videobuf size:%d, vipmem_buf size:%d \n",__FUNCTION__,__LINE__, *size,pcdev->vipmem_bsize);
+    RK29CAMERA_DG("%s..%d.. videobuf size:%d, vipmem_buf size:%d, count:%d \n",__FUNCTION__,__LINE__, *size,pcdev->vipmem_size, *count);
 
     return 0;
 }
@@ -305,7 +427,11 @@ static void rk29_videobuf_free(struct videobuf_queue *vq, struct rk29_buffer *bu
 
     if (in_interrupt())
         BUG();
-
+    /*
+        * This waits until this buffer is out of danger, i.e., until it is no
+        * longer in STATE_QUEUED or STATE_ACTIVE
+        */
+       //videobuf_waiton(vq, &buf->vb, 0, 0);
     videobuf_dma_contig_free(vq, &buf->vb);
     dev_dbg(&icd->dev, "%s freed\n", __func__);
     buf->vb.state = VIDEOBUF_NEEDS_INIT;
@@ -316,6 +442,10 @@ static int rk29_videobuf_prepare(struct videobuf_queue *vq, struct videobuf_buff
     struct soc_camera_device *icd = vq->priv_data;
     struct rk29_buffer *buf;
     int ret;
+    int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+                                               icd->current_fmt->host_fmt);
+       if (bytes_per_line < 0)
+               return bytes_per_line;
 
     buf = container_of(vb, struct rk29_buffer, vb);
 
@@ -333,18 +463,18 @@ static int rk29_videobuf_prepare(struct videobuf_queue *vq, struct videobuf_buff
 
     BUG_ON(NULL == icd->current_fmt);
 
-    if (buf->fmt    != icd->current_fmt ||
+    if (buf->code    != icd->current_fmt->code ||
             vb->width   != icd->user_width ||
             vb->height  != icd->user_height ||
              vb->field   != field) {
-        buf->fmt    = icd->current_fmt;
+        buf->code    = icd->current_fmt->code;
         vb->width   = icd->user_width;
         vb->height  = icd->user_height;
         vb->field   = field;
         vb->state   = VIDEOBUF_NEEDS_INIT;
     }
 
-    vb->size = (((vb->width * vb->height *buf->fmt->depth) + 7) >> 3) ;          /* ddl@rock-chips.com : fmt->depth is coorect */
+    vb->size = bytes_per_line*vb->height;          /* ddl@rock-chips.com : fmt->depth is coorect */
     if (0 != vb->baddr && vb->bsize < vb->size) {
         ret = -EINVAL;
         goto out;
@@ -371,7 +501,7 @@ static inline void rk29_videobuf_capture(struct videobuf_buffer *vb)
        struct rk29_camera_dev *pcdev = rk29_camdev_info_ptr;
 
     if (vb) {
-               if ((pcdev->host_width != pcdev->icd->user_width) || (pcdev->host_height != pcdev->icd->user_height)) {
+               if (CAM_WORKQUEUE_IS_EN()) {
                        y_addr = pcdev->vipmem_phybase + vb->i*pcdev->vipmem_bsize;
                        uv_addr = y_addr + pcdev->host_width*pcdev->host_height;
 
@@ -398,7 +528,8 @@ static void rk29_videobuf_queue(struct videobuf_queue *vq,
     struct soc_camera_device *icd = vq->priv_data;
     struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
     struct rk29_camera_dev *pcdev = ici->priv;
-
+    struct rk29_camera_vbinfo *vb_info;
+        
     dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,
             vb, vb->baddr, vb->bsize);
 
@@ -412,7 +543,31 @@ static void rk29_videobuf_queue(struct videobuf_queue *vq,
                else
                        BUG();    /* ddl@rock-chips.com : The same videobuffer queue again */
        }
+#if CAMERA_VIDEOBUF_ARM_ACCESS
+    if (pcdev->vbinfo) {
+        vb_info = pcdev->vbinfo+vb->i;
+        if ((vb_info->phy_addr != vb->boff) || (vb_info->size != vb->bsize)) {
+            if (vb_info->vir_addr) {
+                iounmap(vb_info->vir_addr);
+                release_mem_region(vb_info->phy_addr, vb_info->size);
+                vb_info->vir_addr = NULL;
+                vb_info->phy_addr = 0x00;
+                vb_info->size = 0x00;
+            }
 
+            if (request_mem_region(vb->boff,vb->bsize,"rk29_camera_vb")) {
+                vb_info->vir_addr = ioremap_cached(vb->boff,vb->bsize); 
+            }
+            
+            if (vb_info->vir_addr) {
+                vb_info->size = vb->bsize;
+                vb_info->phy_addr = vb->boff;
+            } else {
+                RK29CAMERA_TR("%s..%d:ioremap videobuf %d failed\n",__FUNCTION__,__LINE__, vb->i);
+            }
+        }
+    }
+#endif    
     if (!pcdev->active) {
         pcdev->active = vb;
         rk29_videobuf_capture(vb);
@@ -422,12 +577,14 @@ static int rk29_pixfmt2ippfmt(unsigned int pixfmt, int *ippfmt)
 {
        switch (pixfmt)
        {
-               case V4L2_PIX_FMT_YUV422P:
+               case V4L2_PIX_FMT_NV16:
+        case V4L2_PIX_FMT_YUV422P:
                {
                        *ippfmt = IPP_Y_CBCR_H2V1;
                        break;
                }
-               case V4L2_PIX_FMT_YUV420:
+               case V4L2_PIX_FMT_NV12:
+        case V4L2_PIX_FMT_YUV420:
                {
                        *ippfmt = IPP_Y_CBCR_H2V2;
                        break;
@@ -440,62 +597,263 @@ static int rk29_pixfmt2ippfmt(unsigned int pixfmt, int *ippfmt)
 rk29_pixfmt2ippfmt_err:
        return -1;
 }
-static void rk29_camera_capture_process(struct work_struct *work)
+#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_IPP)
+static int rk29_camera_scale_crop_ipp(struct work_struct *work)
 {
        struct rk29_camera_work *camera_work = container_of(work, struct rk29_camera_work, work);
        struct videobuf_buffer *vb = camera_work->vb;
        struct rk29_camera_dev *pcdev = camera_work->pcdev;
        struct rk29_ipp_req ipp_req;
        unsigned long int flags;
+    int src_y_offset,src_uv_offset,dst_y_offset,dst_uv_offset,src_y_size,dst_y_size;
+    int scale_times,w,h,vipdata_base;
+    int ret = 0;
+    
+    /*
+    *ddl@rock-chips.com: 
+    * IPP Dest image resolution is 2047x1088, so scale operation break up some times
+    */
+    if ((pcdev->icd->user_width > 0x7f0) || (pcdev->icd->user_height > 0x430)) {
+        scale_times = MAX((pcdev->icd->user_width/0x7f0),(pcdev->icd->user_height/0x430));        
+        scale_times++;
+    } else {
+        scale_times = 1;
+    }
+    
+    memset(&ipp_req, 0, sizeof(struct rk29_ipp_req));
+    
+    ipp_req.timeout = 100;
+    ipp_req.flag = IPP_ROT_0;    
+    ipp_req.src0.w = pcdev->zoominfo.a.c.width/scale_times;
+    ipp_req.src0.h = pcdev->zoominfo.a.c.height/scale_times;
+    ipp_req.src_vir_w = pcdev->host_width;
+    rk29_pixfmt2ippfmt(pcdev->pixfmt, &ipp_req.src0.fmt);
+    ipp_req.dst0.w = pcdev->icd->user_width/scale_times;
+    ipp_req.dst0.h = pcdev->icd->user_height/scale_times;
+    ipp_req.dst_vir_w = pcdev->icd->user_width;        
+    rk29_pixfmt2ippfmt(pcdev->pixfmt, &ipp_req.dst0.fmt);
+
+    vipdata_base = pcdev->vipmem_phybase + vb->i*pcdev->vipmem_bsize;
+    src_y_size = pcdev->host_width*pcdev->host_height;
+    dst_y_size = pcdev->icd->user_width*pcdev->icd->user_height;
+    
+    for (h=0; h<scale_times; h++) {
+        for (w=0; w<scale_times; w++) {
+            
+            src_y_offset = (pcdev->zoominfo.a.c.top + h*pcdev->zoominfo.a.c.height/scale_times)* pcdev->host_width 
+                        + pcdev->zoominfo.a.c.left + w*pcdev->zoominfo.a.c.width/scale_times;
+                   src_uv_offset = (pcdev->zoominfo.a.c.top + h*pcdev->zoominfo.a.c.height/scale_times)* pcdev->host_width/2
+                        + pcdev->zoominfo.a.c.left + w*pcdev->zoominfo.a.c.width/scale_times;
+
+            dst_y_offset = pcdev->icd->user_width*pcdev->icd->user_height*h/scale_times + pcdev->icd->user_width*w/scale_times;
+            dst_uv_offset = pcdev->icd->user_width*pcdev->icd->user_height*h/scale_times/2 + pcdev->icd->user_width*w/scale_times;
+
+               ipp_req.src0.YrgbMst = vipdata_base + src_y_offset;
+               ipp_req.src0.CbrMst = vipdata_base + src_y_size + src_uv_offset;
+               ipp_req.dst0.YrgbMst = vb->boff + dst_y_offset;
+               ipp_req.dst0.CbrMst = vb->boff + dst_y_size + dst_uv_offset;
+
+               if (ipp_blit_sync(&ipp_req)) {
+                       spin_lock_irqsave(&pcdev->lock, flags);
+                       vb->state = VIDEOBUF_ERROR;
+                       spin_unlock_irqrestore(&pcdev->lock, flags);
+
+                RK29CAMERA_TR("Capture image(vb->i:0x%x) which IPP operated is error:\n",vb->i);
+                RK29CAMERA_TR("widx:%d hidx:%d ",w,h);
+                RK29CAMERA_TR("%dx%d@(%d,%d)->%dx%d\n",pcdev->zoominfo.a.c.width,pcdev->zoominfo.a.c.height,pcdev->zoominfo.a.c.left,pcdev->zoominfo.a.c.top,pcdev->icd->user_width,pcdev->icd->user_height);
+               RK29CAMERA_TR("ipp_req.src0.YrgbMst:0x%x ipp_req.src0.CbrMst:0x%x \n", ipp_req.src0.YrgbMst,ipp_req.src0.CbrMst);
+               RK29CAMERA_TR("ipp_req.src0.w:0x%x ipp_req.src0.h:0x%x \n",ipp_req.src0.w,ipp_req.src0.h);
+               RK29CAMERA_TR("ipp_req.src0.fmt:0x%x\n",ipp_req.src0.fmt);
+               RK29CAMERA_TR("ipp_req.dst0.YrgbMst:0x%x ipp_req.dst0.CbrMst:0x%x \n",ipp_req.dst0.YrgbMst,ipp_req.dst0.CbrMst);
+               RK29CAMERA_TR("ipp_req.dst0.w:0x%x ipp_req.dst0.h:0x%x \n",ipp_req.dst0.w ,ipp_req.dst0.h);
+               RK29CAMERA_TR("ipp_req.dst0.fmt:0x%x\n",ipp_req.dst0.fmt);
+               RK29CAMERA_TR("ipp_req.src_vir_w:0x%x ipp_req.dst_vir_w :0x%x\n",ipp_req.src_vir_w ,ipp_req.dst_vir_w);
+               RK29CAMERA_TR("ipp_req.timeout:0x%x ipp_req.flag :0x%x\n",ipp_req.timeout,ipp_req.flag);
+                
+                       goto rk29_camera_scale_crop_ipp_end;
+               }
+        }
+    }
+    
+rk29_camera_scale_crop_ipp_end:        
+       return ret;    
+}
+#endif
+#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_ARM)
+static int rk29_camera_scale_crop_arm(struct work_struct *work)
+{
+    struct rk29_camera_work *camera_work = container_of(work, struct rk29_camera_work, work);  
+    struct videobuf_buffer *vb = camera_work->vb;      
+    struct rk29_camera_dev *pcdev = camera_work->pcdev;        
+    struct rk29_camera_vbinfo *vb_info;        
+    unsigned char *psY,*pdY,*psUV,*pdUV; 
+    unsigned char *src,*dst;
+    unsigned long src_phy,dst_phy;
+    int srcW,srcH,cropW,cropH,dstW,dstH;
+    long zoomindstxIntInv,zoomindstyIntInv;
+    long x,y;
+    long yCoeff00,yCoeff01,xCoeff00,xCoeff01;
+    long sX,sY;
+    long r0,r1,a,b,c,d;
+    int ret = 0;
+    
+
+    src_phy = pcdev->vipmem_phybase + vb->i*pcdev->vipmem_bsize;    
+    src = psY = (unsigned char*)(pcdev->vipmem_virbase + vb->i*pcdev->vipmem_bsize);
+    psUV = psY + pcdev->host_width*pcdev->host_height;
+    srcW = pcdev->host_width;
+    srcH = pcdev->host_height;
+    cropW = pcdev->zoominfo.a.c.width;
+    cropH = pcdev->zoominfo.a.c.height;
+    psY = psY + pcdev->host_width - pcdev->zoominfo.a.c.width;
+    psUV = psUV + pcdev->host_width - pcdev->zoominfo.a.c.width; 
+    
+    vb_info = pcdev->vbinfo+vb->i; 
+    dst_phy = vb_info->phy_addr;
+    dst = pdY = (unsigned char*)vb_info->vir_addr; 
+    pdUV = pdY + pcdev->icd->user_width*pcdev->icd->user_height;
+    dstW = pcdev->icd->user_width;
+    dstH = pcdev->icd->user_height;
+
+    zoomindstxIntInv = ((unsigned long)cropW<<16)/dstW + 1;
+    zoomindstyIntInv = ((unsigned long)cropH<<16)/dstH + 1;
+    //y
+    //for(y = 0; y<dstH - 1 ; y++ ) {   
+    for(y = 0; y<dstH; y++ ) {   
+        yCoeff00 = (y*zoomindstyIntInv)&0xffff;
+        yCoeff01 = 0xffff - yCoeff00; 
+        sY = (y*zoomindstyIntInv >> 16);
+
+        for(x = 0; x<dstW; x++ ) {
+            xCoeff00 = (x*zoomindstxIntInv)&0xffff;
+            xCoeff01 = 0xffff - xCoeff00;      
+            sX = (x*zoomindstxIntInv >> 16);
+
+            a = psY[sY*srcW + sX];
+            b = psY[sY*srcW + sX + 1];
+            c = psY[(sY+1)*srcW + sX];
+            d = psY[(sY+1)*srcW + sX + 1];
+
+            r0 = (a * xCoeff01 + b * xCoeff00)>>16 ;
+            r1 = (c * xCoeff01 + d * xCoeff00)>>16 ;
+            r0 = (r0 * yCoeff01 + r1 * yCoeff00)>>16;
+
+            pdY[x] = r0;
+        }
+        pdY += dstW;
+    }
 
-       ipp_req.src0.YrgbMst = pcdev->vipmem_phybase + vb->i*pcdev->vipmem_bsize;
-       ipp_req.src0.CbrMst= ipp_req.src0.YrgbMst + pcdev->host_width*pcdev->host_height;
-       ipp_req.src0.w = pcdev->host_width;
-       ipp_req.src0.h = pcdev->host_height;
-       rk29_pixfmt2ippfmt(pcdev->pixfmt, &ipp_req.src0.fmt);
-
-       ipp_req.dst0.YrgbMst = vb->boff;
-       ipp_req.dst0.CbrMst= vb->boff+vb->width * vb->height;
-       ipp_req.dst0.w = pcdev->icd->user_width;
-       ipp_req.dst0.h = pcdev->icd->user_height;
-       rk29_pixfmt2ippfmt(pcdev->pixfmt, &ipp_req.dst0.fmt);
-
-       ipp_req.src_vir_w = ipp_req.src0.w;
-       ipp_req.dst_vir_w = ipp_req.dst0.w;
-       ipp_req.timeout = 100;
-       ipp_req.flag = IPP_ROT_0;
-
-       if (ipp_do_blit(&ipp_req)) {
-               spin_lock_irqsave(&pcdev->lock, flags);
-               vb->state = VIDEOBUF_ERROR;
-               spin_unlock_irqrestore(&pcdev->lock, flags);
-               RK29CAMERA_TR("Capture image(vb->i:0x%x) which IPP operated is error!\n", vb->i);
-               RK29CAMERA_TR("ipp_req.src0.YrgbMst:0x%x ipp_req.src0.CbrMst:0x%x \n", ipp_req.src0.YrgbMst,ipp_req.src0.CbrMst);
-               RK29CAMERA_TR("ipp_req.src0.w:0x%x ipp_req.src0.h:0x%x \n",ipp_req.src0.w,ipp_req.src0.h);
-               RK29CAMERA_TR("ipp_req.src0.fmt:0x%x\n",ipp_req.src0.fmt);
-               RK29CAMERA_TR("ipp_req.dst0.YrgbMst:0x%x ipp_req.dst0.CbrMst:0x%x \n",ipp_req.dst0.YrgbMst,ipp_req.dst0.CbrMst);
-               RK29CAMERA_TR("ipp_req.dst0.w:0x%x ipp_req.dst0.h:0x%x \n",ipp_req.dst0.w ,ipp_req.dst0.h);
-               RK29CAMERA_TR("ipp_req.dst0.fmt:0x%x\n",ipp_req.dst0.fmt);
-               RK29CAMERA_TR("ipp_req.src_vir_w:0x%x ipp_req.dst_vir_w :0x%x\n",ipp_req.src_vir_w ,ipp_req.dst_vir_w);
-           RK29CAMERA_TR("ipp_req.timeout:0x%x ipp_req.flag :0x%x\n",ipp_req.timeout,ipp_req.flag);
-       }
+    dstW /= 2;
+    dstH /= 2;
+    srcW /= 2;
+    srcH /= 2;
+
+    //UV
+    //for(y = 0; y<dstH - 1 ; y++ ) {
+    for(y = 0; y<dstH; y++ ) {
+        yCoeff00 = (y*zoomindstyIntInv)&0xffff;
+        yCoeff01 = 0xffff - yCoeff00; 
+        sY = (y*zoomindstyIntInv >> 16);
+
+        for(x = 0; x<dstW; x++ ) {
+            xCoeff00 = (x*zoomindstxIntInv)&0xffff;
+            xCoeff01 = 0xffff - xCoeff00;      
+            sX = (x*zoomindstxIntInv >> 16);
+
+            //U
+            a = psUV[(sY*srcW + sX)*2];
+            b = psUV[(sY*srcW + sX + 1)*2];
+            c = psUV[((sY+1)*srcW + sX)*2];
+            d = psUV[((sY+1)*srcW + sX + 1)*2];
+
+            r0 = (a * xCoeff01 + b * xCoeff00)>>16 ;
+            r1 = (c * xCoeff01 + d * xCoeff00)>>16 ;
+            r0 = (r0 * yCoeff01 + r1 * yCoeff00)>>16;
+
+            pdUV[x*2] = r0;
+
+            //V
+            a = psUV[(sY*srcW + sX)*2 + 1];
+            b = psUV[(sY*srcW + sX + 1)*2 + 1];
+            c = psUV[((sY+1)*srcW + sX)*2 + 1];
+            d = psUV[((sY+1)*srcW + sX + 1)*2 + 1];
+
+            r0 = (a * xCoeff01 + b * xCoeff00)>>16 ;
+            r1 = (c * xCoeff01 + d * xCoeff00)>>16 ;
+            r0 = (r0 * yCoeff01 + r1 * yCoeff00)>>16;
+
+            pdUV[x*2 + 1] = r0;
+        }
+        pdUV += dstW*2;
+    }
+
+rk29_camera_scale_crop_arm_end:
+
+    dmac_flush_range((void*)src,(void*)(src+pcdev->vipmem_bsize));
+    outer_flush_range((phys_addr_t)src_phy,(phys_addr_t)(src_phy+pcdev->vipmem_bsize));
+    
+    dmac_flush_range((void*)dst,(void*)(dst+vb_info->size));
+    outer_flush_range((phys_addr_t)dst_phy,(phys_addr_t)(dst_phy+vb_info->size));
+
+       return ret;    
+}
+#endif
 
-       wake_up(&(camera_work->vb->done));
+static void rk29_camera_capture_process(struct work_struct *work)
+{
+    struct rk29_camera_work *camera_work = container_of(work, struct rk29_camera_work, work);    
+    struct videobuf_buffer *vb = camera_work->vb;    
+    struct rk29_camera_dev *pcdev = camera_work->pcdev;    
+    //enum v4l2_mbus_pixelcode icd_code = pcdev->icd->current_fmt->code;    
+    unsigned long flags = 0;    
+    int err = 0;    
+
+    if (!CAM_WORKQUEUE_IS_EN())        
+        goto rk29_camera_capture_process_end; 
+    
+    down(&pcdev->zoominfo.sem);
+    if (pcdev->icd_cb.scale_crop_cb)
+        err = (pcdev->icd_cb.scale_crop_cb)(work);
+    up(&pcdev->zoominfo.sem); 
+    
+    if (pcdev->icd_cb.sensor_cb)        
+        (pcdev->icd_cb.sensor_cb)(vb);    
+
+rk29_camera_capture_process_end:    
+    if (err) {        
+        vb->state = VIDEOBUF_ERROR;    
+    } else {
+        if ((vb->state == VIDEOBUF_QUEUED) || (vb->state == VIDEOBUF_ACTIVE)) {
+               vb->state = VIDEOBUF_DONE;
+               vb->field_count++;
+               }
+    }    
+    wake_up(&(camera_work->vb->done));     
+    spin_lock_irqsave(&pcdev->camera_work_lock, flags);    
+    list_add_tail(&camera_work->queue, &pcdev->camera_work_queue);    
+    spin_unlock_irqrestore(&pcdev->camera_work_lock, flags);    
+    return;
 }
 static irqreturn_t rk29_camera_irq(int irq, void *data)
 {
     struct rk29_camera_dev *pcdev = data;
     struct videobuf_buffer *vb;
        struct rk29_camera_work *wk;
+    static struct timeval first_tv;
+    struct timeval tv;
 
     read_vip_reg(RK29_VIP_INT_STS);    /* clear vip interrupte single  */
     /* ddl@rock-chps.com : Current VIP is run in One Frame Mode, Frame 1 is validate */
     if (read_vip_reg(RK29_VIP_FB_SR) & 0x01) {
+        if (!pcdev->fps) {
+            do_gettimeofday(&first_tv);            
+        }
                pcdev->fps++;
                if (!pcdev->active)
                        goto RK29_CAMERA_IRQ_END;
 
-        if (pcdev->frame_inval>0) {
+        if (pcdev->frame_inval>0) {            
             pcdev->frame_inval--;
             rk29_videobuf_capture(pcdev->active);
             goto RK29_CAMERA_IRQ_END;
@@ -504,6 +862,12 @@ static irqreturn_t rk29_camera_irq(int irq, void *data)
             pcdev->frame_inval = 0;
         }
 
+        if(pcdev->fps == RK29_CAM_FRAME_MEASURE) {
+            do_gettimeofday(&tv);            
+            pcdev->frame_interval = ((tv.tv_sec*1000000 + tv.tv_usec) - (first_tv.tv_sec*1000000 + first_tv.tv_usec))
+                                    /(RK29_CAM_FRAME_MEASURE-1);
+        }
+
         vb = pcdev->active;
                /* ddl@rock-chips.com : this vb may be deleted from queue */
                if ((vb->state == VIDEOBUF_QUEUED) || (vb->state == VIDEOBUF_ACTIVE)) {
@@ -521,20 +885,22 @@ static irqreturn_t rk29_camera_irq(int irq, void *data)
         if (pcdev->active == NULL) {
                        RK29CAMERA_DG("%s video_buf queue is empty!\n",__FUNCTION__);
         }
-
-               if ((vb->state == VIDEOBUF_QUEUED) || (vb->state == VIDEOBUF_ACTIVE)) {
-               vb->state = VIDEOBUF_DONE;
-               do_gettimeofday(&vb->ts);
-               vb->field_count++;
-               }
-
-               if ((pcdev->host_width != pcdev->icd->user_width) || (pcdev->host_height != pcdev->icd->user_height)) {
-                       wk = pcdev->camera_work + vb->i;
-                       INIT_WORK(&(wk->work), rk29_camera_capture_process);
-                       wk->vb = vb;
-                       wk->pcdev = pcdev;
-                       queue_work(pcdev->camera_wq, &(wk->work));
-               } else {
+        
+        do_gettimeofday(&vb->ts);
+               if (CAM_WORKQUEUE_IS_EN()) {
+            if (!list_empty(&pcdev->camera_work_queue)) {
+                wk = list_entry(pcdev->camera_work_queue.next, struct rk29_camera_work, queue);
+                list_del_init(&wk->queue);
+                INIT_WORK(&(wk->work), rk29_camera_capture_process);
+                       wk->vb = vb;
+                       wk->pcdev = pcdev;
+                       queue_work(pcdev->camera_wq, &(wk->work));
+            }                                  
+               } else {                    
+                   if ((vb->state == VIDEOBUF_QUEUED) || (vb->state == VIDEOBUF_ACTIVE)) {
+               vb->state = VIDEOBUF_DONE;              
+               vb->field_count++;
+               }
                        wake_up(&vb->done);
                }
     }
@@ -551,7 +917,8 @@ static void rk29_videobuf_release(struct videobuf_queue *vq,
     struct soc_camera_device *icd = vq->priv_data;
     struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
     struct rk29_camera_dev *pcdev = ici->priv;
-
+    struct rk29_camera_vbinfo *vb_info =NULL;
+    
 #ifdef DEBUG
     dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
             vb, vb->baddr, vb->bsize);
@@ -567,16 +934,30 @@ static void rk29_videobuf_release(struct videobuf_queue *vq,
         case VIDEOBUF_PREPARED:
             dev_dbg(&icd->dev, "%s (prepared)\n", __func__);
             break;
-        default:
+        default:  
             dev_dbg(&icd->dev, "%s (unknown)\n", __func__);
             break;
     }
 #endif
        if (vb == pcdev->active) {
                RK29CAMERA_DG("%s Wait for this video buf(0x%x) write finished!\n ",__FUNCTION__,(unsigned int)vb);
-               interruptible_sleep_on_timeout(&vb->done, 100);
+               interruptible_sleep_on_timeout(&vb->done, msecs_to_jiffies(500));
                RK29CAMERA_DG("%s This video buf(0x%x) write finished, release now!!\n",__FUNCTION__,(unsigned int)vb);
        }
+
+    flush_workqueue(pcdev->camera_wq); 
+#if CAMERA_VIDEOBUF_ARM_ACCESS
+    if (pcdev->vbinfo) {
+        vb_info = pcdev->vbinfo + vb->i;
+        
+        if (vb_info->vir_addr) {
+            iounmap(vb_info->vir_addr);
+            release_mem_region(vb_info->phy_addr, vb_info->size);
+            memset(vb_info, 0x00, sizeof(struct rk29_camera_vbinfo));
+        }       
+               
+       }
+#endif    
     rk29_videobuf_free(vq, buf);
 }
 
@@ -602,8 +983,7 @@ static void rk29_camera_init_videobuf(struct videobuf_queue *q,
                                    V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                    V4L2_FIELD_NONE,
                                    sizeof(struct rk29_buffer),
-                                   icd);
-       pcdev->vb_vidq_ptr = q;         /* ddl@rock-chips.com */
+                                   icd,&icd->video_lock);
 }
 static int rk29_camera_activate(struct rk29_camera_dev *pcdev, struct soc_camera_device *icd)
 {
@@ -612,9 +992,9 @@ static int rk29_camera_activate(struct rk29_camera_dev *pcdev, struct soc_camera
 
     RK29CAMERA_DG("%s..%d.. \n",__FUNCTION__,__LINE__);
     if (!pcdev->aclk_ddr_lcdc || !pcdev->aclk_disp_matrix ||  !pcdev->hclk_cpu_display ||
-               !pcdev->vip_slave || !pcdev->vip || !pcdev->vip_input || !pcdev->vip_bus ||
-               IS_ERR(pcdev->aclk_ddr_lcdc) || IS_ERR(pcdev->aclk_disp_matrix) ||  IS_ERR(pcdev->hclk_cpu_display) ||
-               IS_ERR(pcdev->vip_slave) || IS_ERR(pcdev->vip) || IS_ERR(pcdev->vip_input) || IS_ERR(pcdev->vip_bus))  {
+               !pcdev->vip_slave || !pcdev->vip_out || !pcdev->vip_input || !pcdev->vip_bus || !pcdev->pd_display ||
+               IS_ERR(pcdev->aclk_ddr_lcdc) || IS_ERR(pcdev->aclk_disp_matrix) ||  IS_ERR(pcdev->hclk_cpu_display) || IS_ERR(pcdev->pd_display) ||
+               IS_ERR(pcdev->vip_slave) || IS_ERR(pcdev->vip_out) || IS_ERR(pcdev->vip_input) || IS_ERR(pcdev->vip_bus))  {
 
         RK29CAMERA_TR(KERN_ERR "failed to get vip_clk(axi) source\n");
         goto RK29_CAMERA_ACTIVE_ERR;
@@ -627,6 +1007,8 @@ static int rk29_camera_activate(struct rk29_camera_dev *pcdev, struct soc_camera
         goto RK29_CAMERA_ACTIVE_ERR;
     }
 
+       clk_enable(pcdev->pd_display);
+
        clk_enable(pcdev->aclk_ddr_lcdc);
        clk_enable(pcdev->aclk_disp_matrix);
 
@@ -658,9 +1040,9 @@ static int rk29_camera_activate(struct rk29_camera_dev *pcdev, struct soc_camera
              goto RK29_CAMERA_ACTIVE_ERR;
     }
 
-    clk_set_parent(pcdev->vip, parent);
+    clk_set_parent(pcdev->vip_out, parent);
 
-    clk_enable(pcdev->vip);
+    clk_enable(pcdev->vip_out);
     rk29_mux_api_set(GPIO1B4_VIPCLKOUT_NAME, GPIO1L_VIP_CLKOUT);
     ndelay(10);
 
@@ -693,7 +1075,7 @@ static void rk29_camera_deactivate(struct rk29_camera_dev *pcdev)
     read_vip_reg(RK29_VIP_INT_STS);             //clear vip interrupte single
 
     rk29_mux_api_set(GPIO1B4_VIPCLKOUT_NAME, GPIO1L_GPIO1B4);
-    clk_disable(pcdev->vip);
+    clk_disable(pcdev->vip_out);
 
        clk_disable(pcdev->vip_input);
        clk_disable(pcdev->vip_bus);
@@ -708,6 +1090,8 @@ static void rk29_camera_deactivate(struct rk29_camera_dev *pcdev)
 
        clk_disable(pcdev->aclk_ddr_lcdc);
        clk_disable(pcdev->aclk_disp_matrix);
+
+       clk_disable(pcdev->pd_display);
     return;
 }
 
@@ -719,8 +1103,9 @@ static int rk29_camera_add_device(struct soc_camera_device *icd)
     struct rk29_camera_dev *pcdev = ici->priv;
     struct device *control = to_soc_camera_control(icd);
     struct v4l2_subdev *sd;
-    int ret;
-
+    int ret,i,icd_catch;
+    struct rk29_camera_frmivalenum *fival_list,*fival_nxt;
+    
     mutex_lock(&camera_lock);
 
     if (pcdev->icd) {
@@ -728,13 +1113,14 @@ static int rk29_camera_add_device(struct soc_camera_device *icd)
         goto ebusy;
     }
 
-    dev_info(&icd->dev, "RK29 Camera driver attached to camera%d(%s)\n",
-             icd->devnum,dev_name(icd->pdev));
-
+    RK29CAMERA_DG("RK29 Camera driver attached to %s\n",dev_name(icd->pdev));
+    
        pcdev->frame_inval = RK29_CAM_FRAME_INVAL_INIT;
     pcdev->active = NULL;
     pcdev->icd = NULL;
        pcdev->reginfo_suspend.Inval = Reg_Invalidate;
+    pcdev->zoominfo.zoom_rate = 100;
+        
        /* ddl@rock-chips.com: capture list must be reset, because this list may be not empty,
      * if app havn't dequeue all videobuf before close camera device;
        */
@@ -748,13 +1134,38 @@ static int rk29_camera_add_device(struct soc_camera_device *icd)
     if (control) {
         sd = dev_get_drvdata(control);
                v4l2_subdev_call(sd, core, ioctl, RK29_CAM_SUBDEV_IOREQUEST,(void*)pcdev->pdata);
+        #if 0
         ret = v4l2_subdev_call(sd,core, init, 0);
         if (ret)
             goto ebusy;
+        #endif
+        v4l2_subdev_call(sd, core, ioctl, RK29_CAM_SUBDEV_CB_REGISTER,(void*)(&pcdev->icd_cb));
     }
-
+    
     pcdev->icd = icd;
+    pcdev->icd_init = 0;
+
+    icd_catch = 0;
+    for (i=0; i<2; i++) {
+        if (pcdev->icd_frmival[i].icd == icd)
+            icd_catch = 1;
+        if (pcdev->icd_frmival[i].icd == NULL) {
+            pcdev->icd_frmival[i].icd = icd;
+            icd_catch = 1;
+        }
+    }
 
+    if (icd_catch == 0) {
+        fival_list = pcdev->icd_frmival[0].fival_list;
+        fival_nxt = fival_list;
+        while(fival_nxt != NULL) {
+            fival_nxt = fival_list->nxt;
+            kfree(fival_list);
+            fival_list = fival_nxt;
+        }
+        pcdev->icd_frmival[0].icd = icd;
+        pcdev->icd_frmival[0].fival_list = kzalloc(sizeof(struct rk29_camera_frmivalenum),GFP_KERNEL);
+    }
 ebusy:
     mutex_unlock(&camera_lock);
 
@@ -765,12 +1176,13 @@ static void rk29_camera_remove_device(struct soc_camera_device *icd)
     struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
     struct rk29_camera_dev *pcdev = ici->priv;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-
+    struct rk29_camera_vbinfo *vb_info;
+    unsigned int i;
+    
        mutex_lock(&camera_lock);
     BUG_ON(icd != pcdev->icd);
 
-    dev_info(&icd->dev, "RK29 Camera driver detached from camera%d(%s)\n",
-             icd->devnum,dev_name(icd->pdev));
+    RK29CAMERA_DG("RK29 Camera driver detached from %s\n",dev_name(icd->pdev));
 
        /* ddl@rock-chips.com: Application will call VIDIOC_STREAMOFF before close device, but
           stream may be turn on again before close device, if suspend and resume happened. */
@@ -781,24 +1193,31 @@ static void rk29_camera_remove_device(struct soc_camera_device *icd)
     v4l2_subdev_call(sd, core, ioctl, RK29_CAM_SUBDEV_DEACTIVATE,NULL);
        rk29_camera_deactivate(pcdev);
 
-       /* ddl@rock-chips.com: Call videobuf_mmap_free here for free the struct video_buffer which malloc in videobuf_alloc */
-       #if 0
-       if (pcdev->vb_vidq_ptr) {
-               videobuf_mmap_free(pcdev->vb_vidq_ptr);
-               pcdev->vb_vidq_ptr = NULL;
-       }
-       #else
-       pcdev->vb_vidq_ptr = NULL;
-       #endif
-
        if (pcdev->camera_work) {
                kfree(pcdev->camera_work);
                pcdev->camera_work = NULL;
                pcdev->camera_work_count = 0;
+        INIT_LIST_HEAD(&pcdev->camera_work_queue);
        }
-
+#if CAMERA_VIDEOBUF_ARM_ACCESS
+    if (pcdev->vbinfo) {
+        vb_info = pcdev->vbinfo;
+        for (i=0; i<pcdev->vbinfo_count; i++) {
+            if (vb_info->vir_addr) {
+                iounmap(vb_info->vir_addr);
+                release_mem_region(vb_info->phy_addr, vb_info->size);
+                memset(vb_info, 0x00, sizeof(struct rk29_camera_vbinfo));
+            }
+            vb_info++;
+        }
+               kfree(pcdev->vbinfo);
+               pcdev->vbinfo = NULL;
+               pcdev->vbinfo_count = 0;
+       }
+#endif
        pcdev->active = NULL;
     pcdev->icd = NULL;
+    pcdev->icd_cb.sensor_cb = NULL;
        pcdev->reginfo_suspend.Inval = Reg_Invalidate;
        /* ddl@rock-chips.com: capture list must be reset, because this list may be not empty,
      * if app havn't dequeue all videobuf before close camera device;
@@ -810,16 +1229,38 @@ static void rk29_camera_remove_device(struct soc_camera_device *icd)
 
        return;
 }
-
 static int rk29_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
 {
     unsigned long bus_flags, camera_flags, common_flags;
     unsigned int vip_ctrl_val = 0;
-    int ret = 0;
+       const struct soc_mbus_pixelfmt *fmt;
+       int ret = 0;
 
     RK29CAMERA_DG("%s..%d..\n",__FUNCTION__,__LINE__);
 
+       fmt = soc_mbus_get_fmtdesc(icd->current_fmt->code);
+       if (!fmt)
+               return -EINVAL;
+
     bus_flags = RK29_CAM_BUS_PARAM;
+       /* If requested data width is supported by the platform, use it */
+       switch (fmt->bits_per_sample) {
+       case 10:
+               if (!(bus_flags & SOCAM_DATAWIDTH_10))
+                       return -EINVAL;                 
+               break;
+       case 9:
+               if (!(bus_flags & SOCAM_DATAWIDTH_9))
+                       return -EINVAL;                 
+               break;
+       case 8:
+               if (!(bus_flags & SOCAM_DATAWIDTH_8))
+                       return -EINVAL;                 
+               break;
+       default:
+               return -EINVAL;
+       }
+    
        if (icd->ops->query_bus_param)
        camera_flags = icd->ops->query_bus_param(icd);
        else
@@ -835,12 +1276,6 @@ static int rk29_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt
     if (ret < 0)
         goto RK29_CAMERA_SET_BUS_PARAM_END;
 
-       if (common_flags & SOCAM_DATAWIDTH_8) {
-        icd->buswidth = 8;
-       } else if (common_flags & SOCAM_DATAWIDTH_10) {
-           icd->buswidth = 10;
-       }
-
     vip_ctrl_val = read_vip_reg(RK29_VIP_CTRL);
     if (common_flags & SOCAM_PCLK_SAMPLE_FALLING) {
         vip_ctrl_val |= NEGATIVE_EDGE;
@@ -890,26 +1325,36 @@ static int rk29_camera_try_bus_param(struct soc_camera_device *icd, __u32 pixfmt
                         camera_flags, bus_flags);
     return ret;
 }
-static const struct soc_camera_data_format rk29_camera_formats[] = {
-       {
-               .name           = "Planar YUV420 12 bit",
-               .depth          = 12,
-               .fourcc         = V4L2_PIX_FMT_YUV420,
-               .colorspace     = V4L2_COLORSPACE_JPEG,
+
+static const struct soc_mbus_pixelfmt rk29_camera_formats[] = {
+   {
+               .fourcc                 = V4L2_PIX_FMT_NV12,
+               .name                   = "YUV420 NV12",
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_1_5X8,
+               .order                  = SOC_MBUS_ORDER_LE,
+       },{
+               .fourcc                 = V4L2_PIX_FMT_NV16,
+               .name                   = "YUV422 NV16",
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_2X8_PADHI,
+               .order                  = SOC_MBUS_ORDER_LE,
        },{
-               .name           = "Planar YUV422 16 bit",
-               .depth          = 16,
-               .fourcc         = V4L2_PIX_FMT_YUV422P,
-               .colorspace     = V4L2_COLORSPACE_JPEG,
+               .fourcc                 = V4L2_PIX_FMT_YUV420,
+               .name                   = "NV12(v0.0.1)",
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_1_5X8,
+               .order                  = SOC_MBUS_ORDER_LE,
        },{
-               .name           = "Raw Bayer RGB 10 bit",
-               .depth          = 16,
-               .fourcc         = V4L2_PIX_FMT_SGRBG10,
-               .colorspace     = V4L2_COLORSPACE_SRGB,
+               .fourcc                 = V4L2_PIX_FMT_YUV422P,
+               .name                   = "NV16(v0.0.1)",
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_2X8_PADHI,
+               .order                  = SOC_MBUS_ORDER_LE,
        }
 };
 
-static void rk29_camera_setup_format(struct soc_camera_device *icd, __u32 host_pixfmt, __u32 cam_pixfmt, struct v4l2_rect *rect)
+static void rk29_camera_setup_format(struct soc_camera_device *icd, __u32 host_pixfmt, enum v4l2_mbus_pixelcode icd_code, struct v4l2_rect *rect)
 {
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
     struct rk29_camera_dev *pcdev = ici->priv;
@@ -918,34 +1363,33 @@ static void rk29_camera_setup_format(struct soc_camera_device *icd, __u32 host_p
 
     switch (host_pixfmt)
     {
-        case V4L2_PIX_FMT_YUV422P:
+        case V4L2_PIX_FMT_NV16:
+        case V4L2_PIX_FMT_YUV422P:  /* ddl@rock-chips.com: V4L2_PIX_FMT_YUV422P is V4L2_PIX_FMT_NV16 actually in 0.0.1 driver */
             vip_ctrl_val |= VIPREGYUV422;
                        pcdev->frame_inval = RK29_CAM_FRAME_INVAL_DC;
                        pcdev->pixfmt = host_pixfmt;
             break;
-        case V4L2_PIX_FMT_YUV420:
+        case V4L2_PIX_FMT_NV12:
+        case V4L2_PIX_FMT_YUV420:   /* ddl@rock-chips.com: V4L2_PIX_FMT_YUV420 is V4L2_PIX_FMT_NV12 actually in 0.0.1 driver */
             vip_ctrl_val |= VIPREGYUV420;
                        if (pcdev->frame_inval != RK29_CAM_FRAME_INVAL_INIT)
                                pcdev->frame_inval = RK29_CAM_FRAME_INVAL_INIT;
                        pcdev->pixfmt = host_pixfmt;
             break;
-               case V4L2_PIX_FMT_SGRBG10:
-                       vip_ctrl_val |= (VIP_RAW | VIP_SENSOR | VIP_DATA_LITTLEEND);
-                       pcdev->frame_inval = RK29_CAM_FRAME_INVAL_DC;
-                       pcdev->pixfmt = host_pixfmt;
-                       break;
         default:                                                                                /* ddl@rock-chips.com : vip output format is hold when pixfmt is invalidate */
-            vip_ctrl_val |= (read_vip_reg(RK29_VIP_CTRL) & VIPREGYUV422);
+            if (pcdev->frame_inval != RK29_CAM_FRAME_INVAL_INIT)
+                               pcdev->frame_inval = RK29_CAM_FRAME_INVAL_INIT;
+            pcdev->pixfmt = host_pixfmt;
             break;
     }
 
-    switch (cam_pixfmt)
+    switch (icd_code)
     {
-        case V4L2_PIX_FMT_UYVY:
-            vip_ctrl_val |= SENSOR_UYVY;
+        case V4L2_MBUS_FMT_UYVY8_2X8:
+            vip_ctrl_val |= (SENSOR_UYVY|VIP_YUV);
             break;
-        case V4L2_PIX_FMT_YUYV:
-            vip_ctrl_val |= SENSOR_YUYV;
+        case V4L2_MBUS_FMT_YUYV8_2X8:
+            vip_ctrl_val |= (SENSOR_YUYV|VIP_YUV);
             break;
         default :
             vip_ctrl_val |= (read_vip_reg(RK29_VIP_CTRL) & SENSOR_YUYV);
@@ -975,55 +1419,69 @@ static void rk29_camera_setup_format(struct soc_camera_device *icd, __u32 host_p
        return;
 }
 
-static int rk29_camera_get_formats(struct soc_camera_device *icd, int idx,
+static int rk29_camera_get_formats(struct soc_camera_device *icd, unsigned int idx,
                                  struct soc_camera_format_xlate *xlate)
 {
+    struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
     struct device *dev = icd->dev.parent;
-    int formats = 0, buswidth, ret;
-
-    buswidth = 8;
+    int formats = 0, ret;
+       enum v4l2_mbus_pixelcode code;
+       const struct soc_mbus_pixelfmt *fmt;
+
+       ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code);
+       if (ret < 0)
+               /* No more formats */
+               return 0;
+
+       fmt = soc_mbus_get_fmtdesc(code);
+       if (!fmt) {
+               dev_err(dev, "Invalid format code #%u: %d\n", idx, code);
+               return 0;
+       }
 
-    ret = rk29_camera_try_bus_param(icd, buswidth);
+    ret = rk29_camera_try_bus_param(icd, fmt->bits_per_sample);
     if (ret < 0)
         return 0;
 
-    switch (icd->formats[idx].fourcc) {
-        case V4L2_PIX_FMT_UYVY:
-        case V4L2_PIX_FMT_YUYV:
+    switch (code) {
+        case V4L2_MBUS_FMT_UYVY8_2X8:
+        case V4L2_MBUS_FMT_YUYV8_2X8:
             formats++;
             if (xlate) {
                 xlate->host_fmt = &rk29_camera_formats[0];
-                xlate->cam_fmt = icd->formats + idx;
-                xlate->buswidth = buswidth;
+                xlate->code    = code;
                 xlate++;
-                dev_dbg(dev, "Providing format %s using %s\n",
-                       rk29_camera_formats[0].name,
-                       icd->formats[idx].name);
+                dev_dbg(dev, "Providing format %s using code %d\n",
+                       rk29_camera_formats[0].name,code);
             }
 
             formats++;
             if (xlate) {
                 xlate->host_fmt = &rk29_camera_formats[1];
-                xlate->cam_fmt = icd->formats + idx;
-                xlate->buswidth = buswidth;
+                xlate->code    = code;
                 xlate++;
-                dev_dbg(dev, "Providing format %s using %s\n",
-                       rk29_camera_formats[1].name,
-                       icd->formats[idx].name);
+                dev_dbg(dev, "Providing format %s using code %d\n",
+                       rk29_camera_formats[1].name,code);
             }
-                       break;
-               case V4L2_PIX_FMT_SGRBG10:
-                       formats++;
+
+            formats++;
             if (xlate) {
                 xlate->host_fmt = &rk29_camera_formats[2];
-                xlate->cam_fmt = icd->formats + idx;
-                xlate->buswidth = 10;
+                xlate->code    = code;
+                xlate++;
+                dev_dbg(dev, "Providing format %s using code %d\n",
+                       rk29_camera_formats[2].name,code);
+            } 
+
+            formats++;
+            if (xlate) {
+                xlate->host_fmt = &rk29_camera_formats[3];
+                xlate->code    = code;
                 xlate++;
-                dev_dbg(dev, "Providing format %s using %s\n",
-                       rk29_camera_formats[2].name,
-                       icd->formats[idx].name);
+                dev_dbg(dev, "Providing format %s using code %d\n",
+                       rk29_camera_formats[3].name,code);;
             }
-                       break;
+                       break;          
         default:
             break;
     }
@@ -1040,34 +1498,32 @@ static int rk29_camera_set_crop(struct soc_camera_device *icd,
                               struct v4l2_crop *a)
 {
     struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-    struct v4l2_format f;
-    struct v4l2_pix_format *pix = &f.fmt.pix;
+       struct v4l2_mbus_framefmt mf;
+       u32 fourcc = icd->current_fmt->host_fmt->fourcc;
     int ret;
 
-    f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-    ret = v4l2_subdev_call(sd, video, g_fmt, &f);
+    ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf);
     if (ret < 0)
         return ret;
 
-    if ((pix->width < (a->c.left + a->c.width)) || (pix->height < (a->c.top + a->c.height)))  {
+    if ((mf.width < (a->c.left + a->c.width)) || (mf.height < (a->c.top + a->c.height)))  {
 
-        pix->width = a->c.left + a->c.width;
-        pix->height = a->c.top + a->c.height;
+        mf.width = a->c.left + a->c.width;
+        mf.height = a->c.top + a->c.height;
 
-        v4l_bound_align_image(&pix->width, RK29_CAM_W_MIN, RK29_CAM_W_MAX, 1,
-            &pix->height, RK29_CAM_H_MIN, RK29_CAM_H_MAX, 0,
-            icd->current_fmt->fourcc == V4L2_PIX_FMT_YUV422P ?4 : 0);
+        v4l_bound_align_image(&mf.width, RK29_CAM_W_MIN, RK29_CAM_W_MAX, 1,
+            &mf.height, RK29_CAM_H_MIN, RK29_CAM_H_MAX, 0,
+            fourcc == V4L2_PIX_FMT_NV16 ?4 : 0);
 
-        ret = v4l2_subdev_call(sd, video, s_fmt, &f);
+        ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
         if (ret < 0)
             return ret;
     }
 
-    rk29_camera_setup_format(icd, icd->current_fmt->fourcc, pix->pixelformat, &a->c);
+    rk29_camera_setup_format(icd, fourcc, mf.code, &a->c);
 
-    icd->user_width = pix->width;
-    icd->user_height = pix->height;
+    icd->user_width = mf.width;
+    icd->user_height = mf.height;
 
     return 0;
 }
@@ -1077,14 +1533,14 @@ static int rk29_camera_set_fmt(struct soc_camera_device *icd,
 {
     struct device *dev = icd->dev.parent;
     struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-    const struct soc_camera_data_format *cam_fmt = NULL;
     const struct soc_camera_format_xlate *xlate = NULL;
        struct soc_camera_host *ici =to_soc_camera_host(icd->dev.parent);
     struct rk29_camera_dev *pcdev = ici->priv;
     struct v4l2_pix_format *pix = &f->fmt.pix;
-    struct v4l2_format cam_f = *f;
+    struct v4l2_mbus_framefmt mf;
     struct v4l2_rect rect;
-    int ret,usr_w,usr_h;
+    int ret,usr_w,usr_h,icd_width,icd_height;
+    int stream_on = 0;
 
        usr_w = pix->width;
        usr_h = pix->height;
@@ -1096,99 +1552,255 @@ static int rk29_camera_set_fmt(struct soc_camera_device *icd,
         ret = -EINVAL;
         goto RK29_CAMERA_SET_FMT_END;
     }
+    
+    /* ddl@rock-chips.com: sensor init code transmit in here after open */
+    if (pcdev->icd_init == 0) {
+        v4l2_subdev_call(sd,core, init, 0);        
+        pcdev->icd_init = 1;
+    }
 
-    cam_fmt = xlate->cam_fmt;
-
-    cam_f.fmt.pix.pixelformat = cam_fmt->fourcc;
-    ret = v4l2_subdev_call(sd, video, s_fmt, &cam_f);
-    cam_f.fmt.pix.pixelformat = pix->pixelformat;
-    *pix = cam_f.fmt.pix;
+    stream_on = read_vip_reg(RK29_VIP_CTRL);
+    if (stream_on & ENABLE_CAPTURE)
+        write_vip_reg(RK29_VIP_CTRL, (stream_on & (~ENABLE_CAPTURE)));
+    
+       mf.width        = pix->width;
+       mf.height       = pix->height;
+       mf.field        = pix->field;
+       mf.colorspace   = pix->colorspace;
+       mf.code         = xlate->code;
+
+       ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
+
+       if (mf.code != xlate->code)
+               return -EINVAL;
+    
+    icd_width = mf.width;
+    icd_height = mf.height;
        #ifdef CONFIG_VIDEO_RK29_WORK_IPP
-       if ((pix->width != usr_w) || (pix->height != usr_h)) {
-               pix->width = usr_w;
-               pix->height = usr_h;
+       if ((mf.width != usr_w) || (mf.height != usr_h)) {
+        if (unlikely((mf.width <16) || (mf.width > 8190) || (mf.height < 16) || (mf.height > 8190))) {
+               RK29CAMERA_TR("Senor and IPP both invalid source resolution(%dx%d)\n",mf.width,mf.height);
+               ret = -EINVAL;
+               goto RK29_CAMERA_SET_FMT_END;
+       }       
+       if (unlikely((usr_w <16)||(usr_h < 16))) {
+               RK29CAMERA_TR("Senor and IPP both invalid destination resolution(%dx%d)\n",usr_w,usr_h);
+               ret = -EINVAL;
+            goto RK29_CAMERA_SET_FMT_END;
+       }
        }
        #endif
     icd->sense = NULL;
 
     if (!ret) {
-        rect.left = 0;
-        rect.top = 0;
-        rect.width = cam_f.fmt.pix.width;
-        rect.height = cam_f.fmt.pix.height;
 
-        RK29CAMERA_DG("%s..%s..%s icd width:%d  host width:%d \n",__FUNCTION__,xlate->host_fmt->name, cam_fmt->name,
-                                  rect.width, pix->width);
-        rk29_camera_setup_format(icd, pix->pixelformat, cam_fmt->fourcc, &rect);
-        icd->buswidth = xlate->buswidth;
-        icd->current_fmt = xlate->host_fmt;
+        if (mf.width*usr_h == mf.height*usr_w) {
+            rect.width = mf.width;
+            rect.height = mf.height;
+        } else {
+            int ratio;
+            if (usr_w > usr_h) {
+                if (mf.width > usr_w) {
+                    ratio = MIN((mf.width*10/usr_w),(mf.height*10/usr_h))-1;
+                    rect.width = usr_w*ratio/10;
+                    rect.height = usr_h*ratio/10;                    
+                } else {
+                    ratio = MAX((usr_w*10/mf.width),(usr_h*10/mf.height))+1;
+                    rect.width = usr_w*10/ratio;
+                    rect.height = usr_h*10/ratio;
+                }                
+            } else {
+                if (mf.height > usr_h) {
+                    ratio = MIN((mf.width*10/usr_w),(mf.height*10/usr_h))-1;
+                    rect.width = usr_w*ratio/10;
+                    rect.height = usr_h*ratio/10;                     
+                } else {
+                    ratio = MAX((usr_w*10/mf.width),(usr_h*10/mf.height))+1;
+                    rect.width = usr_w*10/ratio;
+                    rect.height = usr_h*10/ratio;
+                }
+            }
+        }
 
-               if (((pcdev->host_width != pcdev->icd->user_width) || (pcdev->host_height != pcdev->icd->user_height))) {
+        rect.left = (mf.width - rect.width)/2;
+        rect.top = (mf.height - rect.height)/2;
+
+        down(&pcdev->zoominfo.sem);        
+        pcdev->zoominfo.a.c.width = rect.width*100/pcdev->zoominfo.zoom_rate;
+               pcdev->zoominfo.a.c.width &= ~0x03;
+               pcdev->zoominfo.a.c.height = rect.height*100/pcdev->zoominfo.zoom_rate;
+               pcdev->zoominfo.a.c.height &= ~0x03;
+               pcdev->zoominfo.a.c.left = ((rect.width - pcdev->zoominfo.a.c.width)/2 + rect.left)&(~0x01);
+               pcdev->zoominfo.a.c.top = ((rect.height - pcdev->zoominfo.a.c.height)/2 + rect.top)&(~0x01);
+        up(&pcdev->zoominfo.sem);
+
+        /* ddl@rock-chips.com: IPP work limit check */
+        if ((pcdev->zoominfo.a.c.width != usr_w) || (pcdev->zoominfo.a.c.height != usr_h)) {
+            if (usr_w > 0x7f0) {
+                if (((usr_w>>1)&0x3f) && (((usr_w>>1)&0x3f) <= 8)) {
+                    RK29CAMERA_TR("IPP Destination resolution(%dx%d, ((%d div 1) mod 64)=%d is <= 8)",usr_w,usr_h, usr_w, (int)((usr_w>>1)&0x3f));
+                    ret = -EINVAL;
+                    goto RK29_CAMERA_SET_FMT_END;
+                }
+            } else {
+                if ((usr_w&0x3f) && ((usr_w&0x3f) <= 8)) {
+                    RK29CAMERA_TR("IPP Destination resolution(%dx%d, %d mod 64=%d is <= 8)",usr_w,usr_h, usr_w, (int)(usr_w&0x3f));
+                    ret = -EINVAL;
+                    goto RK29_CAMERA_SET_FMT_END;
+                }
+            }
+        }
+        
+        /* ddl@rock-chips.com: Crop is doing by IPP, not by VIP in rk2918 */
+        rect.left = 0;
+        rect.top = 0;
+        rect.width = mf.width;
+        rect.height = mf.height;
+        
+        RK29CAMERA_DG("%s..%s Sensor output:%dx%d  VIP output:%dx%d (zoom: %dx%d@(%d,%d)->%dx%d)\n",__FUNCTION__,xlate->host_fmt->name,
+                                  mf.width, mf.height,rect.width,rect.height, pcdev->zoominfo.a.c.width,pcdev->zoominfo.a.c.height, pcdev->zoominfo.a.c.left,pcdev->zoominfo.a.c.top,
+                                  pix->width, pix->height);
+
+                
+        rk29_camera_setup_format(icd, pix->pixelformat, mf.code, &rect); 
+        
+               if (CAM_IPPWORK_IS_EN()) {
                        BUG_ON(pcdev->vipmem_phybase == 0);
                }
+        pcdev->icd_width = icd_width;
+        pcdev->icd_height = icd_height;
+
+        pix->width = usr_w;
+       pix->height = usr_h;
+       pix->field = mf.field;
+       pix->colorspace = mf.colorspace;
+       icd->current_fmt = xlate;        
     }
 
 RK29_CAMERA_SET_FMT_END:
+    if (stream_on & ENABLE_CAPTURE)
+        write_vip_reg(RK29_VIP_CTRL, (read_vip_reg(RK29_VIP_CTRL) | ENABLE_CAPTURE));
        if (ret)
-       RK29CAMERA_TR("\n%s..%d.. ret = %d  \n",__FUNCTION__,__LINE__, ret);
+       RK29CAMERA_TR("\n%s: Driver isn't support %dx%d resolution which user request!\n",__FUNCTION__,usr_w,usr_h);
     return ret;
 }
+static bool rk29_camera_fmt_capturechk(struct v4l2_format *f)
+{
+    bool ret = false;
+
+       if ((f->fmt.pix.width == 1024) && (f->fmt.pix.height == 768)) {
+               ret = true;
+       } else if ((f->fmt.pix.width == 1280) && (f->fmt.pix.height == 1024)) {
+               ret = true;
+       } else if ((f->fmt.pix.width == 1600) && (f->fmt.pix.height == 1200)) {
+               ret = true;
+       } else if ((f->fmt.pix.width == 2048) && (f->fmt.pix.height == 1536)) {
+               ret = true;
+       } else if ((f->fmt.pix.width == 2592) && (f->fmt.pix.height == 1944)) {
+               ret = true;
+       }
 
+       if (ret == true)
+               RK29CAMERA_DG("%s %dx%d is capture format\n", __FUNCTION__, f->fmt.pix.width, f->fmt.pix.height);
+       return ret;
+}
 static int rk29_camera_try_fmt(struct soc_camera_device *icd,
                                    struct v4l2_format *f)
 {
     struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct rk29_camera_dev *pcdev = ici->priv;
     struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
     const struct soc_camera_format_xlate *xlate;
     struct v4l2_pix_format *pix = &f->fmt.pix;
     __u32 pixfmt = pix->pixelformat;
-    enum v4l2_field field;
-    int ret,usr_w,usr_h;
-
+    int ret,usr_w,usr_h,i;
+       bool is_capture = rk29_camera_fmt_capturechk(f);
+       bool vipmem_is_overflow = false;
+    struct v4l2_mbus_framefmt mf;
+    int bytes_per_line_host;
+    
        usr_w = pix->width;
        usr_h = pix->height;
        RK29CAMERA_DG("%s enter width:%d  height:%d\n",__FUNCTION__,usr_w,usr_h);
 
     xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
     if (!xlate) {
-        dev_err(ici->v4l2_dev.dev, "Format %x not found\n", pixfmt);
+        dev_err(icd->dev.parent, "Format (%c%c%c%c) not found\n", pixfmt & 0xFF, (pixfmt >> 8) & 0xFF,
+                       (pixfmt >> 16) & 0xFF, (pixfmt >> 24) & 0xFF);
         ret = -EINVAL;
+        RK29CAMERA_TR("%s(version:%c%c%c) support format:\n",rk29_cam_driver_description,(RK29_CAM_VERSION_CODE&0xff0000)>>16,
+            (RK29_CAM_VERSION_CODE&0xff00)>>8,(RK29_CAM_VERSION_CODE&0xff));
+        for (i = 0; i < icd->num_user_formats; i++)
+                   RK29CAMERA_TR("(%c%c%c%c)-%s\n",
+                   icd->user_formats[i].host_fmt->fourcc & 0xFF, (icd->user_formats[i].host_fmt->fourcc >> 8) & 0xFF,
+                       (icd->user_formats[i].host_fmt->fourcc >> 16) & 0xFF, (icd->user_formats[i].host_fmt->fourcc >> 24) & 0xFF,
+                       icd->user_formats[i].host_fmt->name);
         goto RK29_CAMERA_TRY_FMT_END;
     }
    /* limit to rk29 hardware capabilities */
     v4l_bound_align_image(&pix->width, RK29_CAM_W_MIN, RK29_CAM_W_MAX, 1,
              &pix->height, RK29_CAM_H_MIN, RK29_CAM_H_MAX, 0,
-             pixfmt == V4L2_PIX_FMT_YUV422P ? 4 : 0);
+             pixfmt == V4L2_PIX_FMT_NV16 ? 4 : 0);
 
-    pix->bytesperline = pix->width * DIV_ROUND_UP(xlate->host_fmt->depth, 8);
-    pix->sizeimage = pix->height * pix->bytesperline;
+    pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
+                                                   xlate->host_fmt);
+       if (pix->bytesperline < 0)
+               return pix->bytesperline;
 
-    /* camera has to see its format, but the user the original one */
-    pix->pixelformat = xlate->cam_fmt->fourcc;
     /* limit to sensor capabilities */
-    ret = v4l2_subdev_call(sd, video, try_fmt, f);
-    pix->pixelformat = pixfmt;
-       #ifdef CONFIG_VIDEO_RK29_WORK_IPP
-       if ((pix->width > usr_w) && (pix->height > usr_h)) {
-               pix->width = usr_w;
-               pix->height = usr_h;
-       } else if ((pix->width < usr_w) && (pix->height < usr_h)) {
-               if (((usr_w>>1) < pix->width) && ((usr_h>>1) < pix->height)) {
+       mf.width        = pix->width;
+       mf.height       = pix->height;
+       mf.field        = pix->field;
+       mf.colorspace   = pix->colorspace;
+       mf.code         = xlate->code;
+
+       ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
+       if (ret < 0)
+               goto RK29_CAMERA_TRY_FMT_END;
+    RK29CAMERA_DG("%s mf.width:%d  mf.height:%d\n",__FUNCTION__,mf.width,mf.height);
+       #ifdef CONFIG_VIDEO_RK29_WORK_IPP       
+       if ((mf.width != usr_w) || (mf.height != usr_h)) {
+        bytes_per_line_host = soc_mbus_bytes_per_line(mf.width,icd->current_fmt->host_fmt); 
+               if (is_capture) {
+                       vipmem_is_overflow = (PAGE_ALIGN(bytes_per_line_host*mf.height) > pcdev->vipmem_size);
+               } else {
+                       /* Assume preview buffer minimum is 4 */
+                       vipmem_is_overflow = (PAGE_ALIGN(bytes_per_line_host*mf.height)*4 > pcdev->vipmem_size);
+               }        
+               if (vipmem_is_overflow == false) {
                        pix->width = usr_w;
                        pix->height = usr_h;
+               } else {
+                       RK29CAMERA_TR("vipmem for IPP is overflow, This resolution(%dx%d -> %dx%d) is invalidate!\n",mf.width,mf.height,usr_w,usr_h);
+            pix->width = mf.width;
+            pix->height = mf.height;            
                }
+        
+        if ((mf.width < usr_w) || (mf.height < usr_h)) {
+            if (((usr_w>>1) > mf.width) || ((usr_h>>1) > mf.height)) {
+                RK29CAMERA_TR("The aspect ratio(%dx%d/%dx%d) is bigger than 2 !\n",mf.width,mf.height,usr_w,usr_h);
+                pix->width = mf.width;
+                pix->height = mf.height;
+            }
+        }        
+       }
+       #else
+    pix->width = mf.width;
+       pix->height     = mf.height;    
+    #endif
+    pix->colorspace    = mf.colorspace;    
+
+    switch (mf.field) {
+       case V4L2_FIELD_ANY:
+       case V4L2_FIELD_NONE:
+               pix->field      = V4L2_FIELD_NONE;
+               break;
+       default:
+               /* TODO: support interlaced at least in pass-through mode */
+               dev_err(icd->dev.parent, "Field type %d unsupported.\n",
+                       mf.field);
+               goto RK29_CAMERA_TRY_FMT_END;
        }
-       #endif
-
-    field = pix->field;
-
-    if (field == V4L2_FIELD_ANY) {
-        pix->field = V4L2_FIELD_NONE;
-    } else if (field != V4L2_FIELD_NONE) {
-        dev_err(icd->dev.parent, "Field type %d unsupported.\n", field);
-        ret = -EINVAL;
-        goto RK29_CAMERA_TRY_FMT_END;
-    }
 
 RK29_CAMERA_TRY_FMT_END:
        if (ret)
@@ -1196,7 +1808,7 @@ RK29_CAMERA_TRY_FMT_END:
     return ret;
 }
 
-static int rk29_camera_reqbufs(struct soc_camera_file *icf,
+static int rk29_camera_reqbufs(struct soc_camera_device *icd,
                                struct v4l2_requestbuffers *p)
 {
     int i;
@@ -1206,7 +1818,7 @@ static int rk29_camera_reqbufs(struct soc_camera_file *icf,
      * a dma IRQ can occur for an in-work or unlinked buffer. Until now
      * it hadn't triggered */
     for (i = 0; i < p->count; i++) {
-        struct rk29_buffer *buf = container_of(icf->vb_vidq.bufs[i],
+        struct rk29_buffer *buf = container_of(icd->vb_vidq.bufs[i],
                                                            struct rk29_buffer, vb);
         buf->inwork = 0;
         INIT_LIST_HEAD(&buf->vb.queue);
@@ -1217,10 +1829,10 @@ static int rk29_camera_reqbufs(struct soc_camera_file *icf,
 
 static unsigned int rk29_camera_poll(struct file *file, poll_table *pt)
 {
-    struct soc_camera_file *icf = file->private_data;
+    struct soc_camera_device *icd = file->private_data;
     struct rk29_buffer *buf;
 
-    buf = list_entry(icf->vb_vidq.stream.next, struct rk29_buffer,
+    buf = list_entry(icd->vb_vidq.stream.next, struct rk29_buffer,
                      vb.stream);
 
     poll_wait(file, &buf->vb.done, pt);
@@ -1235,8 +1847,29 @@ static unsigned int rk29_camera_poll(struct file *file, poll_table *pt)
 static int rk29_camera_querycap(struct soc_camera_host *ici,
                                 struct v4l2_capability *cap)
 {
-    /* cap->name is set by the firendly caller:-> */
-    strlcpy(cap->card, rk29_cam_driver_description, sizeof(cap->card));
+    struct rk29_camera_dev *pcdev = ici->priv;
+    char orientation[5];
+    int i;
+
+    strlcpy(cap->card, dev_name(pcdev->icd->pdev), sizeof(cap->card));
+
+    memset(orientation,0x00,sizeof(orientation));
+    for (i=0; i<RK29_CAM_SUPPORT_NUMS;i++) {
+        if ((pcdev->pdata->info[i].dev_name!=NULL) && (strcmp(dev_name(pcdev->icd->pdev), pcdev->pdata->info[i].dev_name) == 0)) {
+            sprintf(orientation,"-%d",pcdev->pdata->info[i].orientation);
+        }
+    }
+    
+    if (orientation[0] != '-') {
+        RK29CAMERA_TR("%s: %s is not registered in rk29_camera_platform_data, orientation apply default value",__FUNCTION__,dev_name(pcdev->icd->pdev));
+        if (strstr(dev_name(pcdev->icd->pdev),"front")) 
+            strcat(cap->card,"-270");
+        else 
+            strcat(cap->card,"-90");
+    } else {
+        strcat(cap->card,orientation); 
+    }
+    
     cap->version = RK29_CAM_VERSION_CODE;
     cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
 
@@ -1323,7 +1956,7 @@ static void rk29_camera_reinit_work(struct work_struct *work)
 {
        struct device *control;
     struct v4l2_subdev *sd;
-       struct v4l2_format cam_f;
+       struct v4l2_mbus_framefmt mf;
        const struct soc_camera_format_xlate *xlate;
        int ret;
 
@@ -1331,25 +1964,88 @@ static void rk29_camera_reinit_work(struct work_struct *work)
 
        control = to_soc_camera_control(rk29_camdev_info_ptr->icd);
        sd = dev_get_drvdata(control);
+    v4l2_subdev_call(sd, video, s_stream, 0);  /* ddl@rock-chips.com: Avoid sensor autofocus thread is running */
        ret = v4l2_subdev_call(sd,core, init, 1);
 
-       cam_f.fmt.pix.width = rk29_camdev_info_ptr->icd->user_width;
-       cam_f.fmt.pix.height = rk29_camdev_info_ptr->icd->user_height;
-       xlate = soc_camera_xlate_by_fourcc(rk29_camdev_info_ptr->icd, rk29_camdev_info_ptr->icd->current_fmt->fourcc);
-       cam_f.fmt.pix.pixelformat = xlate->cam_fmt->fourcc;
-       ret |= v4l2_subdev_call(sd, video, s_fmt, &cam_f);
+       mf.width = rk29_camdev_info_ptr->icd->user_width;
+       mf.height = rk29_camdev_info_ptr->icd->user_height;
+       xlate = soc_camera_xlate_by_fourcc(rk29_camdev_info_ptr->icd, rk29_camdev_info_ptr->icd->current_fmt->host_fmt->fourcc);        
+       mf.code = xlate->code;
 
+       ret |= v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
+    v4l2_subdev_call(sd, video, s_stream, 1);
        write_vip_reg(RK29_VIP_CTRL, (read_vip_reg(RK29_VIP_CTRL)|ENABLE_CAPTURE));
 
        RK29CAMERA_TR("Camera host haven't recevie data from sensor,Reinit sensor now! ret:0x%x\n",ret);
 }
 static enum hrtimer_restart rk29_camera_fps_func(struct hrtimer *timer)
 {
+    struct rk29_camera_frmivalenum *fival_nxt=NULL,*fival_pre=NULL, *fival_rec=NULL;
+    int rec_flag,i;
+    
        RK29CAMERA_DG("rk29_camera_fps_func fps:0x%x\n",rk29_camdev_info_ptr->fps);
-       if (rk29_camdev_info_ptr->fps < 3) {
+       if (rk29_camdev_info_ptr->fps < 2) {
                RK29CAMERA_TR("Camera host haven't recevie data from sensor,Reinit sensor delay!\n");
                INIT_WORK(&rk29_camdev_info_ptr->camera_reinit_work, rk29_camera_reinit_work);
                queue_work(rk29_camdev_info_ptr->camera_wq,&(rk29_camdev_info_ptr->camera_reinit_work));
+       } else {
+           for (i=0; i<2; i++) {
+            if (rk29_camdev_info_ptr->icd == rk29_camdev_info_ptr->icd_frmival[i].icd) {
+                fival_nxt = rk29_camdev_info_ptr->icd_frmival[i].fival_list;                
+            }
+        }
+        
+        rec_flag = 0;
+        fival_pre = fival_nxt;
+        while (fival_nxt != NULL) {
+
+            RK29CAMERA_DG("%s %c%c%c%c %dx%d framerate : %d/%d\n", dev_name(&rk29_camdev_info_ptr->icd->dev), 
+                fival_nxt->fival.pixel_format & 0xFF, (fival_nxt->fival.pixel_format >> 8) & 0xFF,
+                           (fival_nxt->fival.pixel_format >> 16) & 0xFF, (fival_nxt->fival.pixel_format >> 24),
+                           fival_nxt->fival.width, fival_nxt->fival.height, fival_nxt->fival.discrete.denominator,
+                           fival_nxt->fival.discrete.numerator);
+            
+            if (((fival_nxt->fival.pixel_format == rk29_camdev_info_ptr->pixfmt) 
+                && (fival_nxt->fival.height == rk29_camdev_info_ptr->icd->user_height)
+                && (fival_nxt->fival.width == rk29_camdev_info_ptr->icd->user_width))
+                || (fival_nxt->fival.discrete.denominator == 0)) {
+                
+                fival_nxt->fival.index = 0;
+                fival_nxt->fival.width = rk29_camdev_info_ptr->icd->user_width;
+                fival_nxt->fival.height= rk29_camdev_info_ptr->icd->user_height;
+                fival_nxt->fival.pixel_format = rk29_camdev_info_ptr->pixfmt;
+                fival_nxt->fival.discrete.denominator = rk29_camdev_info_ptr->frame_interval;                
+                fival_nxt->fival.reserved[1] = (rk29_camdev_info_ptr->icd_width<<16)
+                                                    |(rk29_camdev_info_ptr->icd_height);
+                fival_nxt->fival.discrete.numerator = 1000000;
+                fival_nxt->fival.type = V4L2_FRMIVAL_TYPE_DISCRETE;
+                
+                rec_flag = 1;
+                fival_rec = fival_nxt;
+            }
+            fival_pre = fival_nxt;
+            fival_nxt = fival_nxt->nxt;            
+        }
+
+        if ((rec_flag == 0) && fival_pre) {
+            fival_pre->nxt = kzalloc(sizeof(struct rk29_camera_frmivalenum), GFP_ATOMIC);
+            if (fival_pre->nxt != NULL) {
+                fival_pre->nxt->fival.index = fival_pre->fival.index++;
+                fival_pre->nxt->fival.width = rk29_camdev_info_ptr->icd->user_width;
+                fival_pre->nxt->fival.height= rk29_camdev_info_ptr->icd->user_height;
+                fival_pre->nxt->fival.pixel_format = rk29_camdev_info_ptr->pixfmt;
+
+                fival_pre->nxt->fival.discrete.denominator = rk29_camdev_info_ptr->frame_interval;
+                
+                fival_pre->nxt->fival.reserved[1] = (rk29_camdev_info_ptr->icd_width<<16)
+                                                    |(rk29_camdev_info_ptr->icd_height);
+                
+                fival_pre->nxt->fival.discrete.numerator = 1000000;
+                fival_pre->nxt->fival.type = V4L2_FRMIVAL_TYPE_DISCRETE;
+                rec_flag = 1;
+                fival_rec = fival_pre->nxt;
+            }
+        }
        }
 
        return HRTIMER_NORESTART;
@@ -1362,12 +2058,12 @@ static int rk29_camera_s_stream(struct soc_camera_device *icd, int enable)
        int ret;
 
        WARN_ON(pcdev->icd != icd);
-
+    pcdev->frame_interval = 0;
        vip_ctrl_val = read_vip_reg(RK29_VIP_CTRL);
        if (enable) {
                pcdev->fps = 0;
                hrtimer_cancel(&pcdev->fps_timer);
-               hrtimer_start(&pcdev->fps_timer,ktime_set(2, 0),HRTIMER_MODE_REL);
+               hrtimer_start(&pcdev->fps_timer,ktime_set(1, 0),HRTIMER_MODE_REL);
                vip_ctrl_val |= ENABLE_CAPTURE;
        } else {
         vip_ctrl_val &= ~ENABLE_CAPTURE;
@@ -1380,6 +2076,182 @@ static int rk29_camera_s_stream(struct soc_camera_device *icd, int enable)
        RK29CAMERA_DG("%s.. enable : 0x%x \n", __FUNCTION__, enable);
        return 0;
 }
+int rk29_camera_enum_frameintervals(struct soc_camera_device *icd, struct v4l2_frmivalenum *fival)
+{
+    struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+    struct rk29_camera_dev *pcdev = ici->priv;
+    struct rk29_camera_frmivalenum *fival_list = NULL;
+    struct v4l2_frmivalenum *fival_head=NULL;
+    int i,ret = 0,index;
+    
+    index = fival->index & 0x00ffffff;
+    if ((fival->index & 0xff000000) == 0xff000000) {   /* ddl@rock-chips.com: detect framerate */ 
+        for (i=0; i<2; i++) {
+            if (pcdev->icd_frmival[i].icd == icd) {
+                fival_list = pcdev->icd_frmival[i].fival_list;            
+            }
+        }
+        
+        if (fival_list != NULL) {
+            i = 0;
+            while (fival_list != NULL) {
+                if ((fival->pixel_format == fival_list->fival.pixel_format)
+                    && (fival->height == fival_list->fival.height) 
+                    && (fival->width == fival_list->fival.width)) {
+                    if (i == index)
+                        break;
+                    i++;
+                }                
+                fival_list = fival_list->nxt;                
+            }
+            
+            if ((i==index) && (fival_list != NULL)) {
+                memcpy(fival, &fival_list->fival, sizeof(struct v4l2_frmivalenum));
+            } else {
+                ret = -EINVAL;
+            }
+        } else {
+            RK29CAMERA_TR("%s: fival_list is NULL\n",__FUNCTION__);
+            ret = -EINVAL;
+        }
+    } else {  
+
+        for (i=0; i<RK29_CAM_SUPPORT_NUMS; i++) {
+            if (pcdev->pdata->info[i].dev_name && (strcmp(dev_name(pcdev->icd->pdev),pcdev->pdata->info[i].dev_name) == 0)) {
+                fival_head = pcdev->pdata->info[i].fival;
+            }
+        }
+        
+        if (fival_head == NULL) {
+            RK29CAMERA_TR("%s: %s is not registered in rk29_camera_platform_data!!",__FUNCTION__,dev_name(pcdev->icd->pdev));
+            ret = -EINVAL;
+            goto rk29_camera_enum_frameintervals_end;
+        }
+        
+        i = 0;
+        while (fival_head->width && fival_head->height) {
+            if ((fival->pixel_format == fival_head->pixel_format)
+                && (fival->height == fival_head->height) 
+                && (fival->width == fival_head->width)) {
+                if (i == index) {
+                    break;
+                }
+                i++;
+            }
+            fival_head++;  
+        }
+
+        if ((i == index) && (fival->height == fival_head->height) && (fival->width == fival_head->width)) {
+            memcpy(fival, fival_head, sizeof(struct v4l2_frmivalenum));
+            RK29CAMERA_DG("%s %dx%d@%c%c%c%c framerate : %d/%d\n", dev_name(rk29_camdev_info_ptr->icd->pdev),
+                fival->width, fival->height,
+                fival->pixel_format & 0xFF, (fival->pixel_format >> 8) & 0xFF,
+                           (fival->pixel_format >> 16) & 0xFF, (fival->pixel_format >> 24),
+                            fival->discrete.denominator,fival->discrete.numerator);                        
+        } else {
+            if (index == 0)
+                RK29CAMERA_TR("%s have not catch %dx%d@%c%c%c%c index(%d) framerate\n",dev_name(rk29_camdev_info_ptr->icd->pdev),
+                    fival->width,fival->height, 
+                    fival->pixel_format & 0xFF, (fival->pixel_format >> 8) & 0xFF,
+                           (fival->pixel_format >> 16) & 0xFF, (fival->pixel_format >> 24),
+                           index);
+            else
+                RK29CAMERA_DG("%s have not catch %dx%d@%c%c%c%c index(%d) framerate\n",dev_name(rk29_camdev_info_ptr->icd->pdev),
+                    fival->width,fival->height, 
+                    fival->pixel_format & 0xFF, (fival->pixel_format >> 8) & 0xFF,
+                           (fival->pixel_format >> 16) & 0xFF, (fival->pixel_format >> 24),
+                           index);
+            ret = -EINVAL;
+        }
+    }
+rk29_camera_enum_frameintervals_end:
+    return ret;
+}
+
+#ifdef CONFIG_VIDEO_RK29_DIGITALZOOM_IPP_ON
+static int rk29_camera_set_digit_zoom(struct soc_camera_device *icd,
+                                                               const struct v4l2_queryctrl *qctrl, int zoom_rate)
+{
+       struct v4l2_crop a;
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       struct rk29_camera_dev *pcdev = ici->priv;
+       
+/* ddl@rock-chips.com : The largest resolution is 2047x1088, so larger resolution must be operated some times
+   (Assume operate times is 4),but resolution which ipp can operate ,it is width and height must be even. */
+       a.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       a.c.width = pcdev->host_width*100/zoom_rate;
+       a.c.width &= ~0x03;    
+       a.c.height = pcdev->host_height*100/zoom_rate;
+       a.c.height &= ~0x03;
+       
+       a.c.left = ((pcdev->host_width - a.c.width)>>1)&(~0x01);
+       a.c.top = ((pcdev->host_height - a.c.height)>>1)&(~0x01);
+
+    down(&pcdev->zoominfo.sem);
+       pcdev->zoominfo.a.c.height = a.c.height;
+       pcdev->zoominfo.a.c.width = a.c.width;
+       pcdev->zoominfo.a.c.top = a.c.top;
+       pcdev->zoominfo.a.c.left = a.c.left;
+    up(&pcdev->zoominfo.sem);
+    
+       RK29CAMERA_DG("%s..zoom_rate:%d (%dx%d at (%d,%d)-> %dx%d)\n",__FUNCTION__, zoom_rate,a.c.width, a.c.height, a.c.left, a.c.top, pcdev->host_width, pcdev->host_height );
+
+       return 0;
+}
+#endif
+static inline struct v4l2_queryctrl const *rk29_camera_soc_camera_find_qctrl(
+       struct soc_camera_host_ops *ops, int id)
+{
+       int i;
+
+       for (i = 0; i < ops->num_controls; i++)
+               if (ops->controls[i].id == id)
+                       return &ops->controls[i];
+
+       return NULL;
+}
+
+
+static int rk29_camera_set_ctrl(struct soc_camera_device *icd,
+                                                               struct v4l2_control *sctrl)
+{
+
+       struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+       const struct v4l2_queryctrl *qctrl;
+    struct rk29_camera_dev *pcdev = ici->priv;
+    int ret = 0;
+
+       qctrl = rk29_camera_soc_camera_find_qctrl(ici->ops, sctrl->id);
+       if (!qctrl) {
+               ret = -ENOIOCTLCMD;
+        goto rk29_camera_set_ctrl_end;
+       }
+
+       switch (sctrl->id)
+       {
+       #ifdef CONFIG_VIDEO_RK29_DIGITALZOOM_IPP_ON
+               case V4L2_CID_ZOOM_ABSOLUTE:
+               {
+                       if ((sctrl->value < qctrl->minimum) || (sctrl->value > qctrl->maximum)){
+                       ret = -EINVAL;
+                goto rk29_camera_set_ctrl_end;
+               }
+            ret = rk29_camera_set_digit_zoom(icd, qctrl, sctrl->value);
+                       if (ret == 0) {
+                               pcdev->zoominfo.zoom_rate = sctrl->value;
+            } else { 
+                goto rk29_camera_set_ctrl_end;
+            }
+                       break;
+               }
+    #endif
+               default:
+                       ret = -ENOIOCTLCMD;
+                       break;
+       }
+rk29_camera_set_ctrl_end:
+       return ret;
+}
 
 static struct soc_camera_host_ops rk29_soc_camera_host_ops =
 {
@@ -1388,8 +2260,9 @@ static struct soc_camera_host_ops rk29_soc_camera_host_ops =
     .remove            = rk29_camera_remove_device,
     .suspend   = rk29_camera_suspend,
     .resume            = rk29_camera_resume,
+    .enum_frameinervals = rk29_camera_enum_frameintervals,
     .set_crop  = rk29_camera_set_crop,
-    .get_formats       = rk29_camera_get_formats,
+    .get_formats       = rk29_camera_get_formats, 
     .put_formats       = rk29_camera_put_formats,
     .set_fmt   = rk29_camera_set_fmt,
     .try_fmt   = rk29_camera_try_fmt,
@@ -1398,16 +2271,23 @@ static struct soc_camera_host_ops rk29_soc_camera_host_ops =
     .poll              = rk29_camera_poll,
     .querycap  = rk29_camera_querycap,
     .set_bus_param     = rk29_camera_set_bus_param,
-    .s_stream = rk29_camera_s_stream   /* ddl@rock-chips.com : Add stream control for host */
+    .s_stream = rk29_camera_s_stream,   /* ddl@rock-chips.com : Add stream control for host */
+    .set_ctrl = rk29_camera_set_ctrl,
+    .controls = rk29_camera_controls,
+    .num_controls = ARRAY_SIZE(rk29_camera_controls)
+    
 };
 static int rk29_camera_probe(struct platform_device *pdev)
 {
     struct rk29_camera_dev *pcdev;
     struct resource *res;
-    int irq;
+    struct rk29_camera_frmivalenum *fival_list,*fival_nxt;
+    int irq,i;
     int err = 0;
 
-    RK29CAMERA_DG("%s..%s..%d  \n",__FUNCTION__,__FILE__,__LINE__);
+    RK29CAMERA_TR("RK29 Camera driver version: v%d.%d.%d  Zoom by %s\n",(RK29_CAM_VERSION_CODE&0xff0000)>>16,
+        (RK29_CAM_VERSION_CODE&0xff00)>>8,RK29_CAM_VERSION_CODE&0xff,CAMERA_SCALE_CROP_MACHINE);
+    
     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
     irq = platform_get_irq(pdev, 0);
     if (!res || irq < 0) {
@@ -1429,17 +2309,21 @@ static int rk29_camera_probe(struct platform_device *pdev)
 
        pcdev->hclk_cpu_display = clk_get(&pdev->dev, "hclk_cpu_display");
        pcdev->vip_slave = clk_get(&pdev->dev, "vip_slave");
-       pcdev->vip = clk_get(&pdev->dev,"vip");
+       pcdev->vip_out = clk_get(&pdev->dev,"vip_out");
        pcdev->vip_input = clk_get(&pdev->dev,"vip_input");
        pcdev->vip_bus = clk_get(&pdev->dev, "vip_bus");
 
        pcdev->hclk_disp_matrix = clk_get(&pdev->dev,"hclk_disp_matrix");
        pcdev->vip_matrix = clk_get(&pdev->dev,"vip_matrix");
 
+       pcdev->pd_display = clk_get(&pdev->dev,"pd_display");
+
+       pcdev->zoominfo.zoom_rate = 100;
+
     if (!pcdev->aclk_ddr_lcdc || !pcdev->aclk_disp_matrix ||  !pcdev->hclk_cpu_display ||
-               !pcdev->vip_slave || !pcdev->vip || !pcdev->vip_input || !pcdev->vip_bus ||
-               IS_ERR(pcdev->aclk_ddr_lcdc) || IS_ERR(pcdev->aclk_disp_matrix) ||  IS_ERR(pcdev->hclk_cpu_display) ||
-               IS_ERR(pcdev->vip_slave) || IS_ERR(pcdev->vip) || IS_ERR(pcdev->vip_input) || IS_ERR(pcdev->vip_bus))  {
+               !pcdev->vip_slave || !pcdev->vip_out || !pcdev->vip_input || !pcdev->vip_bus || !pcdev->pd_display ||
+               IS_ERR(pcdev->aclk_ddr_lcdc) || IS_ERR(pcdev->aclk_disp_matrix) ||  IS_ERR(pcdev->hclk_cpu_display) || IS_ERR(pcdev->pd_display) ||
+               IS_ERR(pcdev->vip_slave) || IS_ERR(pcdev->vip_out) || IS_ERR(pcdev->vip_input) || IS_ERR(pcdev->vip_bus))  {
 
         RK29CAMERA_TR(KERN_ERR "failed to get vip_clk(axi) source\n");
         err = -ENOENT;
@@ -1465,15 +2349,31 @@ static int rk29_camera_probe(struct platform_device *pdev)
        if (pcdev->pdata && (strcmp(pcdev->pdata->meminfo.name,"camera_ipp_mem")==0)) {
                pcdev->vipmem_phybase = pcdev->pdata->meminfo.start;
                pcdev->vipmem_size = pcdev->pdata->meminfo.size;
+
+        if (!request_mem_region(pcdev->vipmem_phybase,pcdev->vipmem_size,"rk29_vipmem")) {
+            err = -EBUSY;
+            goto exit_ioremap_vipmem;
+        }
+        pcdev->vipmem_virbase = ioremap_cached(pcdev->vipmem_phybase,pcdev->vipmem_size);
+        if (pcdev->vipmem_virbase == NULL) {
+            dev_err(pcdev->dev, "ioremap() of vip internal memory(Ex:IPP process/raw process) failed\n");
+            err = -ENXIO;
+            goto exit_ioremap_vipmem;
+        } 
+               
                RK29CAMERA_DG("\n%s Memory(start:0x%x size:0x%x) for IPP obtain \n",__FUNCTION__, pcdev->pdata->meminfo.start,pcdev->pdata->meminfo.size);
        } else {
                RK29CAMERA_TR("\n%s Memory for IPP have not obtain! IPP Function is fail\n",__FUNCTION__);
                pcdev->vipmem_phybase = 0;
                pcdev->vipmem_size = 0;
+        pcdev->vipmem_virbase = 0;
        }
        #endif
     INIT_LIST_HEAD(&pcdev->capture);
+    INIT_LIST_HEAD(&pcdev->camera_work_queue);
     spin_lock_init(&pcdev->lock);
+    spin_lock_init(&pcdev->camera_work_lock);
+    sema_init(&pcdev->zoominfo.sem,1);
 
     /*
      * Request the regions.
@@ -1503,11 +2403,17 @@ static int rk29_camera_probe(struct platform_device *pdev)
         goto exit_reqirq;
     }
 
-       pcdev->camera_wq = create_workqueue("camera wq");
+       pcdev->camera_wq = create_workqueue("rk_camera_workqueue");
        if (pcdev->camera_wq == NULL)
                goto exit_free_irq;
        INIT_WORK(&pcdev->camera_reinit_work, rk29_camera_reinit_work);
 
+    for (i=0; i<2; i++) {
+        pcdev->icd_frmival[i].icd = NULL;
+        pcdev->icd_frmival[i].fival_list = kzalloc(sizeof(struct rk29_camera_frmivalenum),GFP_KERNEL);
+        
+    }
+
     pcdev->soc_host.drv_name   = RK29_CAM_DRV_NAME;
     pcdev->soc_host.ops                = &rk29_soc_camera_host_ops;
     pcdev->soc_host.priv               = pcdev;
@@ -1520,11 +2426,28 @@ static int rk29_camera_probe(struct platform_device *pdev)
 
        hrtimer_init(&pcdev->fps_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        pcdev->fps_timer.function = rk29_camera_fps_func;
+    pcdev->icd_cb.sensor_cb = NULL;
 
+#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_IPP)
+    pcdev->icd_cb.scale_crop_cb = rk29_camera_scale_crop_ipp;
+#elif (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_ARM)
+    pcdev->icd_cb.scale_crop_cb = rk29_camera_scale_crop_arm;
+#endif
     RK29CAMERA_DG("%s..%s..%d  \n",__FUNCTION__,__FILE__,__LINE__);
     return 0;
 
 exit_free_irq:
+    
+    for (i=0; i<2; i++) {
+        fival_list = pcdev->icd_frmival[i].fival_list;
+        fival_nxt = fival_list;
+        while(fival_nxt != NULL) {
+            fival_nxt = fival_list->nxt;
+            kfree(fival_list);
+            fival_list = fival_nxt;
+        }
+    }
+    
     free_irq(pcdev->irq, pcdev);
        if (pcdev->camera_wq) {
                destroy_workqueue(pcdev->camera_wq);
@@ -1534,6 +2457,10 @@ exit_reqirq:
     iounmap(pcdev->base);
 exit_ioremap:
     release_mem_region(res->start, res->end - res->start + 1);
+exit_ioremap_vipmem:
+    if (pcdev->vipmem_virbase)
+        iounmap(pcdev->vipmem_virbase);
+    release_mem_region(pcdev->vipmem_phybase,pcdev->vipmem_size);
 exit_reqmem:
     if (pcdev->aclk_ddr_lcdc) {
                clk_put(pcdev->aclk_ddr_lcdc);
@@ -1551,9 +2478,9 @@ exit_reqmem:
                clk_put(pcdev->vip_slave);
                pcdev->vip_slave = NULL;
     }
-       if (pcdev->vip) {
-               clk_put(pcdev->vip);
-               pcdev->vip = NULL;
+       if (pcdev->vip_out) {
+               clk_put(pcdev->vip_out);
+               pcdev->vip_out = NULL;
     }
        if (pcdev->vip_input) {
                clk_put(pcdev->vip_input);
@@ -1582,7 +2509,9 @@ static int __devexit rk29_camera_remove(struct platform_device *pdev)
 {
     struct rk29_camera_dev *pcdev = platform_get_drvdata(pdev);
     struct resource *res;
-
+    struct rk29_camera_frmivalenum *fival_list,*fival_nxt;
+    int i;
+    
     free_irq(pcdev->irq, pcdev);
 
        if (pcdev->camera_wq) {
@@ -1590,8 +2519,21 @@ static int __devexit rk29_camera_remove(struct platform_device *pdev)
                pcdev->camera_wq = NULL;
        }
 
+    for (i=0; i<2; i++) {
+        fival_list = pcdev->icd_frmival[i].fival_list;
+        fival_nxt = fival_list;
+        while(fival_nxt != NULL) {
+            fival_nxt = fival_list->nxt;
+            kfree(fival_list);
+            fival_list = fival_nxt;
+        }
+    }
+
     soc_camera_host_unregister(&pcdev->soc_host);
 
+    iounmap((void __iomem*)pcdev->vipmem_phybase);
+    release_mem_region(pcdev->vipmem_phybase, pcdev->vipmem_size);
+
     res = pcdev->res;
     release_mem_region(res->start, res->end - res->start + 1);
 
@@ -1634,3 +2576,4 @@ module_exit(rk29_camera_exit);
 MODULE_DESCRIPTION("RK29 Soc Camera Host driver");
 MODULE_AUTHOR("ddl <ddl@rock-chips>");
 MODULE_LICENSE("GPL");
+#endif