From c8f5b2f5607e78c61df229259c539a5d9488a013 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Fri, 1 Dec 2006 15:50:59 -0300 Subject: [PATCH] V4L/DVB (4909): Add s/g_parm to cafe_ccic Add s/g_parm support allowing applications to tweak the frame rate. Signed-off-by: Jonathan Corbet Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cafe_ccic.c | 34 +++++++++++++++- drivers/media/video/ov7670.c | 72 ++++++++++++++++++++++++++++++--- 2 files changed, 100 insertions(+), 6 deletions(-) diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index 9d9844e229..e347c7ebc9 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -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, }; diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c index 7d380d7633..89dd18c3c5 100644 --- a/drivers/media/video/ov7670.c +++ b/drivers/media/video/ov7670.c @@ -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; } -- 2.39.5