V4L/DVB (4909): Add s/g_parm to cafe_ccic
authorJonathan Corbet <corbet@lwn.net>
Fri, 1 Dec 2006 18:50:59 +0000 (15:50 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Sun, 10 Dec 2006 11:05:31 +0000 (09:05 -0200)
Add s/g_parm support allowing applications to tweak the frame rate.

Signed-off-by: Jonathan Corbet <corbet@lwn.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
drivers/media/video/cafe_ccic.c
drivers/media/video/ov7670.c

index 9d9844e22951f2dbb2532ef3ba84f64f756e4fc3..e347c7ebc98415b6c8dc0d0d3f0492d0440740a4 100644 (file)
@@ -1671,6 +1671,37 @@ static int cafe_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a)
        return 0;
 }
 
+/*
+ * G/S_PARM.  Most of this is done by the sensor, but we are
+ * the level which controls the number of read buffers.
+ */
+static int cafe_vidioc_g_parm(struct file *filp, void *priv,
+               struct v4l2_streamparm *parms)
+{
+       struct cafe_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = __cafe_cam_cmd(cam, VIDIOC_G_PARM, parms);
+       mutex_unlock(&cam->s_mutex);
+       parms->parm.capture.readbuffers = n_dma_bufs;
+       return ret;
+}
+
+static int cafe_vidioc_s_parm(struct file *filp, void *priv,
+               struct v4l2_streamparm *parms)
+{
+       struct cafe_camera *cam = priv;
+       int ret;
+
+       mutex_lock(&cam->s_mutex);
+       ret = __cafe_cam_cmd(cam, VIDIOC_S_PARM, parms);
+       mutex_unlock(&cam->s_mutex);
+       parms->parm.capture.readbuffers = n_dma_bufs;
+       return ret;
+}
+
+
 static void cafe_v4l_dev_release(struct video_device *vd)
 {
        struct cafe_camera *cam = container_of(vd, struct cafe_camera, v4ldev);
@@ -1724,7 +1755,8 @@ static struct video_device cafe_v4l_template = {
        .vidioc_queryctrl       = cafe_vidioc_queryctrl,
        .vidioc_g_ctrl          = cafe_vidioc_g_ctrl,
        .vidioc_s_ctrl          = cafe_vidioc_s_ctrl,
-       /* Do cropping someday */
+       .vidioc_g_parm          = cafe_vidioc_g_parm,
+       .vidioc_s_parm          = cafe_vidioc_s_parm,
 };
 
 
index 7d380d76338a58c75bb46a2b26120d26c2b426d7..89dd18c3c5cc43e4a281fd450101ce7c1e50a883 100644 (file)
@@ -35,6 +35,11 @@ MODULE_LICENSE("GPL");
 #define QCIF_WIDTH     176
 #define        QCIF_HEIGHT     144
 
+/*
+ * Our nominal (default) frame rate.
+ */
+#define OV7670_FRAME_RATE 30
+
 /*
  * The 7670 sits on i2c with ID 0x42
  */
@@ -291,7 +296,7 @@ static struct regval_list ov7670_default_regs[] = {
        { 0xc9, 0x60 },         { REG_COM16, 0x38 },
        { 0x56, 0x40 },
 
-       { 0x34, 0x11 },         { REG_COM11, COM11_EXP },
+       { 0x34, 0x11 },         { REG_COM11, COM11_EXP|COM11_HZAUTO },
        { 0xa4, 0x88 },         { 0x96, 0 },
        { 0x97, 0x30 },         { 0x98, 0x20 },
        { 0x99, 0x30 },         { 0x9a, 0x84 },
@@ -721,6 +726,63 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt)
        return 0;
 }
 
+/*
+ * Implement G/S_PARM.  There is a "high quality" mode we could try
+ * to do someday; for now, we just do the frame rate tweak.
+ */
+static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
+{
+       struct v4l2_captureparm *cp = &parms->parm.capture;
+       unsigned char clkrc;
+       int ret;
+
+       if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       ret = ov7670_read(c, REG_CLKRC, &clkrc);
+       if (ret < 0)
+               return ret;
+       memset(cp, 0, sizeof(struct v4l2_captureparm));
+       cp->capability = V4L2_CAP_TIMEPERFRAME;
+       cp->timeperframe.numerator = 1;
+       cp->timeperframe.denominator = OV7670_FRAME_RATE;
+       if ((clkrc & CLK_EXT) == 0 && (clkrc & CLK_SCALE) > 1)
+               cp->timeperframe.denominator /= (clkrc & CLK_SCALE);
+       return 0;
+}
+
+static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
+{
+       struct v4l2_captureparm *cp = &parms->parm.capture;
+       struct v4l2_fract *tpf = &cp->timeperframe;
+       unsigned char clkrc;
+       int ret, div;
+
+       if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (cp->extendedmode != 0)
+               return -EINVAL;
+       /*
+        * CLKRC has a reserved bit, so let's preserve it.
+        */
+       ret = ov7670_read(c, REG_CLKRC, &clkrc);
+       if (ret < 0)
+               return ret;
+       if (tpf->numerator == 0 || tpf->denominator == 0)
+               div = 1;  /* Reset to full rate */
+       else
+               div = (tpf->numerator*OV7670_FRAME_RATE)/tpf->denominator;
+       if (div == 0)
+               div = 1;
+       else if (div > CLK_SCALE)
+               div = CLK_SCALE;
+       clkrc = (clkrc & 0x80) | div;
+       tpf->numerator = 1;
+       tpf->denominator = OV7670_FRAME_RATE/div;
+       return ov7670_write(c, REG_CLKRC, clkrc);
+}
+
+
+
 /*
  * Code for dealing with controls.
  */
@@ -1231,10 +1293,10 @@ static int ov7670_command(struct i2c_client *client, unsigned int cmd,
                return ov7670_s_ctrl(client, (struct v4l2_control *) arg);
        case VIDIOC_G_CTRL:
                return ov7670_g_ctrl(client, (struct v4l2_control *) arg);
-       /* Todo:
-          g/s_parm
-          initialization
-       */
+       case VIDIOC_S_PARM:
+               return ov7670_s_parm(client, (struct v4l2_streamparm *) arg);
+       case VIDIOC_G_PARM:
+               return ov7670_g_parm(client, (struct v4l2_streamparm *) arg);
        }
        return -EINVAL;
 }