camera: camera driver support enum frame interval
authorddl <ddl@rockchip.com>
Wed, 28 Sep 2011 03:51:05 +0000 (11:51 +0800)
committerddl <ddl@rockchip.com>
Wed, 28 Sep 2011 08:44:39 +0000 (16:44 +0800)
drivers/media/video/rk29_camera_oneframe.c
drivers/media/video/soc_camera.c
include/media/soc_camera.h

index f1e3350ca374b5fadd3a6d33839dcc465452b071..884ae3db704ac7fec5ab5b511dc0504d129c9445 100755 (executable)
@@ -130,7 +130,7 @@ module_param(debug, int, S_IRUGO|S_IWUSR);
 #define CAM_IPPWORK_IS_EN()     ((pcdev->host_width != pcdev->icd->user_width) || (pcdev->host_height != pcdev->icd->user_height))                                  
 
 //Configure Macro
-#define RK29_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 2)
+#define RK29_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 3)
 
 /* limit to rk29 hardware capabilities */
 #define RK29_CAM_BUS_PARAM   (SOCAM_MASTER |\
@@ -196,6 +196,16 @@ struct rk29_camera_work
        struct rk29_camera_dev *pcdev;
        struct work_struct work;
 };
+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_dev
 {
     struct soc_camera_host     soc_host;
@@ -248,6 +258,7 @@ struct rk29_camera_dev
        struct work_struct camera_reinit_work;
     int icd_init;
     rk29_camera_sensor_cb_s icd_cb;
+    struct rk29_camera_frmivalinfo icd_frmival[2];
 };
 static DEFINE_MUTEX(camera_lock);
 static const char *rk29_cam_driver_description = "RK29_Camera";
@@ -742,8 +753,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) {
@@ -781,6 +793,28 @@ static int rk29_camera_add_device(struct soc_camera_device *icd)
     
     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);
 
@@ -1468,11 +1502,73 @@ static void rk29_camera_reinit_work(struct work_struct *work)
 }
 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)) {
+
+                if (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->fps+2;
+                    fival_nxt->fival.discrete.numerator = 1;
+                    fival_nxt->fival.type = V4L2_FRMIVAL_TYPE_DISCRETE;
+                } else {                
+                    if (abs(rk29_camdev_info_ptr->fps + 2 - fival_nxt->fival.discrete.numerator) > 2) {
+                        fival_nxt->fival.discrete.denominator = rk29_camdev_info_ptr->fps+2;
+                        fival_nxt->fival.discrete.numerator = 1;
+                        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->fps+2;
+                fival_pre->nxt->fival.discrete.numerator = 1;
+                fival_pre->nxt->fival.type = V4L2_FRMIVAL_TYPE_DISCRETE;
+                rec_flag = 1;
+                fival_rec = fival_pre->nxt;
+            }
+        }
        }
 
        return HRTIMER_NORESTART;
@@ -1490,7 +1586,7 @@ static int rk29_camera_s_stream(struct soc_camera_device *icd, int enable)
        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;
@@ -1503,7 +1599,44 @@ 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;
+    int i,ret = 0;
+    
+    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 == fival->index)
+                    break;
+                i++;
+            }                
+            fival_list = fival_list->nxt;                
+        }
+        
+        if ((i==fival->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;
+    }
 
+    return ret;
+}
 static struct soc_camera_host_ops rk29_soc_camera_host_ops =
 {
     .owner             = THIS_MODULE,
@@ -1511,6 +1644,7 @@ 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,
     .put_formats       = rk29_camera_put_formats,
@@ -1522,12 +1656,14 @@ static struct soc_camera_host_ops rk29_soc_camera_host_ops =
     .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 */
+    
 };
 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__);
@@ -1633,6 +1769,12 @@ static int rk29_camera_probe(struct platform_device *pdev)
                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;
@@ -1651,6 +1793,17 @@ static int rk29_camera_probe(struct platform_device *pdev)
     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);
@@ -1708,7 +1861,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) {
@@ -1716,6 +1871,16 @@ 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);
 
     res = pcdev->res;
index db07d81cfe550363aceb6136beb466e28ee3c871..447090a5198d22c8de9e6a18a403e28d6b62ea8f 100644 (file)
@@ -552,7 +552,27 @@ unlock:
 
        return ret;
 }
+static int soc_camera_enum_frameintervals (struct file *file, void  *priv,
+                                          struct v4l2_frmivalenum *fival)
+{
+    struct soc_camera_file *icf = file->private_data;
+       struct soc_camera_device *icd = icf->icd;
+       const struct soc_camera_data_format *format;
+    struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+    struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+    int ret;
+    
+       WARN_ON(priv != file->private_data);
+
+    ret = v4l2_subdev_call(sd, video, enum_frameintervals, fival);
+    if (ret == -ENOIOCTLCMD) 
+        if (ici->ops->enum_frameinervals)
+           ret = ici->ops->enum_frameinervals(icd, fival); 
+        else 
+           ret = -ENOIOCTLCMD;
 
+    return ret;
+}
 static int soc_camera_enum_fmt_vid_cap(struct file *file, void  *priv,
                                       struct v4l2_fmtdesc *f)
 {
@@ -1364,13 +1384,13 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
        .vidioc_streamon         = soc_camera_streamon,
        .vidioc_streamoff        = soc_camera_streamoff,
        .vidioc_queryctrl        = soc_camera_queryctrl,
-        .vidioc_querymenu       = soc_camera_querymenu,                            /* ddl@rock-chips.com:   Add ioctrl - vidioc_querymenu for soc-camera */
+        .vidioc_querymenu       = soc_camera_querymenu,     /* ddl@rock-chips.com:   Add ioctrl - vidioc_querymenu for soc-camera */
        .vidioc_g_ctrl           = soc_camera_g_ctrl,
        .vidioc_s_ctrl           = soc_camera_s_ctrl,
-       .vidioc_g_ext_ctrls    = soc_camera_g_ext_ctrl,                                 /* ddl@rock-chips.com:   Add ioctrl - vidioc_g_ext_ctrls for soc-camera */
-       .vidioc_s_ext_ctrls    = soc_camera_s_ext_ctrl,                                 /* ddl@rock-chips.com:   Add ioctrl - vidioc_s_ext_ctrls for soc-camera */
-       .vidioc_try_ext_ctrls    = soc_camera_try_ext_ctrl,                         /* ddl@rock-chips.com:   Add ioctrl - vidioc_try_ext_ctrls for soc-camera */
-
+       .vidioc_g_ext_ctrls    = soc_camera_g_ext_ctrl,   /* ddl@rock-chips.com:   Add ioctrl - vidioc_g_ext_ctrls for soc-camera */
+       .vidioc_s_ext_ctrls    = soc_camera_s_ext_ctrl,   /* ddl@rock-chips.com:   Add ioctrl - vidioc_s_ext_ctrls for soc-camera */
+       .vidioc_try_ext_ctrls    = soc_camera_try_ext_ctrl,/* ddl@rock-chips.com:   Add ioctrl - vidioc_try_ext_ctrls for soc-camera */
+    .vidioc_enum_frameintervals = soc_camera_enum_frameintervals,/* ddl@rock-chips.com:   Add ioctrl - VIDIOC_ENUM_FRAMEINTERVALS for soc-camera */
        .vidioc_cropcap          = soc_camera_cropcap,
        .vidioc_g_crop           = soc_camera_g_crop,
        .vidioc_s_crop           = soc_camera_s_crop,
index 76ac70e66da22798995fcee303f25b9677b0da71..3455165ee82b487e20969c64d10498e09455e69d 100644 (file)
@@ -65,6 +65,7 @@ struct soc_camera_host_ops {
        void (*remove)(struct soc_camera_device *);
        int (*suspend)(struct soc_camera_device *, pm_message_t);
        int (*resume)(struct soc_camera_device *);
+    int (*enum_frameinervals)(struct soc_camera_device *, struct v4l2_frmivalenum *);
        /*
         * .get_formats() is called for each client device format, but
         * .put_formats() is only called once. Further, if any of the calls to