From 583b8bda5ca2b80236c39388dc7ca830bf8d2c04 Mon Sep 17 00:00:00 2001 From: ddl Date: Wed, 28 Sep 2011 11:51:05 +0800 Subject: [PATCH] camera: camera driver support enum frame interval --- drivers/media/video/rk29_camera_oneframe.c | 179 ++++++++++++++++++++- drivers/media/video/soc_camera.c | 30 +++- include/media/soc_camera.h | 1 + 3 files changed, 198 insertions(+), 12 deletions(-) diff --git a/drivers/media/video/rk29_camera_oneframe.c b/drivers/media/video/rk29_camera_oneframe.c index f1e3350ca374..884ae3db704a 100755 --- a/drivers/media/video/rk29_camera_oneframe.c +++ b/drivers/media/video/rk29_camera_oneframe.c @@ -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; diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index db07d81cfe55..447090a5198d 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -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, diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index 76ac70e66da2..3455165ee82b 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -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 -- 2.34.1